Quick Reference Manual
Quick Reference Manual
2.11-0
Reference
Manual
OpenQM
Reference Manual
Ladybridge Systems Limited
OpenQM
All rights reserved. No parts of this work may be reproduced in any form or by any means - graphic, electronic, or
mechanical, including photocopying, recording, taping, or information storage and retrieval systems - without the
written permission of the publisher.
Products that are referred to in this document may be either trademarks and/or registered trademarks of the
respective owners. The publisher and the author make no claim to these trademarks.
While every precaution has been taken in the preparation of this document, the publisher and the author assume no
responsibility for errors or omissions, or for damages resulting from the use of information contained in this
document or from the use of programs and source code that may accompany it. In no event shall the publisher and
the author be liable for any loss of profit or any other commercial damage caused or alleged to have been caused
directly or indirectly by this document.
Technical Editor
Martin Phillips
Cover Graphic
Ishimsi
Contents 5
Table of Contents
Index 1355
2.11-0
Part
1
Introduction to the QM Database
8 OpenQM
OpenQM is a database management system that allows you to develop and run applications for
your business or personal use. It includes a wide range of advanced tools and features for complex
applications whilst still allowing relatively painless construction of simpler applications.
OpenQM is the only multivalue database product that is available both as a fully supported closed
source commercial product and in open source form for developers who wish to modify the product
under the terms of the General Public Licence. In common with all GPL software, the open source
version comes with no warranty and no support. This documentation describes the commercial
product though most of what is here should apply equally to the open source.
The name OpenQM is often abbreviated to QM and it is this shorter name (which is the operating
system command used to enter the product) that is used in most places within this documentation.
QM has a high degree of compatibility with other multivalue databases systems such as UniVerse,
PI/open, Prime Information, Unidata, D3, Reality and many more.
Facilities are provided to create data files, enter, modify and retrieve data, produce reports and,
where the data processing operation required cannot be achieved using the supplied tools, to
construct powerful programs with the minimum of effort.
The command processor This includes a comprehensive command set to create, modify,
copy and delete files and data stored in them as well as many
commands to control processing. Developers and system
administrators use the command processor directly. End users of
QM applications do not usually have access to the command
processor but the application software will make use of many of
its features.
The query processor This provides facilities to produce reports from stored data using
an English-like command syntax. The query processor also
provides tools to select data which meets particular criteria and to
perform operations on this data. End users who need to produce
reports may be able to make direct use of the query processor or
they may access it via application interfaces.
QMBasic For those occasions where QM does not provide the desired
functions, QMBasic is a very easy to use programming language
with powerful screen manipulation and data handling functions.
QM extends the language found in other multivalue products to
add modern features such as object oriented programming.
2.11-0
Introduction to the QM Database 9
QMClient API The QMClient API is a set of functions that can be used from
Visual Basic applications to access the QM database. This allows
development of applications with a Windows "look and feel".
There are variants of this API library for use with other languages,
including access from inside QMBasic to allow programs to call
subroutines or execute commands on other servers.
Specific topics:
Document Conventions
Items in bold type (DELETE.FILE for example) are keywords that must be entered as they appear
in the description except that in most instances they may be in either upper or lower case.
Items in italics (file.name) represent places in commands or language statements where some
variable data is required. In this case it is the name of a file.
Items enclosed in curly brackets (e.g. {FORCE}) are optional parts of a command or statement.
The curly brackets are not part of the data and should not be typed. The descriptions will explain
when the item should be used and what effect it has.
Lists of alternative keywords are shown separated by vertical bars (e.g. {DATA | DICT}).
Items that may be repeated are followed by ellipsis (...). The text explains the rules governing
related items.
The mark characters are represented by IM, FM, VM, SM, TM and VM.
2.11-0
10 OpenQM
There are many different databases available but they all fall into a small number of basic types.
One of these is the relational database such as Oracle or Access. A relational database holds data
in the form of tables in just the same way that we could store information as tables written on
paper.
Consider an order processing system. We need to hold information about the orders that each
customer has placed. Keeping things very simple, at a minimum we might need a table such as that
shown below.
In this simple table, each row represents an order and each column holds data associated with that
order.
Relational databases are built following a set of rules known as the Laws of Normalisation [E.
Codd : "A Relational Model of Data for Large Shared Data Banks", Communications of the ACM,
June 1970]. The process of transforming data to fit the rules of a relational database is called
normalisation and the steps in this process are referred to as first normal form, second normal
form, and so on.
The First Law of Normalisation states that we may not have repeating data. In practical terms this
means that we cannot add extra columns to the right of the table to allow a customer to order more
than one item at the same time.
There are many reasons why the Laws of Normalisation do not allow this, mostly based on the way
in which the data might be stored by the computer system. If we are to observe the First Law of
Normalisation, we must reconstruct our data in some way that removes the additional columns. One
way would be to split an order that has multiple item across several rows of our table.
2.11-0
Introduction to the QM Database 11
Although we can now store as many items in an order as we wish, things have become more
complicated. Firstly, the details of a single order are now split across multiple rows of our table.
Secondly, we have been forced to add an extra column so that we can know how many lines there
are in the order. Also, we have duplicated some information, a step which actually breaks another
of the Laws of Normalisation. To avoid this last complication, a typical implementation of this sort
of data in a fully normalised system (e.g. Oracle or Access) would break the order into two separate
tables, one containing the basic information about the order and the other containing the details of
the items ordered.
Multivalue database products avoid this complication by removing the need to adhere to the First
Law of Normalisation. We allow a single cell of our table to hold more than one value (hence
"multivalue").
If you have spent many years working with fully normalised databases, you are probably shaking
your head and saying that we cannot do this. Yes, we can do it; it's just a different way to hold our
data.
Think about the advantages: The entire order is all held as a single record; there is no redundant
duplication of data; we do not need an item counter.
The end result of this is that our multivalue view of the world is typically much faster than its fully
normalised counterpart though there will always be situations where this model is not ideal. In such
cases, you can freely revert to using the fully normalised approach. Notice that fully normalised
2.11-0
12 OpenQM
data can be stored in a multivalue database. The opposite tends not to be true.
The time has come to introduce some terminology. A typical application will have many tables,
perhaps hundreds or even thousands though the multivalue model usually results in far fewer tables
than in other data models. Each table is stored as a file. The rows of our table are known as
records and the columns as fields (some users refer to these as attributes). The data stored in a
field may be made up of multiple values.
Note how in our multivalued implementation of the above example, the values in the product and
quantity columns are related together. For any particular order, the first product number belongs
with the first quantity, the second product number belongs with the second quantity and so on. A
typical realistic table may have several separate sets of fields that are linked in this way. The
relationship between the values in different fields (e.g. product and quantity above) is referred to as
an association.
By adopting this data model instead of using additional columns, the data model imposes no limit to
the number of items that may be included in an order.
This extended form of the relational database model is at the heart of the QM database. You may
also see it referenced as post-relational, nested table or NF2 (non-first normal form). They all mean
the same thing.
In a multivalue database, the tables can gain a fourth dimension (subvalues). Continuing with the
above example, perhaps we need to record the serial number of each item that we sell. Thus each
value line in the table depicted above would have subvalues containing the serial numbers for each
item supplied. Order 1002 might become
The model described above leads to a very flexible design in which a database record may have any
number of fields (table columns). The entire record and the constituent fields are of variable length,
there being no restriction applied by QM. A record may exist in the database with no data or with
many megabytes of data.
Every record in a data file has to have a unique record id or primary key that identifies that record
as distinct from all other records in the same table and can be used to retrieve the record. In the
above example, the order number would serve this purpose. Although it may be useful to show the
record id as a column in the tabular representation of the data, the record id is not part of the actual
database record but is instead a handle by which it is accessed. Thus the record above has id 1002
and contains five fields representing the date, customer number, product numbers, quantities and
serial numbers.
Internally, a record is stored as a simple character representation of the data. Because the fields are
of variable length, it is necessary to mark where one field ends and the next begins. This is done by
placing a special marker character called a field mark between the fields. A field may be divided
into values by use of value mark characters and values may be further divided by use of subvalue
mark characters.
2.11-0
Introduction to the QM Database 13
The data model defines two additional mark characters. The text mark is typically used to mark
points in text data where newlines should be inserted. This mark character is often inserted by
programs manipulating data in memory rather than being stored in the database. The item mark is
defined mainly for compatibility with other database systems. Its only reserved use within QM is to
separate items in the DATA queue.
When the multivalue data model was originally invented, the upper half of the ASCII character set
was not defined and the last five of the unused character values were adopted for the internal
representation of the mark characters:
Item mark char(255)
Field mark char(254)
Value mark char(253)
Subvalue mark char(252)
Text mark char(251)
The memory representation of a record containing mark characters for use in QMBasic programs is
known as a dynamic array and there are many specialised program operations for working on this
data.
Fields, values within a field and subvalues within a value are numbered from one upwards. By
convention the record key is sometimes referred to as field zero though it is not strictly part of the
dynamic array and references to field zero are only recognised by QM in certain contexts.
The original multivalue database is usually attributed to Dick Pick (hence the frequently used term
"Pick databases") back in 1968 though their origins can be tracked back further. The current D3
database from TigerLogic is a direct descendant of the original Pick product but there have been
many other players along the way, some large, some small. Some of these are significant to the way
in which QM works.
The Reality database, originally implemented on McDonnell Douglas systems but now owned by
Northgate Information Solutions, closely follows the Pick style of operation. The long defunct
Prime Information database from Prime Computer retained the same data model and general
principles but made some fairly significant changes to the command and programming languages.
In the mid-1980's the various companies with multivalue products hit a problem. The world was
standardising on the Unix operating system but these products did not run on Unix. As a result of
this, McDonnell Douglas developed an "open systems" version of Reality (Reality X) and Prime
Computer developed the PI/open database. At the same time, two start up companies appeared each
with their own Unix based multivalue implementation, VMark (UniVerse) and Unidata (Unidata).
These companies set out to capture users from the existing products as well as taking on new users.
The history is long and complex but to bring it up to date in one step, UniVerse and Unidata are
now both owned by Rocket Software.
2.11-0
14 OpenQM
The UniVerse and Unidata products (usually referred to collectively as U2) follow the Information
style of implementation by default but have features that allow them to look more like the Pick style
if required.
QM was originally developed in 1993 for use as an embedded database but not released as a
product in its own right until 2001. Like the U2 products, it is an Information style database but has
options to make it more like Pick for those who need it.
2.11-0
Introduction to the QM Database 15
1.2 Installation
If you are going to try things out as you read this manual, the first thing we need to discuss is how
to install your own version of QM. This section relates only to the commercial QM product. If you
are planning to use the open source version of QM and build your own system, none of what
follows in this section applies to you. Instead, you must download and build the system from its
source code.
Although QM can be supplied on CD, users normally download the software from the OpenQM
website, www.openqm.com, which ensures that you have the latest version of this rapidly
developing product.
If you purchase a commercial QM licence, you are free to download and install new versions as
often as you wish during the free upgrade period (at least one year but this period can be extended).
After this period expires, there will be a charge for upgrades. The software comes with free support
for the first 60 days beyond which time further support is available on a chargeable basis.
On most platforms, you can also use QM in its single user "Personal Version" mode. This is exactly
the same as the commercial product but is restricted for use in non-commercial activities, typically
as a learning environment, and has a low limit on the size of database file that it will support. The
Personal Version comes with no support beyond any help necessary to get it installed.
You will probably not want to install every revision that is released. The product web site includes a
"What's new in recent releases" page that can be used to help decide when an upgrade is desirable.
To download the software, follow the link to the download page and select the appropriate version
for your platform. Right click on the Download link and select Save Target As to copy the install
file to your system. If you need to move the file from the system on which it is downloaded to a
different system for installation, be sure to use a binary mode copy tool.
If you have a commercial licence or are using an evaluation copy of QM, you can also download
the AccuTerm terminal emulator by following the link from the QM download page. The activation
code is included with your QM licence.
The installation process for QM is exactly the same for a new installation and for an upgrade. The
following sections describe the process for each platform.
Installation on Windows
You must have administrator rights on the PC to install QM as it updates restricted system files.
The self-extracting install file has a name of the form qm_2-11-0.exe, where the numeric
components identify the release. Execute this file. The first screen confirms that you are about to
install QM. Click on the Next button to continue.
2.11-0
16 OpenQM
The install process now displays the software licence. Tick the box to say that you accept the terms
of this licence and click on the Next button.
QM can be installed in any convenient location. The default is C:\QMSYS but this can be changed.
An upgrade installation will offer the directory used for the previous installation as the default.
Having selected the installation directory, you will be asked to specify the program group folder
name in the Start menu. This defaults to QM and is probably best left unchanged.
The final step before installation commences is to select the components to be installed. The
components offered are:
QM Database The QM database itself.
QM Help This document as a Windows help file.
QMTerm A simple terminal emulator.
QM Online Documentation Adobe Acrobat style pdf documentation.
QMClient The Visual Basic API for Windows developers.
After the main installation has been performed, the install process displays a screen in which the
authorisation data can be entered as discussed below.
If this is an upgrade installation, you will be asked if the VOC file should be updated in all
accounts. Although this is probably a good idea, users will be asked about upgrading when they
enter QM if it is left until later.
The installation process does not add QM to the Windows PATH environment variable. Depending
on how you plan to operate your system it may be worth adding the bin subdirectory of the QMSYS
account to the PATH variable.
After installation is complete, you may need to make changes to configuration parameters. Although
the default values work well for most systems, installations with many users or a large number of
database tables may require changes. You can always make further changes later.
The self-extracting archive file of the standard install includes the user documentation as a set of
pdf files and a compiled HTML help file for use on the QM server or on other Windows clients.
Individual pdf manuals and a zip file containing a browser based help package are also available on
the download page.
This mode of installation allows you to carry a complete Windows based QM system on a USB
memory stick and use it on any compatible PC without installing any software on the PC itself.
The first step is to prepare the memory stick for use with QM. The stick must comply with the USB
2 standards - older USB 1 sticks cannot be used. Download the USBCONFIG tool from the
OpenQM website onto the PC that you will use to perform the installation. Alternatively, if you
have a Windows version of QM installed on your PC, this tool will already be in the bin
subdirectory of the QMSYS account. Run this program, following the on screen instructions. This
tool creates a file named memstick on the USB memory stick containing the unique id codes for that
stick. The content of this file is only used during licence application, however, you should not
2.11-0
Introduction to the QM Database 17
To install QM, run the standard Windows installation program as described above, ensuring that
the "USB memory device" check box is ticked and the pathname of the target device is correctly
entered on the destination directory screen. The remainder of the installation process is as above.
The drive letter assigned to the USB device may change each time it is inserted. This will not affect
use of QM.
Although the USB installation of QM is intended for single user use via the QMConsole interface
activated by the process described above, it is possible to run network sessions with a USB version
of QM. Because the USB installation is all about not needing to install anything on the host PC, this
cannot use the QMSvc network service. Instead, a USB installation of QM includes the
QMUSBSrvr network management program to allow telnet and QMClient connections. To start
this, open a Command Prompt window and execute the \qmsys\bin\qmusbsrvr program from the
USB device. Network connections run as the user currently logged in on the Windows system.
When installing on a USB device, the QMClient.dll file is installed in the bin subdirectory of the
QMSYS account instead of in the SYSTEM32 subdirectory of Windows on the hard drive. To use
QMClient on a USB installation, it will be necessary to ensure that the PATH environment variable
includes the QMSYS\bin directory. Typically, this can be achieved by a line such as
PATH=\qmsys\bin;%PATH%
in the .bat file that is used to start QM on the USB device.
You must have superuser access rights to install QM as it updates restricted system files. The
self-extracting install file has a name of the form qm_2-11-0 for Linux, qmf_2-11-0 for FreeBSD,
and qmr_2-11-0 for AIX, where the numeric components identify the release. Execute this file.
The installer confirms that you are about to install QM. Note that any existing installation of QM
must have been shut down before installation of a new version.
The compressed install file is unpacked and the software licence is displayed. You must confirm
that you agree with this licence to continue.
QM can be installed in any convenient location. The default is /usr/qmsys but this can be changed.
An alternative default can be set using the QMSYS environment variable.
After the main installation has been performed, the install process displays a screen in which the
authorisation data can be entered as discussed below.
If this is an upgrade installation, you will be asked if the VOC file should be updated in all
accounts. Although this is probably a good idea, users will be asked about upgrading when they
enter QM if it is left until later.
The installation process does not add QM to the operating system PATH environment variable.
2.11-0
18 OpenQM
Depending on how you plan to operate your system it may be worth adding the bin subdirectory of
the QMSYS account to the PATH variable.
The self-extracting archive file of the standard install does not include the user documentation. This
must be downloaded separately from the web site as individual pdf manuals, a zip file of all the
manuals, a compiled HTML help file for use on Windows clients or a zip file containing a browser
based help package for use on all platforms.
Some Unix systems (e.g. AIX) have a kernel configuration parameter that sets the limit on the
number of files that may be opened simultaneously by one process. The name of this parameter
differs across operating systems but is often NOFILES. QM will automatically handle reaching this
limit but there will be a performance degradation caused by needing to close and reopen files to stay
within the limit. Theer may also be a system wide file limit kernel parameter, often called NFILE
which also needs to be set carefully.
It is recommended that the qmlnxd daemon should be used to monitor for incoming network
connections that are to be routed directly to QM processes (default port 4242 for telnet, 4243 for
QMClient, additional ports for port mapping), however, it is possible to use the inetd (etc) network
service that is part of the operating system to do this job. In this case, the PORT and QMCLIENT
configuration parameters should be set to zero and it will be necessary to create a files in the
/etc/xinetd.d directory for each port to be monitored. The format of these is similar to the example
below.
service qmsrvr
{
id = qmsrvr
port = 4242
bind = 0.0.0.0
type = UNLISTED
protocol = tcp
flags = REUSE NAMEINARGS
socket_type = stream
wait = no
user = root
server = /usr/qmsys/bin/qm
server_args = /usr/qmsys/bin/qm -n
log_on_failure += USERID
disable = no
}
For the QMClient port, the server_args must also include the -q option. It will also be necessary to
add lines to the /etc/services file to reference these new services.
At this release, the Mac install is performed using a variant of the Linux install process. A
graphical installer similar to those used by other Mac software will be introduced in a future
release.
The self-extracting install file has a name of the form qmm_2-11-0, where the numeric components
identify the release.
Open a terminal window and gain administrative rights (consult your operating system
documentation if this concept is new to you). Execute the downloaded file.
2.11-0
Introduction to the QM Database 19
The installer confirms that you are about to install QM. Note that any existing installation of QM
must have been shut down before installation of a new version.
The compressed install file is unpacked and the software licence is displayed. You must confirm
that you agree with this licence to continue.
QM can be installed in any convenient location. The default is /usr/qmsys but Mac users may prefer
to use /var/qmsys. An alternative default can be set using the QMSYS environment variable.
After the main installation has been performed, the install process displays a screen in which the
authorisation data can be entered as discussed below.
If this is an upgrade installation, you will be asked if the VOC file should be updated in all
accounts. Although this is probably a good idea, users will be asked about upgrading when they
enter QM if it is left until later.
The installation process does not add QM to the operating system PATH environment variable.
Depending on how you plan to operate your system it may be worth adding the bin subdirectory of
the QMSYS account to the PATH variable.
The self-extracting archive file of the standard install does not include the user documentation. This
must be downloaded separately from the web site as individual pdf manuals, a zip file of all the
manuals, a compiled HTML help file for use on Windows clients or a zip file containing a browser
based help package for use on all platforms.
At this release, the Mac install is performed using a variant of the Linux install process. A
graphical installer similar to those used by other Mac software will be introduced in a future
release.
The self-extracting install file has a name of the form qmmi_2-11-0, where the numeric components
identify the release.
The installer confirms that you are about to install QM. Note that any existing installation of QM
must have been shut down before installation of a new version.
The compressed install file is unpacked and the software licence is displayed. You must confirm
that you agree with this licence to continue.
QM can be installed in any convenient location. The default is /usr/qmsys but Mac users may prefer
to use /var/qmsys. An alternative default can be set using the QMSYS environment variable.
After the main installation has been performed, the install process displays a screen in which the
authorisation data can be entered as discussed below.
If this is an upgrade installation, you will be asked if the VOC file should be updated in all
2.11-0
20 OpenQM
accounts. Although this is probably a good idea, users will be asked about upgrading when they
enter QM if it is left until later.
From OS X 10.6, the installation process adds the pathname of the QM binaries to the /etc/paths.d
directory which is used to construct the PATH environment variable on login. This will take effect
from the next login. On older versions of the operating system, the installer does not add QM to the
operating system PATH environment variable. Depending on how you plan to operate your system
it may be worth adding the bin subdirectory of the QMSYS account to the PATH variable in a
profile script.
The self-extracting archive file of the standard install does not include the user documentation. This
must be downloaded separately from the web site as individual pdf manuals, a zip file of all the
manuals, a compiled HTML help file for use on Windows clients or a zip file containing a browser
based help package for use on all platforms.
Installation on a PDA
Note that many devices that run Windows CE or Windows Mobile do not provide the full
functionality of a PDA. Users should verify device compatibility.
There are two alternative install files available; qmpda_2-11-0.exe for Windows Mobile 5.0 and
qmpce_2-11-0.exe for the older Windows CE. The 2-11-0 component of the name identifies the
release.
The install file should be executed on a Windows PC to which the PDA is connected via
ActiveSync. QM must be installed under the Program Files directory which is the default offered by
the installer. If this is an upgrade, you will be asked whether to overwrite or remove existing files.
Choose the overwrite option. After the installer has copied the new version to the PDA, complete
installation by clicking on the Launch button. This will display a modified version of the licence
screen shown below.
Licence Authorisation
QM will request licence authorisation data entry as part of the installation process described above.
A new licence can also be applied at any time by use of the UPDATE.LICENCE command in the
QMSYS account or from the command prompt by executing QM with the -L option (case
insensitive).
2.11-0
Introduction to the QM Database 21
You need to enter the details in the boxes surrounded by square brackets as given on your licence
paperwork.
Licence number The unique 10 digit number identifying this licence. If you are using
the Personal Version, enter the word Personal and leave all further
boxes empty.
Max users The maximum number of concurrent processes including Windows
GUI processes such as QMClient.
Expiry date The last date on which this licence is valid.
Authorisation code A case insensitive sequence required to validate your licence details.
Security number A number required to further validate your licence details.
Site text This must be entered exactly as on your licence form.
The system id is used to tie a licence to a specific machine (or USB memory device for a Windows
USB installation). The normal licensing procedure starts with a short term licence that will install
on any system. During the life of this licence, you should supply the system id to your dealer who
will then send you the final permanent licence.
If you subsequently move the QM software to a new system, you will need to arrange with your
dealer to receive a new licence. There will normally be no charge for this so long as you undertake
to remove the old installation. Your licence document will also show how to obtain a short term
emergency licence if you need to move your QM installation to a new system at a time when your
dealer is unavailable.
When installing a new release of QM over an existing version, the previous licence details are
displayed as the defaults. To preserve these either press the return key in each field in turn or use
ctrl-X to exit from the screen.
When updating the licence on a system that uses data encryption, the install process will ask for
entry of the master key if the licence number or system id code has changed.
Post-Installation Questions
On completion of a new installation (not an upgrade), the installer will ask whether QM's internal
2.11-0
22 OpenQM
security system is to be enabled. For more information on this topic, see Application Level Security.
The setting of this option can be amended later using the SECURITY command if necessary.
After a new installation, you may need to set the value of some configuration parameters. In
particular, the values of NUMFILES (the maximum number of files that can be open at the
application level simultaneously) and NUMLOCKS (the maximum number of concurrent record
locks) need to be appropriate to your use of the system.
Many operating systems have a limit on the number of files that can be open simultaneously either
per-process or system wide. It may be necessary to increase this to match the setting of the
NUMFILES parameter. Note that opening a dynamic hashed file in QM requires two operating
system files to be opened. Each alternate key index adds a further operating system file.
Upgrades
All QM licences include a free upgrade period during which new versions can be installed to take
advantage of new features. The upgrade period is initially either one or ten years and can be
extended when it is close to expiry.
To install an upgrade:
1. Download the software from the OpenQM web site.
2. All QM users must log off.
3. On Windows, use the QM Network Control tool from the QM program group to shutdown
the QMSvc service. On other platforms, use qm -stop to shutdown QM.
4. Follow the installation process described above.
Several files within the QMSYS account will be updated but all user accounts will remain
unchanged except for optional updating of the VOC file for any new items. Note that the
NEWVOC file which contains the items to go into the VOC of a new account is completely
overwritten by an upgrade. Where there are site specific items that should be added to the VOC of
all new accounts, it is recommended that a file such as NEWVOC.MODS is created to hold these
and, on completion of an upgrade, this is copied into NEWVOC using a command such as
COPY FROM NEWVOC.MODS TO NEWVOC ALL
The various multivalue database products implement some features differently. This results in
syntactic or semantic differences in some commands or programming statements. If you are
migrating an application to QM from another multivalue product, there are facilities to give closer
compatibility without needing to make extensive modifications to the application.
The OPTION command can be used to enable features that are mostly concerned with the
command environment. This command is typically embedded in the LOGIN paragraph that runs
automatically when a user enters the system.
The QMBasic $MODE directive enables features that affect programming language syntax or
semantics. Although developers could put this directive into every program, it is usually simpler to
2.11-0
Introduction to the QM Database 23
create a record named $BASIC.OPTIONS in the program file to apply mode settings (and other
features) to every program in that file. Alternatively, this record can be put in the VOC file from
where it will affect all programs in files that do not have their own $BASIC.OPTIONS record. For
more details of this record, see the BASIC command.
It is recommended that after migration to QM, developers should spend some time reading the
documentation to discover features of QM that were not in the previous environment so that they
can take advantage of these.
2.11-0
24 OpenQM
QM maintains some persistent data in shared memory that is accessed by all QM users. This
includes the locking tables, user tables, configuration data and other information that must be
visible to all QM user processes.
Windows Systems
On a Windows system except for Windows 98/ME, the shared memory is created by the QMSvc
service. This service must be running for QM to be usable.
Windows 98/ME uses the QMSrvr program in place of QMSvc for network access. QMConsole
sessions on Windows 98/ME do not require that this program is running.
QMSvc or QMSrvr can be started and stopped from the QM Network Control program group item.
In addition, QMSvc can be started, stopped or restarted from the Windows Control Panel Services
screen or by use of the commands shown below from a Command Prompt window when logged in
to Windows with administrator rights.
qmsvc -start
qmsvc -stop
qmsvc -restart
This assumes that the bin subdirectory of the QMSYS account is in the program search path. If not,
the full pathname of the qmsvc executable must be used.
Shutting down the QMSvc service will automatically logout all QM users.
Other Platforms
On other platforms, the QM shared memory must be explicitly loaded before users can enter QM. It
may be manually discarded if required.
On some platforms, the installation process will add system startup and shutdown scripts to start
QM when the system is booted and to take it down gracefully when the system is shutdown. On
other platforms, it may be necessary to do this manually, if desired. QM may be started, stopped or
restarted at any time by typing the commands shown below from the operating system shell.
qm -start
qm -stop
qm -restart
If you are not logged in as root, you may need to prefix these commands with sudo.
2.11-0
Introduction to the QM Database 25
Sometimes it is useful to execute a paragraph or other command script when QM starts. This can
be achieved using the STARTUP configuration parameter to specify the command to be executed.
Multiple STARTUP parameters may be present, each command running as a separate QM
process..
On Windows, the command is run when QMSvc starts. On other platforms, the command is run
when the qm -start command is used.
Because the SYSTEM and root users have privilege levels that may be higher than is appropriate
for the tasks performed by processes initiated by the STARTUP configuration parameter, these
processes can use the AUTHENTICATE command to authenticate user credentials and reduce the
privilege level to that of some other user known to the operating system.
Alternatively, the parameter may include an account name, user name and password
STARTUP=command;account username password
This command will be run using the specified user name and account. Again, the command may not
include double quotes. Because the configuration parameter file is readable by all users, it is useful
to encrypt the password using the AUTHKEY command (described with AUTHENTICATE). In
this case the encrypted password is prefixed by "ENCR:", for example
STARTUP=PHANTOM MAILSERVER;MAIL GSMITH ENCR:2CB51EFC17832221
A startup process will run the MASTER.LOGIN and LOGIN paragraphs in the same way as any
other QM session. A QM process can recognise that it is a startup command by testing the value of
the @TTY variable which will contain "startup". Phantoms started from the startup process will
have this variable set to "phantom".
2.11-0
26 OpenQM
1.4 Deinstallation
Should it be necessary to uninstall the QM database, the following steps are required:
Windows
Execute the QM Uninstaller from the QM program group.
PDA
Use the File Manager to delete QMSYS from the Program Files directory.
Other Platforms
1. Login with superuser rights and type "qm -stop".
2. Run the uninstall program in the qmsys/bin directory.
2.11-0
Introduction to the QM Database 27
1.5 Accounts
A new account may be created from any other account by use of the CREATE.ACCOUNT
command. Alternatively, use the relevant operating system command to make a new directory in a
suitable position and invoke QM in that directory. You will be prompted to confirm that you wish
to make this directory into a new account.
Whichever method you use, QM will create a VOC file in this directory and it is then ready for use.
Other system files may be created subsequently by some commands.
QM maintains a register of account names and their corresponding operating system pathnames in a
file named ACCOUNTS in the QMSYS account. This file is visible from all accounts on the
system but, because ACCOUNTS is the sort of name that might well be used as an application file,
the alternative name QM.ACCOUNTS is used. Account names are mapped to uppercase in QM.
They must start with a letter, may not contain spaces and are limited to 32 characters. The format
of records in the accounts register is:
Id Account name
F1 Account pathname
F2 Account description
F3-9 Reserved for future use
F10-19 Reserved for user use. These fields are not accessed by QM.
VOC The vocabulary, a file that controls all aspects of command processing
within QM.
BP Application programs are written using the QMBasic programming
language. The BP file (Basic Programs) is the default place to keep
application programs. This file must be created when first needed and is
usually a directory file. The compiler output is placed in a file of the same
name as the source file but with a suffix of .OUT added (e.g. BP.OUT).
The output file is created automatically when first required and must be a
directory file.
PVOC The optional private vocabulary file. This is a multifile with subfiles
corresponding to the uppercase form of the user's login name.
$ACC This is the account directory viewed as a QM directory file.
$COMO QM provides a facility to record output that is displayed at the user's
screen in a file. This file is known as a como (command output) file for
compatibility with other systems. The $COMO file is automatically
created as a directory file when the COMO ON command is first used.
2.11-0
28 OpenQM
The command also specifies the record name to be used to store the output.
This file also contains the log files generated by background (phantom)
processes.
$FORMS This VOC entry points to a file in the QMSYS account that is shared by
all accounts as a repository for Pick style form queue definitions created
using the SET.QUEUE command and used by the SP.ASSIGN
command.
$HOLD This is a directory file used to receive output sent to a print unit by a
program or standard command that has been set into mode 3 (output to
hold file).
$SAVEDLISTS This is a directory file used to store saved select lists. See the SAVE.LIST
and GET.LIST commands for more information.
$SCREENS This is a dynamic file used to hold screen definitions that are to be shared
between accounts. See the description of the SCRB screen builder for
more information.
The $COMO, $HOLD and $SAVEDLISTS files tend to collect redundant data as time goes by and
may be cleared using the CLEAN.ACCOUNT command or some other process appropriate to
your application.
2.11-0
Introduction to the QM Database 29
gcat Not directly visible from inside QM, this is the global catalogue directory.
This file should only be accessed using the standard catalogue processing
commands.
NEWVOC The template vocabulary file from which new accounts are created. This
file should not be updated by users as it will be overwritten on upgrading
to a new release.
$IPC This file, not visible from inside QM, is used to support inter-process
communication and cannot be cannot be accessed directly by users. (Not
present on a PDA)
$LOGINS A register of login names of users who may access QM. This file cannot be
accessed by directly users. See Application Level Security for more details.
(Not present on a PDA)
$MAP This file, visible from all accounts, is the default destination for a map of
the system catalogue produced with the MAP command.
SYSCOM The SYSCOM file holds standard definitions for use in QMBasic
programs. It also contains versions of the QMClient include record for
Visual Basic, C and other languages.
temp Windows only. This subdirectory holds temporary files that are used to
pass control information from the QMSvc service to the QM processes that
it starts. All users must have full access to this directory.
terminfo A subdirectory containing definitions of control data for terminal devices.
terminfo.src The master source from which the terminfo definitions are built.
Accounts that are no longer needed can be deleted using the DELETE.ACCOUNT command.
2.11-0
30 OpenQM
1.6 Entering QM
The QM database can be accessed in a number of ways. The simplest is use of a console session.
This is entry into QM directly from the operating system command prompt on the system on which
it is installed. Other methods allow direct connection over a network or via a serial port and are
discussed later in this section.
PDA users should enter QM by using the QM shortcut in the Programs folder. Some commands
may be difficult to use with the default screen size settings. The PDA version can also handle
incoming telnet connections using the NETWAIT command. The remainder of this section is not
applicable to PDA systems.
On Windows systems, once QM has been successfully installed, the program group chosen during
the install (usually QM) will contain an item titled "QM Console". Clicking on this item will open a
console window. This is equivalent to opening a Command Prompt window and executing QM from
there. You will see a copyright line and a site specific licence line. You will then be asked to enter
the name of the account you wish to work in.
On other platforms, login to the operating system and then type qm at the command prompt (this
assumes that the operating system PATH environment variable has been set appropriately). This
technique can also be used from a Command Prompt window on a Windows system. In all cases, if
your current directory when you entered QM was not already a QM account, you will be asked if
you wish to make it into one. Creation of new accounts in this way may be barred for specific users
by the system administrator. See Application Level Security for more details.
When using a console session, you can force entry to a specific account using a command line of
the form
qm -axxx
where xxx is the account name.
TCP/IP network technology assigns each computer on the network a unique address, usually written
as four numbers separated by dots (e.g. 193.118.13.14). When a connection is made to a network
address, the caller also specifies a "port number" which identifies the service to which they wish to
connect. If networking is new to you, it may help to consider the concept of network addresses and
port numbers as being similar to telephone numbers and extensions.
With its default configuration, QM listens for users entering via a network connection on TCP/IP
port 4242. This can be changed to an alternative port or disabled completely by amending the QM
configuration parameters. Windows users who do not have any other telnet software running on
their system may wish to change this to port 23, the default telnet port.
You can connect to QM using most terminal emulators. A licence for the AccuTerm emulator from
AccuSoft Enterprises is bundled with a commercial QM licence. This emulator includes several
features specifically for QM. Although the licence is bundled, you will need to download the latest
version of the emulator software from the AccuSoft website.
2.11-0
Introduction to the QM Database 31
On Windows 98/ME, the installation process installs a server program, QMSrvr, in the bin
subdirectory of the account. This must be started manually though this can be automated via the
Startup folder. Due to a published defect in Windows, the server cannot detect a system shutdown
and must be closed manually.
On later versions of Windows, the QM installation process installs a Windows service (QMSvc) to
manage the network. There should be no need to change anything as it will start and stop
automatically as required.
On all Windows environments, there is a QM Network Control program in the QM program group
that can be used to start and stop the appropriate network server.
On other platforms, the install process will make the necessary changes to the operating system files
that control the network. There should be no need for any manual user intervention unless you
decide to modify the default settings.
Port Mapping
Some software originating in other multivalue environments relies on being able to connect via
multiple telnet ports, each leading to creation of a process with a fixed user number related to the
port number. QM supports this capability via a feature known as port mapping. For more details,
see the PORTMAP configuration parameter.
On Windows NT and later, the QMSvc service can monitor one or more serial ports for incoming
QM connections. This allows entry from directly connected terminals or via dial-up lines. See the
SERIAL configuration parameter of QMSvc for more details.
It is also possible to login a serial port from another QM process using the LOGIN.PORT
command. This will skip the user authentication described below as the new process runs with the
user name and access rights of the user who established the connection. This style of login can be
useful when connecting to automated data collection devices. The LOGIN paragraph would
typically be used to enter the application.
Logging In to QM
Users entering QM directly from a network connection or via a serial port must provide a valid user
name and password for authentication purposes.
On Windows NT and upwards, the user name must also be known to the operating system. Many
users of Windows XP choose to operate their systems with login at the server screen disabled,
however, Windows enforces use of a valid user name on network connections, including "loop
back" to the host system from a terminal emulator running on the same machine. User names can be
set up using the User Administration area of the Windows Control Panel. The QM process will run
as the specified user and with that user's access rights.
2.11-0
32 OpenQM
Earlier versions of Windows (98/ME) did not provide a suitable user authentication system so QM
provides its own. This can be disabled using the SECURITY command if required, leaving the
system open for network users to connect with no authentication.
On other platforms, the user name must be known to the underlying operating system. The resultant
QM process will run as this user and with the access rights of that user. Use the appropriate
operating system administration tools to create and maintain user names.
The -quiet option to the QM executable suppresses display of the copyright and licence details. This
is particularly useful in situations such as scripts using QM as part of a CGI web interface. The
LOGIN.PORT command mentioned above, implies use of the -quiet option so that no data is sent
to the port until the application starts execution.
Device Licensing
Device licensing is an option that allows multiple connections from a single client to share a QM
licence. If your system has this feature enabled, you will see a reference to it in the first few lines of
output from the CONFIG command. QM may be licensed to share a maximum of 2, 4 or 8
sessions per licence.
Device licensing needs support in the client software. This is included in Windows QMConsole
sessions, AccuTerm 2k2 version 5.3c, Winnix version 3, QMTerm and QMClient. With AccuTerm,
device licensing must be enabled via a checkbox in the Advanced options of the Tools, Settings,
Connection menu.
When connecting to QM directly via a network (port 4242 as described above), device licensing is
totally automatic. For entry from the operating system command prompt, the -DL option of the QM
command must be used to initiate the negotiation between the client and QM. Alternatively, setting
an environment variable named QMDL will make QM behave as though this option is present. This
option is necessary because the negotiation process may cause terminal emulators that do not
support it to behave erratically.
2.11-0
Introduction to the QM Database 33
There are two stages to login; user authentication and process initialisation.
User Authentication
On Windows NT and later, users connecting to QM via a network must enter a valid Windows
username and password. The new process runs as that user and with the associated access
permissions.
If security has been turned off and the username does not appear in the user register, the user runs
without administrator rights and an account name prompt is displayed.
On Windows 98/ME, the above mechanism is extended such that QM performs the username and
password validation using its own internal user register as these platforms do not provide an
adequate user authentication system. The newly created process runs with the Windows user name
and access permissions of the user that started the QMServer process.
On other platforms, users connecting to QM via a network usually open telnet sessions as normal
users and then enter QM, perhaps automatically via their profile script. It is, however, possible to
connect directly to QM in which case the security mechanisms described above for Windows NT
and later apply.
Process Initialisation
When a user successfully enters an interactive QM session, the following steps occur:
1. For users entering QM directly from a network connection, QM attempts to determine the
terminal type by use of telnet negotiation commands. If the emulator in use does not
support these, QM looks for an environment variable named TERM and, if this is found,
uses it to set the default terminal type. If this also fails, vt100 is used by default.
For PDA users, the terminal type is set to pda. For QMConsole users on Windows, the
terminal type is set to qmterm. For users entering QM from an operating command prompt
on other platforms, QM looks for an environment variable named TERM and, if this is
found, uses it to set the default terminal type. If this fails, vt100 is used by default.
2.11-0
34 OpenQM
The terminal type can be changed later from within QM using the TERM command. When
using AccuTerm, it is strongly recommended that the terminal types with the -at suffix (e.g.
vt220-at) are used as these enable AccuTerm specific features such as the screen switching
required for the full screen mode of the QMBasic debugger.
2. On all platforms except the PDA, QM then looks for environment variables named LINES
and COLUMNS and, if found and valid, uses these to set the initial size of the terminal
window. When using a QMConsole session on Windows, the displayed window will be
adjusted to be this size. On other connections, it is the user's responsibility to ensure that
the terminal emulator screen dimensions match those expected by QM.
3. The system looks in the QMSYS account VOC file to find a paragraph named
MASTER.LOGIN and, if this exists, executes it. This paragraph can be used for system
wide initialisation such as setting European date format or standard printer associations.
4. The system checks in the user's account VOC file to find an executable (menu, paragraph,
sentence, verb) item named LOGIN and, if this exists, executes it. The LOGIN item is
typically used to perform account specific initialisation and the enter the application. Note
that this happens for all QM processes, including phantoms and QMClient sessions. To exit
from the LOGIN paragraph for a phantom process, insert a line
IF @TTY = 'phantom' THEN STOP
at the relevant point in the paragraph. For a QMClient session, test for 'vbsrvr'. See @TTY
for more details.
Some other multivalue products look for an item named the same as the user's login id. This
can be emulated on QM by creating a LOGIN item that is simply
1: S
2: <<@LOGNAME>>
5. The break key is enabled. By running the MASTER.LOGIN and LOGIN paragraphs with
the break key disabled, the user cannot quit out of any security checking done in these
paragraphs. If a LOGIN paragraph is used to start the application, it may be necessary to
enable the break key at this stage by including a BREAK ON command.
Step 4 above is also executed when the LOGTO command is used to move to a new account.
User specific process initialisation can be performed by testing the content of the @LOGNAME
variable in the MASTER.LOGIN or LOGIN paragraphs. For example,
IF @LOGNAME = 'ADMINISTRATOR' THEN ADMIN.STARTUP
2.11-0
Introduction to the QM Database 35
The QM VOC file normally contains one or more items that represent scripts of commands to be
executed automatically at certain events. Although these are usually paragraphs, all except for the
MASTER.LOGIN item may actually be any executable type of VOC record (verbs, menus, Procs,
etc). None of these items need exist. They provide the means to perform a fixed sequence of
commands at the events described below.
LOGIN
The LOGIN paragraph is executed on entry to QM and also when the LOGTO command is used to
switch to a new account. The break key is inhibited until execution of this paragraph has been
completed. This paragraph is executed for terminal users, phantom processes and QMClient
connections. The @TTY variable can be tested to determine the user type. The LOGIN paragraph
is typically used to set QM option flags perform security checks, set up printers, set terminal
characteristics and enter the application.
Example
PA
DATE.FORMAT ON
IF @TTY = 'phantom' THEN STOP
PTERM CASE NOINVERT
BELL OFF
OPTION NO.USER.ABORTS
BREAK ON
RUN BP MAIN
ON.LOGTO
The ON.LOGTO paragraph is executed on use of the LOGTO command before switching to the
new account. This paragraph might be used, for example, to clear down application specific data
such as named common blocks.
Example
PA
DELETE.COMMON ALL
ON.EXIT
The ON.EXIT paragraph is executed on leaving QM by use of the QUIT command. The break key
is inhibited during execution of this paragraph. An abort occurring in this paragraph will terminate
the QM session immediately.
Example
PA
SELECT TEMP WITH UNO = <<@USERNO>>
IF @SELECTED THEN DELETE TEMP NO.QUERY
2.11-0
36 OpenQM
ON.ABORT
The ON.ABORT paragraph is executed when QM aborts a program due to an internally detected
error, a QMBasic program executes an ABORT statement or when the Abort response is chosen
after use of the break key. The @ABORT.CODE and @ABORT.MESSAGE variables may be
useful in determining the cause of the error. An abort occurring whilst executing the ON.ABORT
paragraph will cause a message to be displayed. The paragraph is not re-entered. Aborts occurring
in commands started using the QMBasic EXECUTE statement with the TRAPPING ABORTS
option do not execute the ON.ABORT paragraph.
The primary role of the ON.ABORT paragraph is to prevent the user reaching a command prompt
if the application fails. It may be useful to include logging of the cause of the abort.
Example
PA
RUN BP LOG.ABORT
QUIT
This item, if present is run when a new incoming telnet connection is established on a PDA using
the NETWAIT command.
This item, if present, must be a paragraph and is executed on initial entry to QM in any account
before the LOGIN paragraph but not when the LOGTO command is used to switch to a new
account. This paragraph is executed with the break key inhibited for terminal users and phantom
processes. It is not executed for QMClient connections.
Example
PA
DATE.FORMAT ON
OPTION NO.USER.ABORTS
OPTION DUMP.ON.ERROR
2.11-0
Part
2
The Command Environment
38 OpenQM
Although applications commonly use the graphical interface capabilities of QM via Visual Basic or
web browsers, developers normally work from the character mode interface command prompt using
a terminal emulator or directly from the system console. Commands can also originate from within
application programs.
Commands entered at the terminal or generated from within a QM application are processed by the
command processor. This uses the vocabulary file (VOC) to determine the meaning of each word or
symbol within the command.
The default command prompt is the colon character. Whenever this is displayed at the start of a
line, QM is ready to accept a new command. The command prompt changes to a double colon if the
default select list is active. This serves as a warning that the select list may impact execution of the
next command. The prompt characters may be modified using the PTERM command.
By default, QM operates with "case inversion" - that is, characters entered in lowercase letters are
displayed in uppercase and vice versa. The original multivalue systems date back to a time when
many terminals did not have lowercase letters and hence the command language was written to
work in uppercase. To make it easy to operate in situations where a user may be switching between
a QM session and, for example, a Word document, QM normally applies case inversion so that the
user does not need to keep hitting the caps lock key.
Actually, QM is largely case insensitive but this feature is retained for compatibility with other
systems. It can be disabled by typing
PTERM CASE NOINVERT
and this would usually be done as an automated part of the login process for an end user of the
application.
A command consists of a number of tokens separated by spaces. Where a token includes spaces, it
must be enclosed in quotes. QM allows use of single quotes, double quotes or backslashes
interchangeably.
The first token of a command normally corresponds to the name of an executable item within the
VOC. This will be the name of a verb, sentence, paragraph, menu or Proc. It is also possible to run
a program from the system catalogue by typing its name as a command. Other valid actions at the
command prompt are:
Command stack operations, prefixed by a dot character
Command editor keystrokes
Save the command without execution by appending a question mark
The command processor performs the VOC look-up for a command in three stages; firstly by
looking for a record with a name matching the first token in the command exactly as entered. If this
fails, it then tries again with the name mapped to uppercase. All system verbs have uppercase
names and can therefore be entered in lowercase, uppercase or a mix. For compatibility with Pick
databases, a third attempt is made with any hyphens in the uppercase version of the name replaced
by dots. Thus a command such as CREATE.FILE can be entered as create.file or
CREATE-FILE.
If the command is not found in the VOC, a check is made in the private and global catalogues. If
2.11-0
The Command Environment 39
the name exists here, the catalogued program is executed. The names of catalogued programs
executed in this way must commence with a letter or an asterisk. When executing a catalogued
program in this manner, the command processor will look for and handle the LPTR and NO.PAGE
keywords in the same way as the RUN command, leaving them in place so that the executed
program will also see them if it performs its own command line scan.
Finally, if the command has still not been located, the command processor looks in the private
vocabulary, if this exists.
Many commands perform the first two phases of this look-up for the remaining tokens on the
command line (file names, keywords, etc), however, commands that might have a detrimental effect
if used in error (DELETE.FILE, for example) either insist on the file name being entered exactly
as it appears in the VOC or prompt for confirmation if the name is not an exact match.
Command lines commencing with an asterisk followed by at least one space are treated as
comments and are ignored except that inline prompts are still processed. Although comments are
primarily of use within paragraphs, they can be entered directly at the keyboard when they will
appear in any active como file.
2.11-0
40 OpenQM
Commands entered at the terminal are stored in a command stack (to be technically correct, it is a
queue but historically users have called it a stack). They may subsequently be recalled for
re-execution by a simple short form command. By default, the stack holds the last 99 commands but
this value can be changed by use of the CMDSTACK configuration parameter. The list is indexed
by number such that the most recent command is numbered as 1, the oldest as 99.
The stack can be manipulated by commands prefixed by a dot character entered at the command
prompt. These allow commands on the stack to be edited and also provide facilities to save and
restore sequences of commands to and from VOC paragraphs.
2.11-0
The Command Environment 41
.X file record Execute command stored in the named file and record. This record
must have the same format as a VOC record.
.? Display a help message regarding the stack manipulation commands.
For compatibility with other environments, a command can also be saved on the stack without
execution by entering it at the command prompt with a question mark as the last character. The
question mark is removed.
The command stack is saved between sessions if the VOC contains a record named
$COMMAND.STACK with field 1 set to X. This record is inserted automatically when a new
account is created but can be deleted if the stack is not to be saved. For console users on Windows
systems, the command stack will be saved into this record on leaving QM and loaded from it on
re-entry. For all other Windows users and on other platforms, presence of this record causes the
command stack to be saved to, or restored from, a file named as the user's login name in the stacks
subdirectory of the account in which QM was entered.
QM supports a secondary, private vocabulary file that is represented by a multi-file named PVOC
with subfile names that correspond to the uppercase form of the user's login name. The .D, .L, .R
and .S commands have an extended form to access the private vocabulary file:
2.11-0
42 OpenQM
The command line editor allows editing of a command line. It is of use in correcting typing errors or
repeating saved commands, possibly after modification.
Ctrl-G Exit from the command stack and return to a clear command
line.
Ctrl-R Search back up the command stack for a given string. The
string may be entered either before or after the Ctrl-R. Using
Ctrl-R again, finds the next item matching the supplied string.
Entering a command line containing only a question mark shows a summary of the command editor
keys.
The command editor operation is controlled by option codes which may be entered in field 3 of the
$RELEASE VOC entry. These are:
E Position the cursor at the end of a recalled command rather than the start.
S Show the stack commands when moving back through the stack.
2.11-0
The Command Environment 43
X Clear the recalled command if the first character typed is not a control code. This mode
cannot be used with E.
2.11-0
44 OpenQM
It may be necessary to terminate a command because, perhaps, it is producing more output than
expected or it is not functioning as required. The break key (usually ctrl-C) can be used to terminate
processing and return to the command prompt.
To protect against accidental use of the break key, QM will display a prompt asking for
confirmation that processing is to be terminated. Valid responses to this prompt are
A Abort. Returns to the command prompt in exactly the same way as an abort generated
by an ABORT statement in a QMBasic program or an ABORT command in a
paragraph. The ON.ABORT paragraph is executed, if present. The @ABORT.CODE
variable will be set to 1. The default select list (list 0) will be cleared if it was active.
D Only offered when appropriate, this option enters the QMBasic debugger.
G Go. Continues processing from where it was interrupted. If the terminal supports the
necessary operations, QM will restore the display image to remove the prompt.
P Creates a process dump file and continues execution.
Q Quit. Returns from the current command to the paragraph, menu, program or command
prompt that initiated the command. The ON.ABORT paragraph is not executed. The
@ABORT.CODE variable will be set to 2. The default select list (list 0) is not cleared.
S Stack. Displays the call stack showing the program name and location for each entry.
W Where. Displays the current program name and location.
X Exit. Aborts totally from QM without executing the ON.EXIT paragraph. This option
should only be used if QM appears to be behaving incorrectly.
? Help. Displays a brief explanatory help text for each option.
The break key is initially disabled on entry to QM but it is enabled after execution of the optional
QMSYS MASTER.LOGIN paragraph and LOGIN VOC item. It is often left disabled in
application software so that users cannot gain access to the command environment. Developers
usually need the break key enabled and this can be done using the BREAK command or the
corresponding QMBasic BREAK statement.
QMBasic programs can establish a break handler to catch use of the break key and take special
action. See the SET.BREAK.HANDLER statement for details.
2.11-0
The Command Environment 45
Output to the display is automatically paginated, where appropriate, by inserting a prompt at the
end of each page of output. The options available at this prompt are
A Abort. Returns to the command prompt in exactly the same way as an abort generated
by an ABORT statement in a QMBasic program or an ABORT command in a
paragraph. The ON.ABORT paragraph is executed, if present. The @ABORT.CODE
variable will be set to 1. The default select list (list 0) will be cleared if it was active.
Q Quit. Returns from the current command to the paragraph, menu, program or command
prompt that initiated the command. The ON.ABORT paragraph is not executed. The
@ABORT.CODE variable will be set to 2. The default select list (list 0) is not cleared.
S Suppress pagination. Continues execution with no further pagination prompts.
Other Any other key continues execution until a further pagination prompt is displayed.
The number of lines per page can be adjusted from its initial value by use of the TERM command.
Pagination can be disabled by application software or by use of the NO.PAGE option to some
commands.
2.11-0
46 OpenQM
The VOC file is central to everything that QM does. This file is the vocabulary of words and
symbols that may appear in commands and holds many other things as well. The initial VOC file is
a copy of NEWVOC from the QMSYS directory. By modifying the VOC it is possible to change
the names of commands to meet particular needs of an application or user. It would be possible, for
example, to include French translations of all the command names. More often, changes are made
simply to use wording that is more appropriate to the manner in which the product is used.
Records in the VOC are of differing types, the type of the record being determined by the first one
or two characters of field 1 of the record. The remainder of field 1 after the identifying characters
may contain any value and is typically used to comment the role of the VOC entry.
D Data item
Defines a field within a data file. D type entries may appear in the VOC but are more
commonly found in dictionaries.
F File
Defines a file, relating its application level name for use within QM to its operating
system pathname.
K Keyword
Many commands have keywords which affect the behaviour of the command or
introduce optional clauses in the command syntax.
M Menu
A menu record defines a menu that can be displayed by executing the VOC entry.
PA Paragraph
A paragraph is a sequence of commands that can be executed by entering the name of
the VOC entry.
PH Phrase
A phrase is a short form for a sequence of items to be substituted into query processor
commands.
PQ PROC
A PROC is the predecessor of paragraphs. QM supports PQN style PROCs for use
when migrating applications. It is recommended that new developments should use
paragraphs or QMBasic programs instead.
Q Remote File
A remote file pointer refers to a file in another QM account, perhaps on a different
server.
R Remote
An R type VOC entry points to a record in another file which is constructed in the same
way as an executable (M, PA, R, S or V type) VOC entry.
2.11-0
The Command Environment 47
S Sentence
A sentence is a single command.
V Verb
A verb is the portion of a command which identifies the part of QM which will process
it.
X Other
X type records may be used to store miscellaneous information in the VOC.
VOC record types Y and Z will never be defined as part of the standard QM product and are
available for whatever purpose a developer may find useful. Other type codes not listed above may
be defined in future releases.
Users may add handlers for other VOC record types that are to be usable as commands. This is
done by creating a VOC record named $VOC.PARSER:
Field 1 X
Field 2 A multivalued list of VOC record type codes.
Field 3 A corresponding multivalued list of catalogued handler subroutine names.
The handler is a QMBasic subroutine taking two arguments; the verb name and the VOC record.
The VOC includes an F-type entry referencing itself so that commands that access the VOC do not
have to treat it as a special case. Users must not modify this VOC entry as any change is likely to
cause QM to malfunction because internal components reference the VOC by pathname.
The VOC also includes a Q-type entry named MD as a synonym for VOC for compatibility with
other systems.
The vocabulary file is shared by all users of the account to which it belongs. To allow users to store
private commands (verbs, sentences, paragraphs, menus, Procs), QM also supports use of a private
vocabulary file that is separate for each operating system level user name. This is a multi-file
named PVOC with subfiles names that are the uppercase version of the user's login name. The
private vocabulary is checked only after attempting to find the item in the VOC and the catalogue.
It is only used to locate command names, not other VOC record types such as phrases, keywords or
files.
The private vocabulary file may be created and modified directly by of CREATE.FILE, ED, SED
, etc. Alternatively, the "dot commands" of the command stack editor include options in .D, .L, .R
and .S to access the private vocabulary. First use of .S in this mode will create the private
vocabulary file if it does not already exist.
Unlike the VOC file, which the command processor opens by pathname, the private vocabulary is
opened using the normal indirection via a VOC F-type record. It is therefore possible to set up the
VOC record such that groups of users share a common private vocabulary or so that one user sees
the same private vocabulary from multiple accounts.
2.11-0
48 OpenQM
The optional LOGIN, ON.EXIT, ON.LOGTO and ON.ABORT command scripts must reside in
the VOC file, not the private VOC.
2.11-0
The Command Environment 49
Although D-type records may be stored in the VOC file, they are more usually found in
dictionaries. A D-type entry in the VOC can be used to reference a field in any file whereas a
D-type entry in a dictionary can only be used in queries against the associated file.
1: D { descriptive text }
2: Field number. This is the position in the data record at which the field described by this
dictionary entry can be found. A value of zero denotes the record id.
3: { Conversion code }
4: { Display name. This will be used as the default column heading by the query processor. }
5: Format specification
6: Single/multivalue flag. Set as S if the field is always single valued or M if it can be
multivalued.
7: { Association name. Where a multivalued field has a value by value relationship with some
other multivalued field defined in the same dictionary, this name links the fields together.}
8: {Available for user use in any way. Not referenced by QM. }
Fields 9 onwards are reserved for internal use and users should not assume anything about their
content.
2.11-0
50 OpenQM
Every file referenced by an application is accessed via an F-type VOC record. This record maps the
QM name of the file to the pathnames of the data and dictionary components.
1: F { descriptive text }
2: The pathname(s) of the data portion of the file. In a multi-file, the pathname of each subfile
appears as a separate value in this field
3: Dictionary pathname. This field is empty if the file has no dictionary.
4: Subfile names for a multifile. This field is empty for a simple file.
5: File inclusion flags for ACCOUNT.SAVE and FILE.SAVE.
There are three possible values:
D Include only the dictionary of this file in the save
E Exclude this file from the save
I Include this file in the save
Leaving the field empty causes ACCOUNT.SAVE and FILE.SAVE to fall back on
alternative file selection methods.
6: Special file open modes for QMBasic OPEN and OPENSEQ operations. This affects the
data part only and may be any compatible combination of the codes listed below. For a
multifile, these modes apply to all elements.
S Sets synchronous (forced write) mode on the file (dynamic hashed files only).
T Suppress translation of restricted characters in directory file record ids. This
affects only the data portion of the file. See also the NO.MAP option to the
QMBasic OPENstatement. This flag can be set using the NO.MAP option to the
CREATE.FILE or CONFIGURE.FILE commands.
Applications that make direct access to this field should allow for the presence of codes not
in the above list.
Either pathname field may be blank to indicate that the file portion does not exist.
Three special pathname prefixes are allowed:
· @QMSYS will be replaced by the QMSYS account directory pathname, ensuring that
references to items in the QMSYS account will still function if a new release is installed at
a different location.
· @TMP will be replaced by the pathname in the TEMPDIR configuration parameter.
· @HOME will be replaced by the value of the HOME environment variable. Windows users
may need to create this variable before using this feature.
By using F-type VOC items to locate files indirectly rather than embedding file pathnames in the
application, the VOC entry becomes the only place where the pathname is recorded. If a file is
moved, perhaps to balance loading across multiple disks, only the VOC entry needs to be amended;
the application itself is not affected.
Where two or more accounts share a file, the VOC files in each account could have F-type records
mapping the QM name to the pathnames. This is not recommended. Instead, the account that owns
the file should have an F-type record and all other accounts should have Q-type records to access
the file indirectly.
2.11-0
The Command Environment 51
VFS:handler:detail
to make use of the Virtual File System.
2.11-0
52 OpenQM
Keywords affect the behaviour of commands or introduce optional components in the command
syntax. Keywords are defined by K-type VOC records.
1: K { descriptive text }
2: Keyword number
3: { alternative expansion }
Each keyword is assigned a number which appears in field 2 of a keyword VOC entry.
Keywords with internal number 0 in field 2 are ignored by the query processor and some other parts
of QM. They are provided to allow construction of more natural English sentences. For example,
the THAN keyword can be used with other elements such as GREATER and LESS to allow a
query such as
LIST STOCK WITH PRICE GREATER THAN 100
instead of
LIST STOCK WITH PRICE GREATER 100
Users can freely add new keywords with internal number 0 as required.
In some cases, a keyword is also needed as a command name (e.g. OFF which is a synonym for
QUIT but also a modifier in several other commands). A keyword can never be the first token in a
command. If the command processor finds a K-type VOC item used as the first token in a
command, it looks for an alternative VOC record structure starting at field 3.
2.11-0
The Command Environment 53
A VOC menu record defines a menu of numbered options to be displayed to the user when the menu
entry is executed. Because menu records may be very large, they are often stored in some other file
with a VOC R-type record as a remote pointer to the actual menu definition.
1: M { descriptive text }
2: Menu title line to appear at the top of the screen.
3: Item text. This field is multivalued with one value for each menu entry. Blank entries are
allowed to insert spacing in the menu. Each menu entry is numbered except as described
under field 4 below.
The descriptions are normally displayed starting on the third line of the screen, left justified.
If the menu has more items than will fit in a single column on the screen and the items are
all sufficiently short, the menu will be displayed as two columns. Any menu items that will
not fit on the screen are lost.
4: Action. This field is multivalued with entries corresponding to the text in field 3. If the
action is terminated by a semicolon, the menu processor issues a "Press return to continue"
prompt when the command is completed. Blank entries cause the field 3 text to be treated as
a sub-title and not numbered on the displayed menu.
5: Help text. A multivalued set of one line help texts corresponding to each menu option in the
previous fields.
6: Access key. An optional multivalued set of access control keys corresponding to the menu
items. The access key value is passed to the access control subroutine if this is used.
7: Hide inaccessible entries. This field may be single valued in which case it applies to all
menu entries or it may have one value for each menu item. Each value present is a boolean
(1 or 0 corresponding to true or false) flag indicating whether inaccessible menu entries
should be hidden (not displayed) or shown as unavailable.
8: Access subroutine. This optional field contains the name of an access control subroutine
(see below).
9: Prompt text. If present, this text replaces the default option prompt.
10: Exit codes. An optional multivalued list of codes which when entered at the option prompt
will exit from the menu. If this field is blank, entering a null response to the menu prompt
will exit from the menu. Because exit codes are processed before option numbers, it is
possible to include an option that causes an exit by specifying the option number as an exit
code.
11: Stop codes. An optional multivalued list of codes which when entered at the option prompt
will generate an abort event, terminating all active processing and returning to the command
prompt. If this field is blank, it defaults to Q. Because stop codes are processed before
option numbers, it is possible to include an option that causes a stop by specifying the
option number as a stop code.
Menus may be constructed and maintained using the menu editor MED.
When used on a PDA, QM allows selection of menu options using a stylus tap. Clicking on or
2.11-0
54 OpenQM
Access Control
A menu may include run time selection of which options are to be offered to the user. This is
managed by a user written access control subroutine named in field 8 of the menu definition. When
the menu is displayed, this subroutine is called for all entries that have an access key defined in field
6 to determine whether the option is to be offered. The subroutine takes three arguments; the
returned true/false accessibility flag, the menu name and the access key. Typically, the access key
would be a name that refers to a group of users such as ADMIN or SALES. Access control
subroutines may be used by multiple menus and, where necessary, can use the menu name in the
decision process that controls display. The subroutine should return the first argument as true (1) if
the menu item is to be allowed, false (0) if it is to be disabled.
Field 7 of the menu definition contains the "hide" flag which controls the action taken when a menu
option is disabled for a user. Setting this to 0 or leaving it blank, displays the option with its option
number enclosed in parentheses. Entry of this option number at the menu prompt will be ignored.
Setting the hide flag to 1, completely hides the disabled option.
For an access key of ADMIN, this subroutine enables the menu option only if the user is logged in
as an administrator. For all other access key values, it reads a user record and checks that the user
is in the relevant department. The U.DEPT token used above would be defined in an include record.
2.11-0
The Command Environment 55
1: PA { descriptive text }
2: First sentence
3: Second sentence
4: etc...
Field 1 of the VOC paragraph record commences with PA, fields 2 onwards are the commands to
execute. Any sentence within the paragraph may be broken into shorter parts by using the
underscore character to indicate that the command continues on the next line.
The Cn and In control codes of inline prompts may be used to substitute additional text from the
sentence that started the paragraph into the commands within the paragraph.
Paragraphs may contain a number of special commands and constructs that are not allowed in
sentences. These are
Paragraphs may invoke other paragraphs. Beware of accidental recursive invocation of the same
paragraph.
There are four reserved paragraph names for special functions. These are:
LOGIN Executed on entry to QM and also when the LOGTO command is used to
switch to a new account.
ON.LOGTO Executed on use of the LOGTO command before switching to the new
account.
The QMSYS account may contain a paragraph with a further reserved name:
2.11-0
56 OpenQM
2.11-0
The Command Environment 57
A phrase can be used in query processor sentences. When the sentence is executed, the phrase name
is replaced by the phrase expansion. Typically, phrases are used to give names to groups of fields to
be displayed or selection criteria.
1: PH { descriptive text }
2: Phrase expansion
Phrases may be included in the VOC but are more commonly found in dictionaries. A phrase in the
VOC can be used in queries against any file whereas a phrase in a dictionary can only be used in
queries against the associated file.
Where a phrase is very long it may be broken into multiple lines within the VOC record by
terminating all but the final line with an underscore character. When the phrase is substituted into a
command, the lines are merged, replacing the underscore with a single space.
2.11-0
58 OpenQM
PROCs are the predecessor of paragraphs. They are generally thought to be much harder to
understand and maintain but are supported in QM for compatibility with other systems. New
applications should use paragraphs or QMBasic programs in place of PROCs.
PROCs come in two styles identified by the VOC record type; standard PROCs (PQ) and new style
PROCs (PQN). QM supports the major features of PROCs but is not a full implementation of the
various PROC environments found in other multivalue environments.
Because development of new PROCs is discouraged, only an overview of what elements of PROCs
are supported by QM is given here. It is not intended as a detailed reference document or a learning
aid.
Proc Buffers
A PROC works by manipulating data in a set of buffers, each stored internally as a field mark
delimited dynamic array (PQN) or a space delimited string (PQ). These are:
The PIB initially holds the command that started the PROC and any command line options. A
PROC can use the PIB to store other data during its operation.
The SIB is typically used to store user input entered in response to the IN statement.
The POB is used to construct a command to be executed. Execution of the assembled command is
triggered by use of the P statement or by termination of the PROC.
The SOB, often called the stack, is used to hold data to be processed by the command in the POB.
It can also hold supplementary commands to be executed after the POB has been executed.
At any moment, one input and one output buffer is considered as being active. The SP and SS
statements can be used to make the primary or secondary input buffer active respectively. Similarly
the STOFF and STON statements can be used to select the primary or secondary output buffers as
active.
2.11-0
The Command Environment 59
The input buffer pointer is used to identify a position within the active input buffer.
When a PROC starts, the primary input and output buffers are active and the input buffer pointer
points to the start of the PIB.
There are ten file buffers, numbered from 0 to 9. File buffers 1 to 9 are the standard file buffers.
File buffer 0 is the fast file buffer and can be accessed with a special buffer reference syntax.
The eleven numbered select lists can be accessed using the select list buffers.
Buffer References
Many statements can reference buffers using the tokens shown below:
An indirect reference uses the content of one buffer to index into another.
In a file buffer, field 0 references the record id associated with the buffer.
A-References
An A-reference is a reference to data in the active input buffer using the syntax of the A statement
described in the following section. When used in this form, an A-reference does not move the input
pointer or change the content of the buffers.
A Move a field from the active input buffer to the end of the active output buffer.
A{c}{p}{,m}
Move up to m characters of field p to the output buffer, enclosing the text in character c.
c may be any character except a digit, left bracket or comma and defaults to a space.
Specifying c as a backslash suppresses the surround character. The surround character is
ignored if the data is copied to the secondary output buffer.
If p is omitted, data is copied from the field addressed by the current position of the input
pointer.
If m is omitted, data is copied until the end of the field is reached.
2.11-0
60 OpenQM
A({n}{,m})
Move up to m characters, starting at character n, to the output buffer.
If n is omitted, data is copied from the current position of the input pointer.
If m is omitted, data is copied until the end of the field is reached.
The input pointer is positioned following the last character moved.
Data copying normally terminates at the end of the field. Use the PROC.A or PICK.PROC
modes of the OPTION command to enable compatibility with D3 where the copy continues
past the end of the field.
If the input pointer is at the start of a field, it is moved back to the start of the previous field.
Otherwise it is moved back to the start of the current field.
The output buffer pointer is move back to the previous field, truncating the data at its new
position.
C Comment
Ctext
All text following the C is ignored.
D{ref|p}{,m}{+}
ref is a direct or indirect reference to a buffer containing the field number of the active input
buffer that is to be displayed.
p is the field number of the active input buffer that is to be displayed. If p is zero, the entire
input buffer is displayed.
m is the maximum number of characters to be displayed.
+ suppresses the normal newline after display
The content of the primary and secondary input and output buffers is displayed.
DF{n}
The content of the specified file buffer is displayed. If n is omitted or specified as zero, the fast
file buffer is displayed.
DSn
The content of the specified select buffer is displayed. If n is omitted, it defaults to zero.
The input buffer pointer is moved forward to the start of the next field. If the pointer was in the
last field, it is moved to the end of the buffer.
F;element{;element...}
The F; statement performs integer arithmetic using a stack. The element list contains values to
be added to the stack and operators to be performed against the stack values.
ref A direct or indirect reference to a buffer element to be placed on the stack.
n A numeric constant to be placed on the stack. The value may be preceded by C.
+ Adds the top two stack items, replacing them by the result.
- Subtracts the top stack item from the next item, replacing them by the result.
* Multiplies the top two stack items, replacing them by the result.
/ Divides the second item on the stack by the first item, replacing them by the truncated
integer result.
R Divides the second item on the stack by the first item, replacing them by the remainder
value.
{ Interchanges the top two items on the stack.
_ Interchanges the top two items on the stack.
?P Moves the top item from the stack into the primary input buffer at the input pointer
position.
?ref Moves the top item from the stack into the specified register location.
F-C{LEAR} n
The file buffer for file n is cleared.
F-D{ELETE} n
The record identified by the file and id associated with file buffer n is deleted. An error will be
reported if there is no open file associated with the file buffer.
F-F{REE} {n {id|ref}}
The record identified by the file and id associated with file buffer n is deleted. The record id
may be specified using a buffer reference. If no id is specified or it is a null string, all locks in
that file are released. An error will be reported if there is no open file associated with the file
buffer.
If no file number or id are specified, all locks associated with files opened by the PROC are
released.
2.11-0
62 OpenQM
F-R{EAD} n {id|ref}
The record with id specified by id or by the direct or indirect ref is read into file buffer n. If the
record cannot be found, the PROC continues at the next statement, otherwise this statement is
skipped. In either case, the record id will be stored as field zero of the file buffer.
F-U{READ} n {id|ref}
The record with id specified by id or by the direct or indirect ref is read into file buffer n,
locking it for update. If the record cannot be found, , the PROC continues at the next statement,
otherwise this statement is skipped. In either case, the record id will be stored as field zero of
the file buffer and the process will own the lock.
F-W{RITE} n
The record stored in file buffer n is written using the id stored in field zero of the file buffer.
GO label|A-ref|ref|F|B
The PROC continues execution at the given position.
label specifies a numeric label attached to the destination.
A-ref is an A-reference used to determine the destination label.
ref is a direct or indirect buffer reference to a location containing the label.
2.11-0
The Command Environment 63
GOSUB label
Label specifies a numeric label at the start of the subroutine.
Execution continues at the given location. The subroutine may return to the statement following
the GOSUB by use of RSUB.
H{text|ref}
The literal text or the content of the buffer location identified by the direct or indirect ref is
added to the active output buffer.
IF Conditional execution
I{B}Htext|ref|\| \}
Copies the unquoted literal text or the data addressed by the direct or indirect buffer ref to the
active input buffer at the position given by the input buffer pointer. If this is positioned at the
start of a field, the entire field is replaced. If it is positioned part way though the field, the new
data is appended to the portion before the input pointer position.
The input buffer pointer is not moved by this operation.
For compatibility with other systems, the following additional syntax elements are recognised in
PQN style Procs or in PQ style Procs executed without the PICK.PROC mode of the OPTION
command enabled:
The \ token with no preceding space, clears the field addressed by the input buffer pointer.
If the pointer is positioned part way through a field, characters before the pointer position
are retained.
The \ token with a preceding space, inserts an empty field. This syntax is not recognised as
a special case if the PICK.PROC mode of the OPTION command is enabled.
Leading and trailing spaces are removed and multiple embedded are compressed to single
spaces. If the B option is not present, the spaces are then converted to field marks.
I{B}N{c}
The secondary input buffer is activated and the user input overwrites any existing content. All
leading and trailing spaces in the input data are removed and multiple embedded spaces are
compressed to a single space. If the B option is not present, all remaining spaces are then
replaced by field marks. The optional prompt character c specifies an alternative to the default
of a question mark and remains in effect for subsequent input until another prompt character is
set.
I{B}P{P}{c}ref
User input overwrites the location specified by the direct or indirect ref. If ref is omitted, the
field addressed by the input buffer pointer in the primary input buffer is overwritten. All leading
and trailing spaces in the input data are removed and multiple embedded spaces are compressed
to a single space. If the B option is not present, all remaining spaces are then replaced by field
marks. The optional prompt character c specifies an alternative to the default of a question
mark and remains in effect for subsequent input until another prompt character is set. The
prompt character must be present if ref is used.
In a PQ style Proc, entering a blank response retains the existing content of the input buffer. A
PQN style Proc would clear the buffer.
L{'text'|ref|(col),...}{+}
Outputs the items specified in the comma separated list. These may be quoted literal text or the
data addressed by the direct or indirect buffer ref. Use of ref may be followed by an input
conversion code enclosed in semicolons or an output conversion code enclosed in colons.
The (col) element can be used to move to a specific column number where the leftmost column
is column one.
The + element suppresses the normal newline at the end of the output.
The list may span multiple lines by breaking it after a comma.
LC Close printer
The printer is closed and the output is passed to the underlying print management system for
printing.
LE Page eject
LHDR{'text'|ref|(col)|P|T|Z|n|,...}
Sets the page header using the items specified in the comma separated list. These may be quoted
literal text or the data addressed by the direct or indirect buffer ref. Use of ref may be followed
by an input conversion code enclosed in semicolons or an output conversion code enclosed in
colons.
The (col) element can be used to move to a specific column number where the leftmost column
is column one.
The P element inserts the page number.
The T element inserts the date and time.
The Z element restarts page numbering.
The n element specifies a number of newlines.
The list may span multiple lines by breaking it after a comma.
Specifies that output from the L statement is to be directed to the terminal. This is mainly
useful for debugging purposes.
M Mark
The M statement marks a location in a PROC for use by the GO F and GO B operations.
2.11-0
66 OpenQM
MV destination source
destination is a direct or indirect reference to the buffer location to which data is to be copied.
source is a list of one or more items to be copied. Each item may be direct or indirect buffer
reference or a quoted literal string.
A comma separating two items inserts the items as separate fields. Use of two or more
consecutive commas with no source item between them skips fields in the destination.
An asterisk between two items concatenates them.
An asterisk after a file buffer reference as the last item in the source list copies all remaining
fields from the file buffer.
An asterisk followed by a number after a file buffer reference in the source list copies the given
number of fields from the file buffer.
An underscore as the last item in the list truncates the destination by removing all fields after
the last one copied.
MVA Move data from one location to another as a sorted multivalued field
Otext{+}
The unquoted literal text is displayed on the user's terminal. The optional + token suppresses
the normal newline after output.
P{P}{H}{X}{W}{Ln}
The command in the primary output buffer is passed to the command processor for execution.
Any data in the secondary output buffer is queued up as data for use by the executed command.
If there is any unprocessed data remaining after the command has been executed, the first field
of this data is passed to the command processor for execution, using the remaining fields as
data. This cycle continues until all the data has been processed.
The P option displays the content of the output buffer before execution of the command.
2.11-0
The Command Environment 67
Q Quit
Qtext
The PROC and all other underlying programs, paragraphs, menus, etc are terminated,
displaying the optional unquoted text on the user's terminal. The user is returned to the
command prompt, executing any ON.ABORT VOC entry on the way.
RI{f|(col)
Used with no options, this statement clears both input buffers, resets the pointer to the start of
the primary input buffer and makes this the active buffer.
The f option specifies that the primary input buffer is to be cleared from field f onwards,
leaving the input buffer pointer positioned at the end of the remaining data.
The (col) option specifies that the primary input buffer is to be cleared from the given character
position, leaving the input buffer pointer positioned at the end of the remaining data.
Both output buffers are cleared and the primary output buffer is activated.
RSUB{n}
Without the n option, the PROC continues execution at the statement following the last
GOSUB executed.
n specifies that execution is to continue starting n lines following the GOSUB.
The RSUB statement is ignored if the PROC is not in a subroutine.
RTN{n}
The PROC returns to the PROC from which it was called, continuing execution n lines after the
[] statement that called the current PROC. If n is omitted, it defaults to 1.
2.11-0
68 OpenQM
Sf|ref|(col)
Moves the input buffer pointer of the active input buffer at the specified position.
f specifies that the pointer is to be positioned at field f.
ref is a direct or indirect buffer reference used to obtain the field number.
The (col) option sets the pointer to the given character position.
The primary output buffer is activated. This statement can also be written as STOF or ST
OFF.
The secondary output buffer is activated. This statement can also be written as ST ON.
T Terminal output
Telement{,element...}
Outputs each element of a comma separated list to the terminal. The elements may be:
text Quoted literal text
ref A direct or indirect buffer reference identifying the data to be displayed. This
may be followed by an input conversion code enclosed in semicolons or an
output conversion code enclosed in colons.
(col) Position the cursor to the specified column of the current line. The value of col
may be given as a number or as a direct or indirect buffer reference.
(col,row) Position the cursor to the specified row and column. The value of row and col
may be given as a number or as a direct or indirect buffer reference.
B Sounds the terminal "bell".
C Clears the screen.
D Pauses for one second.
In Displays character n where n may be given as a number or a buffer reference.
L Terminates a T...L loop.
Sn Emits n spaces where n may be given as a number or a buffer reference.
T Starts a T...L loop where the elements enclosed in the loop will be executed
three times.
U Moves the cursor up by one line.
Xn Displays character n where n may be given as a number or a buffer reference
to a two digit hexadecimal value.
+ Suppresses the normal newline after display.
The (col) and (col,row) elements can also be used to access the terminal control codes that use
2.11-0
The Command Environment 69
TR {ON|OFF}
The ON option causes the PROC processor to display each statement before it is executed.
The OFF option terminates trace mode.
The space before the mode keyword can be omitted. If no mode is specified, tracing is enabled.
Uname
The catalogued program identified by name is called. This program should take no arguments
and can access the PROC buffers using @-variables.
U01A6
action, action...
This special user exit emulation processes successive lines of the Proc as being a comma
separated list of codes that control updates to the screen. Processing continues on the next line
of the Proc if the final character of the current line is a comma. The codes available are:
(col,row) position cursor to specified location.
B sound the terminal "bell".
C clear screen.
In display character with ASCII decimal value n.
Xn display character with ASCII hexadecimal value n.
"text" display text. The cursor is left positioned immediately following the text.
The col, row and n values may be buffer references.
U01AD
filename id fno action
This special user exit emulation reads four parameters from the next line of the Proc. These
may be literal values or buffer references. The record identified by filename and id is read and
field fno is extracted from it. The case insensitive value of action determines the destination for
this data:
a append to alternative (non-active) output buffer.
p append to primary output buffer.
s append to active output buffer.
t display on user's terminal.
v verifies that record exists.
va verifies that attribute fno exists.
If the successful, the next line of the Proc is skipped, otherwise it is executed.
2.11-0
70 OpenQM
Xtext
Displays the optional unquoted text and terminates the PROC, returning to the calling PROC,
program, menu, etc.
+n
The specified numeric value is added to the field of the active input buffer identified by the
input buffer pointer. Non-numeric data is treated as zero.
-n
The specified numeric value is subtracted from the field of the active input buffer identified by
the input buffer pointer. Non-numeric data is treated as zero.
2.11-0
The Command Environment 71
A Q-type VOC record points to a file defined in the VOC of another account.
1: Q { descriptive text }
2: Account name or pathname. Leave blank for the same account.
3: VOC record name in target account
4: Server name for files accessed using QMNet
Field 2 contains the account name. If field 2 is blank, the target record is assumed to be in the same
VOC file as the Q-pointer. If files 4 is blank and the user does not have account barring restrictions
(see Application Level Security), the account location may be specified as a pathname.
Field 3 holds name of a VOC record in the target account. This VOC item must be either an F-type
(file) or a further Q-type record. A chain of Q pointers is inefficient and should be avoided. To trap
closed loops of Q-pointers, a chain with more than ten Q-pointers will cause an error when
attempting to open the file.
If the remote file is on a different QM server, this is specified by putting the server name in field 4
of the VOC entry. The network address and user authentication information is defined using the
SET.SERVER command.
Access to a file via a Q-pointer may fail if account barring restrictions are active for the user
attempting to open the file.
2.11-0
72 OpenQM
An R type VOC entry points to a record in another file which is constructed in the same way as an
executable (M, PA, R, S or V type) VOC entry.
1: R { descriptive text }
2: File name
3: Record name
4: {Security subroutine name}
The file name in field 2 must correspond to an F-type or Q-type entry in the same VOC.
The record name in field 3 is the record in the target file that holds the item to be executed.
An R-type VOC record can optionally hold the name of a catalogued security subroutine in field 4.
This subroutine can be used to determine whether the user is to be allowed to execute the command
pointed to by the R-type record. If the validation fails or the subroutine cannot be found in the
catalogue a message is displayed:
This command is restricted (verb)
2.11-0
The Command Environment 73
1: S { descriptive text }
2: Sentence text
A sentence is a command containing a verb and, optionally, its arguments. Sentence names may be
entered in response to the command prompt in the same way as a verb. Any arguments following
the sentence name on the command line entered at the keyboard will be appended to the sentence
retrieved from the VOC.
Field 1 of a VOC sentence record must commence with a letter S. Field 2 holds the text of the
sentence. This text replaces the sentence name in the current command and parsing continues with
the first word of the substituted sentence.
Where a sentence is very long it may be broken into multiple lines within the VOC record by
terminating all but the final line with an underscore character. When the sentence is executed, the
lines are merged, replacing the underscore with a single space.
Any additional text following the sentence name in a command that starts the sentence will be
appended to the sentence expansion retrieved from the VOC. For example, the EDIT.LIST
command is actually a sentence stored as
1: S
2: ED $SAVEDLISTS
Typing
EDIT.LIST MYLIST
actually executes the command
ED $SAVEDLISTS MYLIST
This automatic appending of additional text in the command makes stored sentences very useful as
the start of commands but prevents effective use of some inline prompt control codes in the sentence
expansion.
2.11-0
74 OpenQM
A V type record defines a command name and determines the QM component that will be used to
process the command.
1: V { descriptive text }
2: Dispatch code
3: Processor
4: { Qualifying information }
5: { Security subroutine }
The dispatch code identifies the type of processor referenced by field 3. It may be:
CA A catalogued verb. Field 3 holds the catalogue name of the function to be executed. For
system supplied verbs, field 4 may also be significant and should not be altered.
IN An internal verb. Field 3 holds an identifying number which determines the action of
the verb.
Users may add their own V-type records for catalogued programs (usually by use of the
CATALOGUE verb) or make copies of standard records to provide synonyms for other verbs.
A V-type VOC record can optionally hold the name of a catalogued security subroutine in field 5.
This subroutine can be used to determine whether the user is to be allowed to execute the command.
If the validation fails or the subroutine cannot be found in the catalogue a message is displayed:
This command is restricted (verb)
2.11-0
The Command Environment 75
X-type VOC items are miscellaneous data storage records which may be used in any way the
application designer wishes.
1: X { descriptive text }
2: user data
Fields 2 onwards are available for data storage. Users may freely create X type records for their
own purposes but should avoid names containing $ signs as these may clash with system defined
records.
2.11-0
76 OpenQM
Security subroutines
An R-type or V-type VOC entry can optionally include the name of a catalogued security
subroutine in field 4 (R-type) or field 5 (V-type). This subroutine can be used to determine whether
the user is to be allowed to execute the command.
The security subroutine is written using QMBasic. A simple subroutine that prompts for a
password is shown below.
RETURN @FALSE
END
If the validation fails or the subroutine cannot be found in the catalogue a message is displayed:
This command is restricted (verb)
The security subroutine mechanism can also be used for other purposes such as auditing use of
specific commands, diagnostic traps, etc.
2.11-0
The Command Environment 77
Inline prompts provide a means to prompt for data needed by a sentence or paragraph when it is
executed. The DATA command does not affect inline prompting which always takes its response
from the keyboard. There are also variants on inline prompts that retrieve data from other sources,
providing a generalised way to substitute variable items into a command.
where
control determines the way in which the prompt is displayed and how it is actioned on
subsequent execution of the same statement or another with the same text. Control
codes are generally case sensitive. A single inline prompt may have multiple
control elements.
text is the prompt text to be displayed. An equals sign is automatically added to the end
of the prompt text.
check is used to check whether the response to the prompt is valid. If omitted, no
checking is performed.
The control option has two parts; the display control and the response control. Both parts are
optional.
The display control may contain any of the following items. Multiple items may be concatenated,
separated by commas, and are performed in the order in which they appear.
@(col, row) specifies the display position for the prompt text. The QMBasic @() function
variants with a negative value for the first (or only) argument are also
supported.
@(BELL) sounds the audible warning. The BELL OFF command will suppress this
action.
@(TOF) Positions to the top left of the display. This is equivalent to use of @(0,0).
The response control consists of one of the items listed below. If omitted, the prompt is actioned
only for the first occurrence of a prompt with the given text. Subsequent execution of the same
inline prompt or another with the same text will not cause a prompt to be displayed but will use the
response to the previous prompt. All prompt responses are discarded on return to the command
prompt. The CLEAR.PROMPTS command can be used to discard all inline prompt responses
from within a paragraph.
A Always prompt. This is usually needed on the first occurrence of each prompt
in a loop so that each iteration of the loop prompts again.
2.11-0
78 OpenQM
Cn Used in paragraphs to take the n'th token of the sentence that started the
paragraph as the response to the prompt. No prompt text will appear unless the
implicit response fails to meet the check conditions. The C control code has
several extended forms:
Cm-n Returns tokens m to n.
Cn+ Returns tokens n onwards.
C# Returns the number of tokens in the command line.
All formats of the C control code except C# may include a default value. For example,
<<C4:SALES>>
The default value will be applied if the prompt would otherwise return a null string.
CHANGE(str, old, new) Change all occurrences of substring old in str with new. Argument
values may be enclosed in quotes if necessary to avoid any syntactic
ambiguity.
F(file, key {,field {, value {, subvalue}}}) Use record key of the data portion of the
named file as the response to the prompt. The optional field, value and
subvalue allow extraction of a particular part of the record.
ICONV(str, code) Apply input conversion code to str. Argument values may be enclosed in
quotes if necessary to avoid any syntactic ambiguity.
In Used in paragraphs to take the n'th token of the sentence that started the
paragraph as the response to the prompt. If this is a null string or the implicit
response fails to meet the check conditions, an input prompt appears.
Ln Extracts the next item from select list n. If n is omitted, it defaults to zero.
When the select list is exhausted, a null string is returned. This control code
does not need to be used with the A control code in a loop as it always reads
the next list entry.
OCONV(str, code) Apply output conversion code to str. Argument values may be enclosed
in quotes if necessary to avoid any syntactic ambiguity.
R Prompt repeatedly for input, concatenating data with an intervening space until
a blank line is entered.
R(string) Prompt repeatedly for input, concatenating the responses with string between
responses until a blank line is entered. The string may not include field mark
characters. An abort will occur if a field mark is specified as part of string.
Sn Take the n'th token of the sentence entered at the command prompt as the
response to the prompt. If this is a null string or the implicit response fails to
meet the check conditions, an input prompt appears.
SUBR(name) Execute catalogued QMBasic function name, returning the result of this
function as the value of the inline prompt.
SUBR(name, arg1, arg2) Execute catalogued QMBasic function name, passing in the given
2.11-0
The Command Environment 79
arguments and returning the result of this function as the value of the inline
prompt. Up to 254 arguments may be specified. These may be enclosed in
quotes if necessary to avoid any syntactic ambiguity.
U Converts the data entered in the response to the prompt to uppercase. Note that
this control must appear before any other control options to which it is to
apply.
@var The name of an @-variable, including user defined names (see the SET
command), may be used to retrieve the value of the given variable. A default
value may be applied by use of a prompt of the form:
<<@name:value>>
The default value will be applied if the prompt would otherwise return a null
string.
$var The name of an operating system environment variable may be used to retrieve
the value of the given variable. A default value may be applied by use of a
prompt of the form:
<<$name:value>>
The default value will be applied if the prompt would otherwise return a null
string.
The Cn and In control codes are only useful in paragraphs. A command that references a paragraph
(PA-type VOC entry) may include additional text that can be accessed using these control codes. In
a command that references a stored sentence (S-type VOC entry), any additional text following the
sentence name is added to the end of the sentence expansion, making effective use of these control
codes impossible. There is no reason why a paragraph cannot contain only a single sentence if these
control codes are to be used.
The <<@var>> construct allows @variables to be inserted into any command, simplifying
paragraph structure. For example:
SAVE.LIST LIST.<<@USERNO>>
could be used to save a select list with a name that includes the user number to ensure uniqueness
for the duration of the user's QM session.
The check code performs simple data validation and is either a pattern match template or an input
conversion code. Multiple patterns can be specified separated by the word OR with a single space
either side. For example,
3N'-'4N OR 4N'-'3N
Input conversion codes must be enclosed in brackets. Any of the codes that can be used with the
ICONV() function may be used. The check is considered successful if no conversion error occurs.
The value returned by the prompt is the actual text entered, not the result of the conversion.
2.11-0
80 OpenQM
Entry of QUIT at the keyboard in response to an inline prompt will abort and return to the
command prompt. The @ABORT.CODE variable will be set to 2 as for QUIT entered at other
prompts.
Inline prompts are expanded as the first stage of processing a command. This has two important
effects:
An inline prompt in a comment line will be evaluated. This slightly strange effect can be useful
as a means to perform all prompts at the start of the paragraph rather than as they are needed,
perhaps much later.
An IF command in a paragraph where the conditioned statement includes an inline prompt will
display the prompt before determining whether the condition is true. The paragraph can always
be structured in a way to avoid this behaviour.
A single command may contain multiple inline prompts. These will be evaluated left to right. Nested
inline prompts will be evaluated from the inside outwards.
The response to an inline prompt may not include the left or right double angle bracket symbols (<<
and >>) or field marks. Entering a response containing one of these will cause the prompt to be
repeated.
When used as an item to test in an IF command, the prompt will usually need to be enclosed in
quotes so that a response that contains spaces or reserved keywords does not cause the command
parsing to fail. For example
IF <<Customer number>> = "" THEN STOP
should be written as
IF "<<Customer number>>" = "" THEN STOP
Examples
PA
SELECT ORDERS SAVING UNIQUE CUST.NO_
WITH DATE AFTER <<Start date>>
LIST CUSTOMERS NAME_
HEADING "Clients ordering after <<Start date>>"
The above paragraph uses two identical inline prompts. The first asks the user to enter a start date
for a SELECT operation. The second prompt will not repeat the request as the answer is already
known. Note that the prompt text can contain spaces and that the inline prompt substitution occurs
even though it is part of a quoted string.
PA
* <<Target file>>
RUN OVN.PROCESS
OVN.RPT <<Target file>>
In this example, the inline prompt is in a comment. Although the prompt will be issued at the start
of the paragraph, the result is not used until the final command. If the OVN.PROCESS program
takes a considerable length of time to execute, this technique allows the prompt to be answered
early, without having to wait for the program to complete.
2.11-0
The Command Environment 81
PA
* <<I2,Target file>>
RUN OVN.PROCESS
OVN.RPT <<Target file>>
By adding the I2 control option to the previous example, the paragraph will take the target file name
from the second word on the command line if present, prompting if it is not given.
PA
LOOP
IF <<A,Customer>> = "" THEN STOP
LIST ORDERS WITH CUST.NO = <<Customer>>
REPEAT
This paragraph uses a loop in which the user is prompted to enter a customer number. If this is a
null string, the paragraph terminates. Otherwise it lists the ORDERS file records for this customer.
Note the use of the A option on the first prompt in the loop so that it is repeated on each cycle of the
loop. Without this, the paragraph would list the orders for the same customer continuously until
stopped by user action.
PA
LOOP
IF <<L,ID>> = "" THEN STOP
MYPROG <<ID>>
REPEAT
This paragraph uses a loop to walk through the default select list, executing MYPROG for each
entry taken from the list.
SAVE.STACK <<@LOGNAME>>
DISPLAY Domain is <<$USERDOMAIN>>
These two commands show use of the inline prompt mechanism to insert the value of system
variables into commands. The first uses an internal QM @variable to retrieve the user's login name,
the second accesses the operating system USERDOMAIN environment variable.
This example uses the inline prompt mechanism to access the QM licence number via the QMBasic
SYSTEM() function.
See also:
CLEAR.PROMPTS
2.11-0
82 OpenQM
Pattern matching is a way to test whether data has a particular structure. It can be used for data
validation and as a means to extract the part of a data item that matches against a specified element
of the pattern. The pattern matching operations are the query processor LIKE and UNLIKE
keywords, the QMBasic MATCHES operator, MATCHFIELD() and MATCHESS() functions,
and the M search of ED. All of these compare a character string with a pattern template.
Pattern matching breaks the character set into three classes of character, each represented by a
character type code:
A Alphabetic, upper and lowercase A - Z
N Numeric, digits 0 - 9
X Any character, including alphanumerics
There are also three ways to specify how many characters are present:
4 Exactly 4 characters
2-7 Between 2 and 7 characters
0 Any number of characters, including none
The template consists of one or more concatenated items formed from pairs of lengths and character
type:
The values n and m are integers with any number of digits. m must be greater than or equal to n.
The 0X code is a wildcard that matches against anything. It has a commonly used synonym:
... Zero or more characters of any type
The 0A, nA, 0N, nN and "string" patterns may be preceded by a tilde (~) to invert the match
condition. For example, ~4N matches four non-numeric characters such as ABCD (not a string
which is not four numeric characters such as 12C4).
A null string matches patterns ..., 0A, 0X, 0N, their inverses (~0A, etc) and "".
The 0X and n-mX patterns match against as few characters as necessary before control passes to
2.11-0
The Command Environment 83
the next pattern. For example, the string ABC123DEF matched against the pattern 0X2N0X
matches the pattern components as ABC, 12 and 3DEF.
The 0N, n-mN, 0A, and n-mA patterns match against as many characters as possible. For example,
the string ABC123DEF matched against the pattern 0X2-3N0X matches the pattern components as
ABC, 123 and DEF.
The template string may contain alternative patterns separated by value marks. The source data will
match the overall pattern if any of the pattern values match.
The MATCHESS() function can be used to compare each element of a dynamic array with a
pattern, returning a equivalently structured dynamic array of true/false values. Note the spelling of
this function with the trailing S to "pluralise" the name in the same way as other multivalue function
names.
Examples
It is often acceptable to omit the quotes around literal components. The above example would also
match
A1-3N3A
There is no confusion between the leading A as a literal or as a character type as it is not preceded
by a length value. It is, however, recommended that the quotes should be included. Omitting the
quotes in a pattern used in the MATCHFIELD() function may affect the function's behaviour as
each character of the literal will be counted as a separate component of the pattern.
A program might need to test whether data entered by a user is a non-negative integer (whole
number) value. The QMBasic NUM() function can be used to test for numeric data but this would
allow fractional or negative values. Testing against a pattern of "1-4N" would allow only integer
values in the range 0 to 9999. To remove the upper limit, a pattern of 1N0N tests for one digit
followed by any number of further digits, including none.
2.11-0
84 OpenQM
2.8 Printing
QM applications do not drive printing devices directly. Instead they reference numbered print units
with no knowledge of where the output will actually go. This leads to a very flexible printing system
where the output can be sent to a printer, a file or the user's screen. QM uses the underlying Print
Manager on Windows or the operating system spooler on other platforms to perform output to
printer devices.
Windows Mobile and Windows CE used on PDA devices have no built-in printer support. Third
party software packages are required to print on these platforms. QM retains support for mode 3
print units as described below.
Each QM session has its own pool of print units, numbered from 0 to 255. In most cases, if a print
unit is not specified in a command, printer 0, the default printer, is used. Application developers are
free to use these print units in any way that meets their needs. They might correspond to different
printers, different paper types on the one printer, selection of portrait or landscape mode, etc.
Although it is unlikely, all 256 print units can be used simultaneously.
The QMBasic PRINT statement directs its output to printer 0 unless the ON clause is used to
specify some other printer:
PRINT ON 4 "Invoice Summary"
Within QMBasic programs printer 0 is treated as a special case. If the program has not used the
PRINTER ON statement (or the LPTR qualifier to the RUN command), output to printer 0 is
actually sent to the user's screen rather than the printer. This allows an application to use either the
screen or the default printer simply by choosing whether to execute the PRINTER ON statement
rather than having to implement two alternative paths for every place that performs output.
QMBasic programs can also reference print unit -1 as a synonym for the user's screen.
Unless otherwise defined, print unit 0 is directed to the system's default printer and all other print
units are directed to the $HOLD file. Almost all applications will need to modify this default
behaviour by using the SETPTR command. This command is frequently executed from the
MASTER.LOGIN paragraph in the QMSYS account (to affect all users), from the LOGIN
paragraph of a specific account (to affect only users of that account), or from within the
application.
The SETPTR command defines the shape of the printed page (width, depth, margins), the
destination and various options relating to the treatment of the output:
SETPTR unit {, width, depth, top.margin, bottom.margin, mode {, options }}
2.11-0
The Command Environment 85
be set using the AS option of the SETPTR command which includes the ability to add a
rotating sequence number for generate a different name for each output job. This sequence
number can be determined using the QMBasic GETPU() function or the @SEQNO variable.
Mode 4 directs the output the the stdout (standard output) file unit.
Mode 5 buffers the data in the $HOLD file and then sends it to the terminal when the printer is
closed, prefixing it with the control code to enable the terminal auxiliary port and disabling this
port on completion of the print. This feature relies on the mc5 (aux on) and mc4 (aux off)
terminfo items being set correctly.
Mode 6 combines the actions of modes 1 and 3, creating a file and also printing the data.
A print job commences when the first line of output is sent to the printer and normally terminates
when the program closes the print unit either explicitly or implicitly by returning to the command
processor. It is possible to merge output from several successive print programs into one job by use
of the PRINTER command. The KEEP.OPEN option used before output commences followed by
the CLOSE option after the final program completes treats the entire sequence as a single print job.
Although Pick style systems support the ON clause of the Basic PRINT statement, applications
that need only one printer at a time more usually determine the output destination by selecting a
numbered form queue. As an aid to migration, QM provides limited support for Pick style form
queues by use of the SP.ASSIGN command. Internally, QM needs to relate form queue numbers to
the equivalent SETPTR options and this is managed by a mapping file, $FORMS, using the
SET.QUEUE command.
The SET.QUEUE command is very similar to SETPTR but instead of assigning the specified
characteristics to a numbered print unit, they are stored in the $FORMS file with a numeric id that
corresponds to the form queue number. Subsequent use of the SP.ASSIGN command picks up the
form queue details from the $FORMS file and applies these to printer 0 by internal use of
SETPTR. The R option of SP.ASSIGN allows the form characteristics to be applied to a different
print unit.
Whereas each QM process has its own set of 256 numbered print units, form queue numbers and
their settings are normally shared across all QM sessions because the same $FORMS file is visible
to all accounts. By creating alternative $FORMS files and modifying the VOC F-pointer, it is
possible to maintain separate form definitions for specific accounts or groups of accounts.
For more information, see the SP.ASSIGN and SET.QUEUE command descriptions.
Printing on Windows
Windows defines two alternative printing interfaces. The graphical device interface (GDI) allows a
Windows application to construct complex text and graphics images whereas the non-GDI mode
(known in QM as raw mode) is a much simpler interface that permits only simple text output. QM
uses the raw mode by default though, for compatibility with older releases, the GDI configuration
parameter can be used to make GDI the default though QM does not provide any functions to
generate GDI graphics.
Some options of the SETPTR command are applicable only to one or other of the two modes. Also,
some options may not be supported by all Windows print drivers. In most cases, inapplicable
2.11-0
86 OpenQM
QM normally uses the underlying lp command to print data on these platforms though this can be
modified by use of the SPOOLER configuration parameter or the SPOOLER option of the
SETPTR command. SETPTR options that are not applicable are ignored.
Use of print spoolers other than lp may require QM to use different options to the command to pass
the printer name, copy count, etc. To support this, there is an X-type record in the VOC file of the
QMSYS account named $SPOOLERS. This has six associated multivalued fields such that:
Field 2 Spooler name
Field 3 Option to specify printer name
Field 4 Option to specify copy count
Field 5 Option to specify banner text
Field 6 Option to set spooler options
Field 7 Option to set landscape mode
In each case, the variable data to be inserted into the option is represented by a percent sign (%).
The $SPOOLERS file released with QM contains a definition for use of lpr. This has
Field 2 lpr
Field 3 -P %
Field 4 -K %
Field 5 -T "%"
Field 6 -Z "%"
Field 7 -Z "landscape"
Printing to a File
The SETPTR command can be used to direct output to a record in the $HOLD file or to any
specific pathname on the server system. Hold file entries have a default name of Pn where n is the
print unit number but this can be modified in SETPTR to use a different name and/or to add a
rolling sequence number to the name.
When a print unit is directed to a file, a check is made to see if there is a catalogued subroutine
named HOLD.FILE.LOGGER and, if there is, this is called when the file is opened and again when
it is closed. This subroutine can be used, for example, to build a log of hold file entries or to take
some action after the file has been closed. The subroutine takes three arguments; the print unit
number, a flag indicating if this is an open (1) or a close (0), and the pathname of the file being
created.
The PREFIX option of the SETPTR command can be used to specify the pathname of a file
containing printer initialisation commands. The content of this file is sent to the printer before the
first output from the application. A typical use of a prefix file might be to select a paper tray.
The printing system of QM includes features for greater control of PCL printers. These include font
2.11-0
The Command Environment 87
selection, basic graphics and enhanced report formats. The PCL features are enabled by including
the PCL option in the SETPTR command when defining the printer characteristics.
By default, a PCL printer will print in Courier font at 10 characters per inch and 6 lines per inch.
The SETPTR command includes options to specify alternative values for the character and line
spacing. The paper size defaults to A4 but can also be amended using SETPTR. The
LANDSCAPE option will rotate the page through 90 degrees. Default values for the PCL
parameters can also be set using a $PCL VOC record. For more details, see the SETPTR
command.
The query processor also has special support for PCL printers in report generation commands (e.g.
LIST). Page headings, footings and breakpoint values are printed in bold face. The BOXED option
draws a box around the page and separates the heading and footing from the text with horizontal
lines.
Graphical Overlays
The OVERLAY option of the SETPTR command can be used to specify the name of a catalogued
subroutine that will be called at the start of each page of output and can be used to emit printer
specific control codes to draw a graphical overlay on the page. The OVERLAY option of the query
processor reporting commands performs the same action but applies only to the report in which it is
used.
In either usage, the catalogued subroutine takes a single argument which is the print unit number.
Any control strings output by this subroutine should be emitted using the PRINT statement,
normally with the trailing carriage return/line feed suppressed. For PCL printers, it is recommended
that the standard QMBasic PCL control string functions should be used.
Example
subroutine overlay(pu)
$catalog overlay
$include pcl.h
The above subroutine draws a box around an A4 sized page on a PCL printer. Note how it saves
the cursor position to ensure that subsequent application output appears at the correct place.
Because the subroutine is called before any other output to the page, it is possible for the subroutine
to make other changes to the page settings. Note in the above example how the left margin is
indented to bring the application output away from the left edge of the box.
2.11-0
88 OpenQM
2.11-0
The Command Environment 89
Dates
Dates are usually stored as a number of days since 31 December 1967 (day zero). All dates after
that point are represented by positive numbers. All dates before that point are represented by
negative numbers. This form of date is used by all multivalue databases and means that they had no
issue with the millennium (day 11689). The multivalue world had its own date crisis on 18 May
1995 (day 10000) when developers discovered that they had stored the date as four characters of a
composite record id or were sorting dates as character strings rather than numbers such that 17
May 1985 (day 9999) came after 18 May 1995. This potential problem still applies to any
application that handles historic dates but the advantages of working with a simple day number
internally far outweigh any disadvantages.
A user can see the current date in its internal or external form by using the DATE command. This
command can also translate an arbitrary internal or external form date to its counterpart.
A programmer can access the current date using the DATE() function or the @DATE variable.
The difference between the two is that DATE() returns the internal form of the date when the
function is executed whereas @DATE is the internal form of the date when the currently executing
command began.
The D conversion code can be used by applications to transform dates between their internal and
external form.
Times
A user can see the current time in its internal or external form by using the TIME command. This
command can also translate an arbitrary internal or external form time to its counterpart.
A programmer can access the current time using the TIME() function or the @TIME variable. As
described above for dates, the difference between the two is that TIME() returns the internal form
of the time when the function is executed whereas @TIME is the internal form of the time when the
currently executing command began.
The MTconversion code can be used by applications to transform times between their internal and
external form.
Sometimes, an application developer may find it useful to have a composite item that represents
both the date and time. One way to do this is to store it as the day number * 86400 plus the time, a
value that equates to seconds since midnight between 30 and 31 December 1967. QM provides a
function, SYSTEM(1005), to return the current time in this form.
The QMBasic TIMEDATE() function returns a combination of the current date and time in text
format.
2.11-0
90 OpenQM
Epoch Values
Today's business applications are frequently used by networked users who may span time zones.
The date and time functions mentioned above all return data appropriate to the time zone of the QM
process for the user running the application. This time zone is initially determined by the setting of
the TZ environment variable at the operating system level on entry to QM but can be modified
using the TIMEZONE private configuration parameter or the QMBasic SET.TIMZONE statement.
The time zone can differ from one user to another, thus, if two users in different time zones
evaluate the TIME() function simultaneously, the returned value will be different. In some cases,
storing a date or time that is appropriate only to the user who saved it may be meaningful but it is
more likely that we need a way to store dates and times in a time zone independent manner that
represents a moment in time. A value stored in this form can then be converted to the local time
zone of the user later, giving a local representation of that moment in time such that a single stored
time value may be represented differently on the screen for different users.
The underlying principle of this extension to the multivalue date and time handling is that we store
the date/time as an epoch value. This is the number of seconds since the start of January 1970 UTC
(closely related to GMT) and is a concept that is widely used in other computer systems. Because
epoch values are independent of the user's time zone, the same data can be used unambiguously by
all users of the system, regardless of where they are in the world.
Epoch values are generally defined to be 32 bit signed integers. This leads to a limitation that they
can only represent times between 13 December 1901 and 19 January 2038. This is a widely
recognised issue, potentially more widespread than the "millennium bug", that will require changes
to operating systems and run time libraries.
More seriously, Windows support for time zones at the application level is very poor. Although
QM's epoch handling functions will operate to some extent, the time zone name must include the
offset from GMT (which implies that it cannot automatically resolve daylight saving time for an
arbitrary date) and Windows is incapable of processing dates before 1 January 1970 as epoch
values.
The E conversion code provides the combined facilities of the D and MT conversion codes plus
several features that only apply to epoch values.
In Linux and Mac systems, time zone names are taken from the Olson Database and are constructed
from an area and location pair (e.g. America/New_York). In some cases, the location element is
2.11-0
The Command Environment 91
further divided (e.g. America/Indiana/Indianapolis). Names such as GMT, EST, CET, etc are also
recognised.
The Olson Database is part of the operating system, not QM. Updating this database is automatic
on some platforms (e.g. Mac) but may require actions by the system administrator on some other
platforms.
AIX provides partial support for time zones. The default time zone is taken from the TZ
environment variable. Any time zone set using the CONFIG command or the QMBasic
SET.TIMEZONE statement must be in the format required by AIX (e.g. EST5 or EST5EDT).
The Z element of the E conversion code (time zone name) will return a null string.
Windows support for time zones is very limited. The time zone name is of the form
z{+ | -}d{s}
where
z is a three character string representing the name of the current time zone. For example, the
string “CET” could be used to represent Central European time but Windows make no use
of the actual name.
d is an optionally signed item with one or two digits specifying the local time zone’s
difference from GMT in hours. Positive numbers adjust westward from GMT and negative
numbers adjust eastward from GMT. (e.g. EST5, PST+8, CET-1).
s is an optional three character field that represents a name for the local time zone when
daylight saving time is in effect.
2.11-0
92 OpenQM
QM provides a number of ways to trap errors, some applicable to the command environment, some
to QMBasic programs. This section summarises the features of QM error handling.
Error Numbers
QM uses a simple system of error numbers to identify the cause of an error. The formal definition
of these numbers is in a QMBasic include record named ERR.H in the SYSCOM file. The list can
also be found in the Error Numbers section of this manual.
Many commands leave status information in the @SYSTEM.RETURN.CODE variable. The value
of this variable can be tested within a paragraph or a QMBasic program to determine whether the
command was successful. In general, success is indicated by the value of this variable being zero.
Because the query processor uses @SYSTEM.RETURN.CODE to return the number of records
processed, error values are usually returned as the negative of the error number.
The REPORT.SRC command can be used to enable automatic display of the value of
@SYSTEM.RETURN.CODE after every command. This is useful as a debugging aid during
application development.
Many QMBasic program operations leave status information that can be accessed using the
STATUS() function. Although often used for error numbers, the data returned by the STATUS()
function may have other roles. For example, some operations that attempt to get locks return the
user number of the user who owns the lock if the action cannot be completed. Use of the STATUS
()function is documented with the relevant QMBasic statements and functions.
Where an error reported by QM is related to some underlying error reported by the operating
system, the original operating system error code can often be obtained using the OS.ERROR()
function. The QM errors for which this extended error information is available are documented with
the relevant QMBasic statements and functions. They are also marked in the SYSCOM ERR.H
2.11-0
The Command Environment 93
record.
Operating system error numbers vary between platforms and are documented by the operating
system vendor.
Many QMBasic statements that could fail due to external influence have an optional ON ERROR
clause. This would be executed, for example, when attempting to write to a file for which the user
does not have write access.
The default action of QM to this type of error if no ON ERROR clause is present is to abort the
program with a suitable diagnostic message. The ON ERROR clause allows the program to catch
this error and handle it internally instead of aborting.
Very few programs ever need to use the ON ERROR clause. It is only applicable in situations
where the program can take some meaningful action to recover from the error. The default action of
QM is usually adequate. A program that simply uses the ON ERROR clause to abort is likely to
produce a less helpful diagnostic message than would have been displayed without this clause.
2.11-0
Part
3
The QM File System
96 OpenQM
File Types
The files used by QM are of two types; directory files and dynamic files. Directory files do not give
high performance but allow data to be accessed from outside of the QM environment. They are
therefore frequently used for data interchange with other software. Dynamic files offer very high
performance and are typically used for the bulk of the data stored by an application. In addition,
QM supports distributed files which are a way of viewing a collection of separate dynamic files as
though they are one file.
Facilities are provided to create data files, enter, modify and retrieve data, produce reports and,
where the data processing operation required cannot be achieved using the standard commands, to
construct powerful programs with the minimum of effort.
Most files consist of two parts; a data part holding the actual data and a dictionary part holding a
description of the structure of data records. Files do not have to have both parts. Files with no
dictionary portion are fairly common. Dictionaries with no data part usually exist only to provide a
single dictionary common to the data portion of many files. Multiple files that have identical data
structure may share a single dictionary.
For compatibility with other multivalue database products, QM also supports multifiles. These are
a collection of data files that share a common dictionary where the component files are referenced
by a two part name consisting of a file name and a subfile name separated by a comma. See the
CREATE.FILE command for further details.
Files contain data stored as records which are the basic unit of file access. Records are identified by
unique keys which may be any sequence of up to 63 characters. This limit can be increased by the
system administrator.
Normally, QM commands that reference files use a file name that corresponds to an F or Q-type
VOC entry which, in turn, references the actual operating system file to be accessed. There are
three special extended syntaxes for filenames that allow access to files without needing a VOC
entry. Use of these is controlled by the FILERULE configuration option. Users should consider any
impact of the security of their system before enabling these.
Note that in the final form, depending on context, Windows users may need to use forward slash
characters (/) as directory delimiters because the backslash (\) is reserved as a string quote.
Alternatively, the entire "PATH:pathname" construct can be quoted.
For details of file processing from QMBasic programs, see File Processing.
2.11-0
The QM File System 97
As a general rule, files that may be accessed from the operating system level must be directory files
and all other files should be dynamic files. Dynamic files give best performance but records cannot
be accessed from outside of QM.
QMBasic source programs are normally stored in directory files. Dictionaries are automatically
created as dynamic files regardless of the type of the associated data file as a directory file
dictionary could cause severe performance degradation in query processor commands.
Files are created using the CREATE.FILE command which normally creates both a data and
dictionary portion for the file. Either may be created individually by use of the DATA or DICT
keywords. Dictionary portions are not required for files used to hold QMBasic source programs or
include records.
The CREATE.FILE command creates the file and also writes an F-type record to the VOC. If the
file is to be accessed from more than one account, this F-type record may be duplicated in the other
accounts, changing the pathnames in fields 2 and 3 to include the drive and directory components as
necessary. A better method is to use Q-type VOC entries for remote file pointers.
The data portion of a file is created at the specified or default minimum modulus size and with no
records. The dictionary portion has a single record, @ID, added to it to represent the record key.
Files may be deleted using the DELETE.FILE command. The DATA or DICT keywords allow
deletion of just the appropriate portion of the file.
Where the file's pathname in the VOC includes drive or directory components, the DELETE.FILE
command assumes the file to be in some other account and prompts for confirmation that it should
be deleted. If the file is to be retained but the reference to it from the current account is to be
deleted, use the DELETE command to delete the VOC record.
The QM file system uses the underlying operating system file structures to store its data. This
imposes some rules on how the operating system level files should be managed.
On Windows XP systems, use of mapped drives can assign different physical locations to the same
drive letter for different users. This will cause serious problems to QM as it is impossible to identify
a file uniquely. In particular, the locking system is likely to become unreliable.
All QM users should use the same mappings. For users entering QM via a network connection,
including connections looped back to the same machine, the DOS SUBST command may need to be
used to create the drive mapping. This can be included in the LOGIN or MASTER.LOGIN
paragraphs in the form
SH SUBST X: C:\ABC
where X: is the mapped drive letter and C:\ABC is the target directory to which X: is to be
mapped.
Similarly, use of chroot on non-Windows systems destroys the uniqueness of file names. Although
2.11-0
98 OpenQM
this may work in some cases, it can lead to ambiguities that will cause QM to fail in unpredictable
ways. Use of this command is at the user's own risk.
Systems other than Windows allow a file to be renamed or deleted while it is in use. This action is
likely to cause QM to fail and should not be used.
Mark Mapping
Database records are often entered, modified or retrieved by the ED, SED and MODIFY
commands.
In directory files, the internal field mark character is replaced by the ASCII newline character when
a record is written to disk so that fields appear as lines if the record is viewed, edited or printed
from outside QM. Conversely, ASCII newlines are converted to field marks on reading a record.
Mechanisms are provided in QMBasic (see the MARK.MAPPING statement) to turn off this
translation when handling binary data.
2.11-0
The QM File System 99
A directory file is represented by an operating system directory and the records within it by
operating system files. The record key is the name of the operating system file holding the data for
the record except where this would be an invalid name in which case QM performs automatic name
mapping as described below.
Directory files do not give high performance because the process of searching a directory for a file
is, with many operating systems, essentially a linear scan. Locating a record to be read would,
therefore, require on average that half of the entries in the directory are examined. Writing a new
record would require the entire directory to be processed to verify that the file does not already
exist.
Directory files are mainly used for data that is to be processed from outside of QM or for very large
records (hundreds of kilobytes) where the operating system file structures may give better
performance than the hashed file system. Typical uses include storage of QMBasic programs,
COMO (command output) files, and saved select lists.
When a record is written to a directory file, any field mark characters are converted to the operating
system dependent representation of a newline. Thus, each field becomes a line of text which allows
the data to be processed by external software that does not understand the concept of field marks.
Conversely, when data is read from a directory file, the newlines are translated to field marks.
Where the data contains value marks or subvalue marks, these are not translated as it is assumed
that whatever software will process this data must understand multivalued data.
One common use of directory files is to store scanned documents, digital photographs, etc. In this
case, the data is not text divided into fields using the field mark character but is simple binary data
that may contain any sequence of bytes. The data will nearly always contain bytes that appear to be
field marks and other bytes that are the ASCII linefeed character. On writing the data to disk, the
field marks will be converted to newlines. On reading the record back again, all of the newlines get
converted to field marks such that the record does not match the original data written. This is
clearly unacceptable. Application developers using director files to store binary data must suppress
the translation of field marks by use of the QMBasic MARK.MAPPING statement.
Where a record id contains characters that are not valid in operating system file names, QM
automatically replaces them with an alternative representation. This is totally invisible from inside
QM but other software that accesses directory file records must allow for these translations. Rather
than have a different set of translations for each platform, QM adopts a single set based on the most
restrictive platform (Windows) so that data may be moved between environments without
modification of record names. The translations performed are:
* %A % %P
\ %B " %Q
, %C / %S
= %E + %V
> %G : %X
| %J ; %Y
< %L ? %Z
In addition, use of a period or tilde character as the first character in the name will translate this
character to %D or %T respectively. QM uses names with an untranslated leading percent
character to represent the subfiles of a dynamic hashed file. External applications should avoid
writing such items into directory files as they may cause confusion.
2.11-0
100 OpenQM
Character mapping in record ids can be suppressed by use of a flag in field 6 of the F-type VOC
entry that defines the file or by use of the NO.MAP option to the QMBasic OPEN, OPENPATH,
OPENSEQ and DELETESEQ statements.
Depending on the operating system in use, record ids in directory files may be case insensitive.
Note also that the Windows file system does not allow file names that clash with Windows device
names such as COM. Also, Windows ignores a trailing period in a file name. Thus files named
"ABC." and "ABC" are the same item.
When writing a record to a directory file, QM normally opens the operating system file that will
represent this record and writes to it, overwriting any existing data. There is a possibility of data
loss when updating an existing record if the system fails during this write (e.g. a power outage) or if
there is insufficient disk space. To prevent this, the SAFEDIR configuration parameter can be set to
adopt a "safe update" technique where the data is written to a temporary file, the original is deleted
and the temporary item is renamed to replace the original. This removes nearly all possibility of
losing the record but degrades performance of the write.
Records in directory files may be read, written or deleted by applications in exactly the same way as
records in hashed files. The QMBasic programming language provides some additional operations
for directory file access. A record may be opened using the OPENSEQ statement and then
processed on a line by line basis (READSEQ, WRITESEQ, etc) or as a simple binary item (
READBLK, WRITEBLK, etc). In addition, programming statements are provided to simplify
processing of comma separated variable format data (READCSV, WRITECSV).
On all systems except Windows, the DIR.DTM mode of the OPTION command can be used to
cause writes to directory files or closing a sequential file that has been written to update the
date/time modified of the directory.
2.11-0
The QM File System 101
A dynamic file is represented by an operating system directory, the records within it stored in a fast
access file format in the directory. Users should not place any other files in the directory or make
any modifications to the files placed there by QM. Dynamic files are so called because of the
dynamic reconfiguration of the file which takes place automatically to compensate for changes in
the file's size and record distribution.
Record keys may have between 1 and 63 characters but these may not include mark characters or
the ASCII null character. This length limit can be increased to a maximum of 255 by changing the
value of the MAXIDLEN configuration parameter but this can lead to compatibility problems when
transferring data to other systems and significantly increases the size of QM's internal locking
tables.
A dynamic file has two parts; a primary subfile which is examined first when looking for data and
an overflow subfile which contains data which does not fit into its correct location in the primary
subfile. The primary and overflow subfiles are represented by operating system files named %0 and
%1. Prior to release 2.8-0, the names were ~0 and ~1 but this caused problems with some poorly
designed system cleanup utilities that assumed names commencing with a tilde represented
temporary items that could be deleted. There may be additional items named %2, %3, etc that store
data for alternate key indices.
Users do not need to understand the mechanisms that are involved in accessing dynamic files though
the following information will help in determining settings for the parameters which control file
configuration and hence performance. In most cases these can be left at their default values.
Data within a dynamic file is stored in record groups. The number of groups in the files is known
as the modulus. The group in which a record is located is determined mathematically by using the
hashing algorithm associated with the file.
A group consists of a fixed sized area in the primary subfile and, if the data assigned to the group
does not all fit into this area, as many additional overflow subfile blocks as are needed will be
created. A dynamic file performs best when the data is distributed evenly across each group and no
group extends into the overflow area. In reality, this is almost impossible to achieve whilst still
keeping each group reasonably full. A well tuned dynamic file typically has less than 20 percent of
its data in overflow.
The group size parameter determines the size of the primary subfile groups as a multiple of 1024
bytes. This parameter may have a value in the range 1 to 8 and defaults to 1 though this default can
be changed using the GRPSIZE configuration parameter. It should be set to a multiple of the disk
block size if this value is known. As a general rule, use values of 1, 2, 4 or 8.
Where a file contains very large records, performance can be improved by placing these in disk
blocks of their own with just the record key and a reference to their location stored in the primary
subfile. Such records are known as large records and the size above which data is handled in this
way is configurable. The default value of 80% of the group size is good for most purposes. Because
a large record has only its key stored in the primary subfile, a SELECT operation will be faster if
the group is mainly large records but reading the record's data will require at least two disk
accesses. Also, since large records are held in their own disk block(s) rather than sharing with other
records, surplus space at the end of the final block is wasted resulting in higher disk space usage. If
the file will be used frequently in SELECT operations where selection is based only on the record
id, a lower large record size may be beneficial. If data records are frequently read from the file, a
higher large record size may help. In general it is best only to change the large record size if
2.11-0
102 OpenQM
The number of groups in a dynamic file changes with time. QM uses two parameters to determine
when the number of groups should change. At any time, the file's load value is the total size of the
data records (excluding large records) as a percentage of the primary subfile size. This value
changes as records are added, modified or deleted. It may have a value in excess of 100%,
indicating that there is very high usage of overflow space. The split load value (default 80%)
determines the load percentage at which an additional group will be added to the file by splitting the
records in one group into two. The merge load value (default 50%) determines the point at which
two groups are merged back into one. A split may result in the load falling below the merge load or,
conversely, a merge may result in a new load value above the split load. In neither case will the file
be immediately reconfigured back again.
The split and merge loads determine the way in which the file's modulus and hence actual load vary.
A low load results in reduced overflow at the expense of increased disk space. Conversely, a high
load increases overflow but reduces disk usage. High overflow in turn results in poor performance
as more disk blocks must be read to find a record. The split load value determines the load at which
a group will be split into two, the merge load determines the load at which groups will be merged.
The difference between the two values needs to be reasonably large to avoid continual splitting and
merging of groups.
The minimum modulus value determines the size below which the file will not merge groups. The
default setting of this parameter is one, resulting in full dynamic reconfiguration. If the file is
subject to frequent addition or deletion of large numbers of records so that its modulus varies
widely, it may be worth setting the minimum modulus to a typical average size or higher, however,
a file with a higher modulus than is necessary is relatively slow in SELECT operations that must
read the entire file. The minimum modulus parameter can also be used to pre-allocate primary
subfile disk space when creating a new file, minimising fragmentation.
Record ids in dynamic files are normally case sensitive. Case insensitive ids can be selected when
the file is created or a file can be converted at a later date using the CONFIGURE.FILE
command.
The total size of a dynamic file is limited to 2Gb for file versions 0 and 1, and 2147483647 groups
(up to 16384Gb) for version 2 upwards.
The QM file system is highly reliable, however, it is possible for power failures or similar events to
cause the system to shutdown without committing to disk data that is in the operating system cache.
For critical files, it may be useful to enable synchronous (forced write) mode where every write is
flushed to disk immediately. This significantly reduces the risk of file corruption at system failure
but will have a severe impact on performance if the file is updated frequently.
2.11-0
The QM File System 103
Although dynamic files are very reliable, the split/merge mechanism that maintains optimum file
performance introduces the possibility of file corruption in the event of a power failure or other
situation that causes outstanding write operations not to be completed. QM offers a mode of
operation that forms a hybrid between the dynamic file system and the static files found in many
other database products.
The NO.RESIZE option of the CONFIGURE.FILE command can be used to disable splits and
merges, locking the file at its configuration when the command is issued. As new data is added, the
file will extend into overflow, reducing performance. Conversely, if large volumes of data are
deleted, the groups will become less tightly packed, again resulting in reduced performance. Files
can be created with this mode set by use of the NO.RESIZE option to the CREATE.FILE
command.
The file can be reconfigured using the IMMEDIATE mode of the CONFIGURE.FILE command.
This performs the outstanding splits or merges, bringing the file back to the configuration that it
would have had if resizing had not been disabled. For typical file update patterns and reasonably
frequent use, this should be considerably faster than the equivalent resizing of a static file system.
One scenario for use of this mechanism would be to operate the file(s) with resizing disabled during
normal day time activity, perform backups at the start of an overnight downtime period and then
use CONFIGURE.FILE to reconfigure the files ready for the next day. In the unlikely event of a
system failure during the reconfiguration process, the backup provides an up to date copy of the
data. This resizing operation is fully interruptable and can be performed while the file is in use.
To improve performance of applications that repeatedly open and close the same file (e.g. a loop
that calls a subroutine that opens a file locally), QM maintains a cache of files that have been
recently closed at the application level, actually keeping them open at the operating system level.
The mechanism, the DH file cache, means that if the application reopens a file that is in the cache,
there is very little work to be done inside QM.
The size of the DH file cache is controlled by a private configuration parameter, DHCACHE, that
defaults to 10 and may take any value between 0 and 50. For most applications, the default value
will work well.
The cache is automatically flushed at any action within QM itself that may require a cached file to
be closed (e.g. deleting the file), including situations where the action of one QM user may require
the cache to be flushed in some other user's process. The cache is always flushed on return to the
command prompt. A QM process can force the cache to be flushed in all processes using the
QMBasic FLUSH.DH.CACHE statement.
2.11-0
104 OpenQM
A distributed file holds no data. Instead it is simply a reference to a set of separate dynamic files
that may be treated by an application as though they were a single file.
Distributed files allow an application to break a large data set into smaller pieces and reconstruct it
in various ways to optimise performance. For example, a sales processing system might store orders
for each month as a separate file (ORDERS-JAN09, ORDERS-FEB09, ORDERS-MAR09, etc).
Reports of orders in the current month now only require the query to be run using the file that holds
this month's orders. A report based on all orders ever received would require all the separate orders
files to be processed. Rather than running multiple separate queries and merging the results in some
way, this is achieved by creating a distributed file that references all of the monthly order files.
A distributed file gives the application the ability to access data in all of its component part files
without any special logic in the application itself. When a record is to be accessed, QM will work
out which part file would contain the record by applying the partitioning algorithm that defines the
distributed file structure. This algorithm is supplied by the user and is effectively a higher level of
hashing that translates a record id to a file part number.
There is no reason why multiple distributed files cannot reference the same part files in different
combinations. As well as having a distributed file that combines all of the monthly orders files in the
example above, we could also have distributed files to bring together all orders for a quarter or for a
year.
Because the record layout in each part file in a distributed file will be identical, it is normal for a
single dictionary to be shared by all part files and the distributed file.
The partitioning algorithm is written as an I-type expression in the dictionary that defines the part
files. This calculation must be based only on examination of the record id, not the data in the
record, because the data is not available when identifying the part that will contain the record for a
2.11-0
The QM File System 105
read operation. It is possible for the expression to use TRANS() functions to reference other files
but the performance impact of this could be very severe as the expression will be evaluated for
every read, write or delete.
The partitioning algorithm must return an integer part number. This must be in the range 0 to
2147483647 and does not need to be a simple sequential number. Our order file example might use
the year and month as a four digit number (0811, 0812, 0901, 0902, etc).
Where a file uses case insensitive record ids, the result of the partitioning algorithm must not be
affected by the casing of the supplied id. This is because case insensitivity is a property of the part
file and is therefore unknown when the expression is evaluated.
Because an application can update the individual part files independently of the distributed file, it is
essential that records written in this way are placed into the correct part file. Failure to ensure this
may lead to all manner of strange results such as a record appearing in a select list but not being
found by a read operation.
First use of the command will create the distributed file, compiling the partitioning algorithm and
adding the named part file. The newly created distributed file will share the dictionary of the first
part file. Subsequent use of the ADD.DF command will add further part files. The algorithm need
not be specified for the second and subsequent parts and will be ignored if present.
Note that the partitioning algorithm is copied into the distributed file. Changing the expression in
the dictionary will not have any effect. It will be necessary to reconstruct the distributed file.
A new part may be added to a distributed file at any time though QM processes that already have
the file open will not see the new part until the file is closed and reopened.
A part file can be removed from a distributed file using the REMOVE.DF command:
REMOVE.DF dist.file part.file
where
dist.file is the name of the distributed file.
part.file is the name of the part file to be removed. The part number can be used instead of
the name. Use of the keyword ALL in place of part.file deletes the entire
distributed file.
Removing the final part also deletes the distributed file. A part may be removed at any time though
QM processes that already have the file open will continue to use the part until the file is closed and
2.11-0
106 OpenQM
reopened
The components of a distributed file can be listed using the LIST.DF command;
LIST.DF dist.file
where
dist.file is the name of the distributed file.
This command shows a list of the part file pathnames and their associated part numbers.
Alternate key indices can be used with distributed files but are defined on the part files in the usual
way, not on the distributed file. When a distributed file is opened, QM determines which index
names are defined in all of the part files and only these indices are available when referencing the
distributed file. Note that this process is based only on the index name. If two part files have indices
of the same name that are defined differently, the effects are undefined.
A QMBasic program that opens a distributed file can access the data in this file in exactly the same
way as for any other file. The partitioning algorithm will be applied internally by QM for all record
level operations to determine which part file should be accessed.
Locks are maintained at the part file level. Locking a record via an operation that references the
distributed file will apply the lock to the part file in which that record would reside based on the
partitioning algorithm.
Obtaining a file lock on a distributed file will acquire the file lock on all of the component part files.
Because a process is never blocked by its own locks, a program can obtain the file lock on an
individual part file that has been opened separately and then go on to obtain the file lock on the
distributed file. Releasing the file lock on the distributed file would effectively also release the file
lock on the individual part file. Conversely, releasing the file lock on the individual part file would
mean that the file lock on the distributed file was no longer complete. Given the probable
inappropriateness of file locks in distributed files, it is unlikely that this situation is of concern to
application developers.
The FILEINFO() function will return a file type code of FL$TYPE.DIST (7). The FL$PARTS
key value of FILEINFO() will return a field mark delimited list of the part numbers of each part
file. Many of the other key values of this function are inappropriate to distributed files but can be
applied to an individual part by using the DFPART() function to reference the part file.
The INDICES() function will return data for indices that are common to all part files.
The SELECTINDEX statement will return composite data constructed from the indices of all part
files. The index scan position pointer normally set by this operation is irrelevant to distributed files.
2.11-0
The QM File System 107
Use of distributed files with a large number of part files requires the system administrator to think
carefully about the setting of the NUMFILES configuration parameter as each part file will be
opened internally as a separate file.
2.11-0
108 OpenQM
QMNet uses the QMClient interface to provide an extension to the QM file system allowing
network access to files on another QM system. Unlike use of NFS or mapped network drives,
QMNet provides locking of remote records, ensuring that data integrity can be maintained on
distributed data. Where both ends of the connection support it, the network traffic is encrypted.
Use of QMNet creates a server process on the remote system for each separate QM session that has
one or more files open through QMNet. This process will consume a licence. If QM's security
system is enabled on the remote system, the user name of the server process as defined using
SET.SERVER must be registered for access to QM (see Application Level Security)
Two steps are necessary to use QMNet. Firstly, the server must be defined, mapping the server
name to a network address, user name and password. Secondly, the remote file must either be
defined using a Q-type VOC record or it may be accessed using the extended filename syntax server
:account:file.
QMNet supports two styles of server definition; public servers and private servers.
Public server definitions are available to all users of the system. They are created by a user with
administrative rights in the QMSYS account using the SET.SERVER command and persist until
they are explicitly deleted.
Private server definitions are local to the QM session in which they are defined. They are created
using the SET.PRIVATE.SERVER command. On a secure system, access to this command may
be restricted by the system administrator. A private server definition would normally be created
dynamically by the application, either supplying the authentication details internally or prompting
the user.
A server defined with the SET.SERVER command can be accessed by all users. The
ADMIN.SERVERS command can be used to create or modify server definitions to apply
restrictions on which users can access the server.
Each remote file is defined by an extended form of the Q-type VOC entry where field 4 contains the
name of the server.
Once the file has been defined, it may be accessed by programs in the same way as a local file. The
following restrictions apply to access from QMBasic programs:
· The OPENSEQ statement and related sequential file access operations are not supported.
2.11-0
The QM File System 109
A list of all defined QMNet servers accessible by the user can be displayed using the
LIST.SERVERS command.
LIST.SERVERS {ALL}
The ALL option, available only to users with administrative rights, includes servers to which the
user has no access.
The definition for a remote server may be deleted using the DELETE.SERVER or
DELETE.PRIVATE.SERVER command. Deletion of public server definitions is restricted to
users with administrative rights in the QMSYS account.
DELETE.SERVER name
Server Security
The default behaviour of the SET.SERVER command is to create a server definition that may be
accessed by all users of the system. There is a potential security weakness here because the slave
process started on the remote system to handle the QMNet connection runs as the user name
specified in the server definition, regardless of the user name of the local user accessing the remote
file. Security can be improved by arranging that the user name used for the remote slave process is
dependent on the user name or user group of the local user. This can be achieved by use of the
ADMIN.SERVER command or an extended form of the SET.SERVER command.
See also:
DELETE.SERVER, LIST.SERVERS, SET.SERVER
2.11-0
110 OpenQM
The Virtual File System (VFS) allows application designers to provide access to data that appears
to an application as a file but may actually be something quite different. Possible uses of the VFS
include:
A VFS handler is a globally catalogued QMBasic class module that intercepts all attempts to access
the file. It processes requests, storing or retrieving data as appropriate.
A template class module named VFS.CLS is provided in the BP file of the QMSYS account. This
includes a brief description of each of its component functions and subroutines.
There are two steps; creating the VFS handler and creating the VOC entries.
Like all files, a VFS file is identified by an F-type VOC item. It is possible for only some parts of a
file to be VFS items. Thus a file might have a VFS data part but a normal dictionary part. The
components of a multifile can be a mix of VFS and normal items.
A VFS item is identified by the pathname in the F-type VOC entry being specified as "VFS:
handler" where handler is the name of the globally catalogued VFS handler class module. There
is an optional third component to this syntax which will be passed to the handler on opening the
VFS item. The full syntax of the VOC item is thus
VFS:handler:string
This third component could be used, for example, when a single handler class module is used to
access many files. The string might be the pathname or other reference to the actual file to be
opened by the handler.
The QM file system optimises select list generation by arranging that the QMBasic SELECT
statement (not the query processor equivalent) used against a hashed file actually performs the
select group by group as the READNEXT statement is used to walk through the list. Anything that
requires the list to be completed (e.g. using SELECTINFO() to determine the number of items in
the list) will cause the remainder of the list to constructed immediately.
A VFS handler can work in much the same way. The V$SELECT function can return the entire list
or just the initial part of the list. When a program processing this list reaches the end of the list
returned by V$SELECT, the V$CONTINUE.SELECT function is called to return the next part of
the list. The V$COMPLETE.SELECT function will be called if the remainder of the list should be
returned as a single item and the V$END.SELECT subroutine is called to terminate generation of a
partial list.
2.11-0
The QM File System 111
VFS handlers that do not use partial list construction can omit the V$CONTINUE.SELECT,
V$COMPLETE.SELECT and V$END.SELECT entry points.
The Virtual File System does not support alternate key indices. The INDICES(), SELECTINDEX
, SELECTLEFT, SELECTRIGHT, SETLEFT and SETRIGHT operations are not valid with a
VFS item.
2.11-0
112 OpenQM
QM provides several data entry and modification tools, each designed to fit a particular mode of
use.
2.11-0
The QM File System 113
3.8 Dictionaries
Every data file normally has an associated dictionary which describes the structure of the data
records in the file. The dictionary is normally only used by the query processor and a few other
commands. Application developers may find it useful to construct data structure definitions from
the dictionary for use in programs using the GENERATE command.
It is possible to create a file that has no dictionary or for multiple files to share a common
dictionary.
A dictionary contains the following types of record, identified by the leading characters of field 1.
A Pick style data definitions. An A-type record describes data that is held in a field of the
record or calculated from that data.
D Direct data types. A D-type record describes data that is held in a field of the record.
I Indirect data types. An I-type record describes data that can be evaluated from data in
fields of the record, perhaps with reference to other records or other files. It is
essentially a small program that returns a value.
L Links to other files. Used only in query processor commands and dictionary I-type
record expressions.
S Pick style data definitions. An S-type record describes data that is held in a field of the
record or calculated from that data. S-type records are identical to A-type records in
QM.
The names given to A, D, I and S-type dictionary records are the names used in queries to reference
the field. Every field to be used in query processor sentences must have a corresponding dictionary
record. There may be multiple dictionary references to a single field thus allowing synonyms for
query processor commands, perhaps with different default display characteristics.
Field 11 of all data definition record types (A, C, D, I, S) is reserved for user use.
Dictionary record types Y and Z will never be defined as part of the standard QM product and are
available for whatever purpose a developer may find useful. Other type codes not listed above may
be defined in future releases.
2.11-0
114 OpenQM
A and S-type dictionary items are an alternative to the preferred D and I-type items that describe
data stored in database files. QM provides a limited subset of the full A and S-type functionality
found in other multivalue database environments. There is no difference between A and S-type
records within QM.
Field 2 of an A or S-type record holds the field number of the data record to which this dictionary
entry relates. This must be a positive integer value. A value of zero may be used to refer to the
record id. For compatibility with other multivalue database products a value of 9998 or 9999 will
be recognised by the query processor as references to the item number within the query and the
length of the record respectively. Both of these special cases are better implemented using I-type
records. Where field 8 contains an A or F correlative, the value in field 2 is not used.
Field 4 defines the relationship between associated multivalued fields. Within an association, one
field is considered to be the controlling item and the remainder are considered as dependant. The
controlling field has C;p;q;r in field 4 where p, q, r (etc) are the field numbers of the associated
items. The dependant fields all have D;n in field 4 where n is the field number of the controlling
field. Internally, Internally, QM converts Pick style association definitions into an association name
__n. For compatibility with some other multivalue database products, the ASSOC.UNASSOC.MV
mode of the OPTION command can be used to make the query processor treat all multivalue fields
that are not in defined associations and being associated together.
Field 7 contains an optional conversion code to be applied immediately before the data is displayed
in a query processor report. QM does not support use of A or F-correlative expressions in this field.
Field 8 contains an optional expression to be evaluated to calculate the value of the item. This may
be an A or F correlative, an IF expression as an implied A-correlative, or a conversion code to be
applied to the field identified in field 2 of the dictionary record. Conversion codes appearing in field
8 are applied immediately to the data extracted from the record and hence affect sorting and
2.11-0
The QM File System 115
selection.
Field 9 contains the justification code L, R, T or U that determines the alignment of data in a query
processor report.
QM does not support the LPV (load previous value) data item found on Pick systems as it is
dependant on the exact sequence in which the query processor evaluates expressions. The query
optimiser of QM could cause this to behave in an unexpected manner. It is always possible to
restructure dictionary items that used LPV to work without it.
2.11-0
116 OpenQM
Correlatives
A correlative is an expression in field 8 of an A or S-type dictionary item that derives a value from
data in a database record. Although similar in concept to the preferred I-type dictionary items,
correlatives are less powerful and more difficult to maintain. They are provided in QM to aid
migration of applications from other multivalue environments. New developments should use I-type
items instead and it is recommended that correlatives should be converted to I-types as part of the
migration process.
· F-correlatives are written in reverse Polish notation which makes them difficult for less
experienced developers to understand.
Field 8 of the dictionary may be multi-valued. The first value may be an A or F-correlative or a
conversion code. The remaining values may be conversion codes or format codes to be applied to
the result of the correlative. Format codes must be enclosed in either single or double quotes.
String operations in correlatives are normally performed in a case sensitive manner. The correlative
type code can be followed by NOCASE; to select case insensitive string operations for this specific
correlative. Alternatively, the CORRELATIVE.NOCASE mode of the OPTION command can be
used to make all correlatives use case insensitive string operations.
On other multivalue databases, correlatives are processed interpretively and A-correlatives are
translated into their equivalent F-correlative format at the start of a query for improved
performance. On QM, correlatives are compiled in much the same way as I-type expressions so the
potential minor performance advantage of writing an F-correlative directly is lost. The query
processor will compile correlatives automatically when they are first used. The COMPILE.DICT (
CD) command can be used to force a compilation.
Example
A;N(TEL)VM"L(3#) 3#-4#"
The above correlative takes the contents of the field named TEL and then applies a format mask to
it.
A;NOCASE;N(CODE) = 'AX'
The above correlative tests whether the CODE field contains AX. The NOCASE prefix causes
string comparisons to be case insensitive.
A-Correlatives
An A-correlative is an algebraic expression that applies operators to fields, constants and other data
to produce a result. It is similar in concept to an I-type expression but very limited and often
difficult to maintain.
2.11-0
The QM File System 117
The expression is prefixed by A and an optional semicolon. Where the expression consists only of
an IF element, the leading A; can be omitted.
Data items
N(name) A field name. This name is looked up in the dictionary when the correlative is compiled
and run time code generated to extract the field from the current record. QM extends
the capabilities of this function compared to other multivalue products by allowing
name to be a reference to another calculated item (I-type, C-type or correlative).
"string" A constant. All constants, including numeric values, must be enclosed in single quotes,
double quotes or backslashes.
Any of the above three data item types may be followed by R to indicate that the
REUSE() function is to be applied to the data.
D The internal date. This is the actual date at the point when the function is executed, not
a reference to the @DATE variable (which does not change during a command).
T The internal time. This is the actual time at the point when the function is executed, not
a reference to the @TIME variable (which does not change during a command).
+ Adds operands
- Subtracts operands
* Multiplies operands
2.11-0
118 OpenQM
IF p {THEN q} {ELSE r}
Returns q if p is true, r if p is false. Absent elements return a null string.
(conv) Applies the given conversion code to the expression value. Note that conv is not quoted.
OR Logical OR.
Examples
A;3*2
Multiplies the content of field 3 by the content of field 2.
A;(N(PRICE)+N(TAX))(MD2)
Adds the PRICE and TAX fields. The result is then converted using an MD2 conversion code.
A;N(PRICE)*"1175"/"1000"
Adds 17.5% tax to the single valued PRICE field. Note the need to perform the calculation in
two steps because correlatives use integer arithmetic.
A;N(PRICE)*"1175"R/"1000"R
Adds 17.5% tax to each value in the multivalued PRICE field. Note the use of the R qualifier
on both constants in this expression.
A;DESCRIPTION["1","20"]
Extracts the first 20 characters of the DESCRIPTION field.
On systems that process correlatives interpretively, A-correlatives are converted to the more
efficient F-correlative format at the start of a query that uses them. F-correlatives use "reverse
Polish" notation which, whilst actually very simple, is difficult for inexperienced developers to
maintain.
QM compiles both A and F-correlatives to its own internal instruction set and, therefore, the
potential advantage of writing these more complex expressions on other systems is irrelevant.
2.11-0
The QM File System 119
Reverse Polish notation defines data and operations to be performed on it as a series of steps that
manipulate an internal stack. Each step is separated by a semicolon. As an example, consider a
simple A-correlative expression such as
A;1*"11"/"10"
that adds 10% to the value in field 1. As an F-correlative expression this becomes
F;1;"11";*;"10";/
where the steps are
1 Push the value of field 1 onto the stack
"11" Push the constant "11" onto the stack
* Multiply the top two items on the stack, replacing them with the result
"10" Push the constant "10" onto the stack
/ Divide the top two items on the stack, replacing them with the result
Data items
"string" A constant. All constants of this style, including numeric values, must be enclosed in
single quotes, double quotes or backslashes.
Any of the above three data item types may be followed by R to indicate that the
REUSE() function is to be applied to the data. The field number form can be followed
by a conversion code in brackets. If used with R, the sequence is nR(conv).
D The internal date. This is the actual date at the point when the function is executed, not
a reference to the @DATE variable (which does not change during a command).
T The internal time. This is the actual time at the point when the function is executed, not
a reference to the @TIME variable (which does not change during a command).
+ Adds the top two items on the stack, replacing then with the result
- Subtracts the top item on the stack from the next item, replacing them with the result.
* Multiplies the top two items on the stack, replacing then with the result
2.11-0
120 OpenQM
- Divides the second item on the stack by the top item, replacing them with the result.
Note that this is an integer division.
: Concatenates the top stack item on to the end of the second stack item, replacing then
with the result
= Replaces the top two items on the stack by 1 if they are equal, 0 if they are unequal.
# Replaces the top two items on the stack by 1 if they are unequal, 0 if they are equal.
> Replaces the top two items on the stack by 1 if the top item is greater than the second
item, otherwise 0.
< Replaces the top two items on the stack by 1 if the top item is less than the second item,
otherwise 0.
] Replaces the top two items on the stack by 1 if the top item is greater than or equal to
the second item, otherwise 0.
[ Replaces the top two items on the stack by 1 if the top item is less than or equal to the
second item, otherwise 0.
[] Replaces the top three stack items with a substring of third stack item, starting at the
character position given by the second stack item, with a length determined by the top
stack item.
R Replaces the top two stack items with the remainder from dividing the second item by
the top item.
S Replaces the top stack item by the sum of all the values in multivalued item at the top
of the stack.
(conv) Replaces the top item on the stack with the result of applying the given conversion code
to the current top stack item. Note that conv is not quoted.
& Replaces the top two items of the stack with the result of a logical AND between their
values.
! Replaces the top two items of the stack with the result of a logical OR between their
values.
Flow Control
J label Unconditionally jumps to label. There must be a space before the label name.
JF label Jumps to label if the top stack item is false. There must be a space before the label
2.11-0
The QM File System 121
name.
JT label Jumps to label if the top stack item is true. There must be a space before the label
name.
~label Defines a label. The label name may be followed by a space or a semicolon. In QM,
labels in correlatives must be constructed from a letter optionally followed by further
letters, digits, periods, percent signs or dollar signs. Alternatively a label may be wholly
numeric.
Examples
F;3;2;*
Multiplies the content of field 3 by the content of field 2.
F;3;7;+;(MD2)
Adds the field 3 and field 7. The result is then converted using an MD2 conversion code.
F;3;"1175";*;"1000";/
Adds 17.5% tax to the price in field 3. Note the need to perform the calculation in two steps
because correlatives use integer arithmetic.
F;3;"1175"R;*;"1000"R;/
Adds 17.5% tax to each value in the multivalued price in field 3. Note the use of the R qualifier
on both constants in this expression.
F;1;"1";"20";[]
Extracts the first 20 characters of field 1.
2.11-0
122 OpenQM
1: C { descriptive text }
2: QMBasic program, multivalued.
3: { Conversion code }
4: { Display name. This will be used as the default column heading by the query processor.
A special value of a backslash character can be used to specify that no heading is to be
displayed. The text can commence with 'R' (including the quotes) to right justify the
heading, 'X' to suppress the normal dot filler characters, or 'RX' to apply both
modifications. If the display name is multivalued, each value appears as a separate line.}
5: Format specification
6: Single/multivalue flag. Set as S if the field is always single valued or M if it can be
multivalued.
7: { Association name. Where a multivalued field has a value by value relationship with
some other multivalued field defined in the same dictionary, this name links the fields
together. See Associations for more details. }
8: Available for user use in any way. Not referenced by QM.
9-10: Reserved for internal use.
11: Available for user use in any way. Not referenced by QM.
Fields 12 onwards are reserved for internal use and users should not assume anything about their
content.
A C-type dictionary item is a QMBasic program written with each line of the program as a separate
value in field 2. The EV (edit values) command of ED may help in editing this field. The Dive
function of SED provides similar functionality.
The program must return a result via the @ANS variable. This variable is initially zero on entry to
QM, is automatically updated to contain the result of I-type expressions and should be updated by
C-types. Although it is possible to use @ANS to pass a value from evaluation of one C or I-type
item to the next, this is not recommended as the sequence of execution may be indeterminate.
The program can reference data defined by other items in the same dictionary using the {name}
construct where name is a C-type, D-type or I-type item.
2.11-0
The QM File System 123
A D-type record defines a field stored in a data file and has up to 8 fields:
1: D { descriptive text }
2: Field number. This is the position in the data record at which the field described by this
dictionary entry can be found. A value of zero denotes the record id.
For compatibility with other multivalue database products a value of 9998 or 9999 will
be recognised by the query processor as references to the item number within the query
and the length of the record respectively. Both of these special cases are better
implemented using I-type records.
3: { Conversion code }
4: { Display name. This will be used as the default column heading by the query processor.
A special value of a backslash character can be used to specify that no heading is to be
displayed. The text can commence with 'R' (including the quotes) to right justify the
heading, 'X' to suppress the normal dot filler characters, or 'RX' to apply both
modifications. If the display name is multivalued, each value appears as a separate line.}
5: Format specification
6: Single/multivalue flag. Set as S if the field is always single valued or M if it can be
multivalued.
7: { Association name. Where a multivalued field has a value by value relationship with
some other multivalued field defined in the same dictionary, this name links the fields
together. See Associations for more details. }
8: Available for user use in any way. Not referenced by QM.
9-10: Reserved for internal use.
11: Available for user use in any way. Not referenced by QM.
Fields 12 onwards are reserved for internal use and users should not assume anything about their
content.
2.11-0
124 OpenQM
1: I { descriptive text }
2: Expression
3: { Conversion code }
4: { Display name. This will be used as the default column heading by the query processor.
A special value of a backslash character can be used to specify that no heading is to be
displayed. The text can commence with 'R' (including the quotes) to right justify the
heading, 'X' to suppress the normal dot filler characters, or 'RX' to apply both
modifications. If the display name is multivalued, each value appears as a separate line.}
5: Format specification
6: Single/multivalue flag. Set as S if the field is always single valued or M if it can be
multivalued.
7: { Association name. Where a multivalued field has a value by value relationship with
some other multivalued field defined in the same dictionary, this name links the fields
together. See Associations for more details.}
8: Available for user use in any way. Not referenced by QM.
9-10: Reserved for internal use.
11: Available for user use in any way. Not referenced by QM.
Fields 12 onwards are reserved for internal use and users should not assume anything about their
content.
To simplify editing of compound I-type expressions, the "edit values" mode of both the ED and
SED editors can be used to break the expression such that each element appears on a separate line.
2.11-0
The QM File System 125
An L-type record represents a link to another file. It can be used in query processor commands to
reference fields in a dependent file without the need to create an I-type TRANS() expression for
each field. Links can also be used within I-type expressions to minimise the number of explicit
TRANS() operations.
1: L { descriptive text }
2: Id expression
3: File name
The expression in field 2 is constructed in exactly the same was as an I-type expression and derives
the record id of the record(s) in the linked file from data in the original file.
Links can be used to reference D or I-type items in the remote file. They cannot be used to access
Pick style A or S-type items.
Examples
If a library application has two files, BOOKS and TITLES where the record id of BOOKS is
formed from the id of the corresponding TITLES record and the copy number separated by a
hyphen, the following link placed in the dictionary of the BOOKS file could be used to access the
associated TITLES record:
1: L
2: @ID['-', 1, 1]
3: TITLES
Queries based on the BOOKS file could then reference data from the TITLES file using field names
made up from the name of the link record, a % character and the name of the TITLES field to be
accessed. For example, if the above line was named TTL, a query such as
LIST BOOKS TTL%TITLE TTL%AUTHOR
could be used to print a list of book titles and their authors.
The same data could be referenced in an I-type item in the dictionary of the BOOKS file by use of
simply
TTL%TITLE
as the expression (field 2). This is exactly equivalent to writing
TRANS(TITLES, @ID['-' , 1, 1], TITLE, 'X')
Use of links in this way removes the need to include the link expression (@ID['-', 1, 1]) in
every reference to items in the TITLES file. Because use of a link causes a compile time
substitution of the actual TRANS() operation, changing the link record requires all I-types that use
it to be recompiled.
2.11-0
126 OpenQM
A phrase can be used in query processor sentences. When the sentence is executed, the phrase name
is replaced by the phrase expansion. Typically, phrases are used to give names to groups of fields to
be displayed or selection criteria.
1: PH { descriptive text }
2: Phrase expansion
Phrases may also be included in the VOC but are more commonly found in dictionaries. A phrase in
the VOC can be used in queries against any file whereas a phrase in a dictionary can only be used
in queries against the associated file.
Where a phrase is very long it may be broken into multiple lines within the VOC record by
terminating all but the final line with an underscore character. When the phrase is substituted into a
command, the lines are merged, replacing the underscore with a single space.
There are a number of reserved phrase names as listed below. These only operate when stored in the
dictionary of the file to which they relate.
@ A phrase record defining the default list of items to be displayed by LIST and
SORT in the absence of any other field names.
@LPTR A phrase record defining the default list of items to be displayed by LIST and
SORT in the absence of any other field names when output is directed to a
printer. If this record is not present, the query processor uses the @ record
instead.
@MODIFY A phrase record defining the default list of items to be processed by the
MODIFY command.
@SHOW A phrase record defining the default list of items to be displayed by SHOW in
the absence of any other field names.
2.11-0
The QM File System 127
X-type dictionary items are miscellaneous data storage records which may be used in any way the
application designer wishes.
1: X { descriptive text }
2: user data
Fields 2 onwards are available for data storage. Users may freely create X-type records for their
own purposes but should avoid names containing $ signs or starting with the @ character as these
may clash with system defined records.
2.11-0
128 OpenQM
Associations
An association is a set of two or more multivalued fields that are related such that the values are
inter-dependent. For example, an order processing database might contain a file listing the items in
each order. This would require a multivalued list of products and a corresponding multivalued list
of quantities. A realistic data file may contain several associated sets of fields.
The query processor needs to know about this relationship. An association is defined by giving it a
name which appears in field 7 of the dictionary entry of each field in the association. There is also
a phrase record with this name which contains a space separated list of the fields that make up the
association.
Thus, starting from any one element of the association, its dictionary entry can be used to find the
phrase record which, in turn, allows the query processor to find all the members of the association.
For compatibility with some other multivalue database products, the ASSOC.UNASSOC.MV
mode of the OPTION command can be used to make the query processor treat all multivalue fields
that are not in defined associations as being associated together.
2.11-0
The QM File System 129
I-type expressions
An I-type dictionary record defines a calculation based on data in the data file records. Once an
I-type item is defined, it can be referenced in query processor sentences exactly as though it was a
real data field. I-type items are sometimes known as virtual attributes, a term which emphasises
the fact that their values are not physically stored in the database.
An I-type dictionary item differs from a D-type item only in that field 1 contains the type code I and
field 2 contains the actual calculation to be performed. The remaining fields are the same as in a
D-type entry.
Consider a simple stock management system in which each inventory item has two price figures; the
price that we paid to buy the item into the shop and the price that we will charge the customer. If
these are defined by dictionary items named COST and SELL, we can calculate the profit we make
selling an item with a simple I-type expression:
SELL - COST
An I-type expression consists data item names, constants, functions and operators in exactly the
same way as a QMBasic expression. Whereas a QMBasic program would refer to variable names,
an I-type expression uses field names defined in the file's dictionary. These names may be A, C, D,
I or S-type items.
Many of the @-variables used by QMBasic are also available in I-types. The following @-variables
are specific to I-types though some can be used by QMBasic programs to set up the working
environment for the I-type.
Most QMBasic functions are also available in I-type expressions. The following functions are either
specific to I-type expressions or modified from their QMBasic form:
TOTAL() Accumulate totals for use with the query processor CALC keyword.
TRANS() Fetch data from another file.
SUBR() Call a QMBasic subroutine.
Just like a QMBasic program, an I-type must be compiled before it can be used. The query
processor will do this automatically though I-types can be compiled explicitly using the
COMPILE.DICT (synonym CD) command which compiles one or more I-types in a dictionary.
The MODIFY command also provides facilities to compile I-types when they are edited. The object
code is stored in the dictionary record though ED and SED both hide it.
2.11-0
130 OpenQM
Note that where one I-type expression uses the result of another, this is handled by a compile time
substitution rather than a run time subroutine call. The implication of this is that, if the inner
expression is changed, both must be recompiled. The safest way to ensure that everything is
consistent is to use the COMPILE.DICT command to compile the entire dictionary after editing an
I-type that might be used in another expression.
A compound I-type has multiple elements separated by semicolons, each of which is evaluated in
turn, left to right. The value of the first element is stored in an internal variable named @1, the
second in @2, and so on. These variables may be referenced in later elements within the compound
I-type. The value of the immediately previous element may also be referred to by the symbol @.
The overall value of the I-type is the value of the final expression. QM can nest compound I-types.
Use of compound I-types can simplify complex expressions. For example, we might want to
calculate someone's age in whole years from their date of birth. This is actually more complex than
it may at first seem because we need to allow for people born on February 29 or performing the
calculation on February 29. It might be written as a two stage compound I-type:
To simplify editing of compound I-type expressions, the "edit values" mode of both the ED and
SED editors can be used to break the expression such that each element appears on a separate line.
The QMBasic language has a large number of functions that work on each element of a multivalued
data item in turn. These allow developers to write very elegant solutions to apparently complex
tasks without resorting to use of a subroutine with loops. For more details, see Multivalue
Functions.
2.11-0
The QM File System 131
Sometimes data is not stored in the database in the same way as we would wish to present it to a
user. A conversion code determines how data is translated between its internal format and the user
friendly external format.
Although there are many conversion codes, the most important are those that handle dates, times
and scaled decimal values.
Conversion codes appear in field 3 of a C-type, D-type or I-type dictionary item or field 7 of an A
or S-type item. They determine the way in which data is converted prior to output by the query
processor or when input via MODIFY or UPDATE.RECORD. Conversion codes are also used in
the QMBasic ICONV() and OCONV() functions and with the query processor CONV keyword.
2.11-0
132 OpenQM
A; expression
where
Use of A-correlatives as conversion codes can lead to poor performance as they must be
transformed to the equivalent F-correlative and then processed interpretively. When used in the
query processor, this transformation is performed during parsing of the query sentence and hence
only occurs once. When used with the QMBasic ICONV() or OCONV() functions, the
transformation will occur on every use of the conversion function.
An A-correlative used as a conversion code with ICONV() or OCONV() must not contain N()
functions as these cannot be resolved without the dictionary.
When used in field 8 of a Pick style dictionary record, an A-correlative expression is compiled in
the same way as an I-type for optimum performance. The compiled version of the expression is
stored in the dictionary in fields 15 onwards though the ED and SED editors will hide it.
2.11-0
The QM File System 133
The base64 conversion code translates data to or from a format widely used for transmission over
the internet.
B64
Used with OCONV() for output conversion, this operation converts data to base64 format. The
data is returned as a continuous sequence of encoded characters. In common use, this data would
then be divided into lines of manageable length, typically 72 characters. This can be achieved with
the FOLD() function.
Used with ICONV() for input conversion, this operation converts base64 data back to its original
form. Newlines and other filler characters are ignored.
Example
The above program opens the $HOLD file. It then suppresses the normal directory file translation
of newlines to field marks because the item to be read contains binary data (a PDF document).
Having read this record, mark translation is re-enabled. The B64 conversion is used to translate the
PDF to its base64 encoded equivalent. Finally, the FOLD() function is used to wrap the encoded
data into 72 character lines. Because the target file is a directory file and mark translation has been
re-enabled, the field marks in the data returned by the FOLD() function get replaced by newlines.
2.11-0
134 OpenQM
The boolean conversion code converts between the internal representation of false (0) and true (1)
and the external representation Y or N.
Used with OCONV() for output conversion, this conversion code returns N for false (zero or a null
string) or Y for true (all other values).
Used with ICONV() for input conversion, this conversion code returns false (0) for a null string or
a string containing the single character N in upper or lower case. It returns true (1) for a string
containing the single character Y in upper or lower case. Any other input value returns the original
data and sets an error status of 1.
2.11-0
The QM File System 135
The concatenation conversion code concatenates data items, optionally inserting separators between
them. It behaves identically for input conversion with ICONV() and output conversion with
OCONV().
c is the separator. This may be any single character except for a digit, a mark character,
a quote or a backslash. A semicolon specifies that no separator is to be inserted.
Where c is a space or semicolon and the next character is also a space or semicolon,
this is treated as a further separator, allowing insertion of multiple spaces.
Examples
Operation Result
OCONV('abc', 'C;3;"xxx";1') F3xxxF1
OCONV('abc', 'C;3;1') F3F1
OCONV('abc', 'C;"aaa"1"bbb"') aaaF1bbb
OCONV('abc', 'C;1 2') F1 F2
OCONV('abc', 'C;1*2') F1*F2
OCONV('abc', 'C;1**') F1*abc
OCONV('abc', 'C; 3') F3
OCONV('abc', 'C;0=1') 21=F1
2.11-0
136 OpenQM
Inside QM, dates are stored as a number of days since 31 December 1967 (day zero). All dates
after that point are represented by positive numbers. All dates before that point are represented by
negative numbers.
The date conversion code converts a date from its internal day number to one of a number of
external formats or vice versa.
where
y is a digit in the range 0 to 4 specifying the number of digits to appear in the year
number. This defaults to 4.
c is the character to be used to separate the year, month and day components of the
converted date. If omitted, a space is used. Specifying c as the digit 0 suppresses
insertion of a separator between the year, month and day components.
fmt specifies the components to be present in the converted date. Multiple characters may
be chosen from the following list subject to restrictions shown below. If fmt is omitted
it defaults to MDY if American date mode is in use or DMY if European date mode is
in use.
D Day of month.
DO Ordinal day of month (1st, 2nd, 3rd, etc)
E Toggles European date format (day, month, year). See also
DATE.FORMAT.
J Julian date (days since the start of the year).
L Alphabetic month and day names are to appear with only the first
character in uppercase instead of entirely in uppercase.
M Month in format determined by format modifiers. If no format modifiers
are present, a two digit month number is used unless c is present in which
case a three letter alphabetic month is used.
MA Month name.
Q Quarter number (1 to 4).
W Day of week number. Monday is day 1, Sunday is day 7.
WA Weekday name.
WI ISO week number.
X ANSI X12 format date (YYYYMMDD with no separators).
Y Year.
YI ISO year number. This is not always the same as the calendar year as a
date may be in the last week of the previous ISO year or in the first week
of the following ISO year.
2.11-0
The QM File System 137
[f1,f2,f3,f4,f5] These format modifiers affect the way in which the above formats are handled.
Up to five modifiers may be specified and they are associated with the formats in the
order in which they appear in fmt. Format modifiers are
n Use n characters.
A Display as alphabetic (applies to month component only).
An Display as n alphabetic characters (applies to month component only).
Z Suppress leading zeros.
Zn Display as n digits with leading zeros replaced by spaces.
"text" Uses the supplied text as the separator after the associated component.
The following special codes are recognised as part of the D conversion code for ISO8601 format
output. These may not be used with any other conversion elements:
ISO8601W yyyyWwwd
Four digit year number, two digit ISO week number, one digit day of week.
ISO8601W- yyyy-Www-d
Four digit year number, two digit ISO week number, one digit day of week with hyphen
separators.
The following examples show the result of output conversion of a value of 9649 with various
conversion codes. Where affected by DATE.FORMAT setting, both forms are shown.
2.11-0
138 OpenQM
'DDMYL[Z,A,2]' 1 June 94
'DYMD[2,2,2]' 94 06 01
'DW' 3
'DWA' WEDNESDAY
'DWAL' Wednesday
'DMA' JUNE
'DMAL' June
'DQ' 2
'D-YIWI' 1994-22
'DISO8601W' 1994W223
'DISO8601W-' 1994-W22-3
Alphabetic month names may be supplied in the external format date. At least three letters must be
present and conversion is not case sensitive. If more than three letters are present, the must correctly
match the spelling of the month name.
The date conversion system allows some flexibility to the order in which the components of the date
may occur in the input data. Where an alphabetic month name is used, this is processed first.
Numeric components are then assumed to be in the order of the remaining elements of the
conversion code. Thus with a code of DDMY, '1 Jun 94' and 'Jun 1 94' would both convert to 9649,
the internal representation of 1 June 1994.
A date that is entered as a simple digit sequence with no separators (e.g. 020609) will be treated as
being day, month and year components in the order defined by the fmt element of the conversion
code, with a maximum of two digits in the day and month. The year component will be processed as
having the number of digits in the conversion code, defaulting to 4. A trailing year with only two
digits will follow the normal rules as described in the next paragraph.
For dates entered as two digits, year number values in the range 30 to 99 are assumed to be 1930 to
1999 and 0 to 29 are assumed to be 2000 to 2029. This 100 year window can be moved using the
YEARBASE configuration parameter.
Where not included, the day number or month number is assumed to be one and the year number to
be the current year.
For compatibility with Information style multivalue products, a day number that exceeds the
number of days in the month will roll forward into the next month and return a value of 3 from the
STATUS() function. This feature can be suppressed by enabling the NO.DATE.WRAPPING
mode of the OPTION command.
Calendar Differences
The process of converting an external format date to its internal day number and vice versa is not as
easy as it sounds. As well as the slightly complex rules that determine which years are leap years
and hence have 29 days in February, there is a problem of calendar differences. Most of the world
2.11-0
The QM File System 139
now uses the same calendar for business purposes but this has not always been the case. There were
two significant realignments, one in 1752 and an earlier one in 1583 in different parts of the world.
Prior to these changes, the date in one country could be several days different from that elsewhere.
The QM date conversion operations assume the current calendar system and make no adjustment to
handle these realignments. Some multivalue products implement one or other realignment.
Whichever system is used, it will be incorrect in some contexts. Users who require specific handling
of these changes or need to handle dates before 1 January 0001 will need to develop their own date
conversion functions.
See also:
Dates, Times and Epoch Values
2.11-0
140 OpenQM
Epoch values represent a moment in time in a time zone independent manner. They are stored as a
number of seconds since 1 January 1970 GMT (more correctly UTC).
The epoch conversion code converts an epoch value from its internal day number to one of a
number of external formats or vice versa.
The full format of this conversion code is an extension of the D date conversion code:
E {y} {c} {fmt} {[f1, f2, f3, f4, f5, f6, f7]}
where
y is a digit in the range 0 to 4 specifying the number of digits to appear in the year
number. This defaults to 4.
c is the character to be used to separate the year, month and day components of the
converted date. If omitted, a space is used. Specifying c as the digit 0 suppresses
insertion of a separator between the year, month and day components.
fmt specifies the components to be present in the converted date. Multiple characters may
be chosen from the following list subject to restrictions shown below. If fmt is omitted
it defaults to MDY if American date mode is in use or DMY if European date mode is
in use.
A ASCII format date/time (e.g. Thu 16 Apr 15:02:21 2009). No other
elements may be included in the same conversion.
D Day of month.
DO Ordinal day of month (1st, 2nd, 3rd, etc)
E Toggles European date format (day, month, year). See also
DATE.FORMAT.
J Julian date (days since the start of the year).
L Alphabetic month and day names are to appear with only the first
character in uppercase instead of entirely in uppercase.
M Month in format determined by format modifiers. If no format modifiers
are present, a two digit month number is used unless c is present in which
case a three letter alphabetic month is used.
MA Month name.
O{:} Offset from GMT in the form +hh:mm or -hh:mm. The colon separator is
only present if included in the code.
Q Quarter number (1 to 4).
T{H}{S}{s} Time. The H, S and s elements are as for the MT conversion code,
specifying 12 hour clock format, inclusion of seconds, and an
alternative separator for the components of the time value.
W Day of week number. Monday is day 1.
WA Weekday name.
2.11-0
The QM File System 141
[f1,f2,f3,f4,f5,f6,f7] These format modifiers affect the way in which the above formats are
handled. Up to seven modifiers may be specified and they are associated with the
formats in the order in which they appear in fmt. Format modifiers are
n Use n characters.
A Display as alphabetic (applies to month component only).
An Display as n alphabetic characters (applies to month component only).
Z Suppress leading zeros.
Zn Display as n digits with leading zeros replaced by spaces.
"text" Uses the supplied text as the separator after the associated component.
The following special codes are recognised as part of the E conversion code for ISO8601 format
output. These may not be used with any other conversion elements:
ISO8601W yyyyWwwd
Four digit year number, two digit ISO week number, one digit day of week.
ISO8601W- yyyy-Www-d
Four digit year number, two digit ISO week number, one digit day of week with hyphen
separators.
ISO8601T yyyymmddThhmmss
Four digit year number, two digit month number, two digit day number, two digit hours, two
digit minutes, two digit seconds.
ISO8601T- yyyy-mm-ddThh:mm:ss
Four digit year number, two digit month number, two digit day number, two digit hours, two
digit minutes, two digit seconds with separators.
Time Zones
Conversion of an epoch value to an external form date and time is dependent on the time zone for
which the conversion is performed. On entry to QM, the time zone to be used is taken from the
operating system TZ environment variable for the user's process. If this has not been set, the value
of the TZ variable when QM was started is used. If this is also not set, GMT is used.
The time zone name is stored in a private configuration parameter named TIMEZONE. This can be
modified from, for example, the LOGIN paragraph, using the CONFIG command or from within
a program using the QMBasic SET.TIMEZONE statement.
2.11-0
142 OpenQM
The following examples show the result of output conversion of a value of 1234567890 in time
zone EST with various conversion codes. Where affected by DATE.FORMAT setting, both forms
are shown.
2.11-0
The QM File System 143
'EISO8601T-' 2009-02-13T18:31:30
Input conversion with the E code is much more restricted than the range of formats possible on
output conversion. In practical use of the epoch date system, it is likely that the date and time are
entered as separate items. In this case, it may be more flexible to use the D and MT conversions on
the two components separately and then use the MVEPOCH() function to convert these to an
epoch value.
The input data must always consist of a date followed by a time. The date must contain all three
elements (day, month, year).
The simplest E conversion is just the letter E. This may be followed by the D, M and Y elements to
override the default sequence of the date components. Use of a trailing T to represent the time is
valid for consistency but is otherwise ignored as it must be the last element in the data to be
converted. Use of any other conversion code elements may have unspecified effects.
There is some flexibility to the order in which the components of the date may occur in the input
data. Where an alphabetic month name is used, this is processed first and must be at least three
characters. Numeric components are then assumed to be in the order of the remaining elements of
the conversion code. Thus with a code of EDMY, '1 Jun 94' and 'Jun 1 94' would both be treated as
1 June 1994.
For dates entered as two digits, year number values in the range 30 to 99 are assumed to be 1930 to
1999 and 0 to 29 are assumed to be 2000 to 2029. This 100 year window can be moved using the
YEARBASE configuration parameter. and the order of these defaults to day.
The time must be entered in the form hh:mm:ss or hh:mm where the colon may be any non-numeric
character. If the seconds are omitted, a default of zero is used.
See also:
Date, Times and Epoch Values, EPOCH(), MVDATE(), MVDATE.TIME(), MVEPOCH(),
MVTIME(), SET.TIMEZONE
2.11-0
144 OpenQM
F; expression
where
2.11-0
The QM File System 145
The group conversion code treats the source data as being formed from a number of components
separated by a delimiter character and extracts specified components. It works identically on input
and output conversions.
Gcn Returns the first n components of the source data delimited by character c.
Gscn Skips s components and then returns the next n components of the source data
delimited by character c.
Example
Consider a date stored in character form as 03/10/98. The G conversion code could be used to
extract components of this date:
G/1 returns 03
G/2 returns 03/10
G1/1 returns 10
2.11-0
146 OpenQM
The integer conversion codes convert integer values between numeric form and hardware specific
integer representation.
Used with the ICONV() function, the conversion code translates a QMBasic integer numeric value
to the equivalent hardware specific representation of that integer. Used with the OCONV()
function, the conversion code translates a hardware specific representation of an integer value to its
equivalent QMBasic numeric form.
By default, these conversions adopt the byte ordering of the machine on which the program is being
executed. Adding an optional L to the end of the conversion code (ISL, ILL) causes conversion to
assume a low byte first format for the hardware representation of the value. Similarly, adding an
optional H to the end of the conversion code (ISH, ILH) causes conversion to assume a high byte
first format for the hardware representation of the value.
These codes should not be used to encode numeric values to be stored in database files as the
hardware specific representation may include bytes that will be interpreted as mark characters.
These conversions are intended for use in, for example, applications that need to generate hardware
specific data for transmission over communications networks.
2.11-0
The QM File System 147
The length conversion code performs string length constraint checks. It works identically on input
and output conversions and has three forms:
Examples
2.11-0
148 OpenQM
These conversion codes behave identically for both input and output conversion.
The MCT conversion code is implemented differently across various multivalue products. The
default behaviour of QM is to match D3 and other Pick style products where the first letter after a
non-alphabetic character is converted to uppercase, all others to lowercase. Use of the
SPACE.MCT mode of the OPTION command enables the behaviour found in Information style
products such as UniVerse whereby letters immediately following a space are converted to
uppercase, all others to lowercase. In both modes, the first character of the string is converted to
uppercase.
Examples
2.11-0
The QM File System 149
The masked decimal conversion codes convert a number between its internal and external forms.
The formats available provide scaling, currency symbol insertion, thousands separation and a
variety of methods for handling negative numbers.
Scaling provides a means by which items such as currency values which are usually written as
pounds and pence (or dollars and cents) can be handled internally as integer numbers of pence (or
cents) for faster and precise calculation. Scaling is performed by specifying the position of an
assumed decimal point.
Input conversion allows for some degree of flexibility in the exact format used. For example, any of
the negative value representations may be used regardless of the method actually defined in the
conversion code.
ML n {f} {,} {$} {s} {[intl]} {P} {Z} {T} {x{c}} {fx}
where
n is a digit in the range 0 to 9 specifying the number of digits to appear to the right of the
decimal point. Rounding occurs on output conversion in the fractional part and, if the
result is an integer, the decimal point does not appear.
f is a digit in the range 0 to 9 specifying the position of the implied decimal point in the
data to be converted. For example, if the value supplied to an output conversion is
12345 and f is 2, the result is 123.45. Conversely, if the value supplied to an input
conversion is 123.45 and f is 2, the result is 12345. If omitted, f defaults to the same
value as n.
$ specifies that the national currency symbol should be used as a prefix to the converted
data on output conversion and may be present on input conversion. The default
currency symbol is a dollar sign but this may be changed by use of the NLS command
or the SETNLS QMBasic statement.
- places a - sign to the right of negative values or a space to the right of positive values.
2.11-0
150 OpenQM
( encloses negative values in round brackets. A positive value has a space placed to its
right. This element is not allowed when the PICK.ML.CONV.MASK mode of the
OPTION command is in effect.
< encloses negative values in angle brackets. A positive value has a space placed to its
right.
C places the letters cr to the right of negative values or two spaces to the right of positive
values. Use the CRDB.UPCASE keyword of the OPTION command to change this to
CR.
D places the letters db to the right of negative values or two spaces to the right of positive
values. Use the CRDB.UPCASE keyword of the OPTION command to change this to
DB.
[intl] specifies alternative international handling of currency symbols and separators. intl
consists of up to four comma separated items which specify the prefix, thousands
separator, decimal separator and suffix to be applied to the converted value. These
components should be quoted if there is any potential confusion.
Z specifies that a zero value should be represented by a null string on output conversion.
This option is ignored on input conversion.
T specifies that trailing decimal places should be truncated rather than rounded. This
option is ignored on input conversion.
x{c} specifies that the result of an output conversion is to be a field of x characters, left or
right justified as specified by use of ML or MR. If the converted data is longer than x
characters it will be truncated to fit. If it is less than x characters it is padded using
character c or spaces if c is not specified. The value of x may be one or two digits.
If the input data is a null string, the ML and MR codes normally treat this as zero and return an
appropriately formatted conversion of the number zero. If the PICK.NULL mode of the OPTION
command is active, a null string will be returned.
2.11-0
The QM File System 151
The following table sets out a variety of combinations of masked decimal output conversion
features.
Sign handling
12345678 MD0 '12345678'
-12345678 MD0 '-12345678'
12345678 MD0+ '12345678+'
-12345678 MD0+ '12345678-'
12345678 MD0- '12345678 '
-12345678 MD0- '12345678-'
12345678 MD0< ' 12345678 '
-12345678 MD0< '<12345678>'
12345678 MD0( ' 12345678 '
-12345678 MD0( '(12345678)'
12345678 MD0C '12345678 '
-12345678 MD0C '12345678CR'
12345678 MD0D '12345678 '
-12345678 MD0D '12345678DB'
Scale factors
12345678 MD22 '123456.78'
1234567.89 MD22 '12345.68'
-12345678 MD22 '-123456.78'
12345678 MD02 '123457'
12345678 MD02T '123456'
2.11-0
152 OpenQM
The behaviour of a masked decimal input conversion with invalid data provides close compatibility
with other multivalue products but may not be exactly identical as there is some variation. The MD
code will return a null string as its result. The ML and MR codes return the converted form of the
leading numeric part of the data, ignoring any further characters. If there is no leading numeric part,
the original data is returned unconverted. The QMBasic ICONV() function will return a status
code of 1 when attempting to convert invalid data with the MD, ML and MR codes.
The following table sets out a variety of combinations of masked decimal conversion features.
Sign handling
'12345678' MD0 '12345678'
'-12345678' MD0 '-12345678'
'12345678-' MD0 '-12345678'
'<12345678>' MD0 '-12345678'
'(12345678)' MD0 '-12345678'
'12345678CR' MD0 '-12345678'
'12345678DB' MD0 '-12345678'
Scale factors
'123456.78' MD2 '12345678'
2.11-0
The QM File System 153
2.11-0
154 OpenQM
The time conversion code converts a time from its internal representation (number of seconds since
midnight) to a string representing hours, minutes and seconds or vice versa.
where
H specifies that the time is to appear in 12-hour format with either "am" or "pm"
appended. If H is not specified, 24-hour conversion is used for output conversion and
assumed for input conversion. If the AMPM.UPCASE mode of the OPTION
command is active, the appended suffix is in uppercase (AM or PM).
S specifies that output conversion is to include the seconds field. Input conversion
determines whether seconds are included by examination of the data to be converted.
c is the character to separate the hours, minutes and seconds fields. If omitted, a colon is
used. The separator character should be enclosed in quotes if required to avoid
syntactic ambiguity (for example MT'h' for French format times such as 09h30). A pair
of adjacent quotes can be used to specify that no separator is to be inserted.
Examples
See also:
Dates, Times and Epoch Values
2.11-0
The QM File System 155
The radix conversion codes convert a number to/from binary (MB), octal (MO) or hexadecimal
(MX).
Input Conversion
The MB, MO and MX conversions take a number represented by a character string of binary, octal
or hexadecimal digits and converts it to an internal integer value.
Addition of the 0C suffix to these codes (MB0C, MO0C, MX0C) takes a character string holding a
series of binary, octal or hexadecimal digits and translates each group of 8, 3 or 2 digits to the
corresponding ASCII character. If the source data is not an exact multiple of 8, 3 or 2 digits in
length, as appropriate to the conversion type, implied leading zeros are added.
Output Conversion
The MB, MO and MX conversions convert a number to binary, octal or hexadecimal form as a
character string. Non-integer values are truncated towards zero. Negative values are treated as
unsigned 32 bit values. Leading zeros are suppressed.
The addition of the 0C suffix to any of these conversion codes treats the source data as a character
string and converts each character to its binary, octal or hexadecimal representation.
Examples
Input conversion:
Source data Conversion Result
1110 MB 14
37777777762 MO -14
97AB MX 38827
010000010100001001000011 MB0C ABC
101102103 MO0C ABC
414243 MX0C ABC
Output conversion:
Source data Conversion Result
19 MB 10011
19 MO 23
19 MX 13
ABC MB0C 010000010100001001000011
ABC MO0C 101102103
ABC MX0C 414243
2.11-0
156 OpenQM
Used as an output conversion, MCDX converts a number from decimal to hexadecimal and MCXD
converts from hexadecimal to decimal. Used as an input conversion, the roles of these two codes are
reversed.
The final character of the conversion code name is optional. They can be written as MCD and
MCX.
2.11-0
The QM File System 157
The field extraction code, only supported for output conversion, extracts a field, value or subvalue
from the source data. It is used most frequently in conjunction with other conversion codes.
2.11-0
158 OpenQM
The P conversion code attempts to match the supplied data against one or more pattern templates
P(template){;(template)...}
where
template is a pattern template as for the MATCHES operator and must be enclosed in
brackets. If more than one template is supplied, they may be separated by
semicolons (;) or forward slashes (/).
The P conversion code tests whether the input data matches template. If a match is found, the
original data is returned. If no match is found, a null string is returned.
If more than one template is provided, the input value is tested against each in turn.
Examples
2.11-0
The QM File System 159
The R conversion code checks whether a numeric value is within a specified range.
Rn,m{;n,m...}
where
n,m specifies a range of numeric values. Negative values are allowed. If more than one n,m
pair is supplied, they may be separated by semicolons (;) or forward slashes (/).
The R conversion code tests whether the input data is an integer value in the range n to m. If the
value is within the specified range, the conversion returns the input data. If the value is outside the
range, a null string is returned.
If more than one n,m pair is provided, the input value is tested against each in turn.
A null input value always returns a null result regardless of the values of n and m.
A non-numeric data item will return the original data. The STATUS() function would then return 1
to indicate an error.
Examples
2.11-0
160 OpenQM
The S (substitution) conversion code allows an application to handle zero or null data items as a
special case.
S;value1;value2
The S code returns a value determined by value1 if the source data is not zero or null, or the value
determined by value2 if the source data is zero or null.
Examples
A file has a date field that contains zero when it is not significant. Using a date conversion would
return this as 31 Dec 1967. The S conversion code could be used to replace the zero by a null string
before applying the date conversion. The dictionary conversion code field could be
S;*;''VMD4DMY
The following table shows a variety of conversions for a data record of "F1FMF2" and a record id of
"ID".
2.11-0
The QM File System 161
The T conversion code uses the source data as a record id to the named file and returns data from
this record.
Tfile;cv;i;o
where
file is the file name. This may be prefixed by either DICT followed by a space or by an
asterisk with no space to reference the dictionary part of the file. Where necessary to
avoid ambiguity, the file name may be enclosed in quotes.
c identifies the action to be taken if the requested record does not exist of the field to be
extracted is null. This is a single letter:
C Returns the record id.
V Displays a warning message and returns a null value.
X Returns a null value
I Like V for input conversion, C for output conversion
O Like C for input conversion, V for output conversion
v specifies the value position to be extracted from the returned data. If omitted, all values
are returned with value and subvalue marks replaced by spaces.
i specifies the field position of the data to be returned when performing an input
conversion.
o specifies the field position of the data to be returned when performing an output
conversion.
This conversion code is closely related to the TRANS() function. Where possible, TRANS() should
be used in preference to the T conversion code for best performance.
2.11-0
162 OpenQM
The text substring extraction code returns a portion of the source data.
Tm,n
Tm
The first form returns n characters starting at character m from the source data. The second form
returns the last m characters of the source data.
2.11-0
The QM File System 163
Users may add their own conversion codes to the system by writing a QMBasic subroutine to
perform the conversion.
Usubrname
or
Usubrname.extension
where
extension is optional qualifying information for the conversion code. This can be accessed
within the subroutine in the @CONV variable.
where
See the U50BB subroutine in the BP file of the QMSYS account for an example of a Pick user exit
routine.
Example
2.11-0
164 OpenQM
END
STATE = 0
RETURN
END
2.11-0
The QM File System 165
Format specifications appear in field 5 of C-type, D-type and I-type dictionary items to determine
the default format of output from the LIST and SORT query processor commands. They are also
used in the QMBasic FMT() function and with the query processor FMT keyword.
where
field.width is the width of the field into which the data is to be formatted. If field.width is
omitted, mask must be specified.
justification indicates the justification mode to be applied. It takes one of the following
values:
data formatted with this code that is wider than field.width is not
wrapped over multiple lines but extends into the space to its right,
possibly overwriting whitespace in later columns.
n specifies the number of decimal places to appear in the result when formatting
numeric data. The value is rounded in the normal manner. If n is zero, the
value is rounded to an integer.
m specifies the scaling factor to be applied. The value being formatted is scaled
by moving the decimal point m - p places to the left, where p is the current
precision value.
mask specifies a mask to be used to format the data. If omitted, field.width must be
specified. Both can be used together.
2.11-0
The QM File System 167
Where the mask specifies more characters than in the data being converted,
positions corresponding to # characters in the mask are replaced by the
fill.char, positions corresponding to * characters in the mask are replaced by
asterisks and positions corresponding to % characters in the mask are replaced
by zeros. If the data is left aligned, the padding is inserted in the rightmost
positions. If the data is right aligned, the padding is inserted in the leftmost
positions.
If the mask specifies fewer characters than in the data being converted, part of
the source data will be lost. A left aligned format will truncate the source data
and a right aligned format will lose data from the start of the source.
Data formatting attempts to handle the data as a number if the decimal places, currency symbol,
comma insertion or null zero features are included in the format specification. If these features are
all absent, or if the data cannot be converted to a number, it is handled as a string. The difference in
handling is relevant when processing data such as a string with leading zeros.
2.11-0
168 OpenQM
2.11-0
The QM File System 169
3.11 Locks
Although the single user environment of a PDA appears not to require locking, the PDA version of
QM retains support for the locking operations for use with QMNet connections and to minimise
changes that need to be made when porting applications from other platforms.
Three types of lock are available on files; file, read and update locks. Each has a different role and
care should be taken to use them correctly.
A file lock applies to the entire file and prevents any other user from obtaining any lock on the file
or records therein. File locks are usually only needed during operations that must handle the file in a
consistent "snap shot" manner when, for example, summing the values of some field from all
records. A process can only acquire a file lock if no other process has any locks on the file or its
records. Conversely, no other process can obtain any other sort of lock within the file while the file
lock is active. Use of file locks can have a severe effect on performance and hence they should only
be used where absolutely necessary.
A file lock is obtained by the FILELOCK statement and is released by the FILEUNLOCK or
RELEASE statements, or on closing the file.
A read lock (sometimes called a shared lock) applies to an individual record and prevents other
processes from obtaining the file lock or an update lock on the same record. Any number of
processes may acquire read locks on the record at the same time. An attempt to obtain a read lock
will fail if another process has the file is locked or has an update lock on the record. Read locks can
be used to ensure that a program sees a consistent view of a set of records, without the risk that
some other process has changed any of these records.
An update lock also applies to an individual record and prevents other processes from obtaining the
file lock or either type of record lock on the same record. Only one process may acquire an update
lock on a record at a time. An attempt to obtain an update lock will fail if another process has the
file is locked or has a read or update lock on the record.
A read or update lock may be acquired on a record that does not exist in the file. This provides a
means of locking a record that is about to be written for the first time.
Read and update locks are obtained by the READL or READU statements (and others). These
locks are released on closing the file, by the RELEASE statement or on return to the command
prompt. Additionally, read and update locks are normally released by writing or deleting the locked
record, however, the WRITEU and DELETEU statements provide a means of writing or deleting
without releasing the lock.
Although it is possible to hold very many record locks at a time, this tends to indicate poor
application design and may have an adverse effect on performance. The system wide limit on the
number of concurrent locks is determined by the NUMLOCKS configuration parameter. If this
limit is reached, the program will behave as though the record is locked by another user, taking the
2.11-0
170 OpenQM
LOCKED clause of the relevant QMBasic statement with a STATUS() value of -1 or, if no
LOCKED clause is present, waiting for space to become available. A message will be written to
the system error log file.
Where an attempt to obtain a lock fails, the QMBasic language provides two methods of handling
the situation. A program may either wait automatically for the lock to be released or it may regain
control and take some action of its own (see the LOCKED clause of the QMBasic file handling
statements). For compatibility with some other multivalue database products, the LOCK.BEEP
mode of the OPTION command can be used to cause the system to emit a beep at the terminal once
per second while waiting for a record lock or file lock.
A process is not affected by its own locks. Thus it is possible to take a record lock on a record from
a file for which the file lock is held or, conversely, to take the file lock while holding one or more
record locks. Taking a read lock on a record for which an update lock is held or vice versa will
convert the lock type.
Locks are associated with the underlying operating system file, not the VOC reference to the file.
QM will correctly track locks relating to the same file however it was opened. Where a file has been
opened more than once simultaneously by a single process, the locks are released on the final close
of the file.
Locks are also associated with the particular file variable referenced when they are acquired. Thus,
if an application opens the same file more than once, closing one of the file references will
automatically release any locks acquired using that file variable but leave other locks in place.
Similarly, use of the form of the RELEASE statement that takes only a file variable will release
locks associated with that file variable. This mechanism ensures that developers do not need to be
aware of how other modules within the application operate.
The lock handling operations of QMBasic only operate with correctly structured applications. The
non-locking versions of the READ and WRITE operations, etc, take no part in the locking system
and hence can access a file regardless of its lock state. The individual statement descriptions give
more information.
A correctly written application never writes or deletes a record without locking it first, however, for
compatibility with other multivalue database products, this is not enforced by default except within
transactions. A poorly written program that uses READ in place of READU and then writes the
record could overwrite a record that is locked by another user. The MUSTLOCK configuration
parameter can be used to enforce tight control of locks, eliminating this potential problem. This
parameter is not supported on the PDA version of QM.
Enabling lock rule enforcement may not be easy when porting existing applications to QM. Because
multivalue systems have not enforced these rules in the past, programmers sometimes omitted use of
locks in situations where there would never be contention. For example, overnight processing might
not use locks because the developer knew that it is run at a time when there are no other users on
the system. Programs that write a record that is known not to exist also appear not to need locks.
Both of these examples actually represent bad programming practice as the assumption made by the
developer may subsequently turn out not to be true due to changes in business operation.
Task Locks
2.11-0
The QM File System 171
QM also provides task locks, sometimes known as process synchronisation locks, that are not
related to any particular file and are typically used to ensure that some task cannot be performed by
two users simultaneously.
A task lock is simply an numbered entry in a 64 element locking table. A process acquires a task
lock using the LOCK command or the QMBasic LOCK statement. If the lock is already owned
by another user, the process either waits for it to be released or handles the situation for itself. On
completion of the task, the process can release the lock using the CLEAR.LOCKS command or
the QMBasic UNLOCK statement.
Task locks can be difficult to use because the lock is not related to a file, record, etc and the
application designer must choose one that is not also used for some other purpose. Because task
locks are shared across all accounts, this implies a possible unwanted interaction between different
applications.
2.11-0
172 OpenQM
Select lists are lists of things to be processed, usually record keys from a file. The list may contain
all record keys or only those where the key or record data meets some specified criteria. Using
select lists simplifies and speeds up many data processing operations using commands or within
QMBasic programs.
There are two types of select list; numbered lists and select list variables.
The eleven numbered select lists are numbered 0 to 10 and are visible to all parts of a QM session.
List 0 is referred to as the default select list and is used by some verbs such as COPY to determine
the records (or files for some other verbs) to be processed.
With QM in its default modes, numbered select lists are created by the SELECT or SSELECT
query processor commands. The SELECT command builds a list of keys of records meeting the
specified criteria but with no apparent ordering to the list. The SSELECT command is similar but
the list is in order of record key value. The SELECT command is faster both during generation of
the list and subsequent processing of records as its order reflects the placement of records within the
file.
Numbered select lists can also be created by the QMBasic SELECT statement. This statement
builds a list of all records in the file and provides no means of including or excluding records by
selection criteria. Programs can then read keys sequentially from the list using the READNEXT
statement.
Numbered select lists may also be saved to records in the $SAVEDLISTS file using SAVE.LIST
and later restored using GET.LIST. Lists that have been written to other files by QMBasic
programs may be restored using FORM.LIST. The EDIT.LIST command allows editing of select
lists. Saved select lists may be copied using COPY.LIST, deleted using DELETE.LIST or
merged using MERGE.LIST.
Because the numbered select lists are visible to all parts of a QM session, a list created in the
command language may be used by a QMBasic program, or vice versa. Named lists saved to the
$SAVEDLISTS file can be shared across separate QM processes. They are often used to create a
list of records that may be processed many days later. For example, an application might generate a
list of overdue accounts and immediately use this list to send letters to the relevant clients. A saved
copy of this list might then be used two weeks later to check if the overdue accounts have now been
paid.
A select list represents a "snapshot" of the file at the time when it was generated. Adding, deleting
or modifying records will not affect the select list. Thus, if a file may be modified by another
process between generation of the select list and retrieval of records for processing, the program
must allow for records that have been deleted or no longer meet the selection criteria.
A special type of select list, an exploded list, is constructed using the BY.EXP or BY.EXP.DSND
keywords of the query processor. In an exploded select list, the multivalued field from which it was
created generates a separate entry for each value or subvalue. The internal representation of this list
includes information to identify the value and subvalue positions of the corresponding data element.
This can be retrieved by the QMBasic READNEXT statement and is used automatically by some
2.11-0
The QM File System 173
A QMBasic program can create a select list in a variable by using the SELECTV statement. This
can be processed item by item within the application by use of READNEXT in the same way as a
numbered list. There is no practical limit to the number of separate select list variables that may
exist at one time.
To ease migration from Pick style multivalue database products, the PICK.SELECT mode of the
$MODE compiler directive can be used to make SELECT produce select list variables instead of
numbered lists.
2.11-0
174 OpenQM
An alternate key index provides a method to access data file other than by the primary key (record
id).
Consider a file holding information about orders with, for example, 100000 records in it. For
simplicity, assume that these records are made up of 10 orders from each of 10000 customers. To
locate all the orders placed by a specific customer would require all 100000 records to be processed
to find the 10 that we want.
Using an alternate key index on the customer number field of the order records, QM can look up the
customer in the index and then go directly to the 10 order records.
An alternate key index is created using the CREATE.INDEX command. This defines the index
content but does not populate it. The BUILD.INDEX command builds the actual index and
activates it. From that point forwards, QM will maintain the index automatically and the query
processor will use it automatically. No changes are required to application software.
The functions of the CREATE.INDEX and BUILD.INDEX commands are combined in the
MAKE.INDEX command.
Once an index has been built, it is maintained totally automatically by QM such that it is impossible
to write or delete a record without the corresponding index updates being applied The only situation
where an index should possibly not correctly reflect the data in the file is after a power failure
where some data may not have been flushed to disk. In this case, the REBUILD.ALL.INDICES
command can be used to rebuild all indices in an account.
The query processor will also use the index totally automatically where it appears relevant.
Indices can be built on real data stored in the file (dictionary D-type or A/S-type without a
correlative) or on calculated values (dictionary C/I-type or A/S-type with a correlative). When
using calculated values, it is essential that the expression relies only on data from the file to which
the index applies and is not time variant. Thus an index using data retrieved from another file using
the TRANS() function, a T-conversion or a subroutine that performs a read will fail because the
index will not be updated if the remote file is modified. Similarly, an index built using a calculation
that uses the date or time (age calculated from a date of birth, for example) will fail because the
expression does not always return the same output value for the same input.
These are both examples of the one and only rule that determines whether an index based on a
calculated value will work: The virtual attribute expression must always return the same value
when evaluated for the input data.
When using a C-type index or an I-type that calls a subroutine, the index expression must not cause
any write or delete operations to occur in the file to which the index applies.
For an index to be effective, each entry in the index should lead to a very small proportion of the
data in the file. Index entries that lead to very large numbers of records are less effective and may
also be costly to access or update. The worst case of this is indexing on a simple yes/no value.
A file may have up to 32 indices. The more indices there are, the longer it will take to update a
record in the data file though this should be outweighed by the advantage of being able to use the
indices in queries. Also, it should be remembered that indexing on a multivalued field may require
many index entries to be updated when writing a data record.
2.11-0
The QM File System 175
Indices can be deleted using the DELETE.INDEX command if they are no longer wanted. A report
of any or all indices on a file can be produced with the LIST.INDEX command.
A large data import or other process involving extensive updates to a file may run faster with
indexing disabled. A subsequent use of BUILD.INDEX may be significantly faster than the time
saved by disabling the index because it can process the data in sorted order, optimising the way in
which the underlying index structures are built. To enable this mode of operation, use the
DISABLE.INDEX command to turn off the indices, perform the data import or processing, and
then use BUILD.INDEX to reconstruct the indices. QM does not support the ENABLE.INDEX
and UPDATE.INDEX commands found in some other multivalue products as the possibility of
enabling the index without reconstructing it means that the index will not reliably reflect the stored
data. QM's implementation of DISABLE.INDEX allows individual indices to be disabled. Also
note that while an index is disabled, it will not be used by the query processor.
Internally, an AK is stored as a balanced tree structure in which the index keys (data field values)
are in sorted order. When the index is built in case sensitive mode (the default), the sort order of the
indexed data is in accordance with the ASCII character set. Thus an index might contain, in sorted
order:
Lucy
MICHAEL
Mick
Peter
martin
For languages that use characters from the upper half of the character set (e.g. accented characters),
this may not correspond to the conventional way in which the alphabet is sequenced.
An index can also be constructed in case insensitive form. Internally, this is performed by
converting the indexed values to uppercase. Thus, the above example would be stored internally as
LUCY
MARTIN
MICHAEL
MICK
PETER
Notice how the sort order has also changed. Because of this, a case sensitive index cannot be used
to resolve query processor selection clauses that use case insensitive operators and vice versa.
A program can determine whether a file has indices by use of the FILEINFO() function with action
key FL$AK:
IF FILEINFO(FVAR, FL$AK) THEN DISPLAY 'File has indices'
The names of the indices that exist for a file can be determined using the INDICES() function:
NAMES = INDICES(FVAR)
An extended form of the INDICES() function can be used to retrieve the details of a specific index
by name:
INDEX.DATA = INDICES(FVAR, NAME)
2.11-0
176 OpenQM
Programmers can gain access to the index itself using the QMBasic SELECTINDEX statement
and advanced index scanning operations can be performed using SELECTLEFT,
SELECTRIGHT, SETLEFT and SETRIGHT as described below.
Scanning an Index
Because the index keys (data field values) are in sorted order, the index can be used to find records
where the indexed data field value lies within a specified range of values.
The SELECTINDEX statement is used by QMBasic programs to build a select list of records that
have a specific value in an indexed field. As a side effect, this operation leaves a pointer into the
index structure at the position identified by the value referenced in the SELECTINDEX. If there
are no records with the requested indexed value, the pointer is left positioned where such a value
should go. Thus, if the index contained references to records with indexed values 1, 3, 5 and 7, a
SELECTINDEX operation to build a list of records with an indexed value of 4 would return an
empty list but would leave the index pointer between the entries for 3 and 5.
Alternatively, the SETLEFT or SETRIGHT statements may be used to position the pointer at the
extreme left or right of the indexed values.
The SELECTRIGHT or SELECTLEFT statements can be used to walk through the index,
starting at the position of the index pointer and moving to the right (ascending order of indexed
value) or left (descending order of indexed value). This operation creates a select list of records with
the next indexed value in the direction of the scan.
Thus, to walk through an index from beginning to end in ascending order, a program would use
SETLEFT to position at the start of the data and then perform a series of SELECTRIGHT
operations until no further data is available. For example, if we have an orders file open as ORD.F
and there is an index named CUST.NO for the customer number, we could process orders in
ascending customer number with a loop such as:
SETLEFT 'CUST.NO' FROM ORD.F
LOOP
SELECTRIGHT 'CUST.NO' FROM ORD.F SETTING CUST
LOOP
READNEXT ORD.ID ELSE EXIT
...processing...
REPEAT
UNTIL STATUS()
REPEAT
The outer loop walks through the index returning a select list of orders for each customer, also
setting CUST to the corresponding customer number. The inner loop processes the orders for the
customer.
There is a sample QMBasic class module named INDEX.CLS in the BP file of the QMSYS
account, catalogued as !INDEX.CLS. This class allows an application to scan an index one record
id at a time instead of one indexed value at a time. Full details of its use and internal operation can
be found in the source code.
2.11-0
The QM File System 177
Sometimes an application may build an AK on the primary key. This can be useful where, for
example, the ids are not simple sequential numbers. For this discussion, we will imagine a log file
for which the record id is a timestamp value.
Using a left to right scan loop similar to that above would allow the application to walk through the
log records. Instead of terminating the loop when we reach the end of the index data, we could use
SLEEP to pause for a while and then try again. This would allow us to process new records as they
are added to the log.
Use of SETRIGHT positions after the last record in ascending sort order. Instead of scanning the
entire log from left to right, we could use SETRIGHT to position at the extreme right and then
process only records added after our program starts.
2.11-0
178 OpenQM
3.14 Triggers
A trigger is an optional user written function associated with a hashed file and configured to be
executed when certain file operations are performed. Executed before a write or delete, the trigger
can be used to apply data validation. Executed after a record is written or deleted, the function can
trigger other events such as related file updates. Trigger functions can also be executed after a read
and before or after a clear file operation.
The trigger function is simply a catalogued QMBasic subroutine which is automatically executed as
part of the file operation. The subroutine is passed a mode flag to indicate the action being
performed, the record id, the record data (read or write operations) and a flag indicating whether
the QMBasic ON ERROR clause is present. The subroutine may do whatever processing the
application designer wishes. If the write or delete is to be disallowed, the pre-write or pre-delete
trigger function should set the @TRIGGER.RETURN.CODE variable to a non-zero value such as
an error number or an error message text to cause the write or delete to take its ON ERROR clause
if present or to abort if omitted. The STATUS() function will return ER$TRIGGER when executed
in the program that initiated the file operation. Programs should test STATUS() rather than testing
for @TRIGGER.RETURN.CODE being non-zero to determine whether the trigger function has
disallowed the write or delete as @TRIGGER.RETURN.CODE is only updated when the error
status is set.
The trigger function is set up using the SET.TRIGGER command. After it has been set up, the
trigger function is loaded into memory when first needed tnd is called for all operations defined by
the mode settings in the SET.TRIGGER command. Modifying and recataloguing the trigger
function will have no effect on processes that have the file open until they close and reopen it.
Setting or removing a trigger function while the file is open may not take effect until after the next
access to the file.
If the trigger function is not in the catalogue or has the incorrect number of arguments, no error
occurs until the first action that would call the function. Note that the trigger function must be
visible to all accounts that may reference the file. Where a file is used by multiple accounts, this can
be achieved by using global cataloguing, sharing a private catalogue, or ensuring that the VOC
entry for a locally catalogued trigger function is present in each account. Although it would be
possible for a shared file to use a different trigger function depending on the account from which it
is referenced, this is not recommended.
When using QMNet, the server process runs in the QMSYS account. The implications of this are:
· Trigger functions that apply to files that may be updated via QMNet and any subroutines
called from within them must be globally catalogued.
· Any files opened from within the trigger function must either be defined in the QMSYS VOC
or, more reasonably, must be referenced using the extended filename syntax that includes the
account name or opened by pathname.
where
name is the trigger subroutine name.
mode indicates the point at which the trigger function is being called:
2.11-0
The QM File System 179
When writing trigger functions, the original data of the record to be written or deleted can be
examined by reading it in the usual way. Trigger functions should not attempt to write the record
for which they are called. Neither should they release the update lock on this record as this could
cause concurrent update of the record.
If the value of data is changed by a pre-write trigger function, the modified data is written to the
file. Similarly, a read trigger can modify the data that will be returned to the application that
requested the read. Changes to the value of id will not affect the database update in any way.
Trigger functions may perform all of the actions available to other QMBasic subroutines including
performing updates that may themselves cause trigger functions to be executed.
The mode values correspond to bit positions in a binary value and hence a condition such as
IF MODE = 4 OR MODE = 8 THEN ...
is equivalent to
IF BITAND(MODE, 12) THEN ...
which can simplify some trigger functions. Writing this with the mode value in hexadecimal form
can make it easier to combine modes.
IF BITAND(MODE, 0x0C) THEN ...
Example
2.11-0
180 OpenQM
The following simple trigger function could be used to capture all writes and deletes, logging the
new record data in a "replication log" file which can then be used to maintain a copy of the data on
a separate server. The same trigger function can be applied to many files.
$INCLUDE KEYS.H
FN = FILEINFO(FVAR, FL$VOCNAME)
BEGIN CASE
CASE MODE = FL$TRG.PRE.WRITE
RECORDLOCKU RLG.F, FN:' ':ID
WRITE DATA TO RLG.F, FN:' ':ID
On first call, this trigger routine will open a file named REPLOG which is used for logging.
Because the file variable is stored in a common block, the file will remain open for subsequent calls
to the trigger function.
For write operations (mode FL$TRG.PRE.WRITE), the trigger routine writes a copy of the data to
a record in REPLOG with its id constructed from the file name and record id of the write that is
being replicated.
For delete operations (mode FL$TRG.PRE.DELETE), the trigger routine writes a null record to
REPLOG with its id constructed in the same way.
A separate program, perhaps running via QMNet from another server, could periodically read all
records from the REPLOG file and apply the changes to a copy of the original data, deleting the
REPLOG entry. Note that the REPLOG is not a sequential audit trail but stores only the last update
to any record. Thus a long series of updates will only ever produce a single REPLOG record.
There are two assumptions made by this example. Firstly, the data files being replicated never
contain null records. We can, therefore, recognise a delete operation from the presence of a null
record in the REPLOG. If this were not a safe assumption, we would need to add an extra field to
the REPLOG data to say whether this was a write or a delete.
Secondly, there is an assumption that a file only has a single VOC entry defining it. If this were not
the case, a combination of the filename (FN variable) and record id (ID argument) would not be a
unique reference to the record. If this assumption was not valid, it would be possible to use
2.11-0
The QM File System 181
FILEINFO() to get the pathname of the file and use this instead.
2.11-0
182 OpenQM
It is the user's responsibility to provide a mechanism to prevent disclosure of the key string. The key
provided by the user can be of any length and may contain any characters. QM will automatically
transform this into a form that is valid for use with the AES algorithm. For best security, avoid very
short encryption keys which could be determined by repeated attempts to decrypt the data.
Because this style of encryption is performed outside of QM's control, it is unlikely to be practical
to build alternate key indices on encrypted data.
Record level encryption encrypts an entire record using a single, user defined key and the AES
128, 192 or 256 bit encryption algorithm. Because this encryption occurs deep inside the QM file
system, it is possible to have alternate key indices on fields within a file that uses record level
encryption. Note, however, that the index file itself is not encrypted and hence indexed fields are
partially exposed outside of the encryption system.
Field level encryption allows users to encrypt specific fields within a file, possibly using different
keys or algorithms for each encrypted field. It is not possible to build an alternate key index on an
encrypted field. Field level encryption results in a slight increase in record size because of a
transformation performed to ensure that the encryption process can never produce data that contains
the mark characters.
With either level of encryption, an application may use many different encryption keys and each key
can be made accessible to a selected set of users. A user cannot open a file that uses record level
encryption unless they have access to the key. When using field level encryption, read operations
will return null strings for fields to which the user has no access and write operations will preserve
the previous content of these fields.
The encryption system is managed by a user (or multiple users) known as the security
administrator. This user is responsible for management of the key vault, a file that defines the
names and actual values of all encryption keys used on the system. The key vault is itself encrypted
using the master key which should be known only by the security administrator. This key value is
entered when the key vault is created by first use of CREATE.KEY. If the key vault is moved to
another system or a new licence is applied, the master key must be re-entered either via the licence
entry screen or by use of the RESET.MASTER.KEY command.
Because QM uses key names rather than the actual keys in operations such as creating files or
setting encryption rules, there is no need to restrict knowledge of the key names. The security
administrator sets the actual encryption key value when the key is entered into the key vault and this
can subsequently be applied to data files without knowing what encryption is being used. For
example, the security administrator might define a key named CARDNO for use on fields
containing credit card numbers. Developers can freely apply this without knowing the encryption
key. To ensure that data is not lost in the event of a major system failure, the master key and details
of each key name / key value pair should be stored securely off-site in some way. All security
2.11-0
The QM File System 183
administrator commands require entry of the master key though this is remembered for the duration
of the user's session.
A new encryption key is created using the CREATE.KEY command, available only to users with
administrative rights in the QMSYS account. This command assigns the actual encryption key and
the algorithm to be associated with the key name. The AES 128, 192 and 256 bit algorithms require
a key length of 16, 24 or 32 bytes respectively, however, to enable administrators to use convenient
keys of any length up to 64 characters, QM will transform the key entered by the user into a form
that is valid for the AES algorithms. Specifying a key that is approximately the required internal
length give best security.
Defining a key name makes it accessible to the user that defined it. To make it accessible to other
users, the security administrator uses the GRANT.KEY command, specifying the key name and
the login names of the users or user groups (not Windows) to whom access is to be granted. Access
to a key can subsequently be removed using the REVOKE.KEY command. If a key is no longer
used, it can be removed from the key vault using DELETE.KEY.
The security administrator can use the LIST.KEYS command to report the name, algorithm and
access rights of each encryption key in the key vault. There is no way to report the key string
associated with the key. This same command can be used with a filename to report the encryption
key names used by the file.
The actual encryption process uses the key string defined in the key vault. If a file that uses
encryption is moved to another system, the data in that file will be accessible if the encryption key
names used by the file are added to the new system's key vault with the same encryption algorithm
and key string.
The master key is used only to encrypt the key vault. The master key must be re-entered if the key
vault is moved to another system or possibly as a result of relicensing the system. This is an
automatic part of the QM licensing process and helps to ensure security if, for example, a backup
tape of the system is stolen. If the master key is forgotten, there is no way to retrieve it from the key
vault and hence the vault and all encrypted files would become inaccessible.
A file is created for record level encryption by use of the ENCRYPT keyword to the CREATE.
FILE command, specifying the name of the encryption key to be used.
For field level encryption, the developer creates the file, populates the dictionary and then uses the
ENCRYPT.FILE command to specify the names of each field to be encrypted and the name of the
key to be applied. If the file is not empty, the newly defined encryption is applied to the data. This
command can also be used to apply record level encryption to an existing file.
QM also provides optional protection that makes the data inaccessible even if the entire system is
stolen - a situation that is more likely with portable computers than with corporate servers. This
optional feature requires that the master key is entered every time that QM is started (not for each
user entry into the system). Whilst potentially inconvenient, this mode of operation gives the highest
level of security and is recommended for portable systems. The process of creating the master key
includes a prompt asking if it must be entered to unlock the key vault after system restart. When
this mode is enabled, any user with administrator rights can use the UNLOCK.KEY.VAULT
command to enable access to encrypted files. Until access is unlocked, files using either field or
record level encryption cannot be opened. The need for use of UNLOCK.KEY.VAULT can be
enabled or disabled at any time by using RESET.MASTER.KEY.
To allow files to be moved to systems where the encryption key name clashes with a name already
defined on that system, the SET.ENCRYPTION.KEY.NAME command can be used to update
2.11-0
184 OpenQM
When used with QMClient or QMNet, access to encrypted data is based on the access rights of the
user name under which the process connects to the server system. Because QMClient is a general
library that can be used in various programming environments, it is not possible to apply the
encryption at the client side. Although the data will be decrypted on the remote system (assuming
that the user has access to it), the actual network traffic of QMClient and QMNet uses its own
separate encryption.
ACCOUNT.SAVE, FILE.SAVE and T.DUMP operate within the security rules imposed by use
of QM's encryption features. Files that use record level encryption will not be saved if the user
performing the save does not have access to the encryption key. The data saved for files that use
field level encryption will have all fields for which the user is denied access set to null strings. All
saved data is recorded in decrypted form and hence storage of media created using these tools may
reduce system security. The media format is an industry standard that does not provide a way to
record details of data encryption. Restoring a save in which encrypted fields have been omitted is
unlikely to yield a usable file. Backup of accounts that include encrypted data should be performed
using operating system level tools.
2.11-0
The QM File System 185
3.16 Transactions
A transaction is a group of related database updates to be treated as a unit that must either happen
in its entirety or not at all. From a programmer's point of view, the updates are enclosed between
two QMBasic statements, BEGIN TRANSACTION and END TRANSACTION. All writes and
deletes appearing during the transaction are cached and only take place when the program executes
a COMMIT statement. The program can abort the transaction by executing a ROLLBACK
statement which causes all updates to be discarded.
Transactions affect the operation of file and record locks. Outside a transaction, locks are released
when a write or delete occurs. Transactional database updates are deferred until the transaction is
committed and all locks acquired inside the transaction are held until the commit or rollback.
Because of this change to the locking mechanism, converting an application to use transactions is
usually rather more complex than simply inserting the transaction control statements into existing
programs. The retention of locks can give rise to deadlock situations.
There are some restrictions on what a program may do inside a transaction. In general, QM tries
not to enforce prohibitive rules but leaves the application designer to consider the potential impact
of the operations embedded inside the transaction. Note carefully, that developers should try to
avoid user interactions (e.g. INPUT statements) inside a transaction as these can result in locks
being held for long periods if the user does not respond quickly.
Testing the value of the STATUS() function immediately after the END TRANSACTION
statement will return 0 if the transaction committed successfully, ER_COMMIT_FAIL if an error
occurred during the commit action, or ER_ROLLBACK if the transaction was rolled back.
Sometimes an application may open a file for which updates are not to be treated as part of any
transaction within which they occur. The OPEN and OPENPATH statements both have an option
to open the file in a non-transactional manner.
Example
BEGIN TRANSACTION
READU CUST1.REC FROM CUST.F, CUST1.ID ELSE ROLLBACK
CUST1.REC<C.BALANCE> -= TRANSFER.VALUE
WRITE CUST1.REC TO CUST.F, CUST1.ID
The above program fragment transfers money between two customer accounts. The updates are
only committed if the entire transaction is successful.
2.11-0
186 OpenQM
3.17 Replication
Data replication provides a mechanism whereby updates to selected files are automatically exported
to one or more other files, usually on a different system in order to provide resilience to hardware
failure. In normal usage, the intention is to maintain an identical copy of the original files, either so
that the second system can take over or for use as a reporting server. It is, however possible to use
the replication facility to copy data from disparate sources into a single file, perhaps merging data
from satellite offices into a single file at head office.
Basic Principles
The system that exports data is known as the publisher. The system receiving the data is known as
the subscriber. Normally this would be a simple relationship with just one publisher/subscriber
pair, however, QM imposes few restrictions on how replication is used.
Each published file may be exported to multiple subscribers. A subscriber system can publish these
files onwards to further subscribers, cascading data through a series of servers. The only rule is the
sequence of exports must not contain a loop where a file is replicated back to itself. There is an
exception to this rule as described below under "symmetrical replication".
QM does not prevent other updates to the replicated files on the subscriber system. Although use as
a standby system probably requires that updates are not allowed, some other uses of the replication
mechanism can require the ability to apply local updates. It is the application designer's
responsibility to ensure that appropriate rules are imposed.
Because QM is unaware of changes made to directory files from outside of QM, only hashed files
can be published. The subscriber systems, however, may import the data into any type of file.
The export is not instantaneous. The subscribers poll for updates at an interval that is configurable
in the range 1 to 300 seconds, defaulting to five seconds. At this default rate, the subscriber system
will be on average about three seconds behind the publisher though peak loads may increase this
time due to network delays. For a true hot standby where the application does not continue until the
update has been committed on the standby system, use QM triggers. The network delays associated
with this approach will have a substantial effect on application performance.
There are two configuration parameters related to replication on the publisher system, both of
which must be set to enable replication. The REPLDIR parameter specifies the directory where QM
will write the log files that contain data waiting for transfer to the subscribers. This directory will
be created automatically when QM is started if it does not exist. There will be a separate
subdirectory under this location for each subscriber. The REPLPORT parameter specifies the port
on which QM will listen for incoming connections from subscriber systems. This defaults to port
4244 which is the default used by the subscriber.
A file is published by use of the PUBLISH command by a user with administrator rights:
2.11-0
The QM File System 187
The PUBLISH.ACCOUNT command can be used to simplify publishing a large number of files
to the same target server/account.
PUBLISH.ACCOUNT server:account
This command will show a list of files in the current account that are not already published to the
specified target. Files in this list selected for export are then published.
From the point when the PUBLISH command is executed, all updates to the published files will be
logged in the directory specified by the REPLDIR parameter.
When using replication to create a standby system, it is essential that the target files correctly match
the corresponding files on the publisher system before enabling subscription. The easiest way to do
this is to copy the file at the operating system level while not in use and before setting it up for
publishing. Alternatively, copy the file using the QM COPY command after setting it up for
publishing. In the latter case, updates to the publisher system that occur during or after the copy
will be applied when subscription is enabled.
The REPLSRVR configuration parameter must be set to specify the name of the subscriber server.
This must match the server name used in the PUBLISH commands but does not need to be the
same as the network name of the subscriber system.
The SUBSCRIBE command is used by a user with administrator rights to apply updates from the
publisher to the subscriber. This command starts a phantom process that manages the actual data
transfer and is probably best initiated from a STARTUP configuration parameter.
SUBSCRIBE server{:port} username password {options}
The server element of this command may be the network name or ip address of the publisher. The
port number defaults to 4244 if omitted. The username and password must be valid for connection
to the publisher system. The password should preferably be encrypted using the AUTHKEY
command for security and specified with a prefix of ENCR: in the command. A server process
running as this user will be established on the publisher.
Transactions
Updates that were part of a transaction on the publisher will be applied to the subscriber as a group
but not strictly as a transaction. There should be no impact on the replication process or data
integrity.
Encryption
2.11-0
188 OpenQM
Data traffic between the publisher and the subscriber is encrypted though there is an option to
suppress this, perhaps when the data path is entirely within a secure network.
If files that use record or field level data encryption are published, the data is exported in encrypted
form and imported at the subscriber without change. The implication of this is that the target files
on the subscriber system must use the same encryption level and key strings as the source files. This
is a logical step if replication is not to weaken system security.Also, the username of the subscriber
phantom must have full access to all relevant encryption keys.
Because the SUBSCRIBE command writes data in the same way as any other QM process, indices
on the subscriber system will be maintained automatically. If an index is based on evaluation of a
subroutine called with the SUBR() function, the subroutine must be catalogued in a mode that
makes it accessible from the QMSYS account.
Triggers
Trigger functions are not applied on updates at the subscriber. Where triggers are used for data
validation on the publisher, the data does not require revalidation on the subscriber. Where triggers
are used to trigger other events on the publisher, any updates from these events to published files
will also be replicated.
Permissions
All QM users who may update exported files must have write access to the directory specified by
the REPLDIR parameter on the publisher system. The replication system will set the access rights
automatically as each new log file is created.
The username under which the subscription server process runs on the publisher must have read
access to all files that are to be published. Because encrypted data is transferred in encrypted form,
this user does not need to have access to encryption keys.
The username under which the SUBSCRIBE command runs on the subscriber system must have
full access to all subscribed files.
Cancelling Replication
Replication of a single file can be cancelled by using the CANCEL keyword of the PUBLISH
command. Replication of an entire account can be cancelled using the CANCEL keyword with
PUBLISH.ACCOUNT.
Failure Situations
Where replication is used to provide resilience, it is important to understand the failure situations
for which it provides protection and how to recover from them.
2.11-0
The QM File System 189
If the publisher system fails, the subscriber system can take over. Updates that are currently logged
on the publisher but have not been exported to the subscriber will not be present.
The recovery procedure depends on how the subscriber system has been used during the failure
period.
If no changes have been made to replicated files on the subscriber system, no action is necessary.
The subscriber system will periodically attempt to re-establish connection with the publisher and,
when this is successful, the pending updates will be applied.
If users have logged into the subscriber as a standby system and made updates to replicated files,
recovery requires a little work.
a) Terminate the subscriber process before restarting the publisher so that it does not attempt to
reconnect.
b) Consider whether any updates in the replication log files on the publisher are to be allowed to
be applied, possibly overwriting change made on the subscriber or whether they should be
discarded. If updates are to be discarded, login on the publisher when it is restarted, shutdown
any QM processes that may be accessing published files (e.g phantoms created using the
STARTUP configuration parameter), and delete the content of the relevant log file directory.
This is a subdirectory of the same name as the subscriber system under the directory identified
by the REPLDIR configuration parameter. Delete only the files, not the directory.
c) With no QM users logged in on the subscriber system, copy the relevant files back to the
publisher using the QM COPY command, not an operating system level copy.
If the subscriber system fails, the publisher will continue to run with updates queued in the
replication log files. When the subscriber comes back online, these updates will be applied
automatically.
Updates are queued in log files that are limited to approximately 10Mb, switching to a new log file
when this limit is reached. Log files are discarded when they have been completely processed. If the
subscriber fails (or the subscription process is not running), the publisher system will generate a
message in the error log file if the backlog of updates has three or more files (approximately 30Mb).
This message will be repeated at hourly intervals until the situation is resolved.
Network failure is essentially no different from subscriber failure except that the data is still
available for reporting purposes. Updates will restart automatically when the network connection is
restored.
Symmetrical Replication
2.11-0
190 OpenQM
Where replication is used in a simple one publisher / one subscriber configuration, symmetrical
replication can significantly simplify the failure and recovery process.
The two systems are configured to publish files to each other. Updates made on either system will
be replicated on the other but the replication process will not copy an update from the subscriber
back to the publisher from which it came, thus avoiding an endless cycle of updates between the
two systems.
If the primary publisher system fails, users login to the subscriber standby system and continue
work. Updates that they make will be logged for replication back to the primary system and will be
applied when it comes back online. The same considerations apply as described above regarding
updates that were logged on the primary system but did not get sent to the standby system
immediately prior to the failure.
On return of the primary system, users can be moved back at a convenient moment. No data files
need to be copied manually.
Whilst symmetrical replication provides a simple recovery strategy, it is very important to ensure
that updates are not made to the same records on both systems at the same time as there is no
locking between the two systems to control the sequence in which updates would get applied.
Disabling Publishing
If it is necessary to move the directory that stores replication log files to a new location, perhaps for
load balancing across disk drives, this can be accomplished simply by disabling publishing,
modifying the REPLDIR configuration parameter, moving the directory structure, and re-enabling
publishing.
2.11-0
Part
4
QM Commands
192 OpenQM
4 QM Commands
* Comment
$ECHO Paragraph tracing
! Synonym for SH
ABORT Abort processing and return to command prompt
ACCOUNT.RESTORE Restore a Pick style ACCOUNT-SAVE tape
ACCOUNT.SAVE Save an account to tape in Pick compatible format
ADD.DF Add an element to a distributed file
ADMIN Administrative command menu
ADMIN.SERVER Manage security rules for QMNet server connections
ADMIN.USER Username administration for network connections
ALIAS Create a temporary alias for a command
ANALYSE.FILE Analyse structure and usage of dynamic file
ANALYZE.FILE Synonym for ANALYSE.FILE
AUTHENTICATE Reduce privileges of a startup process
AUTHKEY Encrypt password for AUTHENTICATE
AUTOLOGOUT Set inactivity timer
BASIC Compile QMBasic programs
BELL Enable or disable audible alarm
BLOCK.PRINT Print text using large characters
BLOCK.TERM Display text using large characters
BREAK Enable, disable or query break key
BUILD.INDEX Build an alternate key index
CATALOG Synonym for CATALOGUE
CATALOGUE Add program to system catalogue
CD Synonym for COMPILE.DICT
CLEAN.ACCOUNT Remove records from $HOLD, $COMO and $SAVEDLISTS
CLEAR.ABORT Clear the abort status in an ON.ABORT paragraph
CLEAR.DATA Clear the data queue
CLEAR.FILE Remove all records from a file
CLEAR.INPUT Clear keyboard type-ahead
CLEAR.LOCKS Release task locks
CLEAR.PROMPTS Clear inline prompt responses
CLEAR.SELECT Clear one or all select lists
CLEAR.STACK Clear the command stack
CLEARDATA Synonym for CLEAR.DATA
CLEARINPUT Synonym for CLEAR.INPUT
CLEARPROMPTS Synonym for CLEAR.PROMPTS
CLEARSELECT Synonym for CLEAR.SELECT
CLR Clear display
CNAME Rename a file or record within a file
COMO Activate or deactivate command output files
COMPILE.DICT Compile I-types in a dictionary
CONFIG Display licence and configuration parameters
CONFIGURE.FILE Change file configuration parameters
COPY Copy records
COPY.LIST Copy a saved select list
COPY.LISTP Copy a saved select list using Pick style syntax
COPYP Copy records using Pick style syntax
COUNT Count records
CREATE.ACCOUNT Make a new QM account
2.11-0
QM Commands 193
2.11-0
194 OpenQM
2.11-0
QM Commands 195
2.11-0
196 OpenQM
2.11-0
QM Commands 197
4.1 * (Comment)
The * (comment) command allows comment text to be embedded in sentences and paragraphs.
Format
* {text}
A comment line has its first non-space character as an asterisk. There must be at least one space
separating the asterisk from any text. The comment is ignored except that any inline prompt
sequences within text will be executed. This enables prompts to be resolved in a convenient and
logical order ahead of the need to use the responses.
Although comments are mainly used within stored paragraphs, they may be entered at the keyboard
in response to the command prompt. The comment will be recorded in any active como file.
2.11-0
198 OpenQM
4.2 $ECHO
Format
$ECHO {ON}
$ECHO OFF
The $ECHO directive (optionally with a qualifier of ON) enables paragraph tracing. When this
mode is active, the command processor displays the paragraph name, line number and sentence for
each line executed.
$ECHO is not a command, but a control directive for the paragraph interpreter. Consequently it
cannot be entered at the command line and it cannot be executed from a QMBasic program.
$ECHO {ON} if not followed by $ECHO OFF in the same paragraph, turns on echo mode for all
subsequent paragraphs, whether or not they also contain $ECHO directives. If placed in the
LOGIN paragraph, it will turn on echo mode for all paragraphs throughout the account. This can
be done selectively by, for example, testing the login name of the user. In this way, echo mode can
be limited to developers who need it for debugging purposes.
This fragment of paragraph logic turns echo on for user TESTER only. A developer who has a need
to see paragraph commands echoed will log in with that user name. All other users will see
paragraphs acting as usual.
Example
The following paragraph might be used to delete all items in the BP.OUT file for which there is no
corresponding source record in the BP file.
VOC CLEAN.BP
1: PA
2: $ECHO
3: SELECT BP.OUT
4: NSELECT BP
5: IF @SELECTED = 0 THEN STOP
6: DELETE BP.OUT
7: DATA Y
Running this with the $ECHO on line 2 shows are trace of each command prior to execution:
:CLEAN.BP
CLEAN.BP 3: SELECT BP.OUT
223 record(s) selected to list 0
CLEAN.BP 4: NSELECT BP
2.11-0
QM Commands 199
2.11-0
200 OpenQM
4.3 ABORT
The ABORT command terminates all active processing and returns to the command prompt.
Format
ABORT{text}
where
The ABORT command is intended for use where a paragraph detects an application fault and
needs to terminate all active processing. All active commands, sentences, paragraphs, menus, etc
are discarded. Unless the command was run using the QMBasic EXECUTE statement with the
TRAPPING ABORTS option, just before return to the command prompt, QM checks for an
executable item (usually a paragraph) in the VOC named ON.ABORT and, if this is found, runs it.
The ON.ABORT paragraph may examine the @ABORT.CODE variable to determine why it was
invoked. The ABORT command sets this variable to 1. The text, if present, will be stored in
@ABORT.MESSAGE
See also:
CLEAR.ABORT, STOP
2.11-0
QM Commands 201
4.4 ACCOUNT.RESTORE
Format
ACCOUNT.RESTORE {options}
where
The ACCOUNT.RESTORE command processes a Pick style "compatible mode" tape or pseudo
tape and restores data from it into a QM system.
The tape to be restored must first be opened to the process using the SET.DEVICE command.
Items in the save that originated in the MD file are restored to a file named MD-RESTORE from
where the user can then determine which are relevant to QM and require transfer to the VOC file.
Similarly, if a save includes a VOC file, this will be restored to VOC-RESTORE.
Note that restoring a file from a different database product may take considerably longer than
restoring the same save on the other product because the file hashing order will be different and the
data will not appear in group by group order.
The format of ACCOUNT.SAVE tapes varies between multivalue products. A Pick style
"compatible mode" (R83 format) tape commences with
Label
EOF block
Label
Descriptor block
EOF block
2.11-0
202 OpenQM
Label
Data.....
ACCOUNT.RESTORE therefore normally starts by skipping forwards to the third label block.
On some systems, the tape commences simply with a label block followed immediately by the data.
To allow for the possibility of this and other formats, the T.RDLBL and T.READ commands can
be used to position the tape before the first data block. Use of the POSITIONED option in
ACCOUNT.RESTORE will then omit all other positioning from within ACCOUNT.RESTORE
itself.
ACCOUNT.RESTORE reads the account name and other information from the label it finds on
the tape. This account name is then offered as the default account name in a confirmation dialog. If
the name supplied in this dialog exists in the accounts register, the tape is restored into that account.
If the account name supplied is not found in the accounts register, ACCOUNT.RESTORE
prompts for a system pathname to be used as the path to the account. Therefore one can restore a
backup of an existing account by issuing an ACCOUNT.RESTORE command and then supplying
a different name for the account. Any required items can then be copied into another account via a
Q-pointer.
See also:
ACCOUNT.SAVE, FILE.SAVE, FIND.ACCOUNT, RESTORE.ACCOUNTS,
SEL.RESTORE, SET.DEVICE, T.ATT, T.DUMP, T.LOAD, T.xxx
2.11-0
QM Commands 203
4.5 ACCOUNT.SAVE
Format
where
account.name is the name of the account to be saved. If omitted, the command prompts for
the account name.
The ACCOUNT.SAVE command creates a Pick style "compatible mode" pseudo tape and saves a
QM account to it. The account transfer tools are intended for use when migrating to QM from other
systems. Although it would be possible to use this command to create a backup of a QM account, it
is recommended that operating system level tools are used for this purpose.
The tape to be created must first be opened to the process using the SET.DEVICE command.
The command reports its progress by displaying the name of each file as it is saved unless the
DET.SUP option is used.
ACCOUNT.SAVE normally saves all files referenced by F-type records in the VOC of the
account being saved. There is a three level mechanism by which files can be excluded:
2. If field 5 of the VOC record does not specify any of the above flags, the
EXCLUDE.REMOTE and INCLUDE.REMOTE options are used to determine whether
remote files (those with a directory delimiter in their pathnames) are to be saved.
3. If neither of the above methods of file selection is used, the value of the EXCLREM
configuration parameter is used to determine whether remote files are to be saved.
2.11-0
204 OpenQM
By use of a combination of the above methods, it should be possible to achieve total control of what
is included in a save.
Encryption
ACCOUNT.SAVE operates within the security rules imposed by use of QM's encryption features.
Files that use record level encryption will not be saved if the user performing the save does not have
access to the encryption key. The data saved for files that use field level encryption will have all
fields for which the user is denied access set to null strings. All saved data is recorded in decrypted
form and hence storage of ACCOUNT.SAVE media may reduce system security. The media
format used by ACCOUNT.SAVE is an industry standard that does not provide a way to record
details of data encryption. Restoring a save in which encrypted fields have been omitted is unlikely
to yield a usable file. Backup of accounts that include encrypted data should be performed using
operating system level tools.
See also:
ACCOUNT.RESTORE, FILE.SAVE, FIND.ACCOUNT, RESTORE.ACCOUNTS,
SEL.RESTORE, SET.DEVICE, T.ATT, T.DUMP, T.LOAD, T.xxx
2.11-0
QM Commands 205
4.6 ADD.DF
Format
where
First use of the ADD.DF command will create the distributed file, compiling the partitioning
algorithm and adding the named part file. The newly created distributed file will share the dictionary
of the first part file. Subsequent use of the ADD.DF command will add further part files. The
algorithm need not be specified for the second and subsequent parts and will be ignored if present.
When creating a new distributed file, the dictionary reference in the VOC F-pointer created to
define this file is copied from the VOC entry for part.file.
Note that the partitioning algorithm is copied into the distributed file. Changing the expression in
the dictionary will not have any effect. It will be necessary to reconstruct the distributed file.
Example
This pair of commands creates a distributed file named ORDERS that consists of two parts,
ORDERS-08 and ORDERS-09, perhaps corresponding to orders taken in a specific year. The part
numbers are 8 and 9 respectively. The partitioning algorithm is named PART.ALG in the dictionary
of ORDERS-08.
See also:
Distributed files, LIST.DF, REMOVE.DF
2.11-0
206 OpenQM
4.7 ADMIN
Format
ADMIN
The ADMIN command is a multi-level menu of administrative commands. The structure of this
menu and the commands associated with each entry are shown below.
Configuration
Configuration Parameters EDIT.CONFIG
Security Settings SECURITY
Update Licence UPDATE.LICENCE
Accounts
List Accounts LIST QM.ACCOUNTS
Create Account CREATE.ACCOUNT
Delete Account DELETE.ACCOUNT
User Management
List Registered Users LIST.USERS
User Administration ADMIN.USER
System Monitor
Process Management
List Logged-in QM Processes LISTU
Phantom Processes STATUS ALL
Process Status PSTAT
Logout Process LOGOUT
Send Message MESSAGE
Lock Management
List Task Locks LIST.LOCKS
List File and Record Locks LIST.READU
Clear Task Lock UNLOCK TASKLOCK
Clear File Lock UNLOCK FILELOCK
Clear Record Lock UNLOCK
Error Logging SP.VIEW QMSYS errlog
File System
QMNet
List Servers LIST.SERVERS
Create New Server Definition CREATE.SERVER
Server Security Administration ADMIN.SERVER
Delete Server Definition DELETE.SERVER
Performance and Statistics
2.11-0
QM Commands 207
2.11-0
208 OpenQM
4.8 ADMIN.SERVER
The ADMIN.SERVER command allows a system administrator to set security rules on QMNet
public server definitions
Format
ADMIN.SERVER {name}
The default behaviour of the SET.SERVER command is to create a server definition that may be
accessed by all users of the system. There is a potential security weakness here because the slave
process started on the remote system to handle the QMNet connection runs as the user name
specified in the server definition, regardless of the user name of the local user accessing the remote
file. Security can be improved by arranging that the user name used for the remote slave process is
dependent on the user name or user group of the local user. This can be achieved by use of the
ADMIN.SERVER command.
SALES 193.118.14.97
F1=Help
Enter remote user name
The display consists of a series of four line entries with a horizontal separator. Each entry identifies
the remote user name that will be used for the QMNet slave process based on criteria related to the
local user accessing the QMNet file. When creating a QMNet connection, the list is scanned from
the top downwards looking for the first entry that is applicable to the user.
Remote user The user name to be used for the slave process. Changing this name will also
prompt for the associated password.
Local users A comma separated list of user names on the local system who will connect as
the associated remote user name. Specifying this field as ALL, allows
connection by all users.
2.11-0
QM Commands 209
O/S groups A comma separated list of operating system user group names. If the user is a
member of a named group, access is granted with the associated remote user
name. This field is ignored on Windows.
QM groups A comma separated list of QM user group names as set with ADMIN.USER.
If the user is a member of a named group, access is granted with the associated
remote user name.
In the above example, users logged in to the local system as gsmith or dave will connect to the
remote server with user name george. Users who are members of either the operating system user
group named admin or the QM user group of the same name will connect as user name root. All
other users will connect as user name sales.
If the local user does not meet the conditions set by any entry in the list, connection to the server is
not permitted. If a user fits the conditions for more than one entry in the list, the first one found
applies.
The default action of the SET.SERVER command is to create a server definition in which the
remote user is as specified in the command and the local users field is set to ALL.
To move through the entries in the displayed list, use any of the following keys:
The amend a line, simply type new data or use any of the standard editing keys:
Ctrl-A Home Position the cursor at the start of the input data
Ctrl-B Cursor left Move the cursor left one character
Ctrl-D Delete Delete character under cursor
Ctrl-E End Position the cursor at the end of the input data
Ctrl-F Cursor right Move the cursor right one character
Ctrl-H Backspace Backspace one character
Ctrl-K Delete all characters after the cursor
Insert Toggle insert/overlay mode. When overlay mode is enabled, data
entered by the user replaces the character under the cursor rather
than being inserted before this character.
F1 Display help text
F2 Move current entry up by one place
F3 Move current entry down by one place
F4 Import security settings from another server. A prompt box
appears asking for the server name. Entry of a blank response
aborts the action.
2.11-0
210 OpenQM
To insert a new entry, navigate to the bottom of the list and type in new data. The entry can be
moved up if necessary with the F2 key.
To terminate the edit, optionally saving changes, press the Esc key.
See also:
QMNet, DELETE.SERVER, LIST.SERVERS, SET.SERVER
2.11-0
QM Commands 211
4.9 ADMIN.USER
The ADMIN.USER command allows management of the register of user names for network
connections.
Format
ADMIN.USER
The ADMIN.USER command is built around a form filling interface. Initially it displays a request
for a new or existing user name. The F2 key will display a pick list of registered users. Entering a
blank user name exits from the command.
Selection of an existing user displays their details for possible amendment. Entry of a new user
name displays an empty form into which the user's details may be entered.
An entry named DEFAULT (case sensitive) may be created. This will be used by the security
system to determine the rights of any user for whom there is no separate entry in the register.
2.11-0
212 OpenQM
command), any user not appearing in the user register will be able to
perform any of the actions controlled by the above options.
Valid accounts A comma separated list of accounts that the user is allowed to access. If
the "All except those listed below" option is selected, this list is accounts
that the user may not access. In either case, if the list is empty, no
restrictions are imposed.
Action Enter A to amend, F to file changes, D to delete this user or X to exit
without saving any changes.
See also:
CREATE.USER, DELETE.USER, LIST.USERS, PASSWORD, SECURITY, Application
Level Security
2.11-0
QM Commands 213
4.10 ALIAS
Format
where
The ALIAS command creates an alternative name by which a command can be referenced such
that command becomes a synonym for target. It provides a simple mechanism by which standard
commands can be linked to alternative VOC entries as a means of providing improved compatibility
with other multivalue database products. For example, the COPY command could be linked to the
Pick style variant named COPYP by executing
ALIAS COPY COPYP
This change affects only the current process and does not modify the VOC. Typically, ALIAS
commands would be executed from the LOGIN paragraph.
The second form of the ALIAS command removes a previously defined alias for command.
2.11-0
214 OpenQM
4.11 ANALYSE.FILE
The ANALYSE.FILE command (which may be entered using the American spelling) reports
information regarding the structure and efficiency of a dynamic file. It can also be used to produce a
simplified report of a directory file.
Format
where
file.name is the name of the file to be processed. The optional DICT prefix indicates that the
dictionary portion of the file is to be used.
Account : C:\QMSYS
File name : MESSAGES
Path name : C:\QMSYS\MESSAGES
2.11-0
QM Commands 215
See also:
FILE.STAT
2.11-0
216 OpenQM
4.12 AUTHENTICATE
Format
where
A QM process started via the STARTUP configuration parameter without specifying a user name
runs as SYSTEM on Windows and root on other operating systems. These users have very high
levels of privilege that are probably inappropriate to the QM process. The AUTHENTICATE
command allows a process running as one of these users to revise its level of access to that
associated with some other user known to the operating system.
Typically, the STARTUP configuration parameter is used to run a paragraph in the VOC of the
QMSYS account. This might contain, for example,
1: PA
2: LOGTO SALES
3: PHANTOM RUN MONITOR
4: PHANTOM RUN WEB.SERVER
The phantom processes created by this example would run as SYSTEM or root. Inserting
AUTHENTICATE username password
as the first command in the paragraph would cause the phantoms to run as the specified user.
Alternatively, each phantom could contain its own use of AUTHENTICATE to become a different
user.
The AUTHENTICATE command can only be used by SYSTEM and root. Restrictions imposed
by the operating system mean that it is not possible for a user process running under any other user
name to change its access privileges.
In the above example, the user's password has been stored in the paragraph as clear text which may
reduce system security. It would be possible to adapt this example to retrieve the password from an
encrypted file where access to the encryption key is restricted. Alternatively, the
AUTHENTICATE command supports direct use of an encrypted password on the command line.
To use this, the password element of the command is replaced by the encrypted password prefixed
with ENCR: (case insensitive). The encrypted form of the password is derived using the
AUTHKEY command in the QMSYS account as described below.
The AUTHKEY command is available only in the QMSYS account and is restricted to users
registered as administrators. The format of this command is
AUTHKEY password
2.11-0
QM Commands 217
The password should be enclosed in quotes if it contains spaces. The encrypted password value is
displayed on the user's screen and can be transferred easily into the AUTHENTICATE command
using cut and paste in the terminal emulator. The encrypted password is further transformed into a
hexadecimal encoded form to ensure that non-graphic characters cannot cause problems.
The STARTUP configuration parameter also has an extended form that includes the account name,
user name and password. In this case, the password may be encrypted using AUTHKEY in the
same way as for AUTHENTICATE and inserted into the STARTUP parameter with a ENCR:
prefix.
Example
2.11-0
218 OpenQM
4.13 AUTOLOGOUT
The AUTOLOGOUT command sets an inactivity period after which a process will automatically
be logged out.
Format
AUTOLOGOUT {period}
where
period is the inactivity time in minutes. A value of zero disables the timer.
The AUTOLOGOUT command prevents users leaving inactive sessions logged in. If the process
is waiting for input for the given time, it will automatically be logged out. The ON.EXIT paragraph
will be executed if it exists.
Executing the AUTOLOGOUT command with no period option displays the current setting.
Example
AUTOLOGOUT
Autologout is disabled
AUTOLOGOUT 4
AUTOLOGOUT
Autologout period is set to 4 minute(s)
...wait...
Inactivity time expired - Process logged out
Process terminated
In this example, the AUTOLOGOUT command is used to examine the current setting. The
inactivity period is then set to four minutes and the setting displayed again. After four minutes of
inactivity, the process is automatically logged out.
2.11-0
QM Commands 219
4.14 BASIC
Format
where
file.name is the name of the directory file holding the QMBasic source program. If
omitted, the filename defaults to BP.
record.name is the name of the record within the file. Multiple record names may be
specified. An asterisk as the only record.name compiles all programs in
the file. If no names are specified and the default select list is active, the
list will be used to specify the programs to be compiled.
When using a select list or an asterisk to compile all programs, the default action of the BASIC
command is to ignore records with a .H or .SCR suffix. This omits include records that use the
conventional .H suffix (header files) or .SCR suffix (screen definitions). The $BASIC.IGNORE
record described below allows developers to change the rules of which, if any, records are skipped
when using a select list.
Unless the KEEP.OLD.OBJECT mode of the OPTION command is active, any old version of the
object code is deleted before the compilation commences. This ensures that developers who
accidentally miss a compiler error message will not continue testing with the previous version in the
incorrect belief that it is the new version.
CHANGED Compile only if the program is not already in the output file or the date and
time of modification of the source program record as given in the operating
system directory entry is later than that of the compiled program. Used in
conjunction with a select list it enables all modified programs to be
compiled with a single command.
NO.QUERY Suppresses any queries that the compiler may generate such as
replacement of a catalogued item, taking the default action.
2.11-0
220 OpenQM
NOXREF Omit cross reference tables from compiled program. This results in lower
memory usage but run time error messages cannot identify source line
numbers or variable names.
XREF Generates a compiler listing record as for the LISTING option but
includes a cross-reference table of all variables and their use. A line
number in the cross-reference data will be followed by S on lines where the
variable is set and A if it is used as a subroutine or function argument.
The compiler output file, named as the source file but with a .OUT suffix, will be created
automatically if it does not already exist.
Compiling a program signals an event to all QM processes to reload the object code. See the
QMBasic CALL statement for full details.
Compiler options that you wish to use every time you run the QMBasic compiler can be placed in
an X-type VOC record named $BASIC.OPTIONS. To apply these defaults only to programs stored
in a specific file, place the $BASIC.OPTIONS record in that file. The compiler looks first in the
source file and then, if no record has been found, in the VOC.
The first line of the record holds the type code X. The second and subsequent lines of this record
should contain compiler option keywords from the list below. The keywords allowed are:
CATALOGUE {LOCAL | GLOBAL} Automatically catalogues programs after
compilation using the program name as the
catalogue name. The LOCAL and GLOBAL
keywords may be used to specify that the program
is to be catalogued in the given mode instead of in
the private catalogue. The $NO.CATALOGUE
compiler directive can be used in specific program
modules to override this action. Alternatively, the
$CATALOGUE compiler directive in a program
can set an alternative catalogue name or mode.
DEBUGGING Compiles the program in debug mode.
DEFINE name {value} Defines token name in the same way as the
$DEFINE compiler directive. The value may be
a number or a quoted string. If omitted, the token
is assigned a null string as its value.
LISTING Generates a listing record in the compiler output
file.
MODE option.name Sets the given compilation mode as described for
the $MODE compiler directive. Multiple MODE
lines must be used to set more than one option.
NOCASE.STRINGS Compiles the program with case insensitive string
2.11-0
QM Commands 221
The default action of the BASIC command when using a select list or an asterisk to compile all
programs is to ignore source records with a suffix of .H or .SCR. The $BASIC.IGNORE record
allows developers to set their own rules controlling which, if any, records will be ignored. As with
the $BASIC.OPTIONS record, the $BASIC.IGNORE record may be in the VOC or in the program
file.
The first line of the record holds the type code X. The second and subsequent lines of this record
contain pattern matching templates that are applied in turn to the source record id. If any of the
templates match the source record id, the record is ignored. The default action of the BASIC
command is equivalent to having a $BASIC.IGNORE record that contains:
1: X
2: ...'.H'
3: ...'.SCR'
Any record with an id that does not match any of the templates will be compiled. To compile all
records, regardless of their name, create a $BASIC.IGNORE record that contains just the type
code:
1: X
Examples
This command compiles the program in record PROG1 of the PROGRAMS file. A listing record is
produced.
SELECT BP
BASIC CHANGED
This sequence of commands compiles all programs in the BP file which have been updated since
2.11-0
222 OpenQM
they were last compiled. Note that the compiler will omit all records with names ending with .H or
.SCR, the two standard suffix codes for include records.
See also:
CATALOGUE, DELETE.CATALOGUE, MAP
2.11-0
QM Commands 223
4.15 BELL
The BELL command determines whether the audible alarm is sounded by various QM verbs
(typically on encountering error conditions) or by QMBasic programs using the @SYS.BELL
function in a print operation directed to the terminal.
Format
@SYSTEM.RETURN.CODE is returned as
0 after BELL OFF
1 after BELL ON
-ve after an error
Printing CHAR(7) to the terminal sounds the audible alarm regardless of the setting of the bell
status.
2.11-0
224 OpenQM
The BLOCK.PRINT command prints text on the default printer using large characters. The
BLOCK.TERM is similar but directs its output to the terminal
Format
BLOCK.PRINT text
BLOCK.TERM text
where
The BLOCK.PRINT and BLOCK.TERM commands print text using a large font constructed
from a 7 x 7 matrix of characters. On an 80 character printer or terminal, a maximum of 8
characters will fit on a line. The command will wrap long text across multiple lines, breaking on
spaces where possible.
2.11-0
QM Commands 225
4.17 BREAK
The BREAK command controls the action taken on use of the break key. It can be used, for
example, the suppress quits during critical parts of an application.
Format
BREAK ON USER n To enable the break key for the specified user
QM maintains a count of the number of times that breaks are disabled. Each BREAK OFF
command increments this count. The BREAK ON command decrements the count unless it is
already zero. The BREAK COUNT command reports the current value of the break inhibit
counter.
If the break key is pressed whilst breaks are suppressed, the break is deferred until the count returns
to zero by a subsequent use of BREAK ON. The normal action prompt will then appear. The
BREAK CLEAR statement cancels any deferred break event.
For all of the above forms, @SYSTEM.RETURN.CODE is returned as the current value of the
break inhibit counter unless an error occurs, in which case it is set to a negative error code.
The final form, BREAK ON USER n, is only available to users registered as administrators and
enables the break key for the specified user. @SYSTEM.RETURN.CODE is returned as zero
unless an error occurs, in which case it is set to a negative error code.
See also:
BREAK (QMBasic), SET.BREAK.HANDLER, REMOVE.BREAK.HANDLER
2.11-0
226 OpenQM
4.18 BUILD.INDEX
Format
where
filename is the name of the file for which the index is to be built.
field(s) is one or more field names for which indices have been created.
The BUILD.INDEX command deletes any existing index data for the named field(s) and populates
the index by processing all records currently in the file. The ALL keyword can be used to build all
indices that have been created for the file.
Except when used with the CONCURRENT keyword, the BUILD.INDEX command requires
exclusive access to the file and may take some time to complete for a very large file. It is therefore
best executed at quiet times.
The CONCURRENT keyword allows an index to be built while the file is in use. There is a
performance overhead for this and the QMBasic SELECTINDEX, SELECTLEFT and
SELECTRIGHT statements may stall waiting for the build to complete.
See also:
CREATE.INDEX, DELETE.INDEX, DISABLE.INDEX, LIST.INDEX, MAKE.INDEX,
REBUILD.ALL.INDICES
2.11-0
QM Commands 227
4.19 CATALOGUE
The CATALOGUE command (which may be entered with the American spelling for compatibility
with other products) adds a compiled QMBasic program to the global or private catalogue file or as
a locally catalogued entry in the VOC.
Format
where
file.name is the name of the directory file holding the program. If omitted, this
defaults to BP, the .OUT suffix being added automatically.
record.name is the name of the record within the specified file. The record.name
may be specified as an asterisk to catalogue all programs in file.name.
If record.name is omitted and the default select list is active, this list
will be used to determine the programs to be catalogued.
account.
The CATALOGUE command makes a program or subroutine available for access via the
QMBasic CALL statement. Catalogued programs can also be executed as command simply by
entering their name at the command prompt or within a stored sentence or paragraph.
Compiling a program signals an event to all QM processes to reload the object code. See the
QMBasic CALL statement for full details.
Private Cataloguing
Without either the LOCAL or GLOBAL keyword, the program is copied to the private catalogue
in the account from which the command is executed and is available only to users of that account.
Recompiling the program requires that the program is recatalogued so that the new version is
copied to the catalogue directory. A failed compilation, where no object code has been produced,
will not impact users of the previously catalogued version.
The private catalogue is normally a subdirectory, cat, under the account directory but can be moved
by creating an X-type VOC entry named $PRIVATE.CATALOGUE in which field 2 contains the
pathname of the alternative private catalogue directory. This only takes effect when QM is
re-entered or on use of the LOGTO command. This feature is particularly useful where two or
more accounts are to share a common private catalogue. The US spelling, $PRIVATE.CATALOG,
may be used instead. If both are present, the British spelling takes priority.
Global Cataloguing
With the GLOBAL keyword, the program is copied to the global catalogue file in the QMSYS
directory and is available from all accounts. Global cataloguing is also implied by adding one of the
following prefix characters to the catalogue.name of the program:
Use of a prefix character has the disadvantage that the prefix must also be included in calls to the
subroutine as it becomes part of the subroutine name.
Recompiling the program requires that the program is recatalogued so that the new version is
copied to the catalogue directory. A failed compilation, where no object code has been produced,
will not impact users of the previously catalogued version.
Local Cataloguing
With the LOCAL keyword, an entry is written to the VOC file allowing calls only from the account
in which the program is catalogued. This is useful during testing or for functions that are not called
frequently. The first call to programs catalogued in this way are slower than to private or globally
catalogued programs. Once the program has been loaded into memory, speed will be identical.
2.11-0
QM Commands 229
The VOC entry for a locally catalogued program is of type V (verb) and has a dispatch field of CS.
The third field holds the full pathname of the executable program. When QM is installed on a USB
memory device, the pathname will be transformed internally to a format that allows for the drive
letter to be different when the stick is loaded in future. Use of the RELATIVE option to the
CATALOGUE command stores a relative pathname so long as the program is in a subdirectory of
the account directory.
If a locally catalogued program that has a security subroutine defined in its VOC entry is
recatalogued, the security subroutine name is carried forward to the new VOC entry.
Recompiling the program does not require the program to be recatalogued as the VOC pointer will
still be in place. A failed compilation, where no object code has been produced, may cause other
processes to fail.
See also:
BASIC, DELETE.CATALOGUE, FIND.PROGRAM, MAP
2.11-0
230 OpenQM
4.20 CLEAN.ACCOUNT
The CLEAN.ACCOUNT command clears the $HOLD, $COMO and $SAVEDLISTS files.
Format
CLEAN.ACCOUNT
The CLEAN.ACCOUNT command is used to remove records from the $HOLD, $COMO and
$SAVEDLISTS files. Periodic use of this command will ensure that redundant records are not left
in these files. A file cannot be cleaned if there are locks held on records in the file.
2.11-0
QM Commands 231
4.21 CLEAR.ABORT
Format
CLEAR.ABORT
When an application generates an abort event, QM discards all programs, paragraphs, menus, etc
running in the process and returns to the command processor. Before displaying the command
prompt, the system checks for an ON.ABORT item in the VOC (usually a paragraph) and, if found,
executes it.
The ON.ABORT paragraph is intended as a means of preventing a user ever arriving at the
command prompt if the application fails. Typically, the ON.ABORT paragraph simply terminates
the session but it might log the event or perform other processing. If the processing in the
ON.ABORT paragraph causes a further abort, the session is terminated.
Sometimes, it may be useful to restart the application from the ON.ABORT paragraph. In this case,
a further abort should probably re-enter the ON.ABORT paragraph. The normal action of
automatic termination of the session on the second abort can be suppressed by clearing the abort
status in the ON.ABORT paragraph. It then becomes the developer's responsibility to avoid endless
loops if the ON.ABORT action generates a further abort.
See also:
ABORT command, QMBasic ABORT statement
2.11-0
232 OpenQM
4.22 CLEAR.DATA
The CLEAR.DATA command (synonym CLEARDATA) clears the data queue created by the
DATA command or the QMBasic DATA statement.
Format
CLEAR.DATA
The data queue is cleared automatically on return to the command prompt. The CLEAR.DATA
command allows the queue to be cleared within a paragraph, for example, when recovering from
premature termination of a program that uses the data queue.
Example
PA
RUN ARCHIVE.PREVIOUS.YEAR
DATA Y
SELECT ORDERS WITH DATE BEFORE "1 JAN <<@YEAR>>"
DELETE ORDERS
The above paragraph might be used to archive old order data at the start of a new business year and
then delete the old records from the ORDERS file. The archive program asks the user if a report is
to be printed and the DATA statement is used to provide the answer to this question from within the
paragraph. Because it is using a select list, the DELETE command will prompt the user for
confirmation before deleting the selected records.
If the archive program fails before asking whether a report is required, the "Y" in the data queue
will not be read by this program and will still be in the queue when the DELETE command is
executed. It will therefore be used erroneously to answer the delete confirmation prompt.
This situation can be avoided by inserting a CLEAR.DATA statement before the SELECT. In
general, it is good practice to insert a CLEAR.DATA after any command that uses DATA and
could terminate without reading the queued data. This action is not automatic because the data
queue is frequently used to pass data from one program to another.
See also:
CLEAR.INPUT, CLEARDATA QMBasic statement
2.11-0
QM Commands 233
4.23 CLEAR.FILE
Format
If neither the DATA keyword nor the DICT keyword is not specified, only the data portion of the
file is cleared.
If the DICT keyword is specified, only the dictionary portion of the file is cleared.
In the case of a dynamic file, the file returns to its minimum modulus and all overflow space is
released.
2.11-0
234 OpenQM
4.24 CLEAR.INPUT
Format
CLEAR.INPUT
The CLEAR.INPUT command clears all keyboard type-ahead. It may be useful, for example, after
a program terminates at an error to ensure that unprocessed keyboard data is not treated as input to
the next program.
See also:
CLEAR.DATA
2.11-0
QM Commands 235
4.25 CLEAR.LOCKS
Format
CLEAR.LOCKS {lock.number}
where
lock.number is the number of the task lock (0 to 63) to be released. If omitted, all task
locks held by the process are released.
Examples
CLEAR.LOCKS 5
Released task lock 5
This example shows the CLEAR.LOCKS command used to release a specific task lock.
CLEAR.LOCKS
All task locks released
See also:
LIST.LOCKS, LOCK (command), LOCK (QMBasic), TESTLOCK(), UNLOCK
2.11-0
236 OpenQM
4.26 CLEAR.PROMPTS
Format
CLEAR.PROMPTS
Inline prompt responses are cleared automatically on return to the command prompt. The
CLEAR.PROMPTS command allows responses to be cleared within a paragraph should this be
necessary for correct processing of later inline prompts.
See also:
Inline prompts
2.11-0
QM Commands 237
4.27 CLEAR.SELECT
Format
2.11-0
238 OpenQM
4.28 CLEAR.STACK
Format
CLEAR.STACK
The CLEAR.STACK command removes all entries from the current command stack.
See also:
GET.STACK, SAVE.STACK
2.11-0
QM Commands 239
4.29 CLR
Format
CLR
2.11-0
240 OpenQM
4.30 CNAME
The CNAME command (synonym RENAME) changes the name of a file or record(s) within a file.
Format
where
old.file.name is the current name of the file to be renamed.
new.file.name is the new name of the file to be renamed.
or
where
file.name is the name of the file containing the record(s) to be renamed. The optional
DICT prefix specifies that the dictionary portion of the file is to be
processed.
old.record.id is the current name of the record to be renamed.
new.record.id is the new name for the renamed record.
Used with two file names, the CNAME command renames old.file.name to new.file.name. The
VOC record defining the file is renamed. The underlying operating system directories representing
the data file and the dictionary are also renamed if they are the default names and the new names
are acceptable operating system directory names. Where the directory names are not the defaults, as
would be the case for a file created with the PATHNAME option of the CREATE.FILE
command, the directory can be renamed separately using operating system commands but the VOC
entry must be manually edited to match this change.
Used with a single file name and two record names, the CNAME command renames a record
within the file. In this format, multiple records may be renamed in a single command by repeating
the old.record.id TO new.record.id component of the command.
The command
CNAME VOC OLD.NAME TO NEW.NAME
is equivalent to
CNAME OLD.NAME TO NEW.NAME
except that the directory will not be renamed at the operating system level.
2.11-0
QM Commands 241
Examples
This command renames the STOCK file to INVENTORY. The VOC record defining the file is
renamed. The underlying operating system directories representing the data file and the dictionary
are also renamed if they are the default names and the new names are acceptable operating system
directory names.
This command renames two data records within the STOCK file.
2.11-0
242 OpenQM
4.31 COMO
The COMO command controls recording of terminal output in a como (command output) file.
Format
When enabled, all output that is directed to the user's terminal by the process in which the COMO
command is executed is also written to the named record in the como file.
The COMO command is mainly intended as a diagnostic aid during application development but
can be used as a general logging mechanism. It can be used, for example, to look back at an error
message that was overwritten on the screen before the user had time to read it.
Como records are stored in a file named $COMO. This is created automatically when the COMO
ON command is first used. The default pathname of $COMO under the account directory can be
changed by creating the file in an alternative place. The file used for storing como data must be a
directory file. If record.name is not valid as an operating system file name, it will be transformed to
a valid name in the same way as any other directory file record id.
The APPENDING keyword allows data to be appended to an existing como record. If there is no
record with the given name, a new record is created.
The COMO SUSPEND command increments a counter that inhibits logging of output data. The
corresponding COMO RESUME command decrements the counter. Output is logged only when
the counter is zero. The action of these commands cannot take the counter out of the range 0 to 100.
By maintaining a counter instead of a simple on/off toggle, it is possible for stacked operations to
manipulate the inhibit mechanism correctly.
Except when started with the NO.LOG option, a phantom process behaves as though it started with
a COMO ON command, logging all output that would have been sent to the terminal if the same
commands had been executed by a foreground process. For more details, see the PHANTOM
command.
Example
COMO ON LOG
RUN END.OF.YEAR
COMO OFF
SPOOL $COMO END.OF.YEAR
2.11-0
QM Commands 243
The above command sequence turns on command output logging using a record named LOG, runs
an end of year processing program, turns off logging and then sends this log file to the default
printer (print unit 0).
2.11-0
244 OpenQM
4.32 COMPILE.DICT
The COMPILE.DICT command (synonym CD) is used to compile A, C, I and S-type records in
dictionaries.
Format
where
name is the name of the record to be compiled. Multiple names may be given in a
single use of the command. If omitted, all A, C, I and S-type records in the
dictionary are compiled unless the default select list is active, in which case
that list is used.
The COMPILE.DICT ALL and COMPILE LOCAL formats provide an easy way to compile all
items in multiple files. The ALL keyword processes the dictionaries of all files referenced by F-type
VOC entries. The LOCAL keyword restricts this to files that do not have a directory separator in
the dictionary pathname.
A, C, I and S-type records may also be compiled using MODIFY and are automatically compiled
by all query processor commands if necessary.
The main need for the COMPILE.DICT command is where the expression in one dictionary item
uses the value of another. Because nested expressions are handled by a compile time substitution
rather than a run time call, a change to the second expression requires the dictionary item that uses
it to be recompiled. The automatic compilation performed by the query processor will not detect this
need. In general, it is recommended that all dictionary items are recompiled whenever a modification
is made to an expression that may be used by another dictionary item.
2.11-0
QM Commands 245
4.33 CONFIG
The CONFIG command reports your licence details and configuration parameters. It can also be
used to modify the values of some parameters.
Format
CONFIG {LPTR}
CONFIG param new.value
The first format of the CONFIG command allows you to examine your system configuration. The
report shows the licence details followed by the values of configurable parameters. The LPTR
option directs the report to the default printer.
The second form can be used to set parameter param to new.value in the current process. Only
parameters that are maintained on a per-process basis can be modified.
Examples
CONFIG
MUSTLOCK 0
NUMFILES 60
NUMLOCKS 70
OBJECTS 0
OBJMEM 0 kb
SORTMEM 1024 kb
SORTWORK c:\temp
The first section of output corresponds to the licence data entered when the system was installed or
subsequently relicensed. The second section shows the values of configurable parameters from the
QM configuration parameter file.
Example
CONFIG MUSTLOCK 1
This command modifies the value of the MUSTLOCK parameter to be 1. Only the process in which
the command is executed is affected.
2.11-0
246 OpenQM
4.34 CONFIGURE.FILE
Format
where
parameters are the new settings of the file configuration parameters. The following
parameters may be specified:
DYNAMIC Converts file to dynamic hashed type.
Ignored if file is already dynamic.
DIRECTORY Converts file to directory type. Ignored if
file is already a directory.
CASE converts the file to use case sensitive
record ids.
GROUP.SIZE n sets the group size in units of 1024 bytes.
Values in the range 1 to 8 are permitted.
LARGE.RECORD bytes sets the large record size in bytes.
MERGE.LOAD pct sets the merge load factor for the file.
MINIMUM.MODULUS n sets the minimum modulus for the file.
Any positive non-zero value may be used.
SPLIT.LOAD pct sets the split load factor for the file.
DEFAULT resets all parameters to their default
values.
NO.CASE converts the file to use case insensitive
record ids.
NO.MAP suppresses mapping of characters in
directory file record names that are
normally restricted. This option affects
only the data portion of the file and is
therefore invalid when the DICT
keyword is present. Note that when this
option is used the application is
responsible for ensuring that record
names comply with operating system file
name rules. See directory files for more
information.
NO.RESIZE disables file resizing.
RESIZE enables file resizing.
IMMEDIATE causes an immediate file resize, if
2.11-0
QM Commands 247
required.
The CONFIGURE.FILE command adjusts the settings of one or more file parameters. Changes to
the file type or group size result in immediate restructuring of the file and require exclusive access.
Changes only affecting other dynamic file parameters will occur steadily as the file is updated
unless the IMMEDIATE option is used.
Note that converting a file from case sensitive ids to case insensitive ids will result in loss of data if
the file contains records that contain two or more record using keys with alternative casing of the
same text.
The NO.RESIZE option disables the normal automatic split/merge operations that occur in dynamic
files. The IMMEDIATE option can be used later to force the deferred splits/merges to be applied.
See the description of dynamic files for more details on the use of this feature.
The resizing operations of the IMMEDIATE option are fully interruptable and can be performed
while the file is in use.
Examples
This command changes the minimum modulus and split load percentage of the STOCK file. The
actual change will take effect as the file is updated by future access.
2.11-0
248 OpenQM
4.35 COPY
The COPY command copies selected records from one file to another, or within the same file.
Format
where
tgt.file is the file to which the records are to be copied. If omitted, records are copied
within the src.file.
tgt.rec is the name of the record to which src.rec is to be copied. If omitted, the record is
not renamed.
2.11-0
QM Commands 249
Any number of source and target record pairs may be specified. If all records in the file are to be
copied, the keyword ALL may be used in place of specified record names.
If no source records are specified and the default select list is active, this list is used to determine
the records to be copied. A confirmation prompt is issued before copying commences unless the
NO.QUERY keyword is used.
The COPY command does not normally overwrite existing records. The keyword
OVERWRITING allows this operation. Thus a command of the form
COPY FROM src.file TO tgt.file ALL
would only copy records that do not already exist in the target file.
Conversely, the keyword UPDATING copies records only if they already exist in the target file.
The DELETING keyword causes COPY to delete records from the source file after they have been
successfully copied to the target file.
The REPORTING keyword causes a message to be displayed for each record copied.
Example
This command copies all records from the NEWVOC file to the VOC, replacing existing records of
the same name. This could be used, for example, if the VOC had been damaged by an accidental
deletion of some standard records.
See also:
COPYP
2.11-0
250 OpenQM
4.36 COPY.LIST
The COPY.LIST command copies a saved select list to another file or a different record in the
same file. Alternatively, the list can be output to the display.
Format
where
src.list is the name of the saved select list that is to be copied. If src.list is given as *, all
saved select lists in the source file are copied.
tgt.list is the name to be used for the copied select list. If omitted, the list retains its
original name. A tgt.list name cannot be specified when copying all saved lists
from the source file.
src.file is the name of the file holding the src.list to be copied. If omitted, the default saved
lists file $SAVEDLISTS is used.
tgt.file is the name of the file to receive the copied select list. If omitted, the default saved
lists file $SAVEDLISTS is used.
LPTR {n} Output the select list to logical print unit n. If n is not
specified, the default print unit is used.
NO.PAGE Used with the CRT option, this option suppresses the
normal pause between successive pages of output.
The COPY.LIST command is used to copy saved select lists. The FROM and TO options allow
copying from and to files other than the default $SAVEDLISTS file. When the default file is used,
it will be created if it does not already exist.
The COPY.LIST command does not affect any active select lists.
Example
2.11-0
QM Commands 251
This command copies the select list previously stored in $SAVEDLISTS as INVENTORY to a
record of the same name in file INVENT.LISTS. Any existing record of the same name is
overwritten.
See also:
DELETE.LIST, EDIT.LIST, GET.LIST, SAVE.LIST, SORT.LIST
2.11-0
252 OpenQM
4.37 COPY.LISTP
The COPY.LISTP command copies saved select list records from one file to another, or within the
same file using Pick syntax.
Format
where
src.file is the file from which the records are to be copied. The optional DICT prefix
indicates that the dictionary portion of the file is to be used. If omitted, the
$SAVEDLISTS file is used.
id.list is a list of ids of the records to be copied. If specified as an asterisk, all records in
the source file are copied. If omitted, an active select list is used.
options is a list of option codes. These must be prefixed by an open parenthesis. The
available codes are:
B Copy data in binary mode, suppressing translation between field marks and
newlines when copying between a hashed file and a directory file in either
direction. This mode is implied if both are directory files.
D Deletes the source records after copying.
I Suppresses display of record ids.
N Suppresses pagination when displaying records on the terminal.
O Overwrites existing records in the target file.
P Sends the record data to a printer.
S Suppresses field numbers with P or T.
T Sends the record data to the terminal.
If the P or T options are used, the records identified by id.list are sent to the printer or the screen.
If neither the P nor T options are used, the command prompts for a space separated list of
destination record ids. If there are more ids in id.list than in the destination list, the source id is used
as the destination id for the extra items.
The destination list can begin with a file name prefixed by an open parenthesis to direct output to a
different file. The name can optionally be followed by a close parenthesis.
The ALIAS command can be used to make COPY.LISTP the default for COPY.LIST without
removing the ability for other users or software packages to access the original COPY.LIST
command.
The COPY.LISTP command is effectively the same as the COPYP command except that the file
name defaults to $SAVEDLISTS if omitted.
Examples
2.11-0
QM Commands 253
COPY.LISTP * (D
To: (COPIED.LISTS
17 record(s) copied and deleted.
This command copies all records from the $SAVEDLISTS file to the COPIED.LISTS file, deleting
the originals.
This command copies record ORDERS in the COPIED.LISTS file to a record named ORDERS2 in
the same file.
See also:
COPY.LIST
2.11-0
254 OpenQM
4.38 COPYP
The COPYP command copies selected records from one file to another, or within the same file,
using Pick syntax.
Format
where
src.file is the file from which the records are to be copied. The optional DICT prefix
indicates that the dictionary portion of the file is to be used.
id.list is a list of ids of the records to be copied. If specified as an asterisk, all records in
the source file are copied. If omitted, an active select list is used.
options is a list of option codes. These must be prefixed by an open parenthesis. The
available codes are:
A Copy data in text mode, translating between field marks and newlines
when copying between a hashed file and a directory file in either direction.
This option is only needed to override implied binary mode copy when
copy between directory files.
B Copy data in binary mode, suppressing translation between field marks and
newlines when copying between a hashed file and a directory file in either
direction. This mode is implied if both are directory files.
D Deletes the source records after copying.
I Suppresses display of record ids.
N Suppresses pagination when displaying records on the terminal.
O Overwrites existing records in the target file.
P Sends the record data to a printer.
S Suppresses field numbers with P or T.
T Sends the record data to the terminal.
If the P or T options are used, the records identified by id.list are sent to the printer or the screen.
If neither the P nor T options are used, the command prompts for a space separated list of
destination record ids. If there are more ids in id.list than in the destination list, the source id is used
as the destination id for the extra items.
The destination list can begin with a file name prefixed by an open parenthesis to direct output to a
different file. The name can optionally be followed by a close parenthesis.
The ALIAS command can be used to make COPYP the default for COPY without removing the
ability for other users or software packages to access the original COPY command.
Examples
2.11-0
QM Commands 255
COPYP ACCOUNTS * (D
To: (SAVED.ACCOUNTS
17 record(s) copied and deleted.
This command copies all records from the ACCOUNTS file to the SAVED.ACCOUNTS file,
deleting the originals.
COPYP BP PRT.INVOICE
To: PRT.INVOICE2
1 record copied.
This command copies record PRT.INVOICE in the BP file to a record named PRT.INVOICE2 in
the same file.
See also:
COPY
2.11-0
256 OpenQM
4.39 CREATE.ACCOUNT
Format
where
acc.name is the name to be given to the new account. This name must start with a letter
and may not contain spaces. The name will be translated to uppercase and
must not exceed 32 characters in length. The command will prompt for this if it
is not given on the command line.
pathname is the pathname of the operating system directory to hold the account. The
pathname should be enclosed in quotes is it contains spaces. The directory will
be created if it does not already exist but the parent directory must already
exist. The command will prompt for this if it is not given on the command line.
NO.QUERY suppresses the confirmation prompts when the pathname directory already
contains a VOC file or when creating a new directory.
The CREATE.ACCOUNT command creates a new account and populates the VOC file from the
NEWVOC template stored in the QMSYS account. The new account is added to the register of
accounts in the ACCOUNTS file in the QMSYS account.
Creation of accounts by specific users may be barred by the system administrator. See Application
Level Security for more details.
Accounts may be installed anywhere within the operating system file hierarchy. It is often useful to
distribute accounts across disk drives for improved load balancing. Alternatively, related
information can be clustered together in a single partition to simplify replication. It is recommended
that new accounts are not created under the directories of existing accounts as this can lead to
accidental deletion. For example, it is generally not a good idea to create application accounts as
subdirectories of the QMSYS account.
Attempting to create an account in the root directory will ask for confirmation unless the
NO.QUERY keyword has been used.
When QM is installed on a USB memory device, if pathname specifies a directory on the USB
device, this will be transformed internally to a format that allows for the drive letter to be different
when the stick is loaded in future.
2.11-0
QM Commands 257
Example
This command creates a new QM account named SALES in the D:\SALES directory.
See also:
DELETE.ACCOUNT, UPDATE.ACCOUNT
2.11-0
258 OpenQM
4.40 CREATE.FILE
Format
where
portion identifies the part of the file to create. This may be DATA to create just the
data portion, DICT to create just the dictionary portion or omitted to create
both.
file.name is the name of the VOC record to be created to refer to the file. By default, the
operating system pathname used for the directory representing the data file is
the same as file.name and the directory for the dictionary component of a file is
the same but with a .DIC suffix.
The configuration options available when creating a dynamic file to specify the file's configuration
and location are:
CASE creates a file where the record ids will be treated as case
sensitive. This is the default action unless the
CREATE.FILE.NO.CASE mode of the OPTION command
is enabled.
MINIMUM.MODULUS n sets the minimum modulus for the file. Any positive non-zero
value may be used. The default is 1.
GROUP.SIZE size sets the group size as a multiple of 1024 bytes. This must be
in the range 1 to 8. If omitted, the default group size is taken
from the GRPSIZE configuration parameter.
LARGE.RECORD bytes sets the large record size in bytes. The default is 80% of the
group size.
SPLIT.LOAD pct sets the split load factor for the file. The default is 80%.
MERGE.LOAD pct sets the merge load factor for the file. The default is 50%.
2.11-0
QM Commands 259
VERSION vno allows creation of files with internal formats compatible with
older releases of QM.
NO.CASE creates a file where the record ids will be treated as case
insensitive. QM will write records preserving the casing
specified by whatever performs the write. Reads will locate
records regardless of casing. The CREATE.FILE.NO.CASE
mode of the OPTION command can be used to make this the
default action.
NO.RESIZE creates the file with resizing disabled. See
CONFIGURE.FILE and dynamic files for more information.
The USING DICT clause allows creation of a data file that is to share the dictionary of an existing
file. The effect of this option is to copy the content of field 3 of the VOC entry for other.file into
field 3 of the newly created entry rather than setting up a new dictionary.
The ENCRYPT keyword enables record level data encryption and prefixes the name of the
encryption key to be used.
The NO.QUERY option suppresses any confirmation prompts associated with the requested
action.
Case sensitivity of record ids in directory files is dependent on the operating system.
To provide maximum flexibility, QM imposes no restrictions on the file name except that it may not
contain the mark characters or the ASCII null character. Use of spaces in file names is not
recommended as it is likely to lead to problems with some commands. Characters that are not valid
in operating system file names are automatically transformed using the same translations as
described for directory file record ids.
By default, the directories created at the operating system level to represent the QM file and its
dictionary have their names converted to uppercase. The KEEP.FILENAME.CASE mode of the
OPTION command can be used to suppress this conversion.
2.11-0
260 OpenQM
Multifiles
A multifile is a collection of data files that share a common dictionary. Commands and application
software refer to an individual subfile within the multifile by using a name that consists of the file
name and subfile name separated by a comma.
When creating a multifile element, the default action of CREATE.FILE is to create a subdirectory
named file.name under the account and create the element within this directory as subfile. An
alternative location can be specified using the PATHNAME parameter.
The CREATE.FILE command can convert an existing simple file into a multifile. The existing
data becomes a subfile with the same name as the file.
The MODE option can be used to set the file access permissions for the newly created file and its
dictionary. This option is ignored on Windows. The ddd element is the octal value for the
permission flags to be applied to the directory that represents the QM file. These values are as used
on Linux, FreeBSD and AIX where the first digit is the permissions for the owner of the file, the
second digit is the permissions for other users in the group to which the file is assigned, and the
third digit is permissions for all other users. Each digit is formed by adding 4 (write), 2 (read) and 1
(execute).
The sss element is the octal value for the permission flags to be applied to subfiles in the directory
when creating a hashed file. If omitted, this defaults to the same value as ddd.
If the MODE option is not used, the file permissions are taken from the current operating system
umask value.
Examples
This statement creates a dynamic file named STOCK with minimum modulus of 150 and group size
4.
This statement creates a dynamic file named INVOICES. The directory representing this file will
have permission flags of 775 and the subfiles in the directory will have permission flags of 660.
This statement creates a dynamic file named SALES and applies record level data encryption using
the SALESKEY key.
2.11-0
QM Commands 261
This statement creates the data portion of a directory file named PROGRAMS. The full pathname
for this directory file is specified as D:\APPS\PROGRAMS rather than using the default location.
CREATE.FILE ACCOUNTS,NORTH
This statement creates a multifile component named NORTH within the ACCOUNTS file.
See also:
CONFIGURE.FILE, DELETE.FILE, LISTF, LISTFL, LISTFR, data encryption,
CREATE.KEY, ENCRYPT.FILE
2.11-0
262 OpenQM
4.41 CREATE.INDEX
Format
where
filename is the name of the file for which the index is to be built.
field(s) is one or more field names for which indices are to be created.
The CREATE.INDEX command creates the file structures to hold an alternate key index. The
index must subsequently be populated using BUILD.INDEX before it can be used.
The field(s) referenced in the command must correspond to D, I, A, S or C-type dictionary items.
The dictionary items can be deleted once the index has been constructed as all details of the indexed
field are stored in the index file but this is not recommended. The value to be indexed must not
exceed 255 characters. Values longer than this will not be included in the index.
Indices constructed on I or C-type dictionary items or on A or S-type items that use correlative
expressions should be such that they always produce the same result when executed for the same
data record. Examples of possibly invalid I-type expressions would be those that use the date or
time and those that use the TRANS() function to access other files.
The NO.NULLS option specifies that no entry is to be added to the index for records where the
indexed field is null.
The NO.CASE option specifies that the index is to be built using case insensitive key values. The
internal sort order of the index is based on the uppercase form of the data being indexed. A case
insensitive index can be used with case insensitive comparison operators in the query processor but
not with case sensitive operations because of the sort order difference. Conversely, a case sensitive
index can be used with case sensitive comparison operators in the query processor but not with case
insensitive operations.
Normally, the indices are stored as subfiles in the directory that represents the data file. The
PATHNAME option allows the indices to be stored in an alternative location. This might be
useful, for example, to balance loads across multiple disks or to exclude indices from backups as
they can always be recreated.
All indices for a single data file must be stored together. The PATHNAME option can be used
when creating the first index and specifies the pathname of a new directory that will be created at
the same time as the index. If this option is included when creating subsequent indices the
index.path must be the same as for the first index. It is suggested that the pathname should be based
on the data file name for ease of recognition.
Index subfiles can be moved using the operating system level qmidx utility.
2.11-0
QM Commands 263
Data Encryption
Alternate key indices may be applied to files that use record level data encryption but developers
should be aware that the index itself is not encrypted and hence weakens the security of the indexed
fields.
Files using field level encryption cannot have indices on encrypted fields. Also, indices constructed
from calculated values such as I-types that use encrypted fields will fail if the record is updated by
a user that does not have access to the relevant encryption key.
Example
The above commands create and build an index on the DATE field of the ORDERS file.
See also:
BUILD.INDEX, DELETE.INDEX, DISABLE.INDEX, LIST.INDEX, MAKE.INDEX,
REBUILD.ALL.INDICES
2.11-0
264 OpenQM
4.42 CREATE.KEY
The CREATE.KEY command creates a data encryption key. This command can only be executed
by users with administrator rights in the QMSYS account.
Format
where
The command prompts for items not supplied on the command line.
The CREATE.KEY command creates a new entry in the key vault defining the encryption
algorithm and actual key string to be used. If the key vault does not already exist, this command
will create it, prompting for the master key to be used to encrypt the key vault. If the key vault does
exist, the user will be asked to enter the master key unless it has already been entered during this
session.
The keyname may be any sequence of up to 64 letters, digits, periods and hyphens. It is case
insensitive.
The algorithm may be any of AES128, AES192 and AES256. The name is case insensitive.
The keystring is up to 64 characters, is case sensitive and can contain any character. For best
security, the length of the keystring should be close to the actual length needed by the selected
algorithm. This is 16, 24 or 32 characters for the 18, 192 and 256 bit algorithms respectively. The
CREATE.KEY command will automatically transform the supplied key to the required length if
necessary.
Once a key has been defined, it may be referenced in commands that set up encryption without
needing to enter the master key. The keyname does not need to be treated as a secure item. The
keystring, on the other hand, must not be disclosed. It is strongly recommended that a copy of the
keystring is maintained off-site in case it is ever necessary to rebuild the key vault.
The CREATE.KEY automatically grants access to the key to the user that created it. Other users
can be granted access using the GRANT.KEY command
Example
The above command creates a 256 bit encryption key named CARDNO. The actual encryption
string will be entered in response to a prompt.
2.11-0
QM Commands 265
See also:
Data encryption, CREATE.FILE, DELETE.KEY, ENCRYPT.FILE, GRANT.KEY,
LIST.KEYS, RESET.MASTER.KEY, REVOKE.KEY, SET.ENCRYPTION.KEY.NAME,
UNLOCK.KEY.VAULT
2.11-0
266 OpenQM
4.43 CREATE.USER
The CREATE.USER command creates a new user name in the register of users for security
checks.
Format
where
username is the name of the user to be created. User names may be up to 32 character in
length. On Windows systems the name is case insensitive. If omitted, a prompt
is displayed for the user name.
account is the name of the account to be entered when this user logs in except for
phantoms and QMClient processes. If not specified, an account name prompt
will be issued when the user logs in.
The new user will not have administrator rights and all options controlling user rights will be
disabled. See the ADMIN.USER command for a more powerful method of managing user names.
On Windows 98/ME, the new user is created with no password. Either the PASSWORD command
should be used to apply a password or the user should be encouraged to set a password on first
login.
On later versions of Windows and other platforms, this command does not affect the underlying
operating system user name database. If QM's security system is enabled (see the SECURITY
command), users attempting to enter QM who do not appear in the user register will be rejected.
See also:
ADMIN.USER, DELETE.USER, LIST.USERS, PASSWORD, SECURITY, Application
Level Security
2.11-0
QM Commands 267
4.44 CT
The CT (Copy to Terminal) command displays the content of record(s) from a file.
Format
where
filename is the name of the file to be processed. The DICT keyword indicates that the
dictionary portion of filename is to be used.
record is the name of the record to be displayed. Multiple record names may be given in a
single command. If the default select list (list 0) is active, this list is used as the
source of record names. . If the default select list (list 0) is active, this list is used
as the source of record names. Specifying a record name of an asterisk (*) displays
all records in the file. If no record name is given and the default select list is active,
this list will be used to determine which records are reported.
The CT command displays the specified records from file. Each record is preceded by the file and
record names.
When using the default select list as the source of record ids to be processed, a confirmation prompt
is issued prior to commencing the display. This can be suppressed using the NO.QUERY option.
By default, the report shows each line (field) of the record on a separate line, prefixed with the line
number. Lines that are wider than the output device are wrapped to the next line.
The HEX option, produces a report in which the data is displayed in hexadecimal form, two
hexadecimal digits per character.
The BINARY option treats the record as binary data in which field marks are simply part of the
data. The record is shown in both hexadecimal and character format, 16 bytes per line.
Non-printing characters are displayed as dots (.) except for the field mark, value mark and subvalue
mark which as shown as ^, ] and \. Each line is prefixed by the byte offset (from zero) of the first
byte on the line.
Example
2.11-0
268 OpenQM
This command sequence would display each X type record from the VOC.
CT READERS 2
READERS 2
1: Cartwright, D
2: 7 Spring GroveyNottingham
3: 1-1y3-1
The above command displays the record with id 2 from the READERS file. The y in the final line
is a terminal dependent representation of the value mark character.
2.11-0
QM Commands 269
4.45 DATA
The DATA command supplies data to be used by an associated verb or QMBasic program which
would normally take input from the keyboard. It may only be used in paragraphs.
Format
DATA {text}
where
The DATA command must immediately follow the verb to which it is to apply. Multiple DATA
commands may be used to supply data to be processed consecutively by the associated verb or
program. Any intervening blank lines or comments in a sequence of DATA commands will be
ignored except for processing of inline prompts.
When the verb or program executes an INPUT statement, the data from the DATA command(s)
will be used. If all stored data has been used, keyboard input proceeds as normal.
Data stored by the DATA command or the QMBasic DATA statement is cleared on return to the
command prompt. Thus unused data where, for example, a program terminates at an error, will not
be carried forward to a later command. The CLEAR.DATA command can be used to clear the
data queue within a paragraph.
The DATA command cannot be used to provide text for inline prompts.
Example
PA
* <<History>>
LOOP
IF <<A,Record name>> = "" THEN GO DONE
ED BP <<Record name>>
DATA I * <<History>>
DATA FI
REPEAT
DONE:
This paragraph inserts a history comment at the top of QMBasic programs. The editor commands
to insert the text are provided using DATA commands. Note how the history text, which is only
required once as it is common to all files edited, is obtained first using an inline prompt in a
comment. The names of the records to be edited are then obtained in a loop which is terminated
when a null name is entered.
See also:
QMBasic DATA statement
2.11-0
270 OpenQM
4.46 DATE
The DATE command displays the current date and time or translates a date between internal and
external format.
Format
DATE {date}
DATE INTERNAL
where
If no date is specified, the date and time are reported in the form
If date is specified, the converted form of this date (internal to external or vice versa) is reported.
The DATE INTERNAL form shows the internal day number for the current date.
Examples
DATE
Tuesday, February 15, 2000 00:12:50 PM
DATE 10012
Tuesday, May 30, 1995
DATE 1 Oct 99
11597
DATE INTERNAL
14447
2.11-0
QM Commands 271
4.47 DATE.FORMAT
The DATE.FORMAT command selects the date format to be used by default or displays this
setting.
Format
DATE.FORMAT OFF
DATE.FORMAT { ON }
DATE.FORMAT DISPLAY
DATE.FORMAT INFORM
DATE.FORMAT conv.code
DATE.FORMAT OFF selects American date format (month, day, year) as the default for date
conversions.
DATE.FORMAT DISPLAY displays the current setting of the date format mode. If a non-default
conversion code has been set, this is also displayed. @SYSTEM.RETURN.CODE is set to 0 for
American date format or 1 for European date format.
DATE.FORMAT conv.code sets the default conversion code that will be used for date conversions
that specify a code of D with no qualifying options. The conv.code must be a valid date conversion
code. Specifying conv.code as D reverts to the standard default setting.
Examples
DATE.FORMAT ON
DATE.FORMAT DISPLAY
European date format is on
The above commands set European date format and then confirm this selection.
2.11-0
272 OpenQM
4.48 DEBUG
Format
where
file.name is the name of the directory file holding the program to be run. If omitted, this
defaults to BP. The .OUT suffix for the output file is supplied automatically.
LPTR causes output to logical print unit 0 to be directed to the printer. This is
identical in effect to a PRINTER ON statement being performed within the
program.
The DEBUG command enables detailed tracing of the operation of a QMBasic program to aid
development and maintenance.
2.11-0
QM Commands 273
4.49 DELETE
Format
where
DICT indicates that the records are to be deleted from the dictionary portion of
the named file.
record.name is the name of the record to be deleted. Multiple record names may be
specified in a single DELETE command.
NO.QUERY suppresses the confirmation prompt when using a select list. The
NO.SEL.LIST.QUERY mode of the OPTION command can be used to
imply this option.
If no record names are specified and the default select list is active, this list is used to determine the
names of the records to be deleted. A confirmation prompt is issued before deletion commences
unless the NO.QUERY option is used.
If a record to be deleted is locked by another user, a warning message is displayed and the
DELETE command continues without deleting the record.
@SYSTEM.RETURN.CODE is returned as the number of records deleted unless the delete fails in
which case it contains the error code.
Examples
This example selects all records from the STOCK file with PART.NO less than 10000 and deletes
them.
2.11-0
274 OpenQM
This example attempts to delete three specific records from PARTS.FILE. One of the records does
not exist.
2.11-0
QM Commands 275
4.50 DELETE.ACCOUNT
Format
where
acc.name is the name of the account to be deleted. This name must be registered in the
ACCOUNTS file in the QMSYS account (visible to all accounts as
QM.ACCOUNTS).
The DELETE.ACCOUNT command deletes the named account and its entry in the accounts
register. The user will be prompted to confirm whether the account directory is to be deleted.
Deletion of accounts by specific users may be barred by the system administrator. See Application
Level Security for more details.
Before deleting the account, QM checks whether any files in the account are referenced from other
accounts and, if so, displays a list of these files. It also checks whether there are other accounts that
are stored as subdirectories of the account that is to be deleted. The FORCE option can be used to
suppress these checks.
Example
DELETE.ACCOUNT SALES
See also:
CREATE.ACCOUNT, UPDATE.ACCOUNT
2.11-0
276 OpenQM
4.51 DELETE.CATALOGUE
Format
where
If neither the GLOBAL nor the LOCAL keyword is present, the DELETE.CATALOGUE
command deletes entries from the private catalogue unless name has a prefix character that
identifies a globally catalogued item.
The private catalogue is normally a subdirectory, cat, under the account directory but can be moved
by creating an X-type VOC entry named $PRIVATE.CATALOGUE in which field 2 contains the
pathname of the alternative private catalogue directory. This only takes effect when QM is
re-entered or on use of the LOGTO command. This feature is particularly useful where two or
more accounts are to share a common private catalogue. The US spelling, $PRIVATE.CATALOG,
may be used instead, if both are present, the British spelling takes priority.
See also:
BASIC, CATALOGUE, MAP
2.11-0
QM Commands 277
4.52 DELETE.COMMON
Format
DELETE.COMMON name
DELETE.COMMON ALL
where
name is the name of the common block to be deleted. The keyword ALL causes all
named common blocks to be deleted.
The DELETE.COMMON command deletes the named common block. It is particularly useful
when debugging programs.
Common blocks can only be deleted if there is no active program referencing them. When the ALL
keyword is used, blocks that cannot be deleted are ignored and no error is reported. When deleting a
specific common block, a non-fatal error occurs if the block is in use.
Examples
DELETE.COMMON COM1
DELETE.COMMON ALL
See also:
LIST.COMMON
2.11-0
278 OpenQM
4.53 DELETE.FILE
Format
where
file.name is the VOC name of the file to be deleted. The DATA prefix may be used to delete
only the data portion of the file. The DICT prefix may be used to delete only the
dictionary portion of the file.
subfile is the subfile to be deleted from a multifile. If omitted and file.name refers to a
multifile, the entire multifile will be deleted. Use of a subfile name implies use of
the DATA keyword, leaving the dictionary in place.
If no file name is specified and the default select list is active, the DELETE.FILE command will
use this list to determine the files to be deleted.
Deleting the data portion of a file deletes the associated operating system directory and clears field 2
of the VOC record describing the file. Deleting the dictionary portion of a file deletes the directory
representing the dictionary and clears field 3 of the VOC record.
If the DELETE.FILE command results in a VOC record with fields 2 and 3 both null, the VOC
record is also deleted. Thus deleting both portions of a file, the data portion of a file which had no
dictionary or the dictionary portion of a file which had no data portion would also delete the VOC
record.
Where the operating system name of the file recorded in the VOC entry is not the default name for
the file (file.name for the data portion, file.name.DIC for the dictionary portion), the
DELETE.FILE command prompts for confirmation unless the FORCE option is used. This traps
accidental deletion of files which are remote to the account or for which file.name is not the primary
VOC reference.
Example
This command deletes the dictionary part of the file named INVENTORY.
2.11-0
QM Commands 279
See also:
CREATE.FILE, LISTF, LISTFL, LISTFR
2.11-0
280 OpenQM
4.54 DELETE.INDEX
Format
where
field(s) are the names of indexed fields to be deleted. The casing of the name used in the
command must match that of the actual index name.
The DELETE.INDEX command deletes the named indices. Once an index has been deleted, any
queries against the named field(s) may require processing of the entire file to locate records.
Example
This command deletes the index on the DATE field of the ORDERS file.
See also:
BUILD.INDEX, CREATE.INDEX, DISABLE.INDEX, LIST.INDEX, MAKE.INDEX,
REBUILD.ALL.INDICES
2.11-0
QM Commands 281
4.55 DELETE.KEY
The DELETE.KEY command deletes a data encryption key. This command can only be executed
by users with administrator rights in the QMSYS account.
Format
DELETE.KEY {keyname}
where
keyname is the name of the encryption key to be deleted. This is case insensitive.
The command prompts for the key name if it is not supplied on the command line.
The DELETE.KEY command deletes an entry in the key vault defining the encryption algorithm
and actual key string. The user will be asked to enter the master key unless it has already been
entered during this session.
Any data in data files encrypted using this key will become inaccessible.
Example
DELETE.KEY CARDNO
See also:
Data encryption, CREATE.FILE, CREATE.KEY, ENCRYPT.FILE, GRANT.KEY,
LIST.KEYS, RESET.MASTER.KEY, REVOKE.KEY, SET.ENCRYPTION.KEY.NAME,
UNLOCK.KEY.VAULT
2.11-0
282 OpenQM
4.56 DELETE.LIST
Format
DELETE.LIST list.name
where
The DELETE.LIST command deletes a previously saved select list from the $SAVEDLISTS file.
It has no effect on any active select lists.
Example
DELETE.LIST INVENTORY
Deleted saved list 'INVENTORY'.
See also:
COPY.LIST, EDIT.LIST, GET.LIST, SAVE.LIST, SORT.LIST
2.11-0
QM Commands 283
4.57 DELETE.SERVER
The DELETE.SERVER command removes a QMNet server from QM's list of public server
definitions. The DELETE.PRIVATE.SERVER command deletes a private server definition that
is local to the QM session.
Format
DELETE.SERVER name
DELETE.PRIVATE.SERVER name
where
QMNet allows an application to access QM data files on other servers as though they were local
file, with complete support for concurrency control via file and record locks. Servers are defined by
the system administrator using the SET.SERVER or SET.PRIVATE.SERVER command and
may subsequently be deleted with the DELETE.SERVER or DELETE.PRIVATE.SERVER
command.
The DELETE.SERVER command to delete a public server definition requires administrator rights
within QM and can only be executed from the QMSYS account.
Any QMNet connections currently open to the server that is being deleted will not be affected.
Example
DELETE.SERVER ADMIN
See also:
QMNet, ADMIN.SERVER, LIST.SERVERS, SET.SERVER
2.11-0
284 OpenQM
4.58 DELETE.USER
The DELETE.USER command deletes a user name from the register of users for security checks.
Format
DELETE.USER {username}
where
username is the name of the user to be deleted. If omitted, a prompt is displayed for the
user name.
The named user is deleted from the user name register. It is possible to delete a user who is logged
in.
See the ADMIN.USER command for a more powerful method of managing user names.
On Windows NT onwards and on all non-Windows platforms, this command does not affect the
underlying operating system user name database, however, users who do not appear in the register
will not be able to enter QM if the internal security system is enabled.
See also:
ADMIN.USER, CREATE.USER, LIST.USERS, PASSWORD, SECURITY, Application
Level Security
2.11-0
QM Commands 285
4.59 DISABLE.INDEX
The DISABLE.INDEX command disables update and use of one or more alternate key indices.
Format
where
filename is the name of the file for which the index is to be built.
field(s) is one or more field names for which indices have been created.
The DISABLE.INDEX command disables updates and use of the index data for the named
field(s). The ALL keyword can be used to disable all indices that have been created for the file.
This command is of use when importing a large volume of data into a file that uses indices or when
performing batch processing that may update a large proportion of the records stored in the file.
The performance gain of not applying effectively randomly sequenced index updates may be
significantly greater than the cost of using BUILD.INDEX to rebuild the index after the data
import or processing is complete because this command can optimise the sequence in which it
constructs the index.
See also:
BUILD.INDEX, CREATE.INDEX, DELETE.INDEX, LIST.INDEX, MAKE.INDEX,
REBUILD.ALL.INDICES
2.11-0
286 OpenQM
4.60 DISABLE.PUBLISHING
Format
DISABLE.PUBLISHING
The DISABLE.PUBLISHING command, present only in the QMSYS account and restricted to
users with administrator rights, suspends recording of updates to published files in the replication
log area. Any updates applied to published files while publishing is disabled will not be replicated
on the subscriber systems.
The command is intended for use while synchronising the publisher and subscriber files either while
setting up replication or when recovering from a failure of the publisher system.
See also:
Replication, ENABLE.PUBLISHING, PUBLISH, PUBLISH.ACCOUNT, SUBSCRIBE
2.11-0
QM Commands 287
4.61 DISPLAY
Format
The optional colon at the end of the line suppresses the normal newline after the text is displayed.
The second format positions the cursor to the given column and row (both numbered from zero)
before displaying the text. There must be no spaces in the cursor position element. Any spaces
following the close bracket are treated as part of the text. The QMBasic @() function variants with
a negative value for the first (or only) argument are also supported.
Example
A paragraph containing
DISPLAY Hello :
DISPLAY world
would display
Hello world
2.11-0
288 OpenQM
4.62 DUMP
The DUMP command displays the content of record(s) from a file in hexadecimal and character
format.
Format
where
filename is the name of the file to be processed. The DICT keyword indicates that the
dictionary portion of filename is to be used.
record is the name of the record to be displayed. Multiple record names may be given in a
single command. If the default select list (list 0) is active, this list is used as the
source of record names. . If the default select list (list 0) is active, this list is used
as the source of record names. Specifying a record name of an asterisk (*) displays
all records in the file. If no record name is given and the default select list is active,
this list will be used to determine which records are reported.
The DUMP command displays the specified records from file. Each record is preceded by the file
and record names.
The record is treated as binary data in which field marks are simply part of the data. It is shown in
both hexadecimal and character format, 16 bytes per line. Non-printing characters are displayed as
dots (.) except for the field mark, value mark and subvalue mark which as shown as ^, ] and \. Each
line is prefixed by the byte offset (from zero) of the first byte on the line.
When using the default select list as the source of record ids to be processed, a confirmation prompt
is issued prior to commencing the display. This can be suppressed using the NO.QUERY option.
Example
DUMP READERS 2
READERS 2
00000000: 43 61 72 74 77 72 69 67 68 74 2C 20 44 FE 37 20 |
Cartwright, D^7
00000010: 53 70 72 69 6E 67 20 47 72 6F 76 65 FD 4E 6F 74 |
Spring Grove]Not
00000020: 74 69 6E 67 68 61 6D FE 31 2D 31 FD 33 2D 31 |
tingham^1-1]3-1
2.11-0
QM Commands 289
The above command dumps the record with id 2 from the READERS file.
See also: CT
2.11-0
290 OpenQM
4.63 ECHO
Format
The ECHO command allows temporary suspension of keyboard input echo. Echoing is
automatically resumed in the event of an abort.
2.11-0
QM Commands 291
4.64 ED
The ED command enters the QM line editor. The synonym EDIT can be used.
Format
where
DICT indicates that records from the dictionary portion of the file are to be edited.
record.id is the name of the record to be edited. Multiple record ids may be given in
which case each record is edited in turn.
If no record.id is specified and the default select list is active, this list is used to identify the records
to be edited. If no record.id is specified and the default select list is not active, the ED command
prompts for the record.id.
A record.id of * either on the command line or as the first record.id entered in response to the
prompt will cause ED to select all records of the file and edit each in turn.
The editor maintains an update lock on the record that is being edited.
When editing a compiled dictionary item (C-type, I-type, or A/S type with a correlative), ED
removes the compiled code thus forcing recompilation when the modified item is first referenced in
a query.
Overview
The editor takes its commands from the keyboard or the DATA queue. Each command line contains
one editor command. Commands are retained in a stack similar to the command processor stack and
can be repeated without complete retyping. Commands that take arguments specifying their exact
function can be repeated by entering just the command name.
ED normally rejects commands and input text that contain non-printing characters. Where a
non-printing character is to be entered, it can be typed as ^nnn where nnn is the decimal value of
the character. Alternatively, the NPRINT command can be used to enable entry of non-printing
characters.
The editor operates in two modes; edit and input. In edit mode, commands affect the current line
(field). In input mode, new data is entered into the record. The editor numbers lines from one and
the line number is displayed as a four digit number followed by a colon whenever lines are
displayed or during input. The editor command prompt is four hyphens followed by a colon.
2.11-0
292 OpenQM
Positioning Commands
The commands listed below alter the position of the current line. In addition, entering a blank line at
the command prompt advances the current position by one line, displaying the newly selected line.
n
Entering a number at the command prompt positions the current line to line n.
+n
Moves the current line position forward by n lines.
-n
Moves the current line position backward by n lines.
B
The B (bottom) command moves to the last line of the record.
F{n} {string}
The F (find) command moves forward to the next line containing string starting at column
position n (from one). If n is omitted, string must occur at the start of the line.
If string is omitted, the string used by the most recent F command is used. If no F command
has been executed, the editor moves forward by one line.
Gn
The Gn (go to) command moves to line n. This is identical to the n command described above.
G<
The G< command moves to the first line of the currently defined block.
G>
The G> command moves to the last line of the currently defined block.
L{n} {string}
The L (locate) command moves forward to the next line containing string which must be
preceded by a single space or a delimiter chosen from
!"#$%&()*+,-./:=@[]\_`'{}|
All characters after the delimiter will be treated as part of the string to be located. The string is
case sensitive by default but the CASE command can be used to select case insensitive
searches. See the W command for a description of wildcards.
The optional line count, n, limits the search to n lines from the current position. If n is present,
all occurrences of string in the region to be searched are displayed and the current position is
left at the end of the search region.
2.11-0
QM Commands 293
If string is omitted, the string used by the most recent L command is used. If no L command
has been executed, the editor moves forward by one line.
M {pattern}
The M (match) command moves forward to the next line matching pattern. The pattern
argument is any valid pattern as used for the query processor LIKE operator. There must be a
space before pattern.
If pattern is omitted, the string used by the most recent M command is used. If no M command
has been executed, the editor moves forward by one line.
POn
The POn (position) command moves to line n. This is identical to the n command described
above.
T
The T (top) command moves to before line 1. There is no current line after this action.
Displaying Text
Ln
The Ln (list) command displays n lines, moving the current line forward to the final displayed
line. It is similar to the P command except that n must be included. Omitting n results in
execution of a locate command as described above.
P{n}
The P (print) command displays n lines starting at the current line, moving the current line
forward to the final displayed line. The value of n defaults to 23 on first use of the P command
and to the value of n for the most recently executed P command thereafter. There must be no
space between P and n.
PL{{-}n}
The PL (print lines) command displays n lines relative to the current line position. Negative
values of n print lines before the current line. The value of n defaults to 23 on first use of the
PL command and to the value of n for the most recently executed PL command thereafter.
There must be no space between PL and n. The current line position is not changed by this
command.
PP{n}
The PP (print position) command displays n lines surrounding the current line position. The
value of n defaults to 23 on first use of the PP command and to the value of n for the most
recently executed PP command thereafter. There must be no space between PP and n.
Inserting Text
I {text}
The I (insert) command inserts text after the current line, making this the current line. There
must be a single space before text. Any additional spaces are treated as part of the inserted text.
To insert a blank line type I followed by a single space.
If the I command is entered with no text and no space after the I, the editor enters input mode.
2.11-0
294 OpenQM
It will prompt for successive lines until a blank line is entered at which point it returns to edit
mode. Entering a line containing just a single space inserts a blank line.
IB {text}
The IB (insert before) command is similar to the I command described above except that text is
inserted before the current line.
The editor prompts for the start and end line numbers to be inserted. These default to the first
and last lines respectively.
Deleting Lines
D{n}
The Dn (delete) command deletes n lines starting at the current line position. If n is not
specified, only the current line is deleted. The line after the last line deleted becomes current.
DE{n}
Same as Dn described above.
A {string}
The A (append) command appends string to the current line. A single space must separate
string from the command. Any further spaces are treated as part of the inserted text.
B string
The B (break) command splits the current line into two after string. The string argument must
be present and is preceded by a single space. Any additional spaces are treated as part of string.
C/old.string/new.string/{n}{G}{B}
The C (change) command changes old.string to new.string in the current line. The delimiter
around the strings may be any of
!"#$%&()*+,-./:=@[]\_`'{}|
The optional n component specifies that n lines starting at the current line are to be changed.
G causes all occurrences of old.string to be replaced. Without G only the first occurrence on
the line is changed.
B applies the change to the currently defined block rather than the current line. B and n may not
be used together.
The n, G, and B, qualifiers can be placed before the first string delimiter as an alternative to the
2.11-0
QM Commands 295
Searches for old.string are case sensitive by default. See the CASE command for a way to
select case insensitive searches. See the W command for a description of wildcards.
CAT {string}
The CAT command concatenates the current line, string and the following line to form a single
line. Omitting string merges the lines with no intervening characters. There must be a single
space between the command and the string. Any additional spaces are treated as part of string.
DUP {n}
The DUP command duplicates the current line n times. The value of n defaults to one. The first
line added by DUP becomes the current line.
R/old.string/new.string/{n}{G}{B}
Identical to C described above.
R {text}
The R (replace) command replaces the current line with the specified text. There must be a
single space before text. Any additional spaces are treated as part of the replacement text. To
replace a line by a blank line, type R with no text. The space may be omitted in this case.
EV
The EV (edit values) command enters a mode where each value of the current line becomes a
line of its own in a new editable item. To edit subvalues, use the EV command when already in
EV mode. Used with a dictionary I-type entry, the EV command breaks compound I-types into
separate lines to simplify editing.
QV
Exits from EV mode and returns to the previous edit text, discarding any changes made while in
EV mode.
SV
Exits from EV mode and returns to the previous edit text, saving any changes made while in EV
mode.
The Dn (delete) command deletes n lines starting at the current line position. If n is not
specified, only the current line is deleted. The line after the last line deleted becomes current.
Blocks are defined by two pointers; the start and end line. Block operations enable the entire block
to be deleted, moved or copied.
<
Sets the current line to be the start line of the block. When used at the top of the record, the <
command clears the block pointers.
2.11-0
296 OpenQM
>
Sets the current line to be the end line of the block.
<>
Sets the block to be just the current line.
BLOCK
Toggles block verification mode. When enabled, COPY, DROP and MOVE commands cause
a prompt for confirmation prior to performing the operation. Block verification mode is enabled
by default.
COPY
Copies the currently defined block to immediately after the current line position without
affecting the original block.
DROP
Deletes the currently defined block.
MOVE
Copies the currently defined block to immediately after the current line position and deletes the
original block.
PB
The PB (print block) command displays the currently defined block.
DELETE
FD
Prompts for confirmation and then deletes the entire record from the file.
After the record has been deleted, the editor either terminates, continues with the next record
from a select list or prompts for a new record id depending on the way in which it was entered.
The confirmation prompt can be suppressed using the ED.NO.QUERY.FD mode of the
OPTION command.
If record.id is specified, the modified record is saved under the new name. A confirmation
prompt will be issued if a record of this name already exists.
If both filename and record.id are given, the record is saved to the specified file and record.
Again, a confirmation prompt will be issued if a record of this name already exists.
After the record has been saved, the editor either terminates, continues with the next record
from a select list or prompts for a new record id depending on the way in which it was entered.
Two extended forms of the FI command are available for use when editing QMBasic programs:
FIB {{filename} record.id} Files the record and then runs the QMBasic compiler.
2.11-0
QM Commands 297
FIBR {{filename} record.id} Files the record, runs the QMBasic compiler and, if the
compilation is successful, runs the compiled program.
N
When using a select list, the N command moves to the next record in the list. A confirmation
prompt is issued if there are unsaved changes.
QUIT
EX
The QUIT command (which may be abbreviated to Q) and its synonym EX terminates editing
of the current record. A confirmation prompt is issued if there are unsaved changes.
If a select list is in use, the editor will move on to the next record. Use the X command
described below to terminate the entire edit in this case.
If record.id is specified, the modified record is saved under the new name. A confirmation
prompt will be issued if a record of this name already exists.
If both filename and record.id are given, the record is saved to the specified file and record.
Again, a confirmation prompt will be issued if a record of this name already exists.
Unlike the FILE command, editing continues after saving the record. The SAVE command
does not change the names associated with the record being edited. A subsequent SAVE or
FILE with the file and record names omitted will use the original names, not those of an
intermediate SAVE command.
The editor prompts for the start and end line numbers to be saved. These default to the first and
last lines respectively.
X
The X command aborts an edit when a select list is in use without saving any changes made to
the record. A confirmation prompt is issued if there are unsaved changes. Any further entries in
the select list are discarded and the editor terminates.
Miscellaneous Commands
?
The ? command displays status information about the editor and the record being edited. This
includes
The file name and record id
The current line number
Block start and end line positions
The command, if any, which will be reverted by OOPS.
Non-printing character expansion mode status (^)
2.11-0
298 OpenQM
^
Toggles non-printing character expansion mode. When this mode is enabled, non-printing
characters are displayed as ^nnn where nnn is the decimal character number.
CASE OFF
Sets case insensitive mode for the C, F and L commands.
CASE ON
Sets case sensitive mode for the C, F and L commands. This is the default mode of the editor.
COL
Displays a column number ruler to aid alignment of inserted text
HELP {topic}
The HELP command displays a short description associated with the command identified by
topic. If topic is omitted, this command enters the full help system. If topic is present but not
recognised, ED tries to find a help page on this topic from the full help system.
NPRINT
Toggles non-printing character entry mode. When this mode is enabled, non-printing characters
may be included in commands and input text. When disabled, non-printing characters are
rejected but may still be entered using the ^nnn notation where nnn is the decimal character
number.
OOPS
The OOPS command undoes the most recent function that modified the record. It cannot be
used to forget positioning functions.
STAMP
The STAMP command inserts a single comment line below the current line indicating the
account name, user name, date and time of the modification.
SPOOL
The SPOOL command prints a copy of the record on the default printer. If changes have been
made but not yet written to the file, the printed version includes these changes. The optional
lines qualifier specifies the number of lines to be printed starting at the current line. If this is
omitted, the entire record is printed.
W{char}
Specifies a wildcard character that may be used in the C and R text replacement commands or
the F and L search commands. Use of char within the search string of these commands will
match against any single character. The wildcard character may not be a letter or the caret
symbol (^). Use of the W command with no char qualifier turns off the wildcard.
XEQ {command}
The XEQ command executes the specified command which may be any command valid at the
command prompt. The command may include any of the following items to substitute text into
the command:
@FILE The file name
2.11-0
QM Commands 299
Frequently used sequences of editor commands may be saved in a file and subsequently executed by
entering just one command. Pre-stored command sequences can also include loops to repeat a series
of commands.
Command sequences are saved using the .S command. This has several different syntaxes:
.S item Save the most recent command
.Sn item Save command n
.S item n,m Save commands n to m
.S item n m Save commands n to m
In each case, item may be given as either a record id to be created in the default $ED file or as a file
name and record id separated by a space. The values n and m may be given in either order. The
commands are always saved in the same sequence as they appear on the editor command stack. The
first line in the saved item has a type code of E as its first character followed by text describing
when it was created.
The $ED file will be created automatically first time that the .S command is used to save commands
in this file.
Multi-line inserts cannot be repeated from a saved command sequence, will cause the .S command
to fail and, if edited into the pre-stored sequence manually, will be cause a warning message to be
displayed when the command sequence is executed.
Alternatively, a user can create a $ED pre-stored item by using the editor:
ED $ED item.name
The first field of the item must contain E as its first character. Subsequent fields contain one editor
instruction in the sequence that the user requires the operations to be performed.
Other useful command stack extensions for use with stored edit commands are:
.D item Delete the specified item
.L item List the item. If the record id is given as an asterisk, a list of stored edit
sequences in the file is displayed.
.R item Recall a previously saved set of commands to the stack.
2.11-0
300 OpenQM
A stored edit sequence may include the PAUSE command. Execution stops and the user may decide
whether to continue by entering .XR or to terminate the sequence by entering .XK. Other editing
commands may be executed before either of these responses is entered.
The LOOP command can be used to repeat a series of steps in the stored commands. The format is
LOOP lineno count
The edit continues with the command on lineno. The LOOP will be jump back to the specified line
count times before dropping through to the next command. Both lineno and count default to 1 if
omitted.
A loop may validly include use of the FI command to file the record. When processing records from
a select list, the pre-stored sequence continues execution from one record to the next.
The following commands manipulate the editor command stack. Unless otherwise stated, the stack
position argument, n, defaults to one.
.A{n} string
Append string to entry n of the editor command stack.
.C{n}/old.string/new.string/
Change old.string to new.string in line n of the editor command stack.
.D{n}
Delete line n of the editor command stack.
.I{n} string
Insert string as entry n of the editor command stack.
.L{n}
List n lines of the editor command stack. The value of n defaults to nine.
.R{n}
Recall line n of the editor command stack to the top of the stack.
.X{n}
Execute line n of the editor command stack.
See also ED Pre-Stored Commands above for additional command stack features.
2.11-0
QM Commands 301
On entry, ED looks for an X-type VOC record named $ED.OPTIONS and, if this exists, examines
fields 2 onwards of this record for options that set the default modes for the editor. These may be:
BLOCK {ON | OFF} Turn on/off prompting for confirmation on COPY, DROP and
MOVE. Default is ON.
CASE {ON | OFF} Turn on/off case sensitivity for searches (C, F, L). Default is ON.
FIT.SCREEN {ON | OFF}If on, the default display size of the P, PL and PP commands is
chosen to fit the screen size. Default is OFF.
NPRINT {ON | OFF} Turn on/off acceptance of non-printing characters on input.
Default is OFF.
2.11-0
302 OpenQM
4.65 EDIT.CONFIG
Format
EDIT.CONFIG
The EDIT.CONFIG command provides an easy way to modify the QM configuration parameters.
It is available only in the QMSYS account and requires the user to have administrator rights.
ERRLOG=20
EXCLREM=0
FILERULE=7
FIXUSERS=21,10
FSYNC=0
GDI=0
GRPSIZE=1
INTPREC=13
JNLDIR=\qmjnl
JNLMODE=3
LPTRHIGH=66
LPTRWIDE=80
MAXIDLEN=127
MUSTLOCK=0
NETFILES=2
NUMFILES=500
===========================================================
Additive value controlling extended file syntax.
1 = Allow account:file,
2 = Allow server:account:file,
4 = Allow PATH: prefix.
F1=Help
The upper portion of this display shows the configuration data with the cursor positioned on the
currently selected parameter. The lower portion shows descriptive text for the selected parameter. A
message may also appear if the parameter value fails to meet validation rules.
The amend a line, simply type new data or use any of the standard editing keys:
Ctrl-A Home Position the cursor at the start of the input data
Ctrl-B Cursor left Move the cursor left one character
2.11-0
QM Commands 303
To insert a new parameter, press the Return key on the line under which the insertion is to occur.
To terminate the editor, optionally saving changes, press the Esc key.
2.11-0
304 OpenQM
4.66 EDIT.LIST
The EDIT.LIST command invokes the ED line editor to edit a saved select list in the
$SAVEDLISTS file.
Format
EDIT.LIST list.name
where
list.name is the name of the saved select list to be edited. If omitted, a prompt is output.
The EDIT.LIST command enters ED to edit the named saved select list. All editing functions are
available and care should be taken to ensure that the record remains a valid select list.
See also:
COPY.LIST, DELETE.LIST, GET.LIST, SAVE.LIST, SORT.LIST
2.11-0
QM Commands 305
4.67 ENABLE.PUBLISHING
Format
ENABLE.PUBLISHING
The ENABLE.PUBLISHING command, present only in the QMSYS account and restricted to
users with administrator rights, resumes recording of updates to published files in the replication log
area following earlier use of DISABLE.PUBLISHING. Any updates applied to published files
while publishing was disabled will not be replicated on the subscriber systems.
See also:
Replication, DISABLE.PUBLISHING, PUBLISH, PUBLISH.ACCOUNT, SUBSCRIBE
2.11-0
306 OpenQM
4.68 ENCRYPT.FILE
The ENCRYPT.FILE command sets the data encryption key for specific fields or the entire
record.
Format
where
field is the name or field number of the field to which encryption is to be applied.
keyname is the name of the encryption key to be used. This is case insensitive.
The first form of the ENCRYPT.FILE command sets the encryption key for one or more fields
within a file that uses field level encryption. Encryption cannot be applied to a field that is used for
an alternate key index.
The second form of the ENCRYPT.FILE command sets the encryption key for record level
encryption. Alternate key indices can be defined in files that use record level encryption but,
because the index itself is not encrypted, the indexed fields have reduced security.
If the file contains data records when this command is used, the file is processed to apply the
encryption. A system failure or other process abort during this update will leave the file in a
partially encrypted state and hence render it unusable. Always back up a file before using this
command if the file contains data.
Examples
The above command encrypts the CCARD field of the CUSTOMERS file using the CARDNO
encryption key.
The above command encrypts the CUSTOMERS file using the CKEY encryption key for record
level encryption.
See also:
Data encryption, CREATE.FILE, CREATE.KEY, DELETE.KEY, GRANT.KEY,
LIST.KEYS, RESET.MASTER.KEY, REVOKE.KEY, SET.ENCRYPTION.KEY.NAME
2.11-0
QM Commands 307
4.69 FILE.SAVE
Format
where
account.list is a list of the names of the accounts to be saved. If omitted and the default
select list is active, this list is used to determine the accounts to be saved.
Otherwise, all accounts referenced in the QMSYS ACCOUNTS file are saved.
The FILE.SAVE command creates a Pick style "compatible mode" tape and saves one or more
QM accounts to it. Because the media format is defined by Pick, it has now way to represent a
distributed file. These will be omitted and a warning message will be displayed. The data elements
of the distributed file will be saved in the usual way so no data should be lost, however, it will be
necessary to recreate the distributed file itself if the data is restored.
The tape to be created must first be opened to the process using the SET.DEVICE command.
The command reports its progress by displaying the name of each file as it is saved unless the
DET.SUP option is used.
FILE.SAVE normally saves all files referenced by F-type records in the VOC of the account being
saved. There is a three level mechanism by which files can be excluded:
2.11-0
308 OpenQM
2. If field 5 of the VOC record does not specify any of the above flags, the
EXCLUDE.REMOTE and INCLUDE.REMOTE options are used to determine whether
remote files (those with a directory delimiter in their pathnames) are to be saved.
3. If neither of the above methods of file selection is used, the value of the EXCLREM
configuration parameter is used to determine whether remote files are to be saved.
By use of a combination of the above methods, it should be possible to achieve total control of what
is included in a save.
Encryption
FILE.SAVE operates within the security rules imposed by use of QM's encryption features. Files
that use record level encryption will not be saved if the user performing the save does not have
access to the encryption key. The data saved for files that use field level encryption will have all
fields for which the user is denied access set to null strings. All saved data is recorded in decrypted
form and hence storage of FILE.SAVE media may reduce system security. The media format used
by FILE.SAVE is an industry standard that does not provide a way to record details of data
encryption. Restoring a save in which encrypted fields have been omitted is unlikely to yield a
usable file. Backup of accounts that include encrypted data should be performed using operating
system level tools.
See also:
ACCOUNT.RESTORE, ACCOUNT.SAVE, FIND.ACCOUNT, RESTORE.ACCOUNTS,
SEL.RESTORE, SET.DEVICE, T.ATT, T.DUMP, T.LOAD, T.xxx
2.11-0
QM Commands 309
4.70 FILE.STAT
Format
where
account.list is a list of the names of the accounts to be reported. The ALL keyword may be
used to process all accounts. If neither ALL nor a list of accounts is given, a
report is produced for the current account.
LPTR directs the report to the default printer (print unit 0) instead of the screen.
The FILE.STAT command can be used to report a summary of the files present in one of more
accounts. The report that it produces requires a minimum output width of 132 characters.
The mode of operation is determined by the first name in the command line. If this is an account
name, the command reports files in one or more accounts, otherwise the command reports details of
one or more files in the current account.
2.11-0
310 OpenQM
Columns that are not applicable to directory files will be left blank for such files.
See also:
ANALYSE.FILE
2.11-0
QM Commands 311
4.71 FIND.ACCOUNT
Format
FIND.ACCOUNT account.name
where
The tape to be restored must first be opened to the process using the SET.DEVICE command.
Use of FIND.ACCOUNT with an account name that is not present on the tape can be used display
a list of accounts that are on the tape.
See also:
ACCOUNT.RESTORE, ACCOUNT.SAVE, FILE.SAVE, RESTORE.ACCOUNTS,
SEL.RESTORE, SET.DEVICE, T.ATT, T.DUMP, T.LOAD, T.xxx
2.11-0
312 OpenQM
4.72 FIND.PROGRAM
Format
FIND.PROGRAM name
where
The FIND.PROGRAM command examines the local, private and global catalogue areas to locate
the program catalogued as name. If found, it reports the catalogue mode, compilation date/time and
program type. If the program is in more than one catalogue area, they are each reported separately
in the same search order as is used when loading programs into memory.
The FIND.PROGRAM command can be useful in diagnosing problems where the system appears
to be running the wrong version of a program as a result of it being catalogued in multiple
locations.
Example
:FIND.PROGRAM DTMOD
Program is in private catalogue
Compiled 20 Jan 09 16:24:16
Subroutine with 3 arguments
See also:
CATALOGUE
2.11-0
QM Commands 313
4.73 FORMAT
Format
where
file.name is the name of the directory file holding the QMBasic source program. If
omitted, the filename defaults to BP.
If the record.name is omitted and select list 0 is active, this is used as the source of record names to
be formatted. Entries in this select list with a .H suffix are ignored. Thus the command
SELECT BP
The FORMAT command reformats a QMBasic program to comply with a conventional indentation
standard. Programs may be entered with no regard to indentation and subsequently tidied up using
FORMAT.
FORMAT will not move line breaks. Statements must be correctly delimited. The format actions
performed are:
Statements inside conditional blocks (THEN, ELSE, ON ERROR, LOCKED, CASE, etc.)
are indented by three columns.
WHILE and UNTIL statements are aligned with their corresponding LOOP or FOR
statement.
Spaces before commas in statements or argument lists are removed. A single space will follow
such a comma.
Labels are aligned to the left margin and any further text except comments is moved to the next
line.
A comment on the same line as a statement is not moved unless not to do so would place it over
the statement or with less than one space before the semicolon.
2.11-0
314 OpenQM
Comment lines which commence with spaces are moved to the alignment of the surrounding
code except where the preceding line was a comment (excluding trailing comments) in which
case the line is aligned with the preceding line.
EQUate and $DEFINE lines are unchanged to preserve possible user defined column
alignment.
The CASE option converts all language elements, labels and data names to lowercase. Names
corresponding to EQUate or $DEFINEd tokens retain the casing of the definition.
Where a $INCLUDE directive is encountered, the include record is read to establish any
EQUATE or $DEFINE tokens in it. All references to these tokens in the record being
formatted are converted to upper case. The include record itself is not changed.
If FORMAT fails because of faulty syntax such as unmatched THEN and END statements, the
source record remains unchanged. Diagnostic messages to aid location of such errors are displayed.
Example
1 2 3 4 5
12345678901234567890123456789012345678901234567890123456789
SUBROUTINE GET.DATE(PROMPT.TEXT, VALUE)
LOOP
DISPLAY PROMPT.TEXT:;* Prompt for date
INPUT NEW.DATE
VALUE = ICONV(NEW.DATE,"DDMY");* Convert the date
WHILE STATUS()
REPEAT
END
1 2 3 4 5
12345678901234567890123456789012345678901234567890123456789
SUBROUTINE GET.DATE(PROMPT.TEXT, VALUE)
LOOP
DISPLAY PROMPT.TEXT : ;* Prompt for date
INPUT NEW.DATE
VALUE = ICONV(NEW.DATE, "DDMY") ;* Convert the date
WHILE STATUS()
REPEAT
END
1 2 3 4 5
12345678901234567890123456789012345678901234567890123456789
subroutine get.date(prompt.text, value)
loop
display prompt.text : ;* Prompt for date
input new.date
value = iconv(new.date, "DDMY") ;* Convert the date
2.11-0
QM Commands 315
while status()
repeat
end
2.11-0
316 OpenQM
4.74 FORM.LIST
The FORM.LIST command creates an active select list from a list of record keys in a file.
Format
where
file.name is the name of the file holding the list of record keys to be used to form the
select list. The DICT qualifier specifies that the dictionary of the file is to be
processed.
record.id is the name of the record in file.name holding the list of record keys to be used
to form the select list.
The FORM.LIST command reads the named record and uses it to form active select list zero. Any
previously active select list zero is discarded. Typically, the list of record keys has been generated
by a user written program.
Example
In this example, a record named INVENTORY in file INVENT.LISTS is restored to become active
select list zero.
See also:
GET.LIST, SAVE.LIST
2.11-0
QM Commands 317
4.75 FSTAT
Format
where
file.name is the name of the file to be processed. Multiple file names may be included in a
single command. Alternatively, if no file.name is specified and the default select
list is active, this list will be used to determine the files to be processed.
LPTR directs the report to the default printer. When reporting for multiple files, each file's
data appears on a separate page.
The FSTAT command controls collection and reporting of file access statistics for dynamic files
and any associated alternate key indices. Directory files cannot be used with this command but are
included in the global statistics.
Use of FSTAT with the ON keyword clears the statistics counters associated with the file and
enables collection of statistics. The overhead for data collection is extremely low except that a file
that is opened to read only a few records will require a write to update the counters on disk when
the file is closed. The LISTF, LISTFL and LISTFR commands can be used to determine which
files have file statistics enabled.
The second form of FSTAT displays or prints a report of the file access statistics. Data collection
must be enabled when this mode is used. When using a select list, entries that do not correspond to
dynamic files for which statistics are enabled will be ignored.
The GLOBAL keyword displays a report of statistics accumulated across all files regardless of
whether statistics collection is enabled for the individual files. The global counters are reset when
QM is started. On Windows NT and later, this occurs automatically when the last user leaves QM
unless QMSvc has been configured to maintain a persistent shared memory image. The counters
can be reset manually by use of the RESET keyword.
Use of the FSTAT command with no arguments displays a periodic display of the global statistics,
updated once per second. This shows four columns; the overall data since the counts were last reset,
the data since FSTAT was entered, the data for the last second and average per-second values
since FSTAT was entered.
2.11-0
318 OpenQM
Example
2.11-0
QM Commands 319
4.76 GENERATE
Format
GENERATE file.name
where
file.name is the name of the file for which the dictionary is to be processed.
Well structured QMBasic programs should not reference fields by field number but should instead
use names defined using EQUATE tokens. The GENERATE command processes the dictionary
of a named file and constructs an include record with an entry for each field. Optionally, it can also
produce tokens for conversion codes associated with fields.
The generation process is controlled by an X-type record named $INCLUDE in the dictionary. The
fields of this record are:
1 X
2 Target file name for include record. Defaults to BP.
3 Record name to be produced for dynamic array style tokens. Defaults to file.name with .H
suffix.
4 Token prefix for dynamic array style tokens. Each token produced is constructed from the
field name with this prefix. The prefix is separated from the field name by a dot.
5 Text to be inserted into copyright line.
6 "S" if only a single entry is to be included for any field. This is the default. "M" if multiple
D-type records for the same field location should produce separate include tokens. If
duplicates are not enabled, a warning message will be displayed if multiple dictionary
entries are found defining the same field.
7 Include conversion code tokens? "N" omits conversion tokens. "Y" generates tokens for
fields that have conversion codes. "A" generates tokens for all fields including those with a
null conversion code.
8 Type to create: D for dynamic array tokens (default), M for matrix tokens. Both may be
used together in either order.
9 Record name to be produced for matrix style tokens. Defaults to file.name with .MAT.H
suffix.
10 Matrix name for matrix style tokens. Defaults to file.name.
11 Token prefix for matrix style tokens. Each token produced is constructed from the field
name with this prefix. The prefix is separated from the field name by a dot.
If the $INCLUDE record does not exist, it will be created when GENERATE is first run for the
file. A prompt will be issued for the type of tokens to be generated (field 8) and the prefix character
to be inserted into fields 4 and/or 11. All other fields will be left empty except for field 1 (X).
2.11-0
320 OpenQM
When creating the matrix style include record for use with MATREAD, the matrix is dimensioned
to have one more element than the highest field number referenced in the dictionary. This allows for
the different ways in which normal and Pick style matrices handle unexpected fields.
2.11-0
QM Commands 321
4.77 GET.LIST
Format
where
The GET.LIST command retrieves a previously saved select list from $SAVEDLISTS. If the
target list list.no was already active, the retrieved list replaces the previous list.
Examples
GET.LIST OVERDUE.INVOICES
57 records selected.
This example restores the default select list from a list named OVERDUE.INVOICES in the
$SAVEDLISTS file.
GET.LIST INVENTORY TO 3
91 records selected.
See also:
COPY.LIST, DELETE.LIST, EDIT.LIST, FORM.LIST SAVE.LIST, SORT.LIST
2.11-0
322 OpenQM
4.78 GET.STACK
Format
GET.STACK {stack.name}
where
stack.name is the name of the saved command stack. A prompt is issued if this name is
omitted.
The GET.STACK command replaces the current command stack with the record named
stack.name from the $SAVEDLISTS file. The previous content of the command stack is discarded.
Example
GET.STACK <<@LOGNAME>>
Command stack restored from 'jsmith'
This command restores the command stack from a record with id as the user's login name in the
$SAVEDLISTS file.
See also:
CLEAR.STACK, SAVE.STACK
2.11-0
QM Commands 323
4.79 GO
Format
GO label{:}
Any number of lines in a paragraph may be labelled. A label name consists of any sequence of
characters except for spaces and mark characters. The label must be terminated with a colon and, if
there is a command on the same line as the label, there must be at least one space after the colon.
The label name in the GO command may be followed by an optional colon with no intervening
spaces.
The command processor scans forwards through the current paragraph for a line with the given
label. An error is reported if the label is not found and the paragraph is aborted. It is valid for a
paragraph to contain multiple instances of the same label name though this is not recommended as it
can make maintenance more difficult.
It is not possible to jump backwards within a paragraph or from a GO command in one paragraph
to a label in another paragraph.
Example
DISPLAY Line 1
GO SKIP
DISPLAY Line 2
DISPLAY Line 3
SKIP: DISPLAY Line 4
DISPLAY Line 5
would display
Line 1
Line 4
Line 5
2.11-0
324 OpenQM
4.80 GRANT.KEY
The GRANT.KEY command grants access to a specific data encryption key. This command can
only be executed by users with administrator rights in the QMSYS account.
Format
where
name ... is a list if usernames for users to be granted access. If prefixed by the GROUP
keyword, this is a list of user groups. On Windows systems, user and group names
are stored as entered but treated as case insensitive internally. On other platforms,
user and group names are case sensitive.
The GRANT.KEY command grants access to an encryption key to one or more users or user
groups. The user will be asked to enter the master key unless it has already been entered during this
session.
No error occurs if the user or group specified already has access to the key.
Example
The above command grants access to the encryption key named CARDNO for users jsmith and
bjones.
See also:
Data encryption, CREATE.FILE, CREATE.KEY, DELETE.KEY, ENCRYPT.FILE,
LIST.KEYS, RESET.MASTER.KEY, REVOKE.KEY, SET.ENCRYPTION.KEY.NAME,
UNLOCK.KEY.VAULT
2.11-0
QM Commands 325
4.81 HELP
The HELP command provides help on a wide variety of topics. This command is not available on
the PDA version of QM.
Format
HELP
The HELP command invokes the Windows help system in the same way as selection of the help
option from the QM program group. The help system is not available for users connecting from
non-Windows clients though there is a browser based HTML help package available by download.
The operation of this system depends on the way in which the user has entered QM:
· For QM Console users on a Windows server, the help system is invoked on the server for
the specified topic.
· For QMTerm users, a command is sent to the QMTerm session to cause it to open a help
window on the client system. The qm.hlp file must be installed in the QMSYS directory of
the client system.
· For other network users, QM checks the definition of the terminal type in use and, if the u8
(asynchronous command) entry is defined, executes the winhlp32 program on the client
system. The qm.hlp file must be installed in the default location (c:\qmsys\qm.hlp).
· For terminals where the u8 code is not defined, the help system must be run from the QM
program group.
2.11-0
326 OpenQM
4.82 HSM
The HSM command controls the Hot Spot Monitor performance monitoring tool. This command is
not available on the PDA version of QM.
Format
The Hot Spot Monitor records the number of times each program module is called and the
processor time in seconds spent in that module.
The HSM ON command clears any old data and starts monitoring.
The HSM DISPLAY command displays the collected data. It may be used while monitoring is
active or after it has been switched off. The DISPLAY keyword can be omitted.
The USER n option causes the command to affect the specified user and is useful in monitoring
processes that do not display a command prompt.
Note that although QM maintains processor timings internally to microsecond precision and reports
the figures to millisecond precision, some platforms do not provide the raw data to this level. For
example, some Linux systems only report processor usage in units of one hundredth of a second.
Example
HSM ON
... processing ...
HSM DISPLAY
Calls.. CP time... Program
1 0.000 !SCREEN
13 0.060 $CPROC
18 0.000 !PARSER
1 0.000 PRINT.DEFERED
4 0.010 $SETPTR
1 0.000 CHARGE.TOTAL
19 0.034 CALC.INVOICE.VALUE
24 0.000 ADD.MONTH
3 0.000 REVERSE
1 0.000 C:\QM\BP.OUT\PROC
6 17.040 C:\QM\BP.OUT\FINANCE
19 14.010 C:\QM\BP.OUT\INVOICE
1 0.800 C:\QM\BP.OUT\CHECK_EX
1 0.000 $HSM
2.11-0
QM Commands 327
4.83 HUSH
Format
The HUSH command allows temporary suspension of display output. Output is automatically
resumed in the event of an abort.
Example
HUSH ON
SELECT STOCK WITH QTY < REORDER.LEVEL
HUSH OFF
This sequence selects records from the STOCK file but suppresses any terminal output from the
SELECT command. Use of the COUNT.SUP option to SELECT might be a better alternative in
this example.
2.11-0
328 OpenQM
4.84 IF
Format
where
value.1, value.2 are two items to be compared. These may be inline prompts, constants
or @-variables as described below.
In its first form, the IF command compares two values using a specified relational operator. The
values may be inline prompts, constants or @-variables. Null strings or string constants which
include spaces should be enclosed in single or double quotation marks. The value.1 and value.2
items need to be quoted if they may evaluate to strings with embedded spaces or to reserved words
such as the relational operators.
Note that because inline prompts are evaluated as the first stage of processing a command, an inline
prompt in the sentence component of an IF statement will be evaluated before determining whether
the condition is true. To avoid this problem, a statement such as
IF @SYSTEM.RETURN.CODE = 1 THEN LIST <<Filename>>
must be written as
IF @SYSTEM.RETURN.CODE # 1 THEN GO SKIP
LIST <<Filename>>
SKIP:
2.11-0
QM Commands 329
The function of each relational operator as applied to values of different types is the same as its
QMBasic equivalent
The second and third forms of IF check the existence or non-existence of a record. The filename
and id values are identify the file and record id. If the record id contains spaces or other special
characters, it must be enclosed in quotes.
Multiple conditions may be linked by the keywords AND and OR. These operators are of equal
priority and are evaluated left to right. Use of brackets to alter the order of interpretation is not
supported in the IF command.
Examples
PA
BASIC <<Program name>>
IF @SYSTEM.RETURN.CODE = 1 THEN CATALOGUE <<Program name>>
This paragraph compiles a QMBasic program (the record name of which it obtains using an inline
prompt) and, if successful, adds the program to the system catalogue. In this example, use of the
inline prompt in the conditioned statement is not a problem as the prompt was displayed as part of
processing of the previous line.
This example shows how it is possible to produce the effect found in some other multivalue
products where each user may have a separate initialisation script instead of the single LOGIN
paragraph used in QM. Inserting this line in the LOGIN paragraph would check if there was a
paragraph with the same name as the user's login name and, if so, execute it.
2.11-0
330 OpenQM
4.85 INHIBIT.LOGIN
Format
The INHIBIT.LOGIN command can be used to prevent users logging in while system
maintenance tasks are in progress. The command can only be executed by users with administrator
rights.
With the ON option, this command disables further logins. The action will fail if the login inhibit is
already active from some other user.
When executed with the OFF option by the user that set the login inhibit, logins are re-enabled.
With neither option, the command displays the current state of the login inhibit mechanism.
In all cases, @SYSTEM.RETURN.CODE is set to the user number of the user that has set the
login inhibit or to zero if logins are allowed. Success is indicated by the value of
@SYSTEM.RETURN.CODE being equal to @USERNO after use of ON, or zero after use of
OFF.
While logins are inhibited, no new QM processes can be started except for phantom processes
started by the user that set the inhibit. Setting a login inhibit does not logout other users who are
already active.
The login inhibit is automatically released if the user that set it logs out.
Example
INHIBIT.LOGIN ON
RUN SYSTEM.BACKUP
INHIBIT.LOGIN OFF
This sequence prevents new users logging in while the SYSTEM.BACKUP program is executed.
2.11-0
QM Commands 331
4.86 LIST.COMMON
Format
LIST.COMMON
The LIST.COMMON command displays a list of all currently created QMBasic named common
blocks for the process in which the command is executed.
Example
LIST.COMMON
SYS.FILES
SCREEN.DATA
See also:
DELETE.COMMON
2.11-0
332 OpenQM
4.87 LIST.DF
The LIST.DF command lists the part files that form a distributed file.
Format
LIST.DF dist.file
where
The LIST.DF command produces a report that shows the partitioning algorithm name and source
code followed by a list of the part file numbers and their associated pathnames in a distributed file.
Example
LIST.DF ORDERS
Partitioning algorithm: PART.ALG
OCONV(@ID['-',1,1],'DY')
See also:
Distributed files, ADD.DF, REMOVE.DF
2.11-0
QM Commands 333
4.88 LIST.DIFF
The LIST.DIFF command creates a new named select list from the entries that appear in one
named list but not in another named list.
Format
where
list1, list2 identify the select lists to be merged. These must correspond to the names
of records in the $SAVEDLISTS file. If list2 is omitted, a prompt is
displayed for the name.
tgt.list is the name of the new list to be created in $SAVEDLISTS. It is valid for
tgt.list to be the same as one of the source lists. if tgt.list is omitted, a
prompt is displayed for this name.
COUNT.SUP indicates that display of the record count in the merged list is to be
suppressed.
The LIST.DIFF command allows construction of one select list from two others. The resultant list
will contain all of the items that are in list1 but not in list2.
The result list will replace any existing list with the name tgt.list. The ordering of tgt.list is
undefined.
@SYSTEM.RETURN.CODE is set to the number of items in the new list or a negative error code.
Example
This example merges two previously saved select lists, one holding keys for customers in France,
the other for major customers to form a new list containing non-major French customers.
See also:
LIST.INTER, LIST.UNION, MERGE.LIST
2.11-0
334 OpenQM
4.89 LIST.FILES
Format
LIST.FILES
LIST.FILES BRIEF
LIST.FILES DETAIL {{DICT } filename}
LIST.FILES USER {n}
The LIST.FILES command displays the number of files currently open, the peak number of files
open and the limit on the number of open files as set by the NUMFILES configuration parameter.
The BRIEF option restricts the output to show only the first line. Without this option, the
pathnames of all open files are shown.
The DETAIL option extends the report to show the user numbers and user names for each open
file. Used with a file name, it shows only users who have the named file open.
The USER option shows the pathnames of all files open to the specified QM user number. If the
number is omitted, the command shows all files open to the user executing the command.
The NUMFILES configuration parameter is a hard limit on the number of files that may be open at
one time by all QM users. A file opened by multiple users only counts as one file. Attempting to
exceed this limit will cause the application to fail. The displayed peak open count is useful in
determining whether the value of NUMFILES is large enough.
Example
LIST.FILES
Number of files open = 4. Peak = 16. Limit (NUMFILES) = 40.
C:\QM\VOC
C:\QMSYS\$IPC
C:\QM\BP
C:\QM\&SED.EXTENSIONS&
The example above shows the default output from LIST.FILES with the counts and the file
pathnames. Adding the BRIEF option, as below, shows only the counts.
LIST.FILES BRIEF
Number of files open = 4. Peak = 16. Limit (NUMFILES) = 40.
Use of the DETAIL option shows the user numbers and user names of the QM users that have the
files open.
LIST.FILES DETAIL
Number of files open = 4. Peak = 16. Limit (NUMFILES) = 40.
2.11-0
QM Commands 335
C:\QM\VOC
2 smithm, 7 sales
C:\QMSYS\$IPC
2 smithm, 7 sales
C:\QM\BP
7 sales
C:\QM\&SED.EXTENSIONS&
7 sales
2.11-0
336 OpenQM
4.90 LIST.INDEX
The LIST.INDEX command reports details of one or more alternate key indices.
Format
where
field(s) are the names of the fields to be reported. The keyword ALL can be used
instead of a list of fields to report all indices on the file.
LPTR directs the report to the default printer (printer 0). The optional n qualifier
directs the report to an alternative printer.
The first form of the LIST.INDEX command reports information about alternate key indices in
the filename for the named field(s). If no field(s) are specified on the command line, the user is
prompted to enter the indexed field name.
The second form with the ALL keyword in place of the filename produces a composite report of all
files in the account that have alternate key indices. The LOCAL qualifier omits files referenced via
Q-pointers.
2.11-0
QM Commands 337
Use of the STATISTICS (short form STATS) keyword extends the report to include statistical
information about the index showing the number of index entries (different field values) and the
minimum, average and maximum number of records per index entry.
Use of the DETAIL keyword shows the statistics and also shows up to 63 characters of each key
value and the number of records for that key value.
See also:
BUILD.INDEX, CREATE.INDEX, DELETE.INDEX, DISABLE.INDEX, MAKE.INDEX,
REBUILD.ALL.INDICES
2.11-0
338 OpenQM
4.91 LIST.INTER
The LIST.INTER command creates a new named select list from the entries that appear in both of
two other named lists.
Format
where
list1, list2 identify the select lists to be merged. These must correspond to the names
of records in the $SAVEDLISTS file. If list2 is omitted, a prompt is
displayed for the name.
tgt.list is the name of the new list to be created in $SAVEDLISTS. It is valid for
tgt.list to be the same as one of the source lists. if tgt.list is omitted, a
prompt is displayed for this name.
COUNT.SUP indicates that display of the record count in the merged list is to be
suppressed.
The LIST.INTER command allows construction of one select list from two others. The resultant
list will contain all of the items that are in both list1 and list2.
The result list will replace any existing list with the name tgt.list. The ordering of tgt.list is
undefined.
@SYSTEM.RETURN.CODE is set to the number of items in the new list or a negative error code.
Example
This example merges two previously saved select lists, one holding keys for customers in France,
the other for major customers to form a new list containing the major customers in France.
See also:
LIST.DIFF, LIST.UNION, MERGE.LIST
2.11-0
QM Commands 339
4.92 LIST.KEYS
Format
where
The first form of the LIST.KEYS command is available only to users with administrator rights in
the QMSYS account. It produces a report of the encryption key names defined in the key vault,
showing the encryption algorithm name and the users who have access to the key. The actual
encryption key is not reported. The user will be asked to enter the master key unless it has already
been entered during this session.
The second form of the LIST.KEYS command is available to all users and produces a report of the
encryption keys used by the named file.
In either form, the LPTR keyword can be used to direct the output to a printer. If the print unit
number is omitted, the default printer (unit 0) is used.
Examples
LIST.KEYS
Key.............. Algorithm Users..............
Groups.............
CARDNO AES128 jsmith
bjones
RHKEY AES256 jsmart
The above example shows the report from the first format of the LIST.KEYS command. There are
two encryption keys defined on this system.
LIST.KEYS CLIENTS
Filename: CLIENTS
Pathname: /usr/sales/CLIENTS
Field 7, CARDNO
Field 22, RHKEY
The above example shows the report from the second format of the LIST.KEYS command. The
CLIENTS file uses field level encryption with a different key for each encrypted field.
See also:
2.11-0
340 OpenQM
2.11-0
QM Commands 341
4.93 LIST.LOCKS
The LIST.LOCKS command reports the state of the 64 system wide task locks.
Format
LIST.LOCKS
The LIST.LOCKS command displays a table of locks showing the user number of the process
holding each of the 64 task locks where appropriate. The displayed user number is followed by an
asterisk if it is the process from which the LIST.LOCKS command was executed.
Examples
LIST.LOCKS
0: 1: 2: 3: 4: 5: 6: 7: 1*
8: 9: 10: 11: 12: 13: 14: 15:
16: 17: 18: 19: 3 20: 21: 22: 23:
24: 25: 26: 27: 28: 29: 30: 31:
32: 33: 34: 35: 36: 37: 38: 39:
40: 41: 42: 43: 44: 45: 46: 47:
48: 49: 50: 51: 52: 53: 54: 55:
56: 57: 58: 59: 60: 61: 62: 63:
This example shows the display when task locks 7 and 19 are in use. Lock 7 is held by user 1 who
also issued the LIST.LOCKS command. Lock 19 is held by user 3.
LIST.LOCKS
No task locks reserved by any user
See also:
CLEAR.LOCKS, LIST.LOCKS, LOCK (command), LOCK (QMBasic), UNLOCK
2.11-0
342 OpenQM
4.94 LIST.PHANTOMS
Format
LIST.PHANTOMS
Example
LIST.PHANTOMS
User Pid Username Login time Account
2 5001 root 28 May 07:02 QMSYS
34 5220 jenny 28 May 11:24 SALES
See also:
CHILD(), PHANTOM, !PHLOG(), STATUS
2.11-0
QM Commands 343
4.95 LIST.READU
Format
where
user is the user number for which the locks are to be reported. If omitted, all locks
are displayed.
DETAIL includes the limit, current count and peak number of record locks.
LPTR {n} directs output to logical print unit n. If n is omitted, it defaults to zero, the
default print unit.
WAIT includes details of users waiting for locks held by other users.
The LIST.READU command displays or prints details of file, read and update locks held by one or
all users.
Example
In the above report, users 1 and 5 hold record update locks in file 2 (D:\SALES\STOCK) and user
2 has a file lock on file 4 (D:\SALES\INVOICES). User 3 is waiting to lock record 17565 in file 4
but is blocked by user 2. Details of users waiting for locks are only shown if the WAIT keyword is
used.
The first line of the above report is only shown if the DETAIL keyword is used. Note that the
counts are for active record locks only. The file lock and the user waiting for a lock in this example
do not contribute to these numbers. The peak number of locks is useful in determining a good value
for the NUMLOCKS configuration parameter.
The file number is an internal reference to the file and is also needed for the UNLOCK command.
The lock type is shown as RL for shareable record locks, RU for record update locks and FX for
2.11-0
344 OpenQM
file locks. A type code of WAIT is shown for users waiting for locks.
2.11-0
QM Commands 345
4.96 LIST.SERVERS
The LIST.SERVERS command shows a list of QMNet servers known to the system.
Format
QMNet allows an application to access QM data files on other servers as though they were local
files, with complete support for concurrency control via file and record locks. Public servers are
visible to all users and are defined by the system administrator using the SET.SERVER command.
Private servers are defined using SET.PRIVATE.SERVER and are local to the QM session in
which they are defined.
The LIST.SERVERS command displays a list of the server names that have been defined and to
which the user has access. It shows the QM name for the server, the IP address or network name,
the port number, the security status, and the user name that will be used to connect.
The security status column, applicable only to public servers, indicates whether specific security
rules have been set for this server. See the ADMIN.SERVER command for more details.
The ALL option, available only to users with administrative rights, includes servers to which the
user has no access.
The DETAIL keyword, available only to users with administrative rights, extends the report to
show the users/groups that have access for each remote user name. This report needs a screen width
of at least 120 characters.
The LPTR keyword directs the report to a printer. If the unit number n is not given, the default
printer (unit 0) is used.
Example
LIST.SERVERS
Public Servers.. IP address.............. Port... Sec User
name...........
SALES 193.100.13.11 Default No
martin
ADMIN 193.100.13.18 4000 Yes root
Private Servers. IP address.............. Port... Sec User
name...........
HR 193.100.13.41 Default tony
See also:
QMNet, ADMIN.SERVER, DELETE.SERVER, SET.SERVER
2.11-0
346 OpenQM
4.97 LIST.TRIGGERS
The LIST.TRIGGERS command displays a summary of all trigger subroutines used within an
account.
Format
where
LPTR {n} directs output to print unit n. If n is omitted, it defaults to zero, the default
print unit.
The LIST.TRIGGERS command displays a summary of all trigger functions used by files that are
referenced by F or Q type VOC entries unless the LOCAL option is used to omit Q-pointer files.
For each file that has a trigger defined, the command shows the file name, the trigger function name
and the events that activate the trigger. The events are shown in two columns, one for pre-event and
one for post-event, using letters W (write), R (read), D (delete) and C (clear).
Example
In the above report, the ORDERS file has a trigger function named STOCK.CHECK that is
activated for post-write and post-delete events. The STAFF file has a pre-write trigger named
STF.VALIDATE.
2.11-0
QM Commands 347
4.98 LIST.UNION
The LIST.UNION command creates a new named select list from the entries that appear in either
of two other named lists. Items that appear in both lists are not duplicated.
Format
where
list1, list2 identify the select lists to be merged. These must correspond to the names
of records in the $SAVEDLISTS file. If list2 is omitted, a prompt is
displayed for the name.
tgt.list is the name of the new list to be created in $SAVEDLISTS. It is valid for
tgt.list to be the same as one of the source lists. if tgt.list is omitted, a
prompt is displayed for this name.
COUNT.SUP indicates that display of the record count in the merged list is to be
suppressed.
The LIST.UNION command allows construction of one select list from two others. The resultant
list will contain all of the items that are in list1 plus all of the items in list2 that are not also in list1.
The result list will replace any existing list with the name tgt.list. The ordering of tgt.list is
undefined.
@SYSTEM.RETURN.CODE is set to the number of items in the new list or a negative error code.
Example
This example merges two previously saved select lists, one holding keys for customers in France,
the other for major customers to form a new list containing the major customers in France.
See also:
LIST.DIFF, LIST.INTER, MERGE.LIST
2.11-0
348 OpenQM
4.99 LIST.USERS
The LIST.USERS command lists users from the register of users for security checks. The
command is restricted to users with administrator rights.
Format
LIST.USERS
The LIST.USERS command lists the names of all entries in the user name register. This may
include an entry for Console, the pseudo name used for QMConsole connections on Windows
98/ME.
The report shows the user name, the login account (if set), the date and time of last login, whether
the user has administrator rights and whether there are account restrictions on this user. For more
details regarding account restrictions, see Application Level Security.
Example
LIST.USERS
User name....................... Login account... Last
login..... Adm Restr
ADMINISTRATOR 22 Oct 06
17:27 Yes No
BERT QMTEST 04 Nov 02
10:40 No Yes
Console 03 Nov 06
13:49 Yes No
GEORGE SALES 03 Nov 06
09:03 No Yes
MARTIN 01 Nov 06
17:23 No Yes
See also:
ADMIN.USER, CREATE.USER, DELETE.USER, PASSWORD, SECURITY, Application
Level Security
2.11-0
QM Commands 349
4.100 LIST.VARS
Format
LIST.VARS {ALL}
The LIST.VARS command displays the values of user defined @-variables. The optional ALL
keyword extend the display to include the standard @USER.RETURN.CODE and @USER0 to
@USER4 variables.
Example
LIST.VARS
LOOP.CT : 7
LAST.LOG: 41926
See also:
SET
2.11-0
350 OpenQM
4.101 LISTDICT
LISTDICT is a paragraph that lists a dictionary in a format similar to that used by Pick style
systems.
Format
where
filename is the name of the file for which the dictionary is to be listed.
The LISTDICT paragraph reports A and S-type dictionary items in a format similar to that used
by Pick style systems. D and I-type items are also included though the column headings may not
truly reflect the role of the item. The column widths in the report are different depending on the
width of the terminal display.
LISTDICT shows only A, D, I and S-type records. The entire content of a dictionary can be
viewed using LIST.
Examples
LISTDICT ORDERS
The above command produces a Pick style representation of the records in the dictionary of the
ORDERS file.
The above command produces a report of all records in the dictionary of the ORDERS file in the
default QM dictionary list format.
2.11-0
QM Commands 351
4.102 LISTF
Format
LISTF {LPTR}
The LISTF command is a sentence to list all F type VOC entries. The listing shows the VOC name
of the file, the file type, the description (field 1 of the VOC entry), the data portion pathname (field
2) and the dictionary pathname (field 3). The report is sorted by file name.
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
See also:
CREATE.FILE, DELETE.FILE, LISTFL, LISTFR
2.11-0
352 OpenQM
4.103 LISTFL
The LISTFL command lists all files defined in the VOC that are local to the account.
Format
LISTFL {LPTR}
The LISTFL command is a sentence to list all F type VOC entries referencing files that are local to
the account. Selection is performed by reporting only those records for which the data portion
pathname does not contain a back slash. It is thus possible to defeat this selection process by using
absolute pathnames for local files. The CREATE.FILE command always uses the file name only
for a local file.
The listing shows the VOC name of the file, the file type, the description (field 1 of the VOC entry),
the data portion pathname (field 2) and the dictionary pathname (field 3). The report is sorted by
file name.
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
See also:
CREATE.FILE, DELETE.FILE, LISTF, LISTFR
2.11-0
QM Commands 353
4.104 LISTFR
The LISTFR command lists all files defined in the VOC that are remote to the account.
Format
LISTFR {LPTR}
The LISTFR command is a sentence to list all F type VOC entries referencing files that are remote
to the account. Selection is performed by reporting only those records for which the data portion
pathname contains a back slash. It is thus possible to defeat this selection process by using absolute
pathnames for local files. The CREATE.FILE command always uses the file name only for a local
file.
The listing shows the VOC name of the file, the file type, the description (field 1 of the VOC entry),
the data portion pathname (field 2) and the dictionary pathname (field 3). The report is sorted by
file name.
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
See also:
CREATE.FILE, DELETE.FILE, LISTF, LISTFL
2.11-0
354 OpenQM
4.105 LISTK
Format
LISTK {LPTR}
The LISTK command is a sentence to list all K type VOC entries defining keywords.
The listing shows the keyword, the description (field 1 of the VOC entry) and the keyword value.
The report is sorted by keyword value.
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
2.11-0
QM Commands 355
4.106 LISTM
Format
LISTM {LPTR}
The listing shows the VOC name of the menu and its title line.
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
2.11-0
356 OpenQM
4.107 LISTPA
Format
LISTPA {LPTR}
The listing shows the VOC name of the paragraph, the description (field 1 of the VOC entry) and
the first command in the paragraph (field 2).
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
2.11-0
QM Commands 357
4.108 LISTPH
Format
LISTPH {LPTR}
The listing shows the VOC name of the phrase, the description (field 1 of the VOC entry) and the
phrase expansion (field 2).
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
2.11-0
358 OpenQM
4.109 LISTPQ
Format
LISTPQ {LPTR}
The listing shows the VOC name of the PROC, the description (field 1 of the VOC entry) and the
first command in the PROC (field 2).
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
2.11-0
QM Commands 359
4.110 LISTQ
The LISTQ command lists all indirect file references defined in the VOC.
Format
LISTQ {LPTR}
The listing shows the VOC name of the item, the description (field 1 of the VOC entry), target
account (field 2), target file (field 3) and server name (field 4).
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
2.11-0
360 OpenQM
4.111 LISTR
The LISTR command lists all remote items defined in the VOC.
Format
LISTR {LPTR}
The listing shows the VOC name of the item, the description (field 1 of the VOC entry), the target
file (field 2) and the target record id (field 3).
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
2.11-0
QM Commands 361
4.112 LISTS
Format
LISTS {LPTR}
The listing shows the VOC name of the sentence, the description (field 1 of the VOC entry) and the
sentence expansion (field 2).
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
2.11-0
362 OpenQM
4.113 LISTU
The LISTU command lists the users currently in QM. This command is not available on the PDA
version of QM.
Format
LISTU {DETAIL}
The LISTU command displays a list of users in QM. For each user, it shows their QM user
number, the corresponding operating system process id and their network address or device name,
user name and account name. The network address is shown as "Console" for console users
(sessions running QM directly rather than a network connection) or "Phantom" for a background
process. The login time is shown in the local time zone of the user executing the command.
The user executing the LISTU command is marked by an asterisk at the left edge of the displayed
report. For phantom users, the parent user number is shown unless the original parent process has
logged out.
Use of the DETAIL keyword adds a line at the start of the report that shows:
· the current number of interactive (terminal user) processes
· the current number of QMClient processes
· the current number of interactive phantom processes that consume a QM licence
· the current number of other phantom processes that do not consume a QM licence
· the peak number of processes that consumed a licence since QM was started.
Example
LISTU
User Pid Puid Login time Origin : User name,
Account
* 1 156 15 Apr 11:48 Console: ADMINISTRATOR,
QMSYS
2 186 15 Apr 11:21 193.118.13.10: JSMITH,
SALES
4 196 2 15 Apr 12:02 Phantom: ADMINISTRATOR,
QMSYS
The example report above shows three processes logged on. The user running this command is
marked with an asterisk.
Use of the DETAIL keyword might produce a report such as that below, showing the current count
of each process type and the peak number of processes that were included in the licensed user
count.
LISTU DETAIL
2 interactive, 0 QMClient, 0 iPhantom, 1 phantom, 6 peak
User Pid Puid Login time Origin : User name,
Account
* 1 156 15 Apr 11:48 Console: ADMINISTRATOR,
2.11-0
QM Commands 363
QMSYS
2 186 15 Apr 11:21 193.118.13.10: JSMITH,
SALES
4 196 2 15 Apr 12:02 Phantom: ADMINISTRATOR,
QMSYS
See also:
LIST.PHANTOMS, STATUS
2.11-0
364 OpenQM
4.114 LISTV
Format
LISTV {LPTR}
The listing shows the VOC name of the verb, the description (field 1 of the VOC entry), the verb
type (field 2) and the processing function or internal dispatch code (field 3).
The LPTR keyword will direct the output to the printer. Other query processor keywords can be
appended to the command.
2.11-0
QM Commands 365
4.115 LOCK
Format
where
NO.WAIT specifies that the process is not to wait if the lock is not available.
The LOCK command sets one of the 64 system wide task locks. Four situations exist:
If the lock is available, the process acquires the lock and continues. @SYSTEM.RETURN.CODE
will be set to lock.number.
If the lock is already owned by this process, a warning message is displayed and execution
continues. @SYSTEM.RETURN.CODE will be set to lock.number.
If the lock is owned by another process and the NO.WAIT option has been used, a message is
displayed indicating the unavailability of the lock and the process continues. The value of
@SYSTEM.RETURN.CODE will be negative (-ER$LCK) and can be tested to check for this
situation in paragraphs.
If the lock is owned by another process and the NO.WAIT option has not been used, a message is
displayed indicating that the process is waiting and execution is suspended until the lock becomes
available. The break key may be used to interrupt this wait.
Examples
LOCK 5
Set task lock 5
In this example, task lock 5 was available when the LOCK command was executed.
LOCK 5
Waiting for task lock to become available
In this example, task lock 5 held by another process when the LOCK command was executed. The
process waits for the lock to become available.
LOCK 5 NO.WAIT
Task lock is already in use
As in the previous example, task lock 5 was held by another process when the LOCK command
2.11-0
366 OpenQM
was executed. In this case, the NO.WAIT option causes the process to continue without waiting for
the lock to become available.
See also:
CLEAR.LOCKS, LIST.LOCKS, LOCK (command), LOCK (QMBasic), TESTLOCK(),
UNLOCK
2.11-0
QM Commands 367
4.116 LOGIN.PORT
The LOGIN.PORT command logs in a serial port from within another QM session. This command
is currently only available on Windows systems.
Format
where
account is the QM account in which the user is to run. If omitted, the new process runs in
the same account as the user issuing the command.
The LOGIN.PORT command creates a new QM process that uses the named serial port as its
terminal device. This process will run with the same user name as the process performing the
command.
The new process will execute the MASTER.LOGIN and LOGIN paragraphs in the same way as
any other QM process. The LOGIN paragraph could be used, for example, to start a program that
monitors the named port for activity.
2.11-0
368 OpenQM
4.117 LOGMSG
The LOGMSG command adds a line to the system error log. This statement has no effect on the
PDA version of QM.
Format
LOGMSG text
where
This command is identical in effect to use of the LOGMSG statement in a QMBasic program.
QM includes the option to maintain a log of system error messages in a file named errlog in the
QMSYS account. The LOGMSG command can be used to write messages into this file. If the
error log is disabled, the LOGMSG command will be ignored.
2.11-0
QM Commands 369
4.118 LOGOUT
Format
LOGOUT {user}
LOGOUT ALL
where
user is the user number of the process to terminate. Multiple user numbers may be
given.
The LOGOUT command aborts the specified process. A user who does not have administrator
rights can only log out processes running under the same user name.
If user is omitted, the LOGOUT command terminates the user's own session.
The LOGOUT ALL form of the command, available only in the QMSYS account to users with
administrator rights, logs out all QM processes except the one from which it is issued.
When using a telnet connection to a PDA, this command also terminates the NETWAIT
connection monitor.
Example
LOGOUT 2
Phantom 2 : forced logout
See also:
QUIT
2.11-0
370 OpenQM
4.119 LOGTO
The LOGTO command moves to an alternative account directory without leaving QM.
Format
where
name is the name of the target account. This may be an account name as in the
ACCOUNTS register of the QMSYS account or the pathname of the new account
directory.
RESET causes the command processor to discard all active paragraphs, menus, etc.
If the user has account restrictions imposed on them (see Application Level Security), name must
be an account name, not be a pathname.
Multiple accounts are useful where there are several distinct projects. They can also be used to
separate development and production versions of an application.
The LOGTO command closes the current VOC, moves to the account directory specified by name
and opens the VOC of the new directory.
If the RESET keyword is present, any active programs, menus, etc at the current command
processor level are discarded. This is particularly useful when using LOGTO in a menu.
Use of RESET ALL discards all active programs, menus, etc and returns the the bottom level
command processor. If a higher level command processor had been started from a program that
used the TRAPPING ABORTS option of the QMBasic EXECUTE statement, the program will
not trap this action. The RESET ALL mode of LOGTO is not available in QMClient sessions.
If the VOC of the current account contains an executable item named ON.LOGTO, usually a
paragraph, this will be executed before moving to the new account.
If the VOC of the new account contains an executable item named LOGIN, this will be executed on
arrival in the new account.
If the LOGTO action is successful, the account name as reported by the WHO command or
returned as the value of the @WHO system variable is set to the new account.
The QUIT command to leave QM will return to the original account directory before exiting.
2.11-0
QM Commands 371
The LOOP and REPEAT commands define the top and bottom of a group of sentences to be
repeated within a paragraph.
Format
LOOP
sentence(s)
REPEAT
where
The LOOP and REPEAT statements surround one or more sentences to be repeated. The loop
continues until the paragraph terminates by use of STOP or ABORT, something run by the
paragraph causes an abort event, or a GO statement is used to leave the loop.
Loops may be nested to any depth. Each REPEAT statement is paired with a corresponding
LOOP statement and is equivalent to a GO statement that allows backward jumps to a label at the
position of the LOOP statement. The behaviour of paragraphs that branch into or out of loops can
be determined by this label and GO equivalent.
The keywords LOOP and REPEAT are recognised by the paragraph pre-processor and not via the
VOC and hence cannot be replaced by alternative words.
Example
PA
LOOP
IF <<A,File to delete>> = "" THEN GO DONE
DELETE.FILE <<File to delete>>
REPEAT
DONE:
This paragraph prompts for names of files to delete until a blank line is entered. Note the need for
the A control option on the first inline prompt in the loop so that the prompt is repeated on each
cycle.
Because the DONE label is at the end of the paragraph, the above example could alternatively be
written as
PA
LOOP
IF <<A,File to delete>> = "" THEN STOP
DELETE.FILE <<File to delete>>
REPEAT
2.11-0
372 OpenQM
4.121 MAKE.INDEX
The MAKE.INDEX command creates and builds an alternate key index. It is equivalent to use of
CREATE.INDEX followed by BUILD.INDEX.
Format
where
filename is the name of the file for which the index is to be built.
field(s) is one or more field names for which indices are to be created.
The MAKE.INDEX command creates the file structures to hold an alternate key index and then
builds the index.
The field(s) referenced in the command must correspond to D, I, A, S or C-type dictionary items.
The dictionary items can be deleted once the index has been constructed as all details of the indexed
field are stored in the index file but this is not recommended. The value to be indexed must not
exceed 255 characters. Values longer than this will not be included in the index.
Indices constructed on I or C-type dictionary items or on A or S-type items that use correlative
expressions should be such that they always produce the same result when executed for the same
data record. Examples of possibly invalid I-type expressions would be those that use the date or
time and those that use the TRANS() function to access other files.
The NO.NULLS specifies that no entry is to be added to the index for records where the indexed
field is null.
The NO.CASE option specifies that the index is to be built using case insensitive key values. The
internal sort order of the index is based on the uppercase form of the data being indexed. A case
insensitive index can be used with case insensitive comparison operators in the query processor but
not with case sensitive operations because of the sort order difference. Conversely, a case sensitive
index can be used with case sensitive comparison operators in the query processor but not with case
insensitive operations.
Normally, the indices are stored as subfiles in the directory that represents the data file. The
PATHNAME option allows the indices to be stored in an alternative location. This might be
useful, for example, to balance loads across multiple disks or to exclude indices from backups as
they can always be recreated.
All indices for a single data file must be stored together. The PATHNAME option can be used
when creating the first index and specifies the pathname of a new directory that will be created at
the same time as the index. If this option is included when creating subsequent indices the
index.path must be the same as for the first index. It is suggested that the pathname should be based
on the data file name for ease of recognition.
Index subfiles can be moved using the operating system level qmidx program.
2.11-0
QM Commands 373
Except when used with the CONCURRENT keyword, the MAKE.INDEX command requires
exclusive access to the file and may take some time to complete for a very large file. It is therefore
best executed at quiet times. The CONCURRENT keyword allows an index to be built while the
file is in use. There is a performance overhead for this and the QMBsaic SELECTINDEX,
SELECTLEFT and SELECTRIGHT statements may stall waiting for the build to complete.
Data Encryption
Alternate key indices may be applied to files that use record level data encryption but developers
should be aware that the index itself is not encrypted and hence weakens the security of the indexed
fields.
Files using field level encryption cannot have indices on encrypted fields. Also, indices constructed
from calculated values such as I-types that use encrypted fields will fail if the record is updated by
a user that does not have access to the relevant encryption key.
Example
The above command creates and builds an index on the DATE field of the ORDERS file.
See also:
BUILD.INDEX, CREATE.INDEX, DELETE.INDEX, DISABLE.INDEX, LIST.INDEX,
MAKE.INDEX, REBUILD.ALL.INDICES
2.11-0
374 OpenQM
4.122 MAP
Format
where
LPTR specifies that the output is to be sent to a print unit. The print unit number, n,
defaults to 0 if omitted.
FILE specifies that the output is to be sent to a file. If file.name is omitted, the $MAP
file is used by default.
The MAP command produces a combined list of the contents of the global and private catalogues.
Without the FILE keyword, the map shows the name of each catalogued item with its date and time
of compilation and its size, separating the object code and cross-reference tables. Items from the
global catalogue have an asterisk in the leftmost column of the report. The report ends with a line
giving the total size of all reported items.
The file produced with the FILE keyword can be listed using the query processor.
The private catalogue is normally a subdirectory, cat, under the account directory but can be moved
by creating an X-type VOC entry named $PRIVATE.CATALOGUE in which field 2 contains the
pathname of the alternative private catalogue directory. This only takes effect when QM is
re-entered or on use of the LOGTO command. This feature is particularly useful where two or
more accounts are to share a common private catalogue. The US spelling, $PRIVATE.CATALOG,
may be used instead. If both are present, the British spelling takes priority.
Example
The above command prints a map of the catalogue, including system items.
See also:
BASIC, CATALOGUE, DELETE.CATALOGUE
2.11-0
QM Commands 375
4.123 MED
Format
where
menu.name is the name of the menu record to be processed. Menu names are case
sensitive.
If the file or menu names are omitted from the command line, MED prompts for these. When
prompting for menu names, MED will edit the given menu and then prompt for a further name.
This is repeated until a null menu name is entered.
Menus are normally stored in the VOC file but can be stored in any file of the application designer's
choice if an R-type (remote) VOC record is used to point to the menu record in the other file.
If the menu does not exist, MED prompts for confirmation that it is to be created.
2.11-0
376 OpenQM
MED uses a subset of the SED full screen editor default key bindings to allow the user to move
around within the display and enter or modify text. These are:
The leftmost few characters of each line display a line type key. The remainder of the line is
editable and the line on which the cursor is positioned will pan if required to allow text data wider
than the display device.
The bottom line of the screen displays a single line help prompt at all times. Pressing F1 will
display a help page appropriate to the line on which the cursor is positioned. Pressing F1 again
while this help text is displayed will display help on the key bindings.
The first section of the menu data displayed by MED contains information that relates to the entire
menu:
The menu title line
The access control subroutine name (see VOC M-type records)
The prompt text
Exit codes
Stop codes
2.11-0
QM Commands 377
The remainder of the displayed data is a set of sections corresponding to the menu options in the
order in which they will appear on the menu. Each section contains:
The option text
The action sentence. Terminate with a semicolon for an automatic "Press return to continue"
prompt
Help text for the option
The access subroutine key
A flag indicating whether the option is to be hidden if it is unavailable
The separator line between each section has some special features. Pressing the return key while on
this line inserts a new menu option entry under the line. Use of the kill line function (Ctrl-K) on this
line deletes the menu option under the line, placing it in the kill buffer. Repeated use of the kill line
function places all of the deleted menu options in the kill buffer.
When the kill buffer contains one or more complete menu options, use of the paste function (Ctrl-Y)
inserts the kill buffer content under the current option. Use of kill and paste can be used to move
options within the menu.
When on a text line, the kill line function deletes all text after the cursor, placing it in the kill buffer.
The paste function can be used to paste this text into another line.
2.11-0
378 OpenQM
4.124 MERGE.LIST
The MERGE.LIST command creates a new active select list by merging two other lists according
to one of three relational operators.
Format
where
list1, list2 identify the select lists to be merged. These must be select list numbers
in the range 0 to 10. They may not reference the same list.
tgt.list is the number of the select list (0 to 10) to receive the result. If omitted,
select list zero is used. It is valid for tgt.list to reference one of the
source lists.
COUNT.SUP indicates that display of the record count in the merged list is to be
suppressed.
The MERGE.LIST command allows construction of one select list from two others. Use of
MERGE.LIST can be significantly faster than a full select of the file to create the new list.
If either source list has already been partially processed before the MERGE.LIST command is
executed, only the remaining unprocessed items are used. The resultant list will replace any already
active tgt.list. The source lists are cleared after the new list has been set up. The ordering of tgt.list
is undefined.
@SYSTEM.RETURN.CODE is set to the number of items in the new list or a negative error code.
Example
GET.LIST FRANCE.CUSTOMERS TO 1
2.11-0
QM Commands 379
27 records selected.
GET.LIST GERMANY.CUSTOMERS TO 2
31 records selected.
MERGE.LIST 1 UNION 2 TO 3
58 records selected.
This example restores two saved select lists, one holding keys for customers in France, the other for
customers in Germany and merges these to form select list 3 as a list of customers in either of these
countries.
See also:
LIST.DIFF, LIST.INTER, LIST.UNION
2.11-0
380 OpenQM
4.125 MESSAGE
The MESSAGE command sends a message to selected other users. This command is not available
on the PDA version of QM.
Format
where
user identifies the user(s) to receive the message. This may be a user number, a
case insensitive user name, or the keyword ALL. Messages cannot be sent
to phantom or QMClient processes.
message.text is the text of the message to be sent. If omitted from the command line, the
user is prompted to enter the text. With the IMMEDIATE keyword,
messages that are wider than the screen are truncated on terminals that
support immediate message display.
Where a specific user number is given, the MESSAGE command checks that this user is logged in
and is not a phantom process. The ALL keyword sends the message to all non-phantom users
(except the user sending the message).
Messages are normally displayed when the user next arrives at the command prompt. If the
IMMEDIATE keyword is used and the destination process is using a terminal that supports screen
save and restore (QMConsole on Windows, QMTerm, AccuTerm), the message is displayed
immediately and the screen is restored when the user acknowledges the message.
The MESSAGE OFF command disables receipt of messages. Messages sent while message
reception is disabled are not queued for later display and will never be seen. Use of the MESSAGE
command with a user number will report an error if the target user has message reception disabled.
The MESSAGE ON command enables receipt of messages. This is the default state.
2.11-0
QM Commands 381
4.126 MODIFY
Format
where
field.list is the list of field(s) to be modified. Each entry must correspond to a D-type
dictionary entry. These name may alternatively be a PH (phrase) type entry
which will be expanded and all fields referenced by the phrase will be modified.
If no fields are specified on the command line, MODIFY looks for a phrase
named @MODIFY and, if found, uses this as the source of field names. If no
@MODIFY phrase exists, MODIFY will use the @ phrase or, if this also
does not exist, a default list of fields is constructed from the dictionary.
The MODIFY command provides a data editor which uses the dictionary associated with a file to
determine the format in which data is displayed or entered and to provide prompts in terms which
relate to the data. It is useful for making changes to existing records or entering new data.
MODIFY is particularly suited to entry of dictionary records where the prompts remove the need to
remember the meaning of each field.
MODIFY prompts for a record id or uses the next item from id.list or the default select list. Entry
of a question mark (?) at the id prompt will display a pick list of record ids.
If the record already exists, a list of modifiable fields is displayed. This list contains one entry for
each single valued field followed by an entry for each multivalued field or associated set of fields.
The prompt displayed with the list allows the following responses:
item no Entry of an item number from the list selects that field or association for
modification. Data may be entered or modified in a panning input area at the
bottom of the screen. The edit keys available are:
2.11-0
382 OpenQM
Non-printing characters can be inserted using the Ctrl-Q prefix shown above or
by typing ^nnn where nnn is the ASCII character number of the character to
be inserted.
As fields are modified, their values are inserted into the displayed list of fields.
FI Writes the modified record to the file and prompts for a new record id. If the record
was a dictionary I-type or C-type, MODIFY will compile it.
Q Quits from the record, discarding any changes and prompts for a new record id.
Selecting a multivalued field or an association enters a separate display screen showing one line for
each value in the field(s).
The prompt displayed with the list allows the following responses:
line no Entry of a line number from the list selects that value set for modification. Data
may be entered or modified for each field in the association in turn in a panning
input area at the bottom of the screen. The edit keys available are as above.
E Extends the values, repeatedly accepting new data until either a null entry is made
2.11-0
QM Commands 383
in the first field of the association or the exit key (Ctrl-X) is used.
Where the record does not already exist, MODIFY prompts for data for each field in turn and then
allows changes as for an existing record.
When editing a dictionary, MODIFY automatically chooses the editable fields based on the record
type.
2.11-0
384 OpenQM
4.127 NETWAIT
The NETWAIT command is applicable to the PDA version of QM only and waits for an incoming
telnet connection.
Format
NETWAIT
The NETWAIT command waits for an incoming telnet connection, over a network or from a telnet
session running on the same PDA. The command may only be executed from command processor
level 1, not from an EXECUTE in a program.
The PDA version of QM does not support multiple processes. Although this may look as though
there is a second QM session running, when a connection is established, the telnet connection
becomes the keyboard and display for the QM session that executed the NETWAIT command,
leaving the original screen suspended.
If there is an executable VOC item named ON.CONNECT, this will be run in the newly established
telnet session in much the same way as the LOGIN paragraph is executed in normal QM sessions.
There is no reason why, if appropriate, the ON.CONNECT item cannot go on to run LOGIN.
The default terminal type, unless changed in the ON.CONNECT paragraph, will be vt100.
The session may be terminated using the QUIT or LOGOUT commands. Use of QUIT will revert
to NETWAIT to await a new connection. Use of LOGOUT terminates NETWAIT too.
2.11-0
QM Commands 385
4.128 NLS
Format
where
The NLS command sets or reports national language parameter values. The available parameters
and their default values are:
2.11-0
386 OpenQM
4.129 NSELECT
The NSELECT command refines a select list by removing items that are in a named file.
Format
where
from.list is the select list to be used as the source of record ids to be checked against file. If
omitted, the default list (list 0) is used.
to.list is the select list to be receive the modified list. If omitted, the default list (list 0) is
used.
The NSELECT command refines the source select list by removing from it any items that
correspond to record ids present in the named file.
Example
SELECT VOC
NSELECT NEWVOC
LIST VOC
The above sequence of commands builds a list of all records in the VOC file, removes from this list
all items present in NEWVOC and then lists the remaining VOC records. The effect is to show
those VOC records added since the account was created.
2.11-0
QM Commands 387
4.130 OPTION
To ease application portability, options that are not meaningful on a particular QM platform are
ignored.
Format
The OPTION command, normally only used in the LOGIN or MASTER.LOGIN paragraphs, sets
options that determine how the system behaves for that user session. Beware that setting options in
the MASTER.LOGIN paragraph will affect users of the QMSYS account and may cause some
administrative commands to fail. Also, the MASTER.LOGIN paragraph is not executed for
QMClient sessions.
The ON keyword is used to set an option and is the default action if no keyword is present. The
OFF keyword is used to clear an option. The DISPLAY keyword is used to display the current
setting of an option.
The OPTION command with no qualifying information displays the settings of all options. The
LPTR keyword directs this report to the specified print unit, printer zero if unit is omitted.
A single command may contain multiple option names. The ON, OFF or DISPLAY keyword, if
present, may appear at any position within the list of option names.
The OPTION ALL OFF syntax turns off all options. It is useful in LOGIN paragraphs to ensure
that all options are off before turning on those that are required in applications that may use
LOGTO to move between accounts.
Option settings are not automatically inherited by phantom processes unless the INHERIT option
described below is active.
2.11-0
QM Commands 389
These option.name values set multiple options. Other options that were already set when these are
used will not be cleared. These names cannot be used with ON, OFF or DISPLAY.
D3 This option gives closer compatibility with D3. The options
2.11-0
QM Commands 391
2.11-0
392 OpenQM
4.131 PASSWORD
The PASSWORD command changes the password for a QM user on Windows 98/ME.
Format
PASSWORD {username}
The PASSWORD command prompts for the existing password of the user and then prompts twice
for the new password. Terminal echo is suppressed during password entry.
The username argument may only be used by users with administrator rights and allows changes to
the password of a user other than that executing the command.
See also:
ADMIN.USER, CREATE.USER, DELETE.USER, LIST.USERS, SECURITY, Application
Level Security
2.11-0
QM Commands 393
4.132 PAUSE
Format
PAUSE
The PAUSE command, intended for use in paragraphs, pauses processing and displays a prompt
for user input before continuing. By default, this prompt offers two special responses; A to abort
and Q to quit. If the NO.USER.ABORTS mode of the OPTION command is active, the A option
is not offered.
2.11-0
394 OpenQM
4.133 PDEBUG
The PDEBUG command runs the phantom debugger. This command is not available on the PDA
version of QM.
Format
PDEBUG {command}
where
The PDEBUG command waits for a phantom or QMClient process running in the same account
and as the same user name to attempt to enter the debugger. At that point, the process executing the
PDEBUG command will enter the QMBasic debugger and can use this in the usual way except that
it is not possible to view the application screen because a phantom process is not associated with a
terminal device.
The phantom process to be debugged may be started separately or by use of the command option to
the PDEBUG command.
2.11-0
QM Commands 395
4.134 PDUMP
The PDUMP command generates a process dump file for a named QM process.
Format
PDUMP userno
where
The PDUMP command forces generation of a process dump file for the user identified by userno.
Because use of the PDUMP command can weaken system security by allowing a user to see data
inside another user's program, the PDUMP configuration parameter may be used select a mode
where only system administrators can dump processes running under other user names. For
alternative security rules, add a security subroutine to the relevant VOC entry.
2.11-0
396 OpenQM
4.135 PHANTOM
Format
A new background process is started to execute the command which must be a valid verb, sentence
or paragraph. The process from which the PHANTOM command was performed continues without
waiting for command to be completed. A message is displayed indicating the user number
associated with the phantom. The user number is also returned in @SYSTEM.RETURN.CODE. If
the phantom process cannot be started, @SYSTEM.RETURN.CODE holds the negative error
code.
When the background process terminates a message is queued for display immediately before the
next command prompt. This message is
Unless the NO.LOG keyword is used, the phantom process will automatically create a COMO file
named PHn_date_time exactly as though it had commenced with the command
COMO ON PHn_date_time
A QMBasic program can determine this name using the !PHLOG() subroutine.
Output that would normally be directed to the display is suppressed except for recording in the
COMO file. The COMO file may be switched off or redirected as desired from within the phantom
process.
The DATA keyword cause the DATA queue of the process in which the PHANTOM command is
executed to be passed into the phantom process, clearing it in the parent process.
The USER option allows the phantom process to be created as a specific user number within a
range of numbers reserved by the PHANTOMS configuration parameter. An error will occur if
there is already a phantom running as the specified user.
Any attempt to read data from the keyboard will cause the process to abort. DATA statements may
be used in the phantom to supply input that would normally be read from the keyboard.
All QM processes, including phantoms, execute the VOC LOGIN paragraph, if it exists. To exit
from the LOGIN paragraph for a phantom process, insert a line
2.11-0
QM Commands 397
Example
This command starts a phantom process to compile the QMBasic program INVOICE in the BP file.
See also:
CHILD(), LIST.PHANTOMS, !PHLOG(), STATUS
2.11-0
398 OpenQM
4.136 PRINTER
Format
The print.unit argument identifies the print unit on which the action is to occur and must be in the
range -1 to 255. If omitted, print unit zero is used.
The action may be any of the following. Multiple actions may be specified in a single PRINTER
command and will be performed in the order in which they occur on the command line.
The PRINTER command sets or reports the settings of printer control parameters. The action of
each keyword is described in detail below.
2.11-0
QM Commands 399
The print unit is closed. This action overrides any previous use of the KEEP.OPEN option. If this
print unit was directed to a spool file, the data will be printed. Any heading and footing text or file
name associated with the printer is discarded and further use of this print unit by a program or
command will start a new file.
See also:
SETPTR
2.11-0
400 OpenQM
4.137 PSTAT
The PSTAT command displays the status of one or all QM processes. This command is not
available on the PDA version of QM.
Format
where
user is the QM user number or user login name of the process to report. Multiple user
numbers or user names may follow a single USER keyword or there may be
multiple USER keywords in the command line.
The PSTAT command displays diagnostic status information about the processes identified by the
USER option or, if the USER option is omitted, all QM processes.
For each process reported, PSTAT shows the account name, user name, the last command executed
and the current execution point (program name, line number and execution address). Note that the
command shown may have completed and returned to the program from which it was executed.
The level parameter specifies extended report features and is formed by adding together the
following components:
1 Report each program and subroutine in the call stack. If not included, only the currently
active program is reported.
2 Report internal subroutine calls within each reported program and subroutine. If not
included, only external subroutine calls are reported.
Examples
In this example, the most recent command executed by user 2 was RUN INVOICES. It is currently
executing the !SCREEN subroutine at line 953, address 14E6. Because the LEVEL parameter
includes level 2, internal subroutine calls are also shown. The !SCREEN subroutine was called
2.11-0
QM Commands 401
from The INVOICES program at line 105 (address 01BE). This program was started from the
command processor which was itself started from line 104 of program PROC which was itself
started from the command processor.
The same process could be reported in less detail using other values of the LEVEL option as shown
below:
PSTAT USER 2
User Detail
2 Account: SALES, Username: Joe
Command: RUN INVOICES
!SCREEN 953 (14E6)
2.11-0
402 OpenQM
4.138 PTERM
Format
The PTERM BREAK ON or OFF command determines whether use of the break key is
considered to be a break or a data character. If set on, the break key will interrupt processing. If set
off, the break key is treated as a normal data character. The setting of this mode does not affect
interpretation of the telnet break command.
The PTERM BREAK n or ^c command sets the character to be used as the break key. The first
form takes the character number (1 - 31); the second form takes the printable character associated
with the control key (A - Z, [, \, ], ^, _). The default break character is ctrl-C (character 3). Note
that some terminal emulators send a telnet negotiation parameter instead of the break character
itself and may require changes to the emulator configuration to use an alternative character.
The PTERM CASE command determines whether the case of alphabetic characters is inverted on
entry at the keyboard. Running with case inversion enabled may be more natural as, for historic
reasons, the QM command set is all in upper case. In QMBasic programs, case inversion affects
INPUT statements, the KEYCODE() and KEYINC() functions but not the KEYIN() function.
The PTERM CODEPAGE command, available only in Windows console sessions, displays or
sets the code page used to determine how single byte characters are displayed.
The PTERM MARK command can be used to enable a mark character translation feature
2.11-0
QM Commands 403
whereby entry of characters 28 - 30 (ctrl-\, ctrl-], ctrl-^) at the keyboard gets translated to field,
value and subvalue marks respectively. Used without the ON or OFF qualifier, this command
shows the current state. Translation is off by default.
The PTERM NEWLINE command determines whether QM sends CR, LF or a CR/LF pair as the
newline sequence on terminal output. The default mode is CRLF.
The PTERM PROMPT command changes the command prompt from the default colon to string1.
The optional string2 changes the alternative prompt displayed when the default select list is active.
The prompt strings must be quoted and may be from 1 to 10 characters in length.
The PTERM RESET command sets a control string to be sent to the terminal device on return to
the command prompt. This can be used, for example, to ensure that the terminal reverts to a chosen
foreground/background colour scheme regardless of how the application left it set. The string may
include use of the QMBasic style @() function to insert device dependent control codes or any of
the following special codes:
\B Backspace
\E Escape
\F Form feed
\N Newline
\R Carriage return
\T Tab
\^ ^
\\ \
^x Ctrl-x
The PTERM RETURN command determines whether KEYIN() and related QMBasic functions
return 10 (LF) or 13 (CR) when the return key is pressed. The actual effect of this mode setting is
to replace incoming carriage returns with the given character unless the session is operating over a
binary mode telnet connection. The default mode is CR.
The PTERM DISPLAY command reports the current settings of the terminal. PTERM LPTR
directs the same report to the default printer.
See also:
PTERM(), TERM
2.11-0
404 OpenQM
4.139 PUBLISH
The PUBLISH command sets up a file in the current account for replication.
Format
where
src.file is the file to be published. This must be a reference to a VOC F-type record
that defines a hashed file.
server is the name of the server to which the file is to be exported. This must have
been defined using SET.SERVER so that PUBLISH can validate the target
file reference.
account is the name of the account on server to which the file is to be exported.
tgt.file is the name of the target file within account to which the file is to be exported.
The first form of the PUBLISH command marks the specified file as being exported to the
specified target. Multiple targets may be specified in a single command or each target can be
specified separately. Following successful execution of this command, all updates to the file will be
logged for export.
The two forms with the CANCEL keyword terminate publication of the specified file. With a
server name, publication to the specified server is terminated. With the ALL keyword, all
publication of this file is terminated.
The two forms with the QUERY keyword show a list of replication targets, either for the specified
file or for all files.
See also:
Replication, DISABLE.PUBLISHING, ENABLE.PUBLISHING, PUBLISH.ACCOUNT,
SUBSCRIBE
2.11-0
QM Commands 405
4.140 PUBLISH.ACCOUNT
The PUBLISH.ACCOUNT command sets up files in the current account for replication.
Format
where
The first form of the PUBLISH.ACCOUNT command displays a list of files that are candidates
for export to the specified server:account. The display is divided into pages with each file
numbered. Initially, no files are marked for publishing. The following commands, based on those
used by the SHOW command can be entered to modify the publication list:
The ALL and VISIBLE keywords can be abbreviated and do not need a preceding space.
By default, the PUBLISH.ACCOUNT command does not show or publish dictionaries. Including
the DICT keyword extends the list of displayed files to include dictionaries, allowing these to be
included in the list of items selected for publication.
The second form of the PUBLISH.ACCOUNT command with the CANCEL keyword displays a
list of files that are published to the specified server:account. Files for which publication is to be
cancelled can be selected with the keyboard actions listed above.
2.11-0
406 OpenQM
See also:
Replication, DISABLE.PUBLISHING, ENABLE.PUBLISING, PUBLISH, SUBSCRIBE
2.11-0
QM Commands 407
4.141 QSELECT
The QSELECT command constructs a select list from the content of selected records.
Format
QSELECT {DICT} file.name {id... | * | FROM list} {TO list} {SAVING field}
where
TO list specifies the list to be created. If omitted, the default list (list 0) is created.
SAVING field identifies the field from which items are to be taken. If omitted, all fields in the
record are processed. The field item may be a field number or a field name.
The QSELECT command reads selected records from the given file and constructs a select list
from the content of the named field or all fields. Multivalued fields are expanded to give a separate
list entry for each value or subvalue.
If the default select list is active and there are no record ids or FROM clause on the command line,
this list is used to control processing.
Both @SELECTED and @SYSTEM.RETURN.CODE will be set to the number of item selected.
2.11-0
408 OpenQM
4.142 QUIT
The QUIT command terminates the current QM session. The synonym OFF can be used.
Format
QUIT
The QUIT command terminates the QM session. If the account has the command stack recording
option active (see Command Stack), the current command stack is written to the VOC.
The ON.EXIT paragraph, if present, is executed before final return to the operating system.
When using a telnet connection to a PDA, this command returns to NETWAIT to wait for a new
connection.
See also:
LOGOUT
2.11-0
QM Commands 409
4.143 REBUILD.ALL.INDICES
The REBUILD.ALL.INDICES command rebuilds the alternate key index on all files in the
account.
Format
REBUILD.ALL.INDICES {CONCURRENT}
The REBUILD.ALL.INDICES command scans the vocabulary file of the account in which it is
executed and identifies all of the F-type items that reference files that have alternate key indices.
These indices are then rebuilt. If a file is referenced by more than one VOC entry, the indices are
only built once.
Except when executed in the QMSYS account, the command ignores files in the QMSYS account
(e.g. system files).
Under normal circumstances, it should not be necessary to rebuild indices as they should be
correctly maintained in step with updates applied to the associated data files.
REBUILD.ALL.INDICES may be useful after restoring a backup for which indices were omitted
or to ensure system integrity after a power failure.
Except when used with the CONCURRENT keyword, the REBUILD.ALL.INDICES command
requires exclusive access to each file that it processes. It is therefore best executed at quiet times.
The CONCURRENT keyword allows indices to be built while the files are in use. There is a
performance overhead for this and the QMBasic SELECTINDEX, SELECTLEFT and
SELECTRIGHT statements may stall waiting for the build to complete.
See also:
BUILD.INDEX, CREATE.INDEX, DELETE.INDEX, DISABLE.INDEX, LIST.INDEX,
MAKE.INDEX
2.11-0
410 OpenQM
4.144 RELEASE
Format
In the first form, RELEASE releases locks on the specified record id(s) in the named file. The
second form releases the file lock on the named file.
RELEASE can only release locks held by the process in which the command is issued. System
administrators can use the UNLOCK command to release locks held by other users.
Locks are released automatically when a file is closed. Applications can store file variables in a
named common block so that the files remains open when the program terminates. In this case,
locks left in place when the program ends will not be released automatically.
2.11-0
QM Commands 411
4.145 REMOVE.DF
Format
where
part.file is the name of the part file to be removed. The part number may be specified
instead.
The REMOVE.DF command will remove the named part file from the distributed file but does not
delete the part file. If this is the only part file, the distributed file is also deleted.
Use of the ALL keyword in place of the part file name deletes the entire distributed file. The part
files are not deleted by this operation.
Example
This command removes ORDERS-08 as a part file within the ORDERS distributed file.
See also:
Distributed files, ADD.DF, LIST.DF
2.11-0
412 OpenQM
4.146 REPORT.SRC
Format
2.11-0
QM Commands 413
4.147 REPORT.STYLE
The REPORT.STYLE command sets the default query processor report style.
Format
The query processor can highlight selected components of a report using colour on a displayed
report or font weights on a report directed to a PCL printer. The REPORT.STYLE command sets
the default style to be used for all reports unless overridden by an alternative setting using
SETPTR, the QMBasic SETPU statement, or the STYLE option to the query processor.
See the query processor STYLE option for full details of report styles.
2.11-0
414 OpenQM
4.148 RESET.MASTER.KEY
The RESET.MASTER.KEY command resets the encryption master key. This command can only
be executed by users with administrator rights in the QMSYS account.
Format
RESET.MASTER.KEY
The command prompts for the master key string and whether this must be entered every time QM is
started.
The RESET.MASTER.KEY command is intended for use after moving the encryption key vault
from another system or after application of a new licence. It can also be used to enable or disable
the need to enter the master key using UNLOCK.KEY.VAULT every time that QM is started.
The key string entered must be the same as when the key vault was created. The master key cannot
be changed unless the key vault is cleared and rebuilt.
See also:
Data encryption, CREATE.FILE, CREATE.KEY, DELETE.KEY, ENCRYPT.FILE,
GRANT.KEY, LIST.KEYS, REVOKE.KEY, SET.ENCRYPTION.KEY.NAME,
UNLOCK.KEY.VAULT
2.11-0
QM Commands 415
4.149 RESTORE.ACCOUNTS
The RESTORE.ACCOUNTS command restores all accounts from a Pick style FILE.SAVE tape.
Format
where
target is the parent directory under which the restored accounts are to be placed. If
omitted, the pathname specified in the $ACCOUNT.ROOT.DIR VOC entry is
used or, if this record does not exist, the user is prompted for the directory
pathname.
The RESTORE.ACCOUNTS command processes a Pick style FILE.SAVE tape or pseudo tape
and restores data from it into a QM system. It can also restore from a tape containing multiple
ACCOUNT.SAVEs.
The tape to be restored must first be opened to the process using the SET.DEVICE command.
All accounts found on the tape are restored unless there is already an account of the same name or
the target account directory already exists. In these cases, the account is skipped.
For more details of the tape processing applied during restore, see the ACCOUNT.RESTORE
command.
See also:
ACCOUNT.RESTORE, ACCOUNT.SAVE, FILE.SAVE, FIND.ACCOUNT,
SEL.RESTORE, SET.DEVICE, T.ATT, T.DUMP, T.LOAD, T.xxx
2.11-0
416 OpenQM
4.150 REVOKE.KEY
The REVOKE.KEY command removes access to a specific data encryption key. This command
can only be executed by users with administrator rights in the QMSYS account.
Format
where
name ... is a list if usernames for users to be denied access. If prefixed by the GROUP
keyword, this is a list of user groups. On Windows systems, user and group names
are treated as case insensitive.
The REVOKE.KEY command removes access to an encryption key to one or more users or user
groups. The user will be asked to enter the master key unless it has already been entered during this
session.
No error occurs if the user or group specified did not have access to the key.
Example
The above command removes access to the encryption key named CARDNO for users jsmith and
bjones.
See also:
Data encryption, CREATE.FILE, CREATE.KEY, DELETE.KEY, ENCRYPT.FILE,
GRANT.KEY, LIST.KEYS, RESET.MASTER.KEY, SET.ENCRYPTION.KEY.NAME,
UNLOCK.KEY.VAULT
2.11-0
QM Commands 417
4.151 RUN
The RUN command initiates execution of a compiled QMBasic program. It can also be used to
execute VOC style items that are stored in alternative files.
Format
where
file.name is the name of the directory file holding the program to be run. If omitted,
this defaults to BP. The .OUT suffix for the compiler output file is
supplied automatically when using the command to execute a QMBasic
program.
LPTR causes output to logical print unit 0 to be directed to the printer. This is
identical in effect to a PRINTER ON statement being performed within
the program.
2. If a file with the .OUT suffix added to the name is defined in the VOC and can be opened,
record.name is assumed to be the name of a compiled QMBasic program.
3. If the file is not defined in the VOC or cannot be opened for any reason, record.name is
assumed to be the name of a VOC style item (sentence, paragraph, menu, etc) in the named
file without the .OUT suffix.
4. If the item identified by the above steps cannot be found, an error is reported.
By default, output directed to the screen from a program will pause at the end of each page waiting
for user confirmation. For compatibility with some other systems, the RUN.NO.PAGE mode of the
OPTION command can be enabled such that the pause will not occur. If the
PAGINATE.ON.HEADING mode of the OPTION command in also enabled, setting a page
heading or footing in the application will cause the page end pause to be enabled. The NO.PAGE
keyword to the RUN command will override this such that pagination never occurs. This keyword
can also be used when running a catalogued program by entering its name.
2.11-0
418 OpenQM
4.152 SAVE.LIST
The SAVE.LIST command is used to save an active select list for future use.
Format
where
list.name is the name of the record to be created in $SAVEDLISTS to hold the saved
select list.
list.no identifies the select list (0 to 10) to be saved. If omitted, select list zero is used.
The SAVE.LIST command copies an active select list to the $SAVEDLISTS file. This file will be
created if it does not already exist.
If the active list has already been partially processed, only the remaining items are saved. The active
select list is cleared after it has been saved.
@SYSTEM.RETURN.CODE is set to the number of items in the saved list. In the event of an
error, the value is a negative error code.
Example
See also:
COPY.LIST, DELETE.LIST, EDIT.LIST, FORM.LIST GET.LIST, SORT.LIST
2.11-0
QM Commands 419
4.153 SAVE.STACK
Format
SAVE.STACK {stack.name}
where
stack.name is the name to be given to the saved command stack. A prompt is issued if this
name is omitted.
The SAVE.STACK command copies the current command stack to the $SAVEDLISTS file as a
record named stack.name. The file will be created if it does not already exist. Any existing record of
the same name will be overwritten.
Example
SAVE.STACK <<@LOGNAME>>
Command stack 'jsmith' saved in $SAVEDLISTS
This command saves the current command stack to a record with id as the user's login name in the
$SAVEDLISTS file.
See also:
CLEAR.STACK, GET.STACK
2.11-0
420 OpenQM
4.154 SCRB
The SCRB command runs the screen builder to create or modify a screen definition for use by the
QMBasic !SCREEN() subroutine.
Format
where
The QMBasic !SCREEN() subroutine uses screen definitions which are created and maintained
using SCRB. The name of the account’s default screen definition file is stored in field 2 of an
X-type VOC record named $SCRB.FILE and will be used if no file name is given in the SCRB
command line. If this record does not exist, SCRB uses the $SCREENS file which is common to all
accounts. The $SCREENS file may also contain screen definitions which are part of the QM
product. These have a dollar sign in their name and should not be modified or removed.
A screen consists of a number of steps, each of which may have a fixed text display, output of data
from a data record, and input of data into a data record. Data may be converted or formatted on
output and input. Steps that include data input may perform validation within the screen driver
subroutine and may also have user defined help and error messages. Programs can undertake all
aspects of managing the flow from one step to another themselves, pass this task to the screen
driver using a variety of conditional flow control options or use a mixture of the two modes.
The screen builder can automatically generate an include record identifying the screen steps by
name for use in programs that use the screen. This include record will be placed in a nominated file
with the same name as the screen with a .SCR suffix.
On entry to SCRB, the user is invited to enter a screen name unless this has been provided on the
command line. SCRB will look for this in the form entered and, if not found, in uppercase. If
neither exists, a new screen is created.
2.11-0
QM Commands 421
Selecting the H option allows entry/modification of the screen header line. It is useful to include the
screen name in the header, perhaps at the left margin. All the normal input editing keys are
available. Pressing the return key will end the header update.
The L option displays a list of screen steps. The information displayed is the step number and the
fixed text (if any) associated with the step. If the step has no fixed text, the display shows <<step
name>>. The escape key can be used to terminate the list before the last page is displayed.
The P option paints an image of the screen, showing the fixed text associated with steps except
those that are tagged as not to be included in a full screen paint. A prompt is issued allowing
selection of a step number to be executed. This allows easy debugging of the screen from within the
screen builder. Entering X at the action prompt exits from paint mode.
The LPTR option send the screen definition to the printer. Details of each step are printed followed
by a representation of the screen as it would be appear after the screen paint action of the
!SCREEN() subroutine.
The Sn option displays the definition of screen step n. A further prompt allows selection of the
action to be taken
Cn Copy step n over the currently displayed step
Cscrn,n Copy step n of screen scrn over the currently displayed step
D Delete this step
I Insert a new step before this step
Mn Move currently displayed step to become step n
N Advance to the next step
P Move to the previous step
R Return to the top level screen
Sn Move to step n
n Edit step definition starting at item n
2.11-0
422 OpenQM
Name
Steps may optionally be given names. These must be unique within the screen definition and are
used in generating an include record of step names for use in QMBasic programs. The include
record tokens are formed by adding a prefix of SS. to the step name.
Type
The step type determines the way in which the screen driver will handle the step. The type may be
any of the following:
D A display step. Any data item referenced by the step will be displayed but no input
is permitted.
I An input step. The data is displayed as for a display step but input may also be
performed.
N A control step. Any data item referenced by the step is not displayed but
conditional flow control elements based on this data item may still be included.
Gn A step group to be repeated n times. The display step field described below
contains a list of steps to be repeated. The repeat will terminate if the next step
determination of any repeated step evaluates to anything other than the default.
Step groups cannot be nested.
The step type may also include the following qualifying codes:
C Clears the text and data of this step after the step is completed. Usually used with
the X display mode options described later, this feature is particularly useful for
clearing temporary prompt fields from the screen.
Rn This step is to be repeated n times. The repeat will terminate if the next step
evaluates to anything other than the default. Repeated steps may not appear inside
step groups.
X Excludes this step from the initial screen painting process. This should normally be
included on the elements of a repeating group (not a repeated step).
Clear
The clear item contains Y if the screen is to be cleared prior to displaying this step.
Text
Text row
2.11-0
QM Commands 423
Text col
Text mode
The text item contains a fixed text string which will be displayed on the screen at the position given
by the text row and text col values using the text mode display style. The mode may contain any
combination of H to display in half intensity, R to set reverse video (interchange foreground and
background colours) and X (omit from full screen paint).
Field
Value
Subvalue
These items determine the position of the data item to be displayed or input. The field may be
specified as a numeric position or as a filename and field name separated by a space. In the latter
case, the screen builder will look up the actual field position in the dictionary of the specified file
when the screen definition is being entered. Later changes to the dictionary will not cause the screen
definition to change. The value and subvalue fields may be left blank where the entire field or value
is to be displayed.
A value of zero for the field uses an internal temporary variable. This is of particular use in
confirmation prompts, for example, where the data input is used to determine flow through the
screen steps but is not part of the record being amended.
For a repeated step or the elements of a repeating group, the field, value or subvalue may be
specified as ‘1+’, for example, which will cause the screen to use successive items starting at the
given position.
Prompt char
This item may be used to specify a character to appear immediately to the left of the data field. It
will be ignored if the data is displayed at the left margin.
Fill char
The fill character is used to pad out short data items on the display. It is not entered into the stored
data.
Data row
Data col
Data mode
These items operate in the same way as their equivalents for the text area.
For a repeated step or the elements of a repeating group, the row may be specified as y+i where y is
the line on which the first item is to appear and i indicates the number of lines by which the position
is to advance for successive elements. The value of i defaults to 1.
Output len
The output length item specifies the length of the data item on the display. If the actual data is
longer than this, the display is truncated.
Ifile,rec Execute the I-type named rec in the dictionary of file. against the data
2.11-0
424 OpenQM
record.
Tfile,fld,code Apply TRANS() using the data item as the record id to access field fld of
file. The code determines the action if the record is not found. C returns the
record id, X returns a null string.
Justify
This item contains L for left justification or R for right justification.
End mark
This item may be used to specify a character to appear immediately to the right of the data field. It
will be ignored if the data field extends to the right margin.
Input len
The input length item specifies the permissible length of the data. If this value exceeds the output
length, the field is panned to allow entry of long data. Many of the screen definition items are
themselves panned in this way by SCRB.
Required
This item indicates whether the field may be left blank. It may contain:
F For a repeated step or element of a repeating group, the field must not be blank for
the first iteration of the repeat but may be blank for subsequent iterations.
<f>cond The field is required if field <n> (or <f,v> or <f,v,s>) meets the supplied condition.
The condition code is as described for the next step determinations described
below.
D A valid date.
2.11-0
QM Commands 425
Ffilename,n Similar to the simple F validation but, if the record is found, the input data
is replaced by the contents of field n of the record.
Rfile,rec,fld,case,subst
Record rec is read from file. Field fld of this record is scanned for a match
with the input data. If case is X, this scan is case insensitive. If subst is
specified, the input data is replaced with the content of the corresponding
value of field subst of the record. Field fld may be broken down into
subvalues to specify alternative strings all of which are replaced by the
value (not subvalue) in subst.
@subrname Calls the named user supplied validation subroutine. This subroutine takes
three arguments; the return status ( 1 if ok, 0 if error), the data record
being processed and the input data field to be validated.
Xxxx Inverts the condition xxx. For example, XFINDEX would check that there
is no record named as the input data in file INDEX.
Tfile,fld,code Apply TRANS() using the data item as the record id to access field fld of
file. The code determines the action if the record is not found. C returns the
record id, X returns a null string.
Back step
The back step item determines whether the backtab key is allowed and may contain Y, N or blank
which is taken as N. If backtab is allowed, the screen driver will perform the action internally if it
has a step history. If there is no step history, the screen driver returns to the calling program with a
status indicating that the backstep key was used. The back step will correctly back-track through a
repeated step or repeating group.
2.11-0
426 OpenQM
Next step
The next step item defines the action to be taken after the step is completed. It may be multivalued
with conditional elements. A null action simply increments the step number. All next step action
lists effectively end with a null element which would be executed if all previous elements were
conditional and not satisfied.
An action item comprises three parts; a field reference, a condition and an action. The action is
preceded by a colon.
The field reference identifies the field within the screen data which is to be used in the following
condition. This may be specified as <field>, <field,value> or <field,value,subvalue>. If omitted
entirely (as is usual), the data from the current step is used. If a field reference is included, the
condition must also be present.
The condition compares the selected data with a fixed string or numeric value. The generic form of
this is EQ'string', EQnumber or EQ<f,v,s>. The operator may be any of EQ, NE, LT, GT, LE
or GE. If the condition is omitted, the action is performed unconditionally.
The action may be null to advance to the next step, a step number, a step name or X to exit to the
calling program. Within a repeated step or a repeating group any non-null action terminates the
repeat.
Help msg
The help message item defines a message to be displayed if the F1 key is pressed. The message may
be split over multiple lines by using the F2 multivalue entry feature of SCRB.
Error msg
The error message item defines a message to be displayed if input validation fails in a similar
manner to the help message.
Exit key
The exit key item defines the action to be taken if the escape key is pressed. The format and
processing of this item is as for the next step item except that a null value causes an error message
indicating that the exit key is not allowed.
F2 action
The F2 key is used for extended pick-list based help. If this item is blank, F2 is treated the same as
other function keys as described below. There are three formats to this item:
#filename,record.name,sort.field,field.list
This format builds a pick list from given file, record, field. The sort.field and field.list reference
fields in the named record by number. Dictionary names cannot be used in this action.
2.11-0
QM Commands 427
The data is sorted based on the value in the sort.field. The sort.field number may be followed
by R to perform a right justified sort. The field.list is a space separated list of fields to be
displayed. The sort.field must be explicitly referenced if it is to be displayed. The first field in
field.list contains the value to be returned by the selection process.
@subr
@subr(arglist)
Calls a user written subroutine subr to generate the list of items to display. This subroutine
returns the data to be displayed via its first argument, one field per pick list line each containing
a value mark delimited set of data values. The second argument should return the pick list
column number (from one) of the column to be used by the short cut system described below.
Up to four additional arguments may be passed into the subroutine from arglist which contains
literal values separated by commas. No string delimiters are required.
The pick list is displayed as a rolling window. The cursor up/down, page up/down, home and end
keys may be used to explore this window. Keys corresponding to printable characters cause a short
cut jump to a page displaying items starting at the first that commences with the entered character.
The return key will place the data displayed in the first column of the selected item into the screen
field. The escape key will exit from the pick list processing without entering data into the screen
field.
Func keys
The screen driver may accept or reject function keys. Entering Y in this item causes the screen
driver to return function keys to the calling program. Entering N or leaving it blank causes an error
message if function keys are used.
Key val
This field may contain the name of a validation subroutine that will be called after each input
keystroke in the field. The subroutine name is followed by a comma and the error message to be
displayed if validation fails.
The subroutine takes three arguments; the returned status (1 if ok, 0 if error), the data record being
processed and the input data for the field (not just the last keystroke).
Special keys
The screen driver uses the following keys for special purposes. The control key bindings shown
after some entries are provided for compatibility with other parts of QM.
F1 Help
F2 Pick list help
F3 Delete the contents of the current field
F4 Restore the contents of the current field after incorrect entry
Return Execute the next step action
Tab Treated identically to the return key
Ctrl-P Execute the back step action
Exit Execute the exit key action (Ctrl-X)
Home Mode to start of field (Ctrl-A)
End Move to end of field (Ctrl-E)
Cursor left Move left one character (Ctrl-B)
Cursor right Move right one character (Ctrl-F)
Delete Delete character under the cursor (Ctrl-D)
2.11-0
428 OpenQM
Within SCRB itself, the F2 key is used to enter multivalued items such as validation criteria. Input
prompts for successive items appear at the bottom of the screen until a null value is entered.
2.11-0
QM Commands 429
4.155 SECURITY
The SECURITY command enables, disables or reports the state of QM's internal security system.
Format
If security is enabled, users can only enter QM if their user name appears in the user register. Users
who are system administrators within the operating system are not restricted.
If security is disabled, all users who have valid authentication details for access at the operating
system level can use QM.
Use of the SECURITY command is restricted to QMConsole users with administrator rights. If
security is disabled, all users are considered as administrators.
See also:
ADMIN.USER, CREATE.USER, DELETE.USER, LIST.USERS, PASSWORD, Application
Level Security
2.11-0
430 OpenQM
4.156 SED
The SED command is a screen based editor, particularly useful for editing QMBasic source
programs where many lines (fields) can be seen at once.
Format
where
DICT indicates that records from the dictionary portion of the file are to be edited.
record.id is the name of the record to be edited. Multiple record names may be specified.
If no file.name is specified, SED will prompt for this name. The response may include a prefix of
DICT to select the dictionary portion of the file.
If no record.id is specified and the default select list is active, this list is used to identify the records
to be edited. If no record.id is specified and the default select list is not active, SED prompts for
the record.id.
An asterisk (*) either on the command line or as the first record.id entered in response to the
prompt will cause SED to select all records of the file and edit each in turn.
A question mark (?) as the first record.id entered in response to the prompt (not on the command
line) causes direct entry in explore mode, displaying a list of records in the file. The ? character
may be followed by a single space and a selection template as described under the list records
function to produce a restricted list of records.
When editing a compiled dictionary item (C-type, I-type, or A/S type with a correlative), SED
removes the compiled code thus forcing recompilation when the modified item is first referenced in
a query.
SED Topics
2.11-0
QM Commands 431
Changing text
Macros
File Handling
Repeating functions
Miscellaneous functions
Commands
Setting up default modes
Source control
Dynamic key bindings
Extension programming
2.11-0
432 OpenQM
A record to be edited is held in a buffer. Buffers may also hold records being created but not yet
written to disk or other data such as lists of records in a file. SED allows use of up to 20 buffers.
The editor displays a window in which a number of lines of the record being edited can be seen at
any one time. Where a line is wider than the display, the entire window pans from side to side to
maintain the cursor within the display area.
The bottom two lines of the screen display status information. The upper status line shows the file
and record names of the data being edited. If the data has been changed and hence does not match
what is stored in the file, an asterisk is displayed at the start of this line.
The lower status line displays several status fields. From left to right these show
the number of lines in the record
the current cursor position (line and column, both numbered from one)
the status of macro collection
the state of insertion overlay mode
the state of indentation mode
the search mode
the count for repeated functions and operations with a numeric prefix
The lower status line is also used by some editor functions to request qualifying information. A
limited set of editing functions can be used within this prompt area. These are forward char, back
char, start line, end line, delete char, backspace, kill line and insert kill buffer. The kill line
function used in this area deletes all characters after the cursor without affecting the kill buffer.
The insert kill buffer function will insert the first line from the kill buffer at the current cursor
position.
The display may optionally include line numbering. See the LNUM command for further details.
2.11-0
QM Commands 433
SED commands in the default key bindings consist of keystrokes which are
Control shift + key
ESCape followed by another key
Ctrl-X followed by another key
Ctrl-X followed by control shift + key
The table below summarises the standard editor function key bindings but these can be changed. All
other keystrokes except for unused control shift codes cause the character to be inserted into the
record text at the current cursor position.
2.11-0
434 OpenQM
Functions marked with an asterisk cannot be included in a macro and cannot be repeated using the
repeat or repeat count functions.
Some functions are available using alternative key sequences. Such alternatives are shown in the
descriptions.
Most functions can be repeated multiple times by use of the repeat count prefix. Unless otherwise
specified, the repeat count defaults to one if not explicitly set. Some functions use the repeat counter
for different purposes.
When learning SED, the Quick Reference Chart summarises the more important commands.
2.11-0
QM Commands 435
Other Movements
2.11-0
436 OpenQM
2.11-0
QM Commands 437
Top (Esc-<)
Moves to the start of line 1.
2.11-0
438 OpenQM
default. See the TABS command). If this is beyond the end of the data in the current line,
spaces are inserted to extend the line to the required position. The tab function does not insert a
tab character. Use the quote character prefix to do this.
Case sensitive: Data will only be found if it matches the search string exactly.
This is the default search mode.
Case insensitive: The case of both the search string and the data is ignored.
Basic word: Similar to word search mode but the characters valid in the
“word” are extended to cover acceptable syntax for a Basic
program variable name.
The default search mode may changed during initialisation or by commands entered at the SED
command prompt. Use of the up line and down line functions whilst entering the search string
can also be used to change the mode except when collecting functions for a macro.
When a search is included in a macro, the prompt for the search string only occurs when
collecting the macro. Subsequent executions use the same search string. Multiple search
functions in a macro may have different search strings.
View (Ctrl-X V)
The view function prompts for a search string displays a new buffer containing all lines beyond
the current cursor position that include this string, showing the line number and the text of the
line with leading spaces removed. Use any of the standard SED cursor movement functions to
position on a line and press the return key to go to this line of the full record text. The view
buffer is automatically deleted at any editing function that invalidates its content (e.g. entering
new text).
2.11-0
QM Commands 439
2.11-0
440 OpenQM
Data is inserted at the current cursor position. If overlay mode is set the new data overwrites any
existing data at this position, otherwise it is inserted before the character under the cursor. Overlay
mode may be toggled using the overlay function (Ctrl-O) or the OVERLAY command.
The return key inserts a newline. If indent mode is active (see the INDENT command), the cursor
is indented to line up with the previous line.
Any character other than a field mark or item mark may be inserted. The quote character function
(Ctrl-Q or Esc-Q) allows insertion of non-printing characters. It may be used in four ways:
Followed by a number of up to three digits, it inserts the character with that decimal ASCII
sequence.
Followed by V, S or T, it inserts a value mark, subvalue mark or text mark respectively.
Followed by K, it waits for a key to be pressed and then inserts the key binding code required
for this key as described under Dynamic Key Bindings.
Followed by any other character, usually a non-printing character, it will insert that character.
2.11-0
QM Commands 441
If there is data at or beyond the cursor position on the current line, the line is truncated at the
cursor position.
If the cursor is beyond the last data character on the current line, the line break is removed,
bringing data up from the next line.
The data removed by consecutive uses of the kill line function is placed in the kill buffer (see
Functions that Operate on a Block of Data). Any other function will cause a later use of the kill
line function to reset the kill buffer.
The kill line function may also be used in an explore buffer to delete the record named on the
current line.
2.11-0
442 OpenQM
When in a normal data window, some edit functions normally associated with file handling actions
have special usage and allow entry to and exit from value edit mode.
Value edit mode takes the contents of a multivalued field and displays each value as a separate line
in much the same way as the EV command of the ED line editor. While value edit mode is active,
the original parent buffer becomes read only.
Used with a dictionary I-type entry, this mode breaks compound I-types into separate lines to
simplify editing.
Up to parent (Ctrl-X U)
Used in a value edit buffer, this function returns to the parent buffer, saving any changes into
the main buffer.
2.11-0
QM Commands 443
The editor maintains reference to two positions within the record; the cursor position and the mark.
2.11-0
444 OpenQM
Replace (Ctrl-X R)
The replace function prompts for a search string and a replacement string. All occurrences of
the search string from the current cursor position to the end of the record are replaced by the
replacement string. Search modes are applied as described for the forward search function.
When a replace is included in a macro, the prompt for the search and replacement strings only
occurs when collecting the macro. Subsequent executions use the same strings. Multiple
replace functions in a macro may have different strings.
Lowercase (Esc-L)
This function locates the next word in the record and converts it to lowercase.
Uppercase (Esc-U)
This function locates the next word in the record and converts it to uppercase.
2.11-0
QM Commands 445
SED - Macros
The editor allows multiple command sequences to be collected as a macro for subsequent
re-execution.
The functions marked with an asterisk in the table at the start of this description cannot be included
within a macro and will be rejected during collection of a macro.
Use of the repeat function after an execute macro function will repeat the macro. If the repeat
count is set for the repeat function, the macro is executed that number of times. Otherwise the
repeat count applied to the previous execution of the macro is used.
2.11-0
446 OpenQM
After saving the data, the selected file and record names become current. A later use of the save
record function would replace this record not the record that was specified when editing began.
Import (Ctrl-X I)
A prompt is issued for the file and record names for the data to be imported. The data is then
inserted at the current cursor position.
Export (Ctrl-X X)
The export function saves the contents of the region between the cursor and the mark to a file.
A prompt is issued for the file and record names under which the data is to be saved. The file
name may be prefixed by DICT to indicate that the dictionary portion is required.
The find record function will accept the record name on the same response line as the file name
as an alternative to entering the file and record names in response to separate prompts. This is
achieved by separating the file and record names by a single space. SED still attempts to open a
file with a name corresponding to the complete prompt response first to allow for the unlikely
situation of a file name which includes a space.
The find record function maintains a stack of the last 10 files referenced by this command.
The up line and down line functions can be used to restore previous file names from the stack
when the file name prompt is displayed.
A marker is displayed to the left of the buffer number of the current buffer. This marker can be
moved up and down using the up line and down line functions. Pressing return selects the
marked buffer. The cancel function will revert to the previous buffer.
2.11-0
QM Commands 447
The file name may be followed by a selection template separated from the file name by a single
space. If this template begins with the word LIKE or WITH the entire template is taken as a
selection clause for the internally executed SELECT command. If the template does not begin
with either of these words, it is assumed to be a pattern for matching with the SELECT
statement LIKE clause. Thus a template of
PRT...
is equivalent to
WITH @ID LIKE PRT...
Single or double quotes may be used as required to ensure correct parsing of the template.
Multiple conditions may be included exactly as in a SELECT statement. A template not starting
with LIKE or WITH may not include both single and double quotes.
The list of records is displayed in a buffer which is tagged with a pseudo-record name of
--Explore--. If an explore list already exists for this file, the list is rebuilt by this function, thus
showing any changes to the file content.
The normal editor functions may be used to move around this buffer but it cannot be updated.
The return key or the dive function (Ctrl-X Ctrl-D) will cause the editor to read and display
the record identified by the line of the explore list on which the cursor lies. If this record is
already loaded into a buffer, the existing buffer is selected.
The kill line function executed in an explore buffer deletes the record named on the current line.
A confirmation prompt is issued before the record is deleted. If this record is currently loaded
into a buffer, the buffer is also deleted. A second confirmation prompt is issued to confirm this
action.
Up to parent (Ctrl-X U)
Moves 'up' from the displayed record to an explore list for the file holding the record. If the
explore list already exists, the list is not rebuilt by this function.
Used in an explore buffer, this function moves up to a display of all files in the VOC. Diving
into a file from this list shows a list of records in the file. It does not dive into the VOC record
itself.
Used in a value edit buffer, this function returns to the parent buffer, saving any changes into
the main buffer.
2.11-0
448 OpenQM
When not positioned on a $INCLUDE statement, this function enters edit value mode.
2.11-0
QM Commands 449
A function may be repeated multiple times by use of the repeat count prefix. This is performed by
use of the ESCape key followed by the number of times the command is to be repeated. The repeat
count is displayed on the status line. Functions for which a repeat count is irrelevant ignore it.
Functions within macro definitions may be repeated in this way and the execution of the macro
itself may also be repeated.
The repeat function (Ctrl-C or Ctrl-U) repeats the previously executed function. The repeat count
prefix can also be used with this function.
2.11-0
450 OpenQM
Cancel (Ctrl-G)
The cancel function aborts partially entered commands such as searches or repeat counts.
Refresh (Ctrl-L)
The refresh function rebuilds the screen display if it should be corrupted in any way. The
current line is placed at the centre of the screen if possible. Alternatively, the repeat counter
may be used to specify the screen line number on which the current line is to be placed.
Where a select list is in use, SED will move to the next item from this list.
Where only a file name was specified on the command line, SED will prompt for a further
record name.
CompRun (Ctrl-X M)
The CompRun function compiles the QMBasic program in the current window and, if the
compilation is successful, runs the program.
Command (Esc-X)
The command function is used to alter various long term states of the editor and to perform
other actions.
2.11-0
QM Commands 451
SED - Commands
The command function is used to alter various long term states of the editor and to perform other
actions. After entering the command function (Esc-X), a prompt for the command name is issued.
The following commands are available:
BASIC Saves the current record and runs the Basic compiler. This command is similar
to COMPILE (described below) but it inserts marker lines into the source
program where error or warning messages have been produced by the compiler.
BWORD Sets Basic Word mode for search and replace functions as described for the
forward search function.
CASE OFF Sets Case Insensitive mode for search and replace functions.
CASE ON Sets Case Sensitive mode for search and replace functions.
COMPILE Saves the current record and runs the Basic compiler. For compatibility with
SED on other platforms, if this record includes a line
*$CATALOG catname
the compiled program will be catalogued automatically after successful
compilation. The actual cataloguing command issued is
CATALOG filename catname recordname
It is thus possible to perform either private or global cataloguing. The same
action can be performed on QM using the $CATALOG compiler directive.
EXPAND.TABS Expands tab characters in the record being edited to align data on the columns
determined by the current setting of the tab interval. The default tab columns
are 11, 21, 31, etc.
LNUM The LNUM command controls display of line numbering. Used alone, it
toggles the current state of numbering on the displayed buffer. It may also be
used with the following qualifiers:
OFF Turn off line numbering in the current buffer.
ON Turn on line numbering in the current buffer.
ALL Turn on line numbering in all buffers.
OFF ALL Turn off line numbering in all buffers.
ON ALL Synonym for ALL.
OVERLAY Toggles overlay mode. The OVERLAY function (Ctrl-O) has the same effect.
QUIT Ends editing of the current record in a similar way to the quit key sequence but
also aborts any select list.
2.11-0
452 OpenQM
RUN Entering RUN with no qualifying details runs the program in the current buffer
(which must have been compiled). If RUN is followed by any qualifying
details, the command is passed to the command processor for execution.
SPOOL Spools the contents of the current buffer to print unit zero.
The SPOOL command has optional qualifiers which may be used together if
required. LNUM adds a line number prefix to each line printed. REGION
prints only the lines between the mark and the cursor (which may be in either
order). AT followed by a printer name selects the destination printer.
TABS Sets the tab interval to be used by the tab function and the EXPAND.TABS
command. The value given after TABS must be in the range 1 to 99.
TRIM Removes trailing spaces from all lines of the current buffer.
XEQ {cmnd} Executes QM command cmnd. The XEQ command prefix is only required
where cmnd is also an internal SED command. All commands not recognised
by SED are passed to the command processor for execution.
The command function maintains a stack of the last 100 commands executed. The up line and
down line functions can be used to restore commands from the stack when the command prompt is
displayed.
2.11-0
QM Commands 453
On entry, SED looks for a record named &SED.OPTIONS& in the VOC file. This record may be
used to set up default configuration data.
Field 5 may be used to modify the default tab interval used by the tab function and by the
EXPAND.TABS command. The value in this field must be between 1 and 99.
The record should contain no other data. Other fields may be used by later revisions of SED.
2.11-0
454 OpenQM
SED includes a mechanism that may be used to implement a source control system or other special
processing when updated records are written to disk.
Whenever a write is attempted using the save record or write record functions, SED checks for a
catalogued subroutine named SOURCE.CONTROL. If this is present, it is called to validate
whether data may be written to the file. The subroutine is defined as:
where
write.allowed should be returned by the subroutine as true (1) if the write may be
performed, false (0) if not. This argument is 1 on calling the subroutine.
updated should be set true if the subroutine has made any changes to the data in rec
. This argument is 0 on calling the subroutine.
The source control subroutine may be used in any way you wish. Typical uses are simple validation
of whether the record may be written or addition of edit history information prior to writing the
data. In the latter case, where changes are made to the data passed via the rec argument, the
updated flag should be set true so that SED rebuilds its working copy of the data on return.
The following simple example appends a history entry to the end of any record edited in BP or a file
with a name ending .BP but ignores dictionaries.
DISPLAY @(-1):
DISPLAY SPACE(27) : "SOURCE CONTROL INFORMATION" : @(-4)
DISPLAY "Change description:"
PROMPT ""
HDR = ""
TAG = OCONV(DATE(), "D2EL")
LOOP
2.11-0
QM Commands 455
REC<-1> = HDR
UPDATED = @TRUE
RETURN
END
2.11-0
456 OpenQM
The key bindings used in the function descriptions in this manual are the defaults used by SED,
known as the fundamental mode bindings. The dynamic key binding system allows these to be
changed if desired.
On entry, SED looks for a file named &SED.BINDINGS&. In most cases where this exists, it
would be set up as a remote file pointer to a single file shared by all accounts. This file contains
records defining named sets of key bindings.
SED works through a sequence of steps in locating the binding record to be used. This sequence,
described below, is designed to allow almost any user or terminal specific precedence rules to be
created.
If there is no &SED.BINDINGS& file, SED uses the fundamental mode key bindings.
Key bindings can be changed at run time by use of the LOAD.KEYS command. This takes the
name of a key binding record as its argument and the bindings defined in that record will be loaded.
The SAVE.KEYS command saves the current key bindings into a record named in the command
argument (e.g. SAVE.KEYS DEFAULT to generate the DEFAULT bindings record).
Key binding records consist of a series of lines (fields), each of which defines one or more bindings
for the function associated with that line separated by value marks. Control characters are
represented by @A, @B, etc. for Ctrl-A, Ctrl-B, etc. Thus escape is @[. The @ character can be
included in a binding as @@. All characters before the first @ are ignored thus allowing comments
to be included. The SAVE.KEYS command inserts the function name as a comment in each
binding.
One way to create new bindings is to use SAVE.KEYS to create a template which is then edited to
make any desired modifications. The quote char function followed by K inserts the key binding
expansion of the next key pressed and can be used while editing a key binding record. This function
simply inserts the characters sent by the next key pressed. It does not validate the modified binding
record for duplicate or ambiguous key sequences.
Used in this way, quote char waits for the first character to arrive and then sleeps for one second. It
then inserts the codes for all characters waiting to be processed. This ensures that the entire
sequence sent by, for example, a function key is processed. You should wait until the character
sequence appears on the screen before typing any further characters.
2.11-0
QM Commands 457
The extension programming feature allows users to add new functions to the editor. These may
range from simple insertion or modification of text with a single keystroke to complex programs
that manipulate the data to achieve tasks that are specific to your own editor usage.
Extensions may be stored in any QM file. Ideally, this should be a dynamic hashed file and SED
uses &SED.EXTENSIONS& by default. A list of alternative locations to look for extensions can
be defined using the $$EXTENSIONS variable described in SED Extensions - Variables,
Constants and Funcitons. For all except the START.UP extension described below, if an extension
is not found in any of these locations, a final check is made in the &SED.EXTENSIONS& file in
the QMSYS account.
The editor looks for and executes an extension named START.UP on loading the first data record.
Extension names must be upper case and consist only of letters, digits, periods (.) and dollar signs.
Extensions must be compiled before use. This is performed using SED’s COMPILE command
which recognises extension programs as distinct from QMBasic programs. The compiled version is
stored in the same file as the source but with a suffix of -EXT added to the record name.
An extension is executed by the SED run extension function which is normally bound as Esc-E.
Extensions may also be bound directly to user defined key sequences or made available via the
command function. Typically this would be performed by the optional START.UP extension.
The extension programming language is based on the LISP language. This yields programs with
very simple, though somewhat strange looking, structure.
Extension programs come in two types; procedures perform some operation whereas functions
also return a value. The outermost structure of a procedure is
PROC
(
...operations...
)
FUNC
(
...operations...
)
A function returns a value using the return operation at any point in its execution. There is an
implicit return of a zero value at the end of the function text.
Each of these operations is also a procedure or a function in that they perform some operation on
the editing environment and/or they return information that can be used by other operations.
2.11-0
458 OpenQM
Each complete operation and any data items on which it works are enclosed in a further layer of
brackets. Since the language allows functions to be nested to a high degree, a typical program at
first appears to contain a large number of brackets. By applying some thought to the layout of the
program, the actual structure can be made very clear to the reader. The language has no built-in
format rules except that no token (individual word, constant, variable name, etc.) can span lines.
For example, a simple program to provide the equivalent of the STAMP command of ED could be
written as:
PROC
(
(goto.col 1)
(insert ‘*Last updated by ‘ @who ‘ (‘ @logname ‘)’
‘ at ‘ (oconv @time ‘MTS’)
‘ on ‘ (oconv @date ‘D4/’))
(newline 1)
)
The screen is not updated during execution of an extension program except by functions that are
documented as doing so. This allows the extension program to perform complex data movements
without the screen continually tracking the internal workings of the extension. The screen is updated
when the extension terminates.
All extension program source text is case insensitive except for literal strings.
Local Variables
These are names commencing with a letter and containing only letters, digits, periods (.) and dollar
signs. A procedure or function can use at most 250 local variables. Local variables are private to
the procedure or function and the same name used in another procedure refers to a different local
variable.
Global Variables
These are names commencing with a dollar sign and containing only letters, digits, periods (.) and
dollar signs. Global variables are common to all extensions and retain their values until the user
leaves SED.
Global variables beginning with two dollar signs are reserved. Current usage of these names is:
2.11-0
QM Commands 459
Constants
Numeric constants are written as a sequence of digits, optionally prefixed by a sign or including a
decimal point. A numeric constant with an absolute value of less than one must be written with a
leading zero (e.g. 0.5).
A string constant may be enclosed in either single or double quotes. It may contain any character
except the mark characters (which are available using the tokens shown below) and ASCII
character 0 (nul).
The logical values are represented as 0 for false and 1 for true. In general, use of any value other
than zero is treated as true by operations that expect logical values as their arguments.
Key Tokens
The get.key function returns a code that relates to an internal function number. Each function has a
corresponding symbolic name. These all begin with a period (.) and are the same as the comment
inserted at the start of each line of a key binding record with spaces replaced by period. The names
are:
2.11-0
460 OpenQM
.insert .align.text
System Variables
Extension programs may examine the current state of many editor features by use of system
variables. These all begin with a percent sign (%) and are read only (i.e. they cannot be used in a set
function).
Comments
A comment is introduced by an asterisk (*) and extends to the end of the line.
Erroneous Programs
Extension programs may test whether the buffer being processed is read only. Attempts to change
such a buffer are ignored. No error is displayed.
Variables are type variant in the same way as for QMBasic programs and they follow the same
rules. In most cases, attempts to use a non-numeric value where a number is required result in use
of a default.
SED Extensions - Standard variables and functions
Variables are type variant in the same way as for QMBasic programs and they follow the same
rules. In most cases, attempts to use a non-numeric value where a number is required result in use
of a default.
Buffer Information
%file Returns file name for current buffer. This is prefixed by “DICT “ if the
buffer is from the dictionary part of the file.
%id Returns the record id for the current buffer. For an explore buffer or a file
list buffer it returns a pseudo id value.
%buffer.type Returns a type code for the current buffer:
1 : data buffer
2 : explore buffer
3 : file list buffer
%read.only Returns a logical value indicating whether the current buffer is read only.
(set.read.only n) Sets the read only status of the current buffer. If n is non-zero, the buffer
is marked as read only, otherwise modifications are allowed. This function
is of particular use with scratch buffers. It is ignored for buffers
containing explore record lists or file lists.
2.11-0
QM Commands 461
%changed Returns a logical value indicating whether the current buffer is marked as
having been changed since it was last saved.
(set.changed n) Sets the status of the buffer changed flag. If n is zero, the buffer is marked
as unchanged, otherwise it is marked as changed. Use this operation with
care as it can result in data not being saved on leaving the editor. It is of
particular use with scratch buffers.
%overlay Returns a logical value indicating whether the current buffer is operating in
overlay mode.
(set.overlay n) Sets the overlay status of the current buffer. If n is zero, overlay is turned
off, otherwise it is turned on.
%buffer.no Returns the current buffer number.
(prev.buffer n) Select the buffer with buffer number n less than the current one. This
operation cycles to the highest numbered buffer if necessary.
(next.buffer n) Select the buffer with buffer number n greater than the current one. This
operation cycles to the lowest numbered buffer if necessary.
(goto.buffer n) Select buffer number n.
(delete.buffer) Deletes the current buffer. Unlike the SED delete.buffer keyboard
function, this operation allows deletion of modified buffers without any
confirmation checks.
%current.line Returns text of current line.
%current.char Returns character under cursor.
%line.len Returns length of current line.
%line Returns current line number.
%col Returns current column number.
%lines Returns number of lines in current record.
%mark.line Returns the line number of the mark position, zero if no mark set.
%mark.col Returns the column number of the mark position, zero if no mark set.
%scroll Returns current scroll position. This is the line number of the data
displayed on the first line of the screen.
(set.scroll n) Sets the current scroll position to n. The value of n must be greater than
zero and must not be greater than the number of lines in the current buffer.
The next screen update (paint or implicit from some other function) will
move the scroll position if the current line is not in the displayed region of
the buffer.
%pan Returns the current pan position. This is the column number (from one) of
the leftmost displayed column of the current buffer.
(set.pan n) Set the current pan position to n. The value of n must be greater than zero.
The next screen update (paint or implicit from some other function) will
move the pan position if the current cursor position is not in the displayed
region of the buffer.
%tab.interval Returns the current setting of the tab interval.
(set.tab.interval n) Sets the tab interval to n. The value of n must be in the range 1 to 99.
%width Returns the width of the screen display.
%height Returns the number of lines on the screen display excluding the two editor
status lines.
%kill.buffer Returns the content of the kill buffer.
2.11-0
462 OpenQM
(make.buffer name) Makes a new scratch buffer named name. Scratch buffers may be used for
internal purposes of the extension program or as the place to create data
which will later be written to disk. Use of %file with a scratch buffer
returns a null string. %id returns name. This function returns true if
successful, false if not. If a scratch buffer of the given name already exists,
it makes that buffer current and returns true.
(find.buffer file rec) Returns the internal number of the buffer holding data from the given file
and record. Use of a null string as file allows location of a scratch buffer.
This function returns zero if no such buffer exists.
(find.record file rec) Reads record rec from file into a newly created buffer. If the record is
already loaded, it simply switches to that buffer. This function returns true
if successful, false if not.
(save.record) Saves the current buffer. It has no effect on a scratch buffer or if the
current buffer is read only. The normal source control actions are
performed if this editor feature is in use.
(write.record file rec) Writes the current buffer to record rec in file. This operation may result in
the current buffer being renamed. The normal source control actions are
performed if this editor feature is in use. The write.record operation is
ignored if the target record is locked by another user.
2.11-0
QM Commands 463
1 : Case sensitive
2 : Case insensitive
3 : Word search, case insensitive
This function returns a logical value indicating whether the search was
successful. An unsuccessful search does not move the current position.
(del.char n) Delete n characters.
(backspace n) Backspace n characters.
(insert s) Insert string s at current cursor position. Any field marks in the text are
treated as newlines. The insert function can take more than one argument,
each of which is inserted in turn.
(newline rpt) Insert rpt newlines at the current cursor position.
(tab rpt) Advances the cursor to the next tab position as determined by the current
setting of the tab interval. Additional spaces are appended to the current
line if necessary. The rpt argument specifies how by many tab positions
the cursor is to be advanced.
(goto.line a) Go to column 1 of line a.
(goto.col a) Go to column a of current line. The line is extended if necessary by adding
trailing spaces.
(set.mark) Set the mark at the current cursor position.
(swap.mark) Interchange the cursor and mark positions. Has no effect if there is no
mark position defined.
(retype s) Replace the current line by string s.
(set.case mode rpt) Changes the case of the next rpt words in the current buffer. The mode
argument is:
0 : Set lower case
1 : Set upper case
2 : Set capital initial casing
(toggle.chars) Interchanges the character at the cursor position with that in the preceding
column.
(fwd.word n) Moves the cursor forward by n words.
(back.word n) Moves the cursor backward by n words.
(del.word n) Deletes n words from the current cursor position.
(del.back.word n) Deletes n words backwards from the current cursor position.
(copy.region) Copies the region between the mark and the cursor, which may be in either
order, to the kill buffer.
(delete.region) Copies the region between the mark and the cursor, which may be in either
order, to the kill buffer and deletes the text from the buffer.
(close.spaces) Closes multiple spaces around the current cursor position to be just one
space.
2.11-0
464 OpenQM
(int a) Returns the integer portion of value a by truncating any fractional part.
(eq a b) Test a equal to b.
(ne a b) Test a not equal to b.
(lt a b) Test a less than b.
(gt a b) Test a greater than b.
(le a b) Test a less than or equal to b.
(ge a b) Test a greater than or equal to b.
(and a b) Forms logical relationship a and b. The and function can take more than
two arguments, each of which is and'ed in turn.
(or a b) Forms logical relationship a or b. The or function can take more than two
arguments, each of which is or'ed in turn.
(not a) Returns logical inverse of a.
(max a b) Returns the maximum of a and b. If either value is not numeric, this
function returns the item that appears last in collating sequence order.
(min a b) Returns the minimum of a and b. If either value is not numeric, this
function returns the item that appears first in collating sequence order.
(len s) Returns the length of string s.
(char n) Returns the character with ASCII character value n.
(seq c) Returns the ASCII character sequence number of the first character of c.
(cat a b) Returns concatenation of strings a and b. The cat function can take more
than two arguments, each of which is concatenated in turn.
(substr s a b) Returns a substring from s starting at character a, b characters long.
(pad s n) Pad string s with spaces to be n characters long. If string s is already at
least n characters long, this function returns the original string.
(trim s) Returns string s with all leading and trailing spaces removed and all
multiple embedded spaces replaced by a single space.
(trimb s) Returns string s with all trailing spaces removed.
(trimf s) Returns string s with all leading spaces removed.
(upcase s) Returns string s converted to upper case.
(downcase s) Returns string s converted to lower case.
(extract str f v s) Returns field f, value v, subvalue s of string str. Specify v and s as zero to
extract field f, s as zero to extract field f, value v.
(rep str f v s new) Returns a string formed from str with field f, value v, subvalue s replaced
by new. Specify v and s as zero to replace field f, s as zero to replace field f
, value v.
(ins str f v s new) Returns a string formed from str with new inserted before field f, value v,
subvalue s. Specify v and s as zero to insert before field f, s as zero to
insert before field f, value v.
(del str f v s) Returns a string formed from str with field f, value v, subvalue s deleted.
Specify v and s as zero to delete field f, s as zero to delete field f, value v.
(field str d n count) Returns a portion of str starting at the n’th substring delimited by d and
extending for count such substrings.
2.11-0
QM Commands 465
2.11-0
466 OpenQM
(switch val
case a proc1
case b proc2
...
else proc) Executes one of several procedures depending on the value of val. Items a,
b and c (etc.) are values which are compared with val. The else
component is optional and is executed only if none of the preceding
conditions is met.
(loop proc
) Executes proc repeatedly. proc may be one or more procedures. A loop is
terminated by use of exit.
(exit) Exits from the innermost active loop.
(return) Returns from the current PROC.
(return n) Returns n as the value of the current FUNC.
(stop) Terminates extension program and returns to SED edit mode.
(quit n) Terminates current edit. If n is zero, SED continues processing a select list
(equivalent to the quit editor function). For non-zero values of n, SED
terminates the entire sequence (equivalent to the QUIT command).
Setting Variables
(set var val) Set local or global variable var to val.
Extension Control
(unload) Unloads all extensions on exit from outermost extension program.
(bind.command ext name) Binds extension procedure ext as command name. The extension name is
automatically converted to upper case.
(bind.key ext keyseq) Binds extension procedure ext as key sequence keyseq. The extension
name is automatically converted to upper case.
This function returns a logical value indicating whether it was successful.
%key.bindings Returns a dynamic array, each field of which corresponds to a bindable
internal function and consists of one or more values which hold the actual
character sequence. Note that this character sequence is the actual
characters, not the encoded form used in the key bindings records to avoid
use of control characters. The field number of any particular key can be
identified using the key tokens described earlier.
(xeq cmnd) Executes cmnd as though it were entered using the editor command
function. Commands which are themselves bound to extensions cannot be
executed in this way.
SED checks for extensions bound as command names before internal
commands. It is therefore possible to replace a built-in command.
Furthermore, since extensions cannot execute extension commands, the
extension can be used to provide a prelude to a built-in command.
%macro.state Returns state of editor macro system:
0 : Not collecting or executing
1 : Collecting macro
2 : Executing macro
2.11-0
QM Commands 467
The following editor keyboard functions are not available directly as extension operations. They
can all be achieved by use of other operations.
Any user written PROC or FUNC may take arguments. The actual number the compiler expects to
pass is determined by the first reference to that PROC or FUNC and is checked at run time against
the number that are expected by the called item.
2.11-0
468 OpenQM
PROC
ARGS arg1, arg2, arg3...
(
...operations...
)
The arg1, arg2, etc. items are local variables into which the argument values are to be transfered
when the procedure is called.
SED Extensions - An example of a complex extension
The following extension implements a “walk” function which is provided as a standard part of QM
in the &SED.EXTENSIONS& file of the QMSYS account.
This function allows you to define a rectangular block of text and use the cursor keys to “walk” it
left, right, up or down. As the text block “runs over” other text, this reappears on the opposite side
of the block being moved. The walk function is very useful in rearranging tabular data.
To use this extension, first position the cursor at the top left of the block. Execute the extension and
move the cursor to the bottom right of the block by using the up, down, left and right functions then
press the return key. Further use of the up, down, left and right functions will move the defined
block until the return key is pressed once more.
PROC
(
(if %read.only
(status.msg 'Read only buffer')
(beep)
(wait.input)
(return)
)
2.11-0
QM Commands 469
case .down.line
(set ct %prefix.count)
(loop
(if (gt %line %lines) (exit))
(down.line 1)
(if (lt %line.len %col) * Must extend
line
(retype (pad %current.line %col))
)
case .fwd.char
(set x (add %col %prefix.count))
(if (gt x %line.len) (retype (pad %current.line x)))
(goto.col x)
case .back.char
(set x (sub %col %prefix.count))
(if (le x left) (set x left))
(goto.col x)
case .newline
(set height (add (sub %line top) 1))
(set width (add (sub %col left) 1))
(exit)
case .cancel
(status.msg '')
(stop)
else
(beep)
)
)
(goto.line top)
(goto.col left)
2.11-0
470 OpenQM
block
(up.line 1)
(if (lt %line.len rc) * Must extend line
(retype (pad %current.line rc))
)
(set wrapped.bit (substr %current.line left width))
(set ct height)
(loop
(down.line 1)
(set moving.bit (substr %current.line left
width))
(up.line 1)
(retype (cat (substr %current.line 1 lw)
moving.bit
(substr %current.line right
999999)))
(down.line 1)
(set ct (sub ct 1))
(if (eq ct 0) (exit))
)
(down.line height)
(if (lt %line.len rc) * Must extend line
(retype (pad %current.line rc))
)
(set wrapped.bit (substr %current.line left width))
(set ct height)
(loop
2.11-0
QM Commands 471
(up.line 1)
(set moving.bit (substr %current.line left
width))
(down.line 1)
(retype (cat (substr %current.line 1 lw)
moving.bit
(substr %current.line right
999999)))
(up.line 1)
(set ct (sub ct 1))
(if (eq ct 0) (exit))
)
(down.line 1)
(set ct (sub ct 1))
(if (eq ct 0) (exit))
)
(set left (add left 1))
(goto.line top)
(goto.col left)
(set rpt (sub rpt 1))
(if (eq rpt 0) (exit))
2.11-0
472 OpenQM
case .back.char
(set rpt %prefix.count)
(loop
(set lw (sub left 1)) * Width of bit to left
of block
(set right (add left width)) * Col of bit to right
of block
(set rc (sub right 1)) * Righmost column of
block
(down.line 1)
(set ct (sub ct 1))
(if (eq ct 0) (exit))
)
(set left (sub left 1))
(goto.line top)
(goto.col left)
case .newline
(exit)
case .cancel
(status.msg '')
(stop)
else
(beep)
)
)
(status.msg '')
2.11-0
QM Commands 473
(set ct height)
(loop
(retype (trimb %current.line))
(down.line 1)
(set ct (sub ct 1))
(if (eq ct 0) (exit))
)
(goto.line top)
(goto.col left)
)
A single extension source record may contain local procedures and functions that are only
accessible to the other components of that extension. These must follow the main procedure or
function are take the form
LPROC name
ARGS arg1, arg2, arg3...
(
...operations...
)
or
LFUNC name
ARGS arg1, arg2, arg3...
(
...operations...
)
There is no concept of local variable scope. Variable names used within local PROCs and FUNCs
refer to the same set of variables as in the main PROC or FUNC. In particular, note that the
argument variables simply provide an easy way to transfer information into the local PROC or
FUNC. The two alternatives below are exact equivalents.
PROC
(
...
(MYPROC 12 A)
...
)
LPROC MYPROC
ARGS X, Y
(
...
)
PROC
(
...
(SET X 12)
2.11-0
474 OpenQM
(SET Y A)
(MYPROC)
...
)
LPROC MYPROC
(
)...
Although local procedures may recurse (that is call themselves) it is likely that the lack of scoped
variables makes this of limited use.
2.11-0
QM Commands 475
4.157 SEL.RESTORE
The SEL.RESTORE command restores a single file from a Pick style ACCOUNT.SAVE or
FILE.SAVE tape.
Format
where
item.list is a list of records to be restored. The default select list may be used
instead. If omitted, and no list is active, all records are restored.
Unless the POSITIONED option is used, the SEL.RESTORE command prompts for the name of
the account and the file within that account. It then restores the data for this file from the tape into
the specified target file. which must already exist.
The tape to be restored must first be opened to the process using the SET.DEVICE command.
See also:
ACCOUNT.RESTORE, ACCOUNT.SAVE, FILE.SAVE, FIND.ACCOUNT,
RESTORE.ACCOUNTS, SET.DEVICE, T.ATT, T.DUMP, T.LOAD, T.xxx
2.11-0
476 OpenQM
4.158 SELECTINDEX
The SELECTINDEX command constructs a select list from an alternate key index.
Format
where
TO list specifies the list to be created. If omitted, the default list (list 0) is created.
The SELECTINDEX command constructs a select list containing all the indexed values in the
specified alternate key index. It is equivalent to use of the QMBasic SELECTINDEX statement
with no indexed value.
Both @SELECTED and @SYSTEM.RETURN.CODE will be set to the number of item selected.
2.11-0
QM Commands 477
4.159 SET
Format
where
variable is the name of the variable to be set. The leading @ character is optional. The
name may be up to 32 characters and is case insensitive.
value is the value to be stored. This may not include the mark characters. Quotes
should not be used unless they are part of the value to be stored. Leading and
trailing spaces within value are removed; embedded spaces are retained.
The SET command sets a value into a user defined @-variable. The values of system defined
variables @SYSTEM.RETURN.CODE, @USER0 to @USER4 and @USER.RETURN.CODE c
an also be set.
In the second form, the expression may include the four arithmetic operators +, -, * and /. These
operators must be surrounded by spaces. Any @-variables in the expression will be expanded.
Examples
SET USER.RETURN.CODE 1
PA
SET CT 5
LOOP
DISPLAY <<@CT>>
SET CT EVAL @CT - 1
IF @CT = 0 THEN STOP
REPEAT
This paragraph executes the loop five times, displaying the decreasing values stored in @CT on
each cycle.
PA
SET @PRINT ""
IF <<I2,Select branch>> EQ "" THEN STOP
IF <<I3,Print (Y/N)?>> EQ "Y" THEN SET @PRINT LPTR
2.11-0
478 OpenQM
The above paragraph shows use of a user defined @-variable to control whether the paragraph
directs the report to the display or to a printer. The @PRINT variable is set to a null string at the
start of the paragraph in case it already exists from previous actions in the same session. Later, if
the user wants the report sent to a printer, this variable is set to "LPTR". The value of @PRINT is
then included in the query sentence executed by the paragraph.
See also:
LIST.VARS and the QMBasic !ATVAR() and !SETVAR() subroutines.
2.11-0
QM Commands 479
4.160 SET.DEVICE
The SET.DEVICE command opens a tape or pseudo-tape for processing by QM. The synonym
T.ATT may be used.
Format
where
device.name is the pathname of the device to be opened. This must be enclosed in quotes if
it commences with a backslash on Windows.
The SET.DEVICE command assigns a tape device or a file representing a pseudo-tape to the
current QM process. The device can then be used by other tape processing commands such as
ACCOUNT.SAVE, ACCOUNT.RESTORE, T.DUMP, T.LOAD and the T.xxx tape utility
commands.
Note: QM does not support Pick style use of floppy disks as tape devices.
If the format option is not given, SET.DEVICE attempts to detect the format of the image being
attached by examination of the data. A code signifying the format is then stored internally for future
use by the other tape processing utilities.
The NO.QUERY option suppresses the confirmation prompt asking if a previously attached device
should be detached.
Note that access to real tape devices (as opposed to pseudo-tapes) may offer limited functionality.
In particular, the Pick compatible tape transfer tools require the ability to process file mark blocks,
a feature which may not be provided by the underlying operating system device driver. Use of
pseudo-tapes is strongly recommended.
To use a floppy disk drive (e.g. a Pick style account save) specify the device.name as "A:" on
Windows or use the device driver name (probably /dev/fd0) on Linux.
The AS type can be either a single ACCOUNT-SAVE or several ACCOUNT-SAVEs on the same
tape. These multiple saves are created by successive ACCOUNT-SAVE commands issued without
rewinding the tape between saves. If multiple accounts exist, this format is handled like the FS type
by the tape utilities and RESTORE.ACCOUNTS, FIND.ACCOUNT and SEL.RESTORE
operations may all be used.
2.11-0
480 OpenQM
The ULTFS format is a FILE-SAVE format in which several accounts are expected.
The JBS format is essentially the same as the individual files that comprise the ULTFS set. These
files have a single label followed immediately by the account data and are treated like individual AS
types.
See also:
ACCOUNT.RESTORE, ACCOUNT.SAVE, FILE.SAVE, FIND.ACCOUNT,
RESTORE.ACCOUNTS, SEL.RESTORE, T.DUMP, T.LOAD, T.xxx
2.11-0
QM Commands 481
4.161 SET.ENCRYPTION.KEY.NAME
The SET.ENCRYPTION.KEY.NAME command updates a data file to reference a new name for
an encryption key.
Format
where
keyname is the name of the encryption key to be used. This is case insensitive.
The first form of the SET.ENCRYPTION.KEY.NAME command updates the encryption key for
one or more fields within a file that uses field level encryption.
The second form of the SET.ENCRYPTION.KEY.NAME command updates the encryption key
for record level encryption.
Examples
The above command sets the encryption key for the CCARD field of the CUSTOMERS file to be
CARDNO.
The above command sets the record level encryption key for encrypts the CUSTOMERS file to be
CKEY.
See also:
Data encryption, CREATE.FILE, CREATE.KEY, DELETE.KEY, GRANT.KEY,
LIST.KEYS, RESET.MASTER.KEY, REVOKE.KEY
2.11-0
482 OpenQM
4.162 SET.EXIT.STATUS
The SET.EXIT.STATUS command sets the final exit status returned by QM to the operating
system. This command is not available on the PDA version of QM.
Format
SET.EXIT.STATUS value
where
By default, QM returns an exit status of zero to the operating system on termination. The
SET.EXIT.STATUS command allows an application to return an alternative exit status value to
indicate, for example, success or failure. Note that error conditions detected during startup of a QM
session return an exit status of 1.
2.11-0
QM Commands 483
4.163 SET.FILE
The SET.FILE command adds a Q-pointer to the VOC to reference a remote file.
Format
where
account is the name of the account holding the file to be referenced. This name must exist in
the ACCOUNTS file of the QMSYS account. Alternatively, account may be
specified as a QMNet style reference server:account to create a Q-pointer that
links to a file on a remote system.
filename is the name of the file in the remote account. This must correspond to an F or
Q-type VOC entry in that account. Creation of Q-pointer chains where one
Q-pointer points to another is not recommended.
pointer is the name to be given to the Q-pointer created in the local account.
The SET.FILE command prompts for information not provided on the command line. The pointer
defaults to QFILE.
The SET.FILE command creates a Q-pointer in the local account to reference the named file in the
remote account. Q-pointers should be used in preference to multiple F-type records pointing to the
same file as they simplify maintenance and give a sense of ownership of the file to the account
containing the F-type entry.
Examples
The above command creates a Q-pointer named DEV.SALES that references the SALES file in the
DEV account.
The above command creates a Q-pointer named SBY.INVOICES that references the INVOICES
file in the LIVE account on the server named STANDBY.
2.11-0
484 OpenQM
4.164 SET.QUEUE
The SET.QUEUE command creates a relationship between a Pick style form queue number and
the corresponding SETPTR print unit options.
Format
where
depth is the total page length in lines, including the top and bottom margins. A
value of zero implies no pagination of the output data.
top.margin is the number of lines to be left blank at the top of the page.
bottom.margin is the number of lines to be left blank at the bottom of the page.
options qualify the output destination. There should be a comma between each
option.
If only queue is given, the current settings of the form queue are reported.
The SET.QUEUE command creates or modifies an entry in the $FORMS file to relate a Pick style
form queue number to the corresponding SETPTR options. This form queue number can then be
used in the SP.ASSIGN command. See SETPTR for details of the command options.
The SET.QUEUE DISPLAY command displays a report of the settings of all defined form
queues. The optional LPTR keyword directs this report to a printer.
The $FORMS file is normally shared between all accounts by use of a VOC entry that references
the $FORMS file in the QMSYS account. An account can have its own forms definition file by
modifying this VOC entry to point to a file within the account. It is also possible for users to have a
personal forms definition file based on their login id by setting the pathname to be of the form
@HOME\FORMS
where the @HOME element will be replaced by the user's home directory pathname.
SET.QUEUE performs limited validation of the parameters as later use of SP.ASSIGN may
change some of them. For example, it is valid for a SET.QUEUE command to have both the AS
and AT options (see SETPTR). Whichever is not applicable to the mode settings when the
SP.ASSIGN command is used will be discarded.
2.11-0
QM Commands 485
Examples
See also:
SETPTR, SP.ASSIGN
2.11-0
486 OpenQM
The SET.SERVER command defines a QMNet server available to all users. The
SET.PRIVATE.SERVER command defines a QMNet server visible only from the QM session in
which the command is executed.
Format
where
port is the tcp/ip port number on which connection to this server will be made. It
must correspond to the port on which the server listens for incoming QMClient
connections. If omitted, the default QMClient port (4243) is used.
username is the username that will be used to connect to the server. This must be defined
at the operating system level on the server but does not need to be defined on
the local system.
password is the password for the supplied username. It is stored internally in encrypted
form for security.
server.name is the name of another server from which the security data is to be copied.
The command will prompt for command line elements that are omitted.
QMNet allows an application to access QM data files on other servers as though they were local
file, with complete support for concurrency control via file and record locks. The remote server
must have remote access enabled by setting the NETFILES configuration parameter to 2.
Public servers may be defined by any user with system administrator rights using the
SET.SERVER command in the QMSYS account. The NO.QUERY keyword suppresses the
confirmation prompt if the server name is already defined. A public server defined with this
command can be accessed by all users. The ADMIN.SERVER command can be used to create or
modify server definitions to apply restrictions on which users can access the server. Alternatively,
the LIKE keyword can be used to copy the security settings from another public server definition.
Private servers are defined using the SET.PRIVATE.SERVER command. As part of the QM
security system (see Application Level Security), the SET.PRIVATE.SERVER command is only
available to users for which it is enabled in their user register entry. On a system running with
2.11-0
QM Commands 487
Example
This example will create a server known within QM as ADMIN. The server IP address is
193.100.13.18 and connection will use port 4000. The username (root) has been included in the
command but, because the password has been omitted, the command will prompt for this.
See also:
QMNet, ADMIN.SERVER, DELETE.SERVER, LIST.SERVERS
2.11-0
488 OpenQM
4.166 SET.TRIGGER
The SET.TRIGGER command sets, removes or displays the trigger function associated with a
dynamic file.
Format
where
modes is any combination of the following tokens indicating when the trigger will
be executed.
PRE.WRITE Before a write operation
PRE.DELETE Before a delete operation
PRE.CLEAR Before a clear file operation
POST.WRITE After a write operation
POST.DELETE After a delete operation
POST.CLEAR After a clear file operation
READ After a read operation
If no modes are specified, the default is PRE.WRITE and
PRE.DELETE.
The first form of the SET.TRIGGER command sets the name of the trigger function to be
associated with the named file. Any existing trigger function is replaced by this action.
The second form of the SET.TRIGGER command removes the trigger function for the named file.
The third form of the SET.TRIGGER command displays the name and modes of the trigger
function for the named file.
Setting or removing a trigger while the file is open may not take effect until after the next access to
the file.
2.11-0
QM Commands 489
4.167 SETPORT
The SETPORT command sets communications parameters of a serial port. This command is not
available on the PDA version of QM.
Format
SETPORT port {BAUD rate} {BITS bits.per.byte} {PARITY parity} {STOP.BITS stop}
{BRIEF}
where
If only port is given, the current settings of the port are reported.
On some systems, it may be necessary to change the permissions on the device driver to make it
accessible to users.
Example
2.11-0
490 OpenQM
4.168 SETPTR
Format
where
unit is the print unit number in the range 0 to 255 or the keyword DEFAULT.
width is the page width in characters, excluding any left margin. This value is
used to calculate alignment in query processor reports and
headings/footings but does not prevent application programs emitting data
that exceeds this width.
depth is the total page length in lines, including the top and bottom margins. This
value is used to control insertion of form feeds, headings and footings. into
the printed data. A value of zero implies no pagination of the output data.
top.margin is the number of lines to be left blank at the top of the page.
bottom.margin is the number of lines to be left blank at the bottom of the page.
If only unit is given, the current settings of the print unit are reported.
Use of the DEFAULT keyword in place of a unit number records the default values to be used
when a new print unit is accessed without prior use of SETPTR to define its settings. Note that this
operation does not affect the default printer, print unit 0, which is configured with standard default
settings on entry to QM. These can be changed with a SETPTR command specifying unit 0.
The third form of SETPTR with a unit number and the DISPLAY keyword shows the current
settings in a form that can be captured by a program and later used to restore the settings by
executing a SETPTR command with the captured value appended.
When using printer modes 3 or 6, a check is made to see if there is a catalogued subroutine named
HOLD.FILE.LOGGER and, if there is, this is called when the file is opened and again when it is
closed. This subroutine can be used, for example, to build a log of hold file entries or to take some
2.11-0
QM Commands 491
action after the file has been closed. The subroutine takes three arguments; the print unit number, a
flag indicating if this is an open (1) or a close (0), and the pathname of the file being created.
AS { NEXT } { id } Specifies the hold file record name in modes 3 and 6. Use of this
option with other mode values will result in an error. At least one of
the optional components must be present.
id is the name of the record to be created in the $HOLD file. If
omitted, a default name of Punit is used.
The optional NEXT keyword causes QM to attach a cyclic sequence
number to the end of the name so that successive output is stored
separately. Note that this sequence number is shared across all printer
output directed to the $HOLD file by all processes, thus two
successive jobs from one process may have non-adjacent sequence
numbers. The default behaviour is for the sequence number to be four
digits, cycling through the range 0001 to 9999. The next available
sequence number is stored in field 2 of a record named $NEXT in the
dictionary of the $HOLD file. An alternative number of digits in this
value may be specified in field 3 of this dictionary record and must be
in range 3 to 9. The sequence number can be determined using the
GETPU() function or the @SEQNO variable.
AS PATHNAME path Specifies a destination pathname for output in modes 3 and 6. Use of
this option with other mode values will result in an error.
AT printer.name Specifies the printer name in modes 1 and 6. This name must be
enclosed in quotes if it contains spaces or backslashes. The name is
case sensitive except on Windows. Note that printing occurs on the
server on which QM is running and the printer name must be known to
the server. Mode 5 provides a way to print on printers connected to the
client system.
BANNER text Set the text to appear on a banner page.
BRIEF Suppresses the normal confirmation prompt before setting the printer
characteristics. This is typically used in SETPTR commands from
paragraphs or QMBasic programs.
COPIES n Specifies the number of copies to be printed. Some printers may not
handle this option.
EJECT Appends a form feed to the end of the print data.
FORM.FEED mode Determines the form feed sequence used by the QMBasic PRINT
statement. This may be FF or CRFF. The default is CRFF.
GDI Specifies that the GDI mode API calls are to be used to initiate
printing.
INFORM Displays file details when opening a print file in mode 3. The session
will pause for 1.5 seconds after the message is displayed to allow for
situations where the screen would be overwritten.
KEEP.OPEN Keeps the printer open to merge successive printer output. Use the
PRINTER CLOSE command to terminate the print job.
2.11-0
492 OpenQM
LANDSCAPE When used without the PCL option, this option is passed to the
underlying print driver to request landscape format printing where this
is supported. On non-Windows platforms, this is equivalent to use of
OPTIONS "landscape".
LEFT.MARGIN n Inserts a margin of n spaces to the left of the printed data.
NEWLINE mode Determines the newline sequence used by the QMBasic PRINT
statement. This may be CR, LF or CRLF. The default is LF.
NFMT Specifies that no page formatting is to be applied to the output data.
The entire output is treated as a single page with no further inserted
form feeds or top and bottom margins.
NODEFAULT Omitted options normally take their default values. Use of this
keyword leaves the option at its current value.
NOEJECT Suppresses the normal page throw at the end of a print job. This
option applies to Windows only.
OPTIONS xxx Passes the given option(s) to the underlying operating system print
spooler (e.g. OPTIONS "landscape" on non-Windows systems).
OVERLAY subr Identifies a catalogued subroutine that will be executed at the start of
each page of output. This subroutine takes a single argument which is
the print unit number and can be used to send printer control codes for
a graphical page overlay, if required. It should not perform any other
printer output. This option is ignored for Windows GDI mode printing.
PCL Specifies that this printer supports PCL. This option cannot be used
with GDI mode Windows printers.
PORTRAIT Where supported by the underlying print driver, this keyword specifies
that the output is to be printed in portrait format.
PREFIX path Sends the contents of the named file to the printer at the start of each
job. This can be used to send printer specific commands for features
that are not available through other SETPTR options. This option is
ignored for Windows GDI mode printing.
RAW Specifies that the non-GDI mode API calls are to be used to initiate
printing.
SPOOLER name Specifies and alternative spooler to be used on non-Windows systems.
If not specified, the spooler selected by the SPOOLER configuration
parameter is used or, if this is not set, the standard lp spooler is used.
The name can include other spooler options if required but must be
quoted if it includes spaces or other reserved characters. The actual
command executed to print the job will be name with options
appropriate to lp added as follows:
-n copies If COPIES is greater than 1.
-d prt.name To set the printer name if AT is used.
-t banner Banner text if BANNER is used.
-o "options" Text from OPTIONS if used.
-o "landscape" If LANDSCAPE is used.
The SPOOLER option can be used to access another standard
operating system spooler package or to direct output to a user written
2.11-0
QM Commands 493
PCL Printers
The following additional options are available. Although the values set will be saved and can be
accessed by application software, they only affect printing when used with the PCL option. In many
cases, the list of acceptable parameter values can be extended by modifying the SYSCOM
$PCLDATA record.
CPI n Specifies the number of characters per inch. The value may be
non-integer.
DUPLEX Selects duplex (double sided) printing, binding on the long edge.
DUPLEX SHORT Selects duplex (double sided) printing, binding on the short edge.
LANDSCAPE Prints the page in landscape format.
LPI n Specifies the number of lines per inch. The value must be 1, 2, 3, 4, 6,
8, 12, 16, 24 or 48.
PAPER.SIZE xx Specifies the paper size. Valid size names are A4, LETTER, LEGAL,
LEDGER, A3, MONARCH, COM_10, DL, C5, B5.
SYMBOL.SET xx Specifies the character set. Valid values of xx are ROMAN8 (the
default), LATIN1, ASCII, PC8.
WEIGHT xx Specifies the font weight. Valid values of xx are ULTRA-THIN,
EXTRA-THIN, THIN, EXTRA-LIGHT, LIGHT, DEMI-LIGHT,
SEMI-LIGHT, MEDIUM, SEMI-BOLD, DEMI-BOLD, BOLD,
EXTRA-BOLD, BLACK, EXTRA-BLACK, ULTRA-BLACK
though specific printers might not support all values.
When setting a print unit to PCL mode, if the above parameters are not specified, printing defaults
to 10 cpi, 6 lpi, medium weight using A4 paper and the Roman8 symbol set. These defaults can be
modified by adding an X-type record named $PCL to the VOC. This record must have an X as the
first character of field 1. Remaining fields may contain any of the CPI, LPI , PAPER.SIZE,
SYMBOL.SET and WEIGHT parameters as described above. For example:
0001: X
0002: PAPER.SIZE LETTER
0003: LPI 5
Note: The quality of PCL implementations varies widely and these options may not give the
expected results on some printers. In particular, setting some font metrics may cause inconsistent
character placement. It is the application developer's responsibility to ensure that the printed results
are acceptable.
2.11-0
494 OpenQM
Windows Printing
On Windows systems, two styles of interface with the underlying Print Manager are supported. The
GDI mode uses the Windows Graphical Device Interface API calls. Non-GDI mode uses an
alternative set of API calls. For most purposes, the non-GDI mode is likely to be preferable.
The GDI parameter to SETPTR sets GDI mode and the RAW parameter sets non-GDI mode. The
default is normally non-GDI but this can be modified by setting the GDI configuration parameter to
1.
Use of mode 4 (stderr) allows an application developer to direct output to the standard error file
handle. It is the user's responsibility to ensure that this points to an appropriate destination as the
default settings may cause the screen display to be overwritten. Data sent to a mode 4 printer is
output immediately rather than being buffered by QM. Headings, footings and other pagination
related features are ignored for printers in mode 4.
Mode 5 print units direct output to the terminal auxiliary port, typically to a printer local to the
client. The data is buffered by QM until the print unit is closed and then sent to the terminal
prefixed by the string defined in the mc5 terminfo entry for the selected terminal type. The data will
be followed by the string defined by the mc4 terminfo entry. The mc5/mc4 pair should be set to the
control codes necessary to enable/disable the auxiliary port.
The SETPTR DISPLAY command displays a report of the settings of all print unit. The optional
LPTR keyword directs this report to a printer.
Examples
SETPTR 0,,,,,3
Directs print unit 0 output to the default $HOLD file record (P0), leaving all page shape parameters
unchanged.
See also:
Printing, PRINTER, SET.QUEUE, SP.ASSIGN
2.11-0
QM Commands 495
4.169 SH
The SH command executes a shell (operating system) command. This command is not available on
the PDA version of QM.
Format
SH command
!command
SH
where
The SH command executes the given operating system command. No checks are performed on the
command to be executed so care needs to be taken not to do anything that would interfere with
correct operation of QM.
The ! synonym is provided for compatibility with other systems. This form does not need a space
between the ! and the command.
Use of SH without a command starts an interactive shell. Interactive shells are currently only
available for Linux, FreeBSD, AIX and Mac systems when QM is entered from the operating
system command processor. Use the shell exit command to return to QM.
Example
SH DIR
2.11-0
496 OpenQM
4.170 SLEEP
The SLEEP command suspends execution of further commands until a given number of seconds
have elapsed or until a specified time of day.
Format
SLEEP time
where
time is either a number of seconds or a time of day in any format accepted by the MT
input time conversion.
If time is a positive integer value, the process is suspended for that number of seconds.
If time is a time of day such as 8:27PM or 22:00:30, the process is suspended until that time.
Unlike the QMBasic SLEEP statement, the SLEEP command allows for sleeping past midnight.
A SLEEP to 12:00 executed at 13:00 would sleep for 23 hours.
The SLEEP command reports an error if the value of time is not a positive integer and cannot be
converted to a time of day.
2.11-0
QM Commands 497
4.171 SORT.LIST
Format
where
src.list is the name of a previously saved select list in the $SAVEDLISTS file.
tgt.list is the name of the new sorted list to be created in the $SAVEDLISTS file. If
omitted, src.list is replaced.
sort.rule identifies sorting sequence. If omitted, an ascending left aligned sort is used.
The SORT.LIST command sorts a previously saved select list, either creating a new list or
replacing the original.
Example
SORT.LIST INVENTORY DL
This example sorts the list name INVENTORY into descending left aligned sequence, replacing the
original list with the result.
See also:
COPY.LIST, DELETE.LIST, EDIT.LIST, FORM.LIST GET.LIST
2.11-0
498 OpenQM
4.172 SP.ASSIGN
The SP.ASSIGN command uses a form queue number to set the destination and other options for
printer output.
Format
SP.ASSIGN options
O keeps the print unit open until the PRINTER CLOSE command is used.
S Suppresses printing.
The SP.ASSIGN command references the $FORMS file (set up using SET.QUEUE) to relate
Pick style form queue numbers to the corresponding SETPTR options. The options to SP.ASSIGN
can be used to override the settings in the form queue definition.
The Fqno or Qqno options specify the form queue to be used. This defaults to zero if omitted.
The queue number is used to read the corresponding print unit details from the $FORMS file. The
remaining options can be used to override settings in the $FORMS entry.
Use of both the H and S options selects mode 3 printing, directing output to the hold file. When the
H option is used without the S option, print mode 6 is selected causing the output to be written to a
file and also printed.
SP.ASSIGN sets the characteristics of print unit zero, the default printer, unless the Runit option is
given.
Note: SP.ASSIGN is provided to ease migration of applications from Pick style environments. It is
strongly recommended that new applications should make direct use of SETPTR.
Examples
SP.ASSIGN F3
This command uses the definition of form queue 3 to process output sent to the default printer (print
2.11-0
QM Commands 499
unit 0).
SP.ASSIGN HSF3
This command uses the definition of form queue 3 but forces use of print mode 3 to send the data to
a file.
SP.ASSIGN HF3
This is similar to the previous example except that the data is saved to a file and also printed.
SP.ASSIGN 2R4F6
This command uses the definition of form queue 6 to process output sent to print unit 4 but forces
the number of copies to be 2.
See also:
Printing, SETPTR, SET.QUEUE
2.11-0
500 OpenQM
The SP.OPEN command sets the "keep open" flag on the default printer, merging multiple print
requests into a single print job. The SP.CLOSE command resets this option.
Format
SP.OPEN
SP.CLOSE
The SP.OPEN command is equivalent to use of the O option of the SP.ASSIGN command or the
KEEP.OPEN option of the SETPTR command.
When this mode is set, output directed to the default printer (print unit 0) from successive
commands or programs is merged into a single print job. The job is terminated and queued for
printing by use of SP.CLOSE or PRINTER CLOSE.
Example
SP.OPEN
LIST CUSTOMERS,NORTH LPTR
LIST CUSTOMERS,SOUTH LPTR
SP.CLOSE
The above sequence of commands lists records from two elements of the CUSTOMERS multifile as
a single print job.
See also:
SETPTR, SP.ASSIGN
2.11-0
QM Commands 501
4.174 SP.VIEW
The SP.VIEW command views and, optionally, prints records from $HOLD or other files.
Format
where
item is the record id of the record to be processed. If omitted, a pick list of records
is displayed.
LPTR n specifies the default print unit to be used. If omitted, print unit 0 is used.
If only one name is specified on the command line, it is assumed to be the file name if a
corresponding VOC F or Q-type record exists and there is no record of that name in $HOLD.
The SP.VIEW command allows users to view and print records. If no item is specified, a pick list
of records in file is displayed. The cursor keys, page up, page down, home and end keys can be used
to move around within this list. Equivalent actions can be performed using the letter keys or the
SED style control keys.
After an item has been selected, either as described above or by specifying the item name on the
command line, the text of the given record is displayed. The cursor keys, page up, page down, home
and end keys can be used to move around within the data. Equivalent actions can be performed
using the letter keys or the SED style control keys.
2.11-0
502 OpenQM
The S option prompts for the print unit (defaulting to that in the LPTR option, if used), asks
whether line numbering is to be used and then prints the item.
2.11-0
QM Commands 503
4.175 SPOOL
Format
where
record(s) is a list of records to be printed. If no record ids are specified, SPOOL will use
the default select list to identify the records to be printed.
LINES m n specifies that only line m to n of the record(s) are to be printed. The value of m
must be greater than 0 and the value of n must be greater than m.
LPTR n specifies the print unit to be used. If omitted, print unit 0 is used.
The SPOOL command sends the specified records to print unit 0. The actual destination is
determined by use of either PRINTER or SETPTR.
Use of the LNUM keyword prefixes each line by its line number, a colon and a single space. The
line number is printed as a minimum of four digits but expands if the record has more than 9999
lines.
Example
The above command would print records 01249 and 01250 from the INVOICES file. The SPOOL
command does no formatting of the data except to replace field marks by newlines.
2.11-0
504 OpenQM
4.176 STATUS
The STATUS command displays a list of active phantom processes. This command is not available
on the PDA version of QM.
Format
STATUS { ALL }
where
ALL Displays status information for all phantom processes. Without this option, only
phantoms started by the current user are displayed.
The login time is shown in the local time zone of the user executing the command.
See also:
CHILD(), LIST.PHANTOMS, PHANTOM, !PHLOG()
2.11-0
QM Commands 505
4.177 STOP
Format
STOP
The STOP command is intended as a means of exiting from the middle of a paragraph. The active
paragraph is discarded, control returning to the paragraph, menu, etc from which the paragraph was
started or, if none, to the command prompt.
See also:
ABORT
2.11-0
506 OpenQM
4.178 SUBSCRIBE
The SUBSCRIBE command starts a phantom process that will poll a replication publisher for
updates.
Format
where
port is the port number for connection to the publisher. This must correspond to the
value of the REPLPORT configuration parameter on the publisher and defaults
to 4244 if omitted.
username is the username to be used for the server process established on the publisher.
password is the password associated with username. For security, this should be
encrypted using the AUTHKEY command and specified with an ENCR:
prefix.
The SUBSCRIBE command starts a phantom process that polls for and applies data updates from
the specified publisher. It should normally be executed using the STARTUP configuration
parameter. The command can only be executed in the QMSYS account and by users with
administrator rights.
When subscribing to files that use encryption, the username of the subscriber process must have full
access to the associated encryption keys.
The REPLSRVR configuration parameter must be set to match the subscriber server name as used
when publishing the files with the PUBLISH command.
See also:
Replication, DISABLE.PUBLISHING, ENABLE.PUBLISHING, PUBLISH,
PUBLISH.ACCOUNT
2.11-0
QM Commands 507
4.179 T.DUMP
Format
where
BINARY suppresses conversion of newlines to field marks in directory files. Use this
mode when saving binary data.
FROM listno uses the specified select list to identify the records to be saved.
The T.LOAD command processes the named file to produce a Pick style T-DUMP tape
The tape or pseudo-tape to be created must first be assigned to the process using the
SET.DEVICE command.
By default, the entire content of the named file is saved. If the default select list is active or the
FROM option is used to identify an active select list, that list is used to determine the records to be
saved. Alternatively, a list of ids may be given on the command line.
Encryption
T.DUMP operates within the security rules imposed by use of QM's encryption features. Files that
use record level encryption cannot be saved if the user performing the save does not have access to
the encryption key. The data saved for files that use field level encryption will have all fields for
which the user is denied access set to null strings. All saved data is recorded in decrypted form and
hence storage of T.DUMP media may reduce system security. The media format used by T.DUMP
is an industry standard that does not provide a way to record details of data encryption. Restoring a
save in which encrypted fields have been omitted is unlikely to yield a usable file. Backup of
accounts that include encrypted data should be performed using operating system level tools.
Restrictions
The media format of T.DUMP also imposes a restriction that makes it impossible to save an item
that contains a field mark (character 254) immediately followed by a text mark (character 251). In
2.11-0
508 OpenQM
practical terms, this means that it is unlikely to be possible to use T.DUMP to save binary data
such as compiled programs.
See also:
ACCOUNT.RESTORE, ACCOUNT.SAVE, FILE.SAVE, FIND.ACCOUNT,
RESTORE.ACCOUNTS, SEL.RESTORE, SET.DEVICE, T.ATT, T.LOAD, T.xxx
2.11-0
QM Commands 509
4.180 T.LOAD
Format
where
item.list is the list of items to be restored. The default select list may be used
instead.
BINARY suppresses translation of field marks to newlines in directory files. Use this
mode when restoring binary data.
NO.QUERY suppresses the confirmation prompt when restoring using a select list. The
NO.SEL.LIST.QUERY mode of the OPTION command can be used to
imply this option.
The T.LOAD command processes a Pick style T-DUMP pseudo tape and restores data from it into
the named QM file.
The tape or pseudo-tape to be read must first be assigned to the process using the SET.DEVICE
command.
See also:
ACCOUNT.RESTORE, ACCOUNT.SAVE, FILE.SAVE, FIND.ACCOUNT,
RESTORE.ACCOUNTS, SEL.RESTORE, SET.DEVICE, T.ATT, T.DUMP, T.xxx
2.11-0
510 OpenQM
Format
The tape or pseudo-tape to be processed must first be assigned using the SET.DEVICE command.
See also:
ACCOUNT.RESTORE, ACCOUNT.SAVE, FILE.SAVE, FIND.ACCOUNT,
RESTORE.ACCOUNTS, SEL.RESTORE, SET.DEVICE, T.ATT, T.DUMP, T.LOAD
2.11-0
QM Commands 511
4.182 TERM
Format
TERM
TERM { columns } { , lines } {term.type}
TERM COLOUR { bgc} { , fgc}
TERM DEFAULT
TERM DISPLAY
where
columns is the width of the display device.
lines is the depth (number of lines) of the display device.
bgc is the required background colour
fgc is the required foreground colour
The TERM command with no qualifying information reports the display device settings. It shows
the page width and depth together with the terminal type (as in the @TERM.TYPE variable).
The command may include either or both of the columns and lines values to specify the
characteristics of the display device. If used for a console session or a QMTerm connection with
values of columns and lines less than 256, the command will also set the device window to the
given shape.
The columns value must be in the range 20 to 32767. The lines value must be in the range 10 to
32767.
The term.type option selects the terminal device type. The name given must correspond to an entry
in the terminfo library or may be QMTERM (case independent) for the QMTerm emulator.
The COLOUR (or COLOR) option can be used to set the background and foreground colours.
The colour names are case insensitive and chosen from BLACK, BLUE, GREEN, CYAN, RED,
MAGENTA, BROWN, WHITE, GREY, BRIGHT BLUE, BRIGHT GREEN, BRIGHT CYAN,
BRIGHT RED, BRIGHT MAGENTA, YELLOW, BRIGHT WHITE. The American spelling
GRAY can be used in place of GREY and the two word names can be written with either a space or
a dot between the words.
Note that some terminal emulators only apply the background colour to characters output by the
application, not to the entire window. Thus clearing the screen, for example, may lead to
unexpected results.
The TERM DISPLAY command displays a list of input key codes and output control sequences
for the currently selected terminal type.
2.11-0
512 OpenQM
Example
TERM 120,32
The above command sets the terminal to be 120 columns wide by 32 lines. A subsequent TERM
command with no qualifying information would report
See also:
PTERM
2.11-0
QM Commands 513
4.183 TIME
The TIME command displays the current date and time or translates a time between internal and
external format.
Format
TIME {time}
TIME INTERNAL
If no time is specified, the date and time are reported in the form
If time is specified, the converted form of this time (internal to external or vice versa) is reported.
The TIME INTERNAL form displays the current time in internal form (seconds since midnight).
2.11-0
514 OpenQM
4.184 UMASK
The UMASK command sets the default access rights for files created within the QM session. This
command is not applicable to the PDA version of QM.
Format
UMASK { rights }
The UMASK command operates in the same way as the umask command of Linux, FreeBSD or
AIX, specifying the default access rights for files created within this QM session.
The rights code consists of three octal digits that specify the access permissions that the file is not
to have. The first digit sets the rights for the owner of the file. The second digit sets the rights for
users in the group to which the file is assigned except for the owner. The third digit sets the rights
for all other users. Each digit is formed by adding the values:
4 Do not allow read access
2 Do not allow write access
1 Do not allow execute access (attach access for directories)
If the rights are omitted, the UMASK command reports the current access rights.
2.11-0
QM Commands 515
4.185 UNLOCK
The UNLOCK command, available only in the QMSYS account, releases task, record or file locks
set by any process.
Format
In the first form, UNLOCK releases record ids set by user user.no on file file.no. At least one of
these options must be present. The values of user.no and file.no can be found from the output of
the LIST.READU command. The UNLOCK requires either a list of record ids or the ALL
keyword to determine which records to unlock.
In the second form, the file lock set by the specified user on the given file is released. Again, at least
one of the USER and FILE options must be specified.
The third form allows task locks owned by other users to be released. Any number of locks may be
released in a single command.
The UNLOCK command should be used with great care. Locks are taken by application software
to protect critical operations. Releasing a lock can cause data integrity problems.
Example
LIST.READU
File Path
17 D:\SALES\INVENTORY
File User Type Id
17 4 RU 18464
17 4 RU 21968
UNLOCK USER 4 18464
In this example, LIST.READU is used to check which locks are outstanding and the UNLOCK
command is used to release a specific record lock.
2.11-0
516 OpenQM
4.186 UNLOCK.KEY.VAULT
The UNLOCK.KEY.VAULT command enables access to the encryption key vault when using the
optional vault access security. This command can only be executed by users with administrator
rights.
Format
UNLOCK.KEY.VAULT
The UNLOCK.KEY.VAULT command enables access to encrypted files. This optional level of
security is selected when the master key is created and requires that the key is entered using this
command every time that QM is started (once only, not for each user entering the system). Whilst
potentially inconvenient, this mechanism provides security against data access if the entire system is
stolen. It is recommended for use with portable systems that hold encrypted data.
The key string entered must be the same as when the key vault was created. The master key cannot
be changed unless the key vault is cleared and rebuilt.
See also:
Data encryption, CREATE.FILE, CREATE.KEY, DELETE.KEY, ENCRYPT.FILE,
GRANT.KEY, LIST.KEYS, REVOKE.KEY, SET.ENCRYPTION.KEY.NAME
2.11-0
QM Commands 517
4.187 UPDATE.ACCOUNT
The UPDATE.ACCOUNT command copies all system VOC entries from NEWVOC, setting the
correct locations for system files.
Format
UPDATE.ACCOUNT
The UPDATE.ACCOUNT command copies all NEWVOC items to the VOC file of the current
account. It is useful after an upgrade or if the VOC has been damaged. Unlike a simple COPY
from NEWVOC to the VOC, UPDATE.ACCOUNT checks for changes that may have a
detrimental effect.
Executing this command in the QMSYS account when logged in as a user with administrator rights
prompts to ask whether all registered accounts are to be updated. This can be useful after an
upgrade on a system with many accounts.
See also:
CREATE.ACCOUNT, DELETE.ACCOUNT
2.11-0
518 OpenQM
4.188 UPDATE.LICENCE
The UPDATE.LICENCE command, available only in the QMSYS account, applies new licence
details.
Format
UPDATE.LICENCE
The UPDATE.LICENCE command prompts for the licence information supplied with the product
or at an upgrade.
Care should be taken to enter the information exactly as it appears on the licence information sheet.
When relicensing an existing system, the old licence data is displayed allowing amendment of only
the fields that have changed.
The screen layout for the PDA version is different and omits the user limit field.
Example
LICENCE DETAILS
---------------------------------------------------------
---------------------------------------------------------
2.11-0
QM Commands 519
4.189 UPDATE.RECORD
UPDATE.RECORD simplifies amendment of database files. In batch mode, it allows the same
update to be made to multiple records in a file with just one command, possibly changing the
content of more than one field. In visual mode, it displays a full screen image of fields from the
data record in their external (converted) form, allowing modifications to be entered as the cursor is
moved around the displayed data.
Format
FROM listno
ALL
id { id ...}
INQUIRING {prompt}
Batch mode:
field,value {CONV "spec"} { field,value ...}
DELETING field
{COUNT.SUP}
{VERIFY.SUP}
{EXCLUSIVE}
{WAIT} or {NO.WAIT}
{CREATING}
{OVERWRITING}
{REPORTING}
{LPTR {n}}
{NO.PAGE}
Visual mode:
{ID.SUP}
{COL.SUP}
{DICT} file specifies the file to be updated. The optional DICT keyword
indicates that the dictionary portion of the file is to be updated.
USING {DICT} dict specifies that dict is to be used as the dictionary for file. The
optional DICT keyword uses the dictionary portion of dict.
FROM listno specifies that select list listno (0 to 10) is to be used as the list of
records to process.
2.11-0
520 OpenQM
Only one of these selection styles can be used in a single command. If none of the above record
selection criteria is given and the default select list is active, that list is used.
DELETING field Deletes the specified field from the data record, moving all
subsequent fields back by one position.
NO.WAIT turns off WAIT. It is not normally required as this is the default.
UPDATE.RECORD honours the last WAIT or NO.WAIT on the
2.11-0
QM Commands 521
command line.
OVERWRITING allows overwriting of existing records when changing the record id.
The sequence of the command components must be file specification, record ids, fields and values,
options.
2.11-0
522 OpenQM
UPDATE.RECORD runs in batch mode of the command line includes one or more field/value
specifications.
If the EXCLUSIVE keyword is used, UPDATE.RECORD will obtain exclusive access to the file
by acquiring the file lock. If another user holds a record lock or the file lock when the command is
issued, UPDATE.RECORD will terminate with an error message unless the WAIT keyword has
been used, in which case a message is displayed and it repeats the attempt to lock the file at five
second intervals.
For each record to be processed, UPDATE.RECORD first locks and reads the record. If another
user has the record locked and the WAIT keyword has been used, UPDATE.RECORD will wait
for the record to become available. If the WAIT keyword was not used, the record id is added to a
list of locked records. If either the INQUIRING or REPORTING keywords was used, a message
is output showing the id of the record that could not be locked.
If the specified record does not exist in the file and the CREATING keyword has been used, a new,
empty record is created to which the amendments are then applied. If the CREATING keyword is
not present, the record id is added to a list of missing records
Once the record has been successfully locked, UPDATE.RECORD performs each of the specified
amendments in the order in which they appear on the command line. Each amendment may draw on
the result of preceding amendments. Note in particular, that use of the DELETING option will
result in new field positions for all later fields. The record id may be changed by specifying the
target as field 0 or a dictionary item such as @ID that refers to field 0. Any I-type or EVAL
expressions after the change of record id will see the new id in @ID.
The field specification may be a numeric field position or the name of a D-type item from the
dictionary or the VOC. The value specification may be:
The name of an A, D, I or S-type dictionary or VOC item identifying the field from which data
is to be copied. If this is an I-type item or an A/S-type item with a correlative expression, it
must have been compiled prior to use by UPDATE.RECORD.
The keyword EVAL followed by an I-type expression in single or double quotes. This
expression will be compiled by UPDATE.RECORD and evaluated to determine the new value
of the field.
UPDATE.RECORD honours dictionary conversion specifications for both the source and target
data items. Where the new value for a field is derived via a dictionary name, the value is first
converted to its external form. Where the field to be updated is identified via a dictionary name, the
new value is converted to its internal form prior to storing in the record. If the value specification is
followed by the CONV keyword and a quoted conversion specification, this will overrule any
conversion specified in the dictionary. UPDATE.RECORD will report a warning message if the
conversion generates an error when applied to value.
2.11-0
QM Commands 523
In the absence of the REPORTING and INQUIRING keywords or if the report is directed to a
print unit rather than the display, UPDATE.RECORD displays a progress report in the form of a
series of asterisks.
On completion of the update, UPDATE.RECORD may create two entries in the $SAVEDLISTS
file. If one or more records could not be updated because they were locked by other users, a select
list named &LOCK.userno& is created containing a list of such records. If one or more records
specified for update did not exist in the file and the CREATING keyword was not used, a select
list named &MISS.userno& is created containing a list of the missing record ids.
UPDATE.RECORD deletes any old versions of these lists at the start of the update.
Note that the database locking system is of a voluntary nature. Both the file and record level locking
performed by UPDATE.RECORD only prevent other users acquiring the locks. A program that
does not use locks correctly may still be able to access the file during the update.
Examples
This update amends field IN.STOCK of record 01-1745 in the STOCK file to be zero.
This update processes all records from the SALES file, adding the current value of the
THIS.MONTH field into the TOTAL.SOLD field, resetting THIS.MONTH to zero. The
EXCLUSIVE keyword ensures that the file is not updated by other users during the amendment. A
detailed report of the changes is sent to print unit 2.
This update processes entries of the PAYROLL file specified in response to a record id prompt,
increasing the value of SALARY by 5%.
This update uses select list 2 to identify records of the STOCK file in which field 5 is to be set to
the internal form of the date 12/9/96.
The Report
2.11-0
524 OpenQM
The report shows the start of the amendment for a given record, the changes made to each field and
the termination of the update at the point when the record has been written back to the file. Missing
records and records which have been created by UPDATE.RECORD are highlighted in this report.
A command such as
This example shows the report entries for update of a record found in the file, a record that was not
updated because it was locked by another user and a record that was created by
UPDATE.RECORD.
If the CREATING option was not used, record 01-7491 would have produced the following report
line
2.11-0
QM Commands 525
Visual mode presents a full screen display of the external (converted) form of fields from a data
record. Changes are made by moving the cursor to the desired position and entering or deleting
characters. Modified lines are converted back into their internal form within UPDATE.RECORD
when the cursor is moved to a new line or when the data is to be written back to the file.
By default, the display shows all fields for which a D-type dictionary entry or an A/S=type entry
with no correlative exists. A specific subset of fields can be displayed by creating a dictionary
phrase named @UPDATE.RECORD which lists the required fields (and possibly keywords).
The last two lines of the screen are used as a status area. The upper status line displays the file
name and record id. An asterisk is shown at the start of this line if the data has been changed.
The lower status line shows the field, value and subvalue in which the cursor is positioned and the
dictionary conversion code, format code, association name and single/multivalue flag for the field.
The final field of this status line shows a letter O if UPDATE.RECORD is in overlay mode (see
below).
UPDATE.RECORD uses a subset of the default key bindings of the SED full screen editor. These
all consist of keystrokes which are
Control shift + key
2.11-0
526 OpenQM
The table below summarises the key bindings. All other keystrokes except for unused control shift
codes cause the character to be inserted into the record text at the current cursor position.
2.11-0
QM Commands 527
Some functions are available using alternative key sequences. Such alternatives are shown above
and in the descriptions that follow.
The cancel function (Ctrl-G) can be used to abort partially entered incorrect key sequences and to
terminate certain functions as described below.
Note: A confirmation prompt appears if the cursor is moved from a line that contains a data
conversion error.
Top (Esc-<)
Moves to the start of the first displayed field.
2.11-0
528 OpenQM
Goto (Esc-G)
Prompts for a field, value and subvalue position and moves the cursor to that position. The
position may be specified as:
Fields may be specified by number or name. Omitted field or value components mean " within
the current field/value" unless a higher level component is specified in which case the default is
1. For example:
An asterisk can be use to imply "no change". This is useful when processing associated
multivalued fields. For example:
If the specified value or subvalue does not exists, UPDATE.RECORD will offer to create it.
Data Insertion
Data is inserted at the current cursor position. If overlay mode is set the new data overwrites any
existing data at this position, otherwise it is inserted before the character under the cursor. Overlay
mode may be toggled using the overlay function (Ctrl-O or Ctrl-X O or Insert).
Any character other than a field mark or item mark may be inserted. The quote character function
(Ctrl-Q or Esc-Q) allows insertion of non-printing characters. It may be used in three ways:
Followed by a number of up to three digits, it inserts the character with that decimal ASCII
sequence.
Followed by any other character, usually a non-printing character, it will insert that character.
2.11-0
QM Commands 529
Copy (Esc-W)
The copy copies part of a field to the clipboard buffer. The required sequence of actions is:
Position the cursor on the first character to be copied.
Execute the mark function (Esc-.).
Position the cursor after the last character to be copied. Where the terminal device allows,
the selected characters will be highlighted.
Press the copy key.
The copy function can be cancelled using the cancel function (Ctrl-G).
Cut (Ctrl-W)
The cut function cuts (deletes) part of a field, placing a copy of the deleted text in the clipboard
buffer. The required sequence of actions is:
Position the cursor on the first character to be cut.
Execute the mark function (Esc-.).
Position the cursor after the last character to be cut. Where the terminal device allows, the
selected characters will be highlighted.
Press the cut key.
The cut function can be cancelled using the cancel function (Ctrl-G).
Miscellaneous Functions
The save function cannot be executed if the current line contains a data conversion error.
Command (Esc-X)
The command function allows executing of any valid QM command from within
UPDATE.RECORD. In addition, it supports the following built-in commands:
2.11-0
530 OpenQM
SPOOL Used without any following file name etc. , this command spools a copy of
the record to the default printer.
2.11-0
QM Commands 531
4.190 WHO
The WHO command displays the current user number and account name.
Format
WHO
Each directory holding a VOC file is termed an account. Multiple accounts are useful where there
are several distinct projects. They can also be used to separate development and production versions
of an application.
The WHO command displays the current user number and account name. If the current account is
not the same as the initial account on entry to QM, the initial account name is also displayed.
Example
WHO
1 AC1
LOGTO AC2
WHO
1 AC2 from AC1
In this example, the user enters QM in account AC1. The WHO command shows the user number
and this account name. A LOGTO command is used to transfer to AC2. The WHO command now
shows the new account and the original.
2.11-0
532 OpenQM
4.191 WHERE
Format
WHERE
This command is a simple sentence that displays the value of the @PATH system variable.
Example
WHERE
C:\QMACC\SALES
2.11-0
Part
5
Query Processing
534 OpenQM
5 Query Processing
QM verbs that select records from files or produce reports are handled by the query processor. All
query processor verbs follow a common format.
SORT.LABEL List records meeting specified criteria in address label format, in order of
record id
SREFORMAT Builds a new file from data in the source file, in order of record id
SSELECT Create a select list of records meeting specified criteria in order of record
id
SEARCH Create a select list of records meeting specified criteria which include text
matching over the entire record
All query processor verbs follow the same general format though not all parts are applicable to all
verbs. The components of the command may be in any order except that the file name must
immediately follow the verb and the order may be significant in repeated instances of an element.
2.11-0
Query Processing 535
{display.clause }
{record.id...}
{FROM select.list.no}
{TO select.list.no}
where
{DICT} file.name identifies the file to be processed. The optional DICT keyword
indicates that the dictionary part of the file is to be processed. The
DICT.DICT file will be used as the dictionary defining the items in the
dictionary being reported.
USING {DICT} file.name indicates that a dictionary other than the one normally associated
with the file is to be used.
selection.clause specifies criteria determining which records from the file are to be
included.
FROM select.list.no specifies that a select list is to be used to control which records are
processed. If the FROM option is not used and the default select list
(list 0) is active, this list will be used automatically. If used in
conjunction with one or more record.id items, only records that appear
in the select list and are named record.ids will be processed.
TO select.list.no for verbs that produce a select list, specifies which list is to be created.
If the TO option is not used, the default select list (list 0) is used.
Phrases defined in the VOC or the dictionary may be included at any point in a query processor
command and will be expanded at that position in the command line.
Literal values used in selection or sort clauses do not need to be enclosed in quotes unless they
correspond to names defined in either the VOC or the file's dictionary or if the contain spaces,
commas or quotes. Use of quotes is recommended to prevent incorrect interpretation of commands.
The default actions of the query processor can be controlled by adding an X-type record to the VOC
file or to the dictionary of the file referenced by the query command. Field 2 of this record contains
query processor command line elements that will be inserted into a LIST, SORT, LIST.LABEL
or SORT.LABEL command after the file name but before any further command line options. Field
3 works in the same way but is applied to SELECT, SSELECT and SEARCH commands.
In either case, the options may extend over multiple lines by use of an underscore as the last
character of the line to indicate that a continuation line is present. The lines are merged together
with the underscore replaced by a single space. The field numbers described above are applied to
the record after merging continuation lines.
The query processor checks first for this optional record in the dictionary of the file. If it is not
found, it then looks in the VOC. It is therefore possible to use a VOC record to set account level
defaults which can be overridden by an alternative record in individual dictionaries. A
$QUERY.DEFAULTS record in the dictionary with a type code of X but no further content will
effectively disable use of the VOC $QUERY.DEFAULTS record whilst not applying any defaults
of its own.
Links
Dictionary L-type records can be used to represent a relationship between two files without the need
to include a separate I-type TRANS() expression for each field.
In a query command, a link is used by specifying a field name that is constructed from the link
name and the name of a field in the linked file, separated by a percent sign (%).
For example, consider a library application where the BOOKS file representing a physical copy of
a book uses a composite key constructed from the id of a record in the TITLES file and the copy
number, separated by a hyphen. A link record could be placed in the dictionary of the BOOKS file:
TITLES 1: L
2: @ID['-', 1, 1]
3: TITLES
A query against the BOOKS file may then refer to fields from the TITLES file as, for example,
TITLES%AUTHOR. The linked field (AUTHOR in this example) must be a D or I-type item.
Links cannot be used to access Pick style A or S-type dictionary items.
To allow use of field names that contain % characters, the query processor only interprets a field
name containing a % character as a link if there is no dictionary or VOC item corresponding to the
entire name.
2.11-0
Query Processing 537
A selection clause may be provided to specify criteria governing which records are processed by
the command. If omitted, all records are processed. Selection clauses can be used with all query
processor verbs
The selection clause is described in detail under the WITH and WHEN keywords. The records to
be processed by a query can also be specified by use of a select list. The FROM keyword can be
used to specify the list to be used. If this is not present and the default list (list zero) is active, this is
used automatically.
The performance of queries against large files can be improved dramatically by use of alternate key
indices. These are index files that relate a particular value of a data field or virtual attribute to the
ids of records that have that value. Alternate key indices are created in a two step operation using
the CREATE.INDEX and BUILD.INDEX commands. Once an index has been built, it is
maintained automatically by QM and is used by the query processor whenever it is advantageous to
do so.
Ranges of values can also be satisfied using indices if the upper and lower limits are defined in the
first two conditional elements. For example,
LIST STOCK WITH QOH > 3 AND QOH < 10 AND SUPPLIER = 27
will use an index on the QOH field to access the data whereas
LIST STOCK WITH QOH > 3 AND SUPPLIER = 27 AND QOH < 10
will not. Use of unnecessary brackets may also defeat the indexing system. For example,
LIST STOCK WITH QOH > 3 AND (QOH < 10 AND SUPPLIER = 27)
will not use the index as the second conditional element is not a simple item.
Selection clause comparisons are case sensitive by default. Case insensitivity can be applied by
including the NO.CASE qualifier after the relational operator or by use of the QUERY.NO.CASE
mode of the OPTION command. See Alternate Key Indices for a discussion of why a case sensitive
index cannot be used to resolve a case insensitive selection clause element or vice versa.
The PICK.IMPLIED.EQ mode of the OPTION command can be used to select Pick style
behaviour where a field name followed by a literal value enclosed in double quotes has an implied
equals operator. Thus
LIST CLIENTS WITH CUST.NO "1234" "5678"
is equivalent to
LIST CLIENTS WITH CUST.NO = "1234" "5678"
Without this option, the semantics of the query are such that the two literal values are treated as
record ids and the selection element restricts processing to records in which the CUST.NO field is
not empty.
See also:
Qualified display clauses
2.11-0
538 OpenQM
The optional sort clause determines the order in which records are inserted into the select list (
SELECT, SSELECT, SEARCH) or reported (LIST, SORT, LIST.ITEM, SORT.ITEM).
Sorting is performed before conversion of data to its external format. Thus sorts of date fields, for
example, will correctly sequence dates regardless of their conversion.
The justification mode of the field's format is used to determine whether a left of right aligned sort is
performed. For dates, a right aligned sort is required to avoid problems with dates with internal
values of differing numbers of digits.
There are two sort clause operators for single valued fields, BY and BY.DSND, which differ only
in that BY sorts into ascending order and BY.DSND sorts into descending order. Similarly, there
are two exploded sort operators, BY.EXP and BY.EXP.DSND, for use with multivalued fields.
These explode the multivalued records to their single valued equivalents, allowing a query to
process values in sequence.
Where multiple sort items are specified, the query processor examines them in the order in which
they appear in the command. The second and subsequent sort items are only examined where the
previous sort was not sufficient to identify the record sequence.
The SORT, SORT.ITEM and SSELECT verbs are equivalent to the LIST, LIST.ITEM and
SELECT verbs with a BY @ID clause as the final sort.
The sorting process compares items to establish their correct position in sorted order.
When using a left aligned sort, items are compared character by character from the left hand end
until a difference is encountered. The relative sort position of the two items is then determined by
the collating sequence order of the characters that differ.
When using a right aligned sort, the comparison process is considerably more complex. Each item
is considered to be formed from a series of elements that may be numeric or non-numeric. The
numeric elements are compared as numeric values, including allowing for a leading sign character
on the first element only. The non-numeric elements are compared character by character, left to
right as for a left aligned sort. Where the first element of one item is numeric and the first element
of the other is non-numeric, the numeric one is positioned earlier in the sorted result.
Although right aligned sorts are most commonly used with data that is entirely numeric, the above
process ensures that it operates correctly with mixed data types, producing a logical and consistent
sorted result. The following example shows the correct sort order for the same data using both left
and right aligned sort modes.
Left: +3, -6, 103, 10A, 1943, 1A1, 1B1, 7CX, A1A, A1C, AA, BD1, BD94, BF20, XX90
Right: -6, 1A1, 1B1, +3, 7CX, 10A, 103, 1943, A1A, A1C, AA, BD1, BD94, BF20, XX90
2.11-0
Query Processing 539
The optional display clause determines which fields (columns) are reported and how they are
displayed. This clause is applicable to the LIST and SORT verbs only. If omitted, the query
processor uses the default listing phrase to determine what is shown.
There are a wide variety of options in this clause. Some determine the actual layout of the data
while others set breakpoints at which totals, averages, etc are to be reported.
Fields appear in the report left to right in the order of the display clause elements. The default view
of the record id (@ID) is always shown as the leftmost column unless it is suppressed using the
ID.SUP keyword.
The display clause is constructed from the elements in the table below.
ENUM MULTI.VALUE
CALC NO.NULLS
CUMULATIVE
Each data item may optionally be prefixed by one of the qualifiers in the first column and followed
by any number of compatible options from the third column.
Where no such item is defined in the dictionary or the VOC, the Fn data item is recognised by the
query processor as a reference to field n, treating the data as single valued with a format code of
"15T". These display characteristics can be modified using other elements from the table above.
For improved compatibility with other multivalue databases, QM supports the concept of qualified
display clauses. These combine the role of the display clause with simple selection clause elements.
Because qualified display clauses lead to a potential ambiguity in the interpretation of a query, this
feature must be enabled using the QUALIFIED.DISPLAY mode of the OPTION command.
2.11-0
540 OpenQM
A qualified display clause element inserts a conditional test after the data item but before any items
from the third column of the table above. This conditional test consists of an operator and a field or
value against which the test is to be performed. It may not include the AND or OR operator or the
use of brackets.
If a query sentence contains no display clause, the query processor looks in the dictionary for a
PH-type (phrase) entry named @. If this is found, it is attached to the end of the query sentence.
Typically, this phrase contains a default list of fields to be shown but it may also include other
query sentence elements. If there is no @ phrase, only the record id will be shown.
Where a report is directed to a printer by using the LPTR keyword, the query processor's search for
a default listing phrase is extended by first looking for a phrase named @LPTR. If this is not found,
the query processor uses the @ phrase as for reports directed to the screen. This extra stage allows
users to set up a different set of default fields for the printer and the screen, usually because printers
tend to be wider than the screen and can therefore fit more data.
2.11-0
Query Processing 541
The SELECT and SSELECT verbs build a select list containing the keys of records meeting
specified criteria. SSELECT is equivalent to SELECT with a final sort by record id.
Example
This command builds a select list containing the ids of VOC records with field one starting with an
upper case F. Such a list corresponds to all files defined by the VOC.
The list of record ids (or other data when using SAVING) is stored in select list 0 unless the TO
clause is used to specify a different list.
Chained Selects
For compatibility with other multivalue products, if the CHAINED.SELECT mode of the
OPTION command is active, a SELECT or SSELECT that returns a list with at least one entry
will examine the DATA queue. If there is anything in this queue, the first queue item is read and
executed as a command. This allows applications to create sequences of commands that will be
executed if the SELECT is successful. For example, a QMBasic program might contain
DATA 'LIST STOCK'
EXECUTE 'SELECT SALES SAVING MULTIVALUED PART'
or a paragraph might perform the same action with
PA
SELECT SALES SAVING MULTIVALUED PART
DATA LIST STOCK
Note that DATA statements always follow the command to which they apply in a paragraph.
This mechanism originated in Pick style databases where a Proc might contain
2.11-0
542 OpenQM
PQ
STON
HLIST STOCK
STOFF
HSELECT SALES SAVING MULTIVALUED PART
P
or, resequencing the commands,
PQ
HSELECT SALES SAVING MULTIVALUED PART
STON
HLIST STOCK
P
The chaining process can continue over multiple selections, taking one command at a time from the
data queue:
PA
SELECT VOUCHERS SAVING SALE
DATA SELECT SALES SAVING UNIQUE MULTIVALUED PART
DATA LIST STOCK
2.11-0
Query Processing 543
5.5 SEARCH
The SEARCH verb is similar to SELECT except that it also prompts for entry of one or more text
strings. Records that meet any other selection criteria given on the command line are tested for the
presence of the search strings at any position in the record.
Up to 20 search strings may be specified. Entry of search strings is terminated by entering a blank
response to the prompt. Use of the STRINGS keyword takes the search strings from the specified
file and record, each field being taken as a separate search string.
The optional NO.CASE keyword makes the search string test case insensitive.
By default, the SEARCH verb builds a list of all records that contain any of the supplied search
strings. This can be changed by use of the ALL.MATCH or NO.MATCH keywords. The
ALL.MATCH keyword specifies that the selected records must contain all of the supplied strings.
The NO.MATCH keyword specifies that the selected records must not contain any of the supplied
strings.
Example
SEARCH BP
String: !SORT
The above lines entered at the keyboard would search all QMBasic source programs in the BP file
for references to the !SORT() subroutine.
See also:
ALL.MATCH, NO.CASE, NO.MATCH
2.11-0
544 OpenQM
The LIST and SORT verbs produce reports from QM files. The LIST verb displays records in the
order in which they are encountered in the file unless a sort clause in present in the command. The
SORT verb is equivalent to LIST with a final sort by record id.
The record id is always reported as the first item in the output unless the ID.SUP keyword has been
used to suppress it. The format of this item is determined by the @ID dictionary record. If this
record is not found in the dictionary, a default format is used.
If field names are specified in the command, these fields are displayed in the order specified. If no
field names are present, the query processor looks for a phrase in the dictionary defining a default
set of fields to be reported. If the LPTR keyword has been included, the query processor first looks
for a phrase record named @LPTR. If this cannot be found or the LPTR keyword was not used, it
looks for a phrase record named @. The @LPTR and @ phrases can be used to create separate
default field name lists for output to the printer and the display respectively. If no @LPTR or @
record is found, only the record id is reported.
The default listing phrase may include field qualifiers, selection, sort and display clause items.
The LIST and SORT verbs normally produce a tabular format report with items listed side by side.
If the total width of the items to be reported exceeds the width of the display or printer to which the
report is directed, a vertical format report is produced. This can be forced by use of the
VERTICALLY keyword.
The PAN keyword allows reports wider than the display to be produced using the left and right
cursor keys to pan part or all of the displayed data.
The SCROLL keyword allows scrolling back and forward using the up and down cursor keys.
When LIST or SORT are used to list a dictionary with the no display clause, the action of the
default listing phrase (@), includes transformation of A and S-type dictionary items into a form that
maps onto the standard dictionary display format used for other types.
2.11-0
Query Processing 545
Example
This command lists all records from the STOCK file for which the quantity in stock (QTY field) is
less than or equal to the reorder level (REORDER.LEVEL field). These two fields are displayed
together with the record id.
2.11-0
546 OpenQM
The LIST.ITEM and SORT.ITEM verbs display data from QM files in its internal format. The
LIST.ITEM verb displays records in the order in which they are encountered in the file unless a
sort clause in present in the command. The SORT.ITEM verb is equivalent to LIST.ITEM with a
final sort by record id.
The output from these verbs displays the record id followed by each field on a separate line. No
conversion or formatting is performed on the data. Multivalued data will be displayed with
embedded mark characters.
The display normally prefixes each field with its field number. The COL.SUP keyword can be used
to suppress this.
The ID.SUP keyword can be used to suppress display of the record id.
The SCROLL keyword allows scrolling back and forward using the up and down cursor keys.
Example
This command lists the content of record 16798 of the STOCK file.
2.11-0
Query Processing 547
The LIST.LABEL and SORT.LABEL verbs are used to print address labels from QM files. The
LIST.LABEL verb processes records in the order in which they are encountered in the file unless a
sort clause in present in the command. The SORT.LABEL verb is equivalent to LIST.LABEL
with a final sort by record id.
The optional clauses to LIST.LABEL and SORT.LABEL work in exactly the same way as for
LIST and SORT except that arithmetic field modifiers (AVERAGE, ENUMERATE, MAX,
MIN, PERCENTAGE, TOTAL), breakpoints (BREAK.ON, BREAK.SUP) and the page
format keywords (COL.SUP, COL.HDR.SUPP, COL.SPACES, HDR.SUP, DBL.SPC,
FOOTING, GRAND.TOTAL, HEADING, PAN, SCROLL, VERTICALLY) are not allowed.
The LIST.LABEL and SORT.LABEL commands produce a vertical style report set out into the
positions of labels on the printed page. The label page shape may be defined by a record in the
dictionary of the file or in the VOC file, or it may be entered in response to prompts.
If the command includes the LABEL keyword, this may be followed by the name of an X-type
label template record stored in the dictionary or in the VOC. This record contains the page shape as
a series of lines. Only the leading numeric part of each line is used thus allowing comments to be
inserted explaining what each number represents. A typical label might read:
1: X
2: 2 Count of labels across the page
3: 8 Count of labels per column
4: 42 Characters per line on each label
5: 7 Lines per label
6: 0 Indentation to first column of leftmost label
7: 6 Horizontal space between labels
8: 3 Lines between labels
9: 1 Omit blanks
The final field determines whether blank lines within a label should be omitted. It should be set to 1
to omit or 0 to include such lines.
2.11-0
548 OpenQM
If no LABEL keyword is present in the command line (or any phrase use by the query), the query
processor looks for a default label template stored in a record named @LABEL in the dictionary of
the file or in the VOC. This action can be suppressed by use of LABEL NO.DEFAULT in the
command.
If no label template has been specified and either there is no @LABEL record or the
NO.DEFAULT keyword has been used, the query processor will prompt the user to enter the label
shape parameters in the same order as above. The omit blanks option must be entered as Y or N.
It may be necessary to check that a printer font is chosen where the line spacing fits correctly onto
the label page. The SETPTR command top margin may also need to be set to fit the page.
Example
This command prints address labels from all records in the CUSTOMERS file. Each label contains
data from the NAME and ADDRESS fields. A label template named ADDR.LABELS is used.
2.11-0
Query Processing 549
The REFORMAT verb constructs a new file from data in the source file. It is of use, for example,
when constructing intermediate files in complex reporting processes.
REFORMAT behaves like LIST except that the data identified by the display clause is used to
populate a new file instead of being displayed or printed. The first item in the data is used as the
record id for the item in the new file. The remaining items form the fields within the record.
REFORMAT does not automatically prefix the display clause with @ID.
The SREFORMAT command is identical to REFORMAT except that it sorts by record id after
any other sorting has been applied.
The TO clause can be used to name the target file on the command line. If this clause is not present,
a prompt is displayed for the file name. The file must already exist.
When used with breakpoints, data from the detail and total lines is directed to the output file but the
grand total is omitted.
Example
This command constructs a new file, CUST.BY.ZIP, keyed by zip code and containing two data
fields, the customer number and name. Note that if two or more customers share the same zip code,
the record will be overwritten by the second and subsequent items.
2.11-0
550 OpenQM
5.10 COUNT
The COUNT verb reports the number of records meeting specified criteria.
Example
This command counts records on the INVOICES file for which the PAYMENT.DATE field is null.
This might be a valid means of identifying unpaid invoices.
2.11-0
Query Processing 551
5.11 SUM
The SUM verb reports the total of the values in named fields.
Example
This command the BALANCE field of records on the INVOICES file for which the
PAYMENT.DATE field is null.
2.11-0
552 OpenQM
5.12 SHOW
Format
MAX n specifies the maximum number of items that may be selected for the returned list.
MIN n specifies the minimum number of items that may be selected for the returned list.
Returning no items is always valid regardless of the value of n.
Examples
SHOW BP
Displays a list of records in the BP file from which items may be chosen to build a select list.
For each client in the CLIENTS file with an outstanding balance greater then their credit limit,
display the company name and the calculated amount by which the client has exceeded their credit
limit. Display of the CLIENTS file record id is suppressed. The result of the SHOW operation
becomes the default select list (list 0).
Displays the id, quantity and reorder level fields of each item in the STOCK file. The result of the
SHOW operation is saved in select list 3.
Shows a list of CLIENTS file ids, the company name formatted to fit a 30 character wide field and
the date on which the client was last called using the D2/ conversion for this date.
2.11-0
Query Processing 553
The SHOW command displays a list of records from the file being processed. This display consists
of
A page heading which may be omitted using the HDR.SUP keyword. A default page heading is
used unless specifically set by use of the HEADING keyword. The SHOW command does not
support use of embedded control codes in page headings.
Column headings which may be omitted using the COL.SUP keyword. The heading is taken
from the display name field of the dictionary entry for the item in the column. If blank, the field
name is used.
Data from records being processed. The items displayed are the record id (unless the ID.SUP
keyword has been used) and other fields named on the command line.
If the total width of the named fields exceeds the available space, SHOW will drop trailing
fields until the data fits the display width or only one (plus the record id, if not suppressed)
remains. If the data still does not fit after dropping fields, the remaining fields are displayed
in reduced space.
The SHOW command splits multivalued items onto successive lines and correctly relates
values and subvalues in associated fields. A record is never split between two pages, a new
page being started if necessary. If a single record requires more lines than will fit on a
screen page, it is truncated.
Each item on the page is numbered for reference in the commands that manipulate the list.
The number starts at one for the first item on each page.
Using the commands listed below, the user can scroll through the displayed records setting or
clearing a marker (displayed as an asterisk next to the record number) which indicates whether the
record is to be included in the generated select list.
N Move to the next page. The return key with no command text has the same effect.
Q Quit from record selection. Any records marked with an asterisk are entered into the new
select list.
R Redisplay the screen. This is useful if a data transmission error causes screen corruption.
^^ Synonym for R.
2.11-0
554 OpenQM
? Display help text on the error line. Use the return key to walk through this text, line by
line. Any key other than the return key will terminate the help display.
S item Select item. The space before the item description is optional. An asterisk will be
displayed next to all selected items.
C item Clear item, removing the asterisk marker from the screen.
A range of numbers in the form a-b which indicates that the command is to be applied to all
items from that tagged with number a to that tagged with number b. There must be no spaces
either side of the hyphen.
The keyword VISIBLE to apply the command to all items on the current page.
The keyword ALL to apply the command to all items in the list.
Multiple item specifications may be included in a single command by using either a space or a
comma as a separator. For example "1,4,8-11".
The VISIBLE and ALL keywords may be abbreviated by omitting any number of trailing letters
(e.g. VIS or V).
2.11-0
Query Processing 555
Field qualifiers
% Synonym for PERCENTAGE
AS Define synonym for field and qualifiers
ASSOC Include field in association
ASSOC.WITH Associate two fields
AVERAGE Report average of field values
AVG Synonym for AVERAGE
BREAK.ON Define field as breakpoint control item.
BREAK-ON Synonym for BREAK.ON
BREAK.SUP Define field as non-displayed breakpoint control item.
BREAK-SUP Synonym for BREAK.SUP
CALC Calculate total of I-type item
CALCULATE Synonym for CALC
COL.HDG Set column heading for displayed item
CONV Specify conversion to be applied to field
CUMULATIVE Report cumulative value of field
DISPLAY.LIKE Display field using attributes of another field
DISPLAY.NAME Synonym for COL.HDG
ENUM Synonym for ENUMERATE
ENUMERATE Count number of values in specified field
EVAL Defines expression to be evaluated
FMT Specify format for display of field
MAX Report maximum value of a field
MIN Report minimum value of a field
MULTI.VALUE Treat field as multivalued
MULTIVALUED Synonym for MULTI.VALUE
NO.NULLS Suppress null fields in MIN and AVG calculations
PCT Synonym for PERCENTAGE
PERCENT Synonym for PERCENTAGE
PERCENTAGE Report percentages
SINGLE.VALUE Treat field as single-valued
SINGLEVALUED Synonym for SINGLE.VALUE
TOTAL Report total of field values
SEARCH options
ALL.MATCH Record must contain all given strings
NO.CASE Case insensitive option for SEARCH
NO.MATCH Record must contain none of the given strings
STRINGS Specifies a file and record containing the search strings
2.11-0
556 OpenQM
Display options
BOXED Generates a boxed report on a PCL printer
CAPTION Synonym for GRAND.TOTAL
COL.HDG.ID Use field names as default column headings
COL.HDR.SUPP Suppress page and column headings
COL.HDR.SUP Synonym for COL.HDR.SUPP
COL-HDR-SUPP Synonym for COL.HDR.SUPP
COL-HDR-SUP Synonym for COL.HDR.SUPP
COL.SPACES Specifies inter-column spacing
2.11-0
Query Processing 557
Miscellaneous
ABSENT.IGNORE Ignore unfound records
ABSENT.NULL Treats an absent record as a null item rather than an error
LABEL Specifies the label template for LIST.LABEL and SORT.LABEL
LOCKING Takes a file lock on the file being processed, preventing updates
NO.INDEX Do not use an alternate key index for record selection
REQUIRE.INDEX Do not perform the query unless an alternate key index can be
used
TO Specifies the output file name for REFORMAT. See also CSV
2.11-0
558 OpenQM
and DELIMITER
USING Use an alternative dictionary
2.11-0
Query Processing 559
5.14 ABSENT.IGNORE
The ABSENT.IGNORE keyword suppresses the message at the end of a query command showing
records that have not been found.
Format
ABSENT.IGNORE
The query processor normally builds a list of records that were specified on the command line or via
a select list but were not found. This list is displayed on completion of the command. Sometimes it
might be valid for the list to contain items that might not be present and should be ignored. In this
case the list of unfound records is not required. The ABSENT.IGNORE keyword causes the query
processor to ignore missing records.
Example
SELECT VOC
LIST NEWVOC
This pair of commands builds a list of all records in the VOC and then uses this list to display a
report of the same records from the NEWVOC file. There will be records in the VOC that do not
appear NEWVOC and a list of these will be shown on completion of the report.
SELECT VOC
LIST NEWVOC ABSENT.IGNORE
This pair of commands produces the same report but omits the list of records that were not found in
NEWVOC.
2.11-0
560 OpenQM
5.15 ABSENT.NULL
The ABSENT.NULL keyword treats an absent record as a null item rather than an error.
Format
ABSENT.NULL
There are situations where two or more related files share a common (or related) record id but some
ids may not appear in all of the files. The ABSENT.NULL keyword, normally used with a select
list, allows reports to be constructed that draw data from the complete set of files, returning a null
record for any item that is not present in the main file processed by the query. A dictionary I-type
entry can then be used to retrieve data from the related files.
Example
The dictionary for FILE1 contains an I-type entry, F2REF, that is a simple TRANS() using the
record id of FILE1 to access the same record in FILE2, returning data from this file.
TRANS(FILE2, @ID, FIELD.NAME, 'X')
2.11-0
Query Processing 561
5.16 ALL.MATCH
The ALL.MATCH keyword used in a SEARCH command specifies that the records to be selected
must contain all of the given search strings.
Format
ALL.MATCH
Without this keyword, the SEARCH command builds a list of records containing any of the
supplied search strings. With ALL.MATCH, the records must contain all of the supplied strings.
Example
SEARCH BP ALL.MATCH
String: STOCK.FILE
String: STK.F
String:
This command builds a list of records in the BP file containing both the given strings.
See also:
NO.CASE, NO.MATCH, SEARCH
2.11-0
562 OpenQM
5.17 AND
The AND selection clause operator links two selection criteria where both must be true for the
record to be selected. The synonym & can be used.
Format
where
The AND selection clause operator returns true if both condition.1 and condition.2 are true.
Alternatively, multiple WITH clauses can be used.
The AND and OR operators are normally of equal priority and will be evaluated strictly left to
right. Brackets may need to be used to enforce evaluation in an different order. Thus a query such
as
LIST CLIENTS WITH REGION = 1 AND VALUE > 1000 OR REGION = 2
AND VALUE > 500
may need brackets to achieve the desired effect
LIST CLIENTS WITH (REGION = 1 AND VALUE > 1000) OR (REGION = 2
AND VALUE > 500)
Pick style multivalue database products give AND priority over OR such that the above query
would not need the brackets. This behaviour can be enabled in QM by use of the
QUERY.PRIORITY.AND mode of the OPTION command.
Example
This command lists items found on the STOCK file with a QTY field of over 100 and a REORDER
field of less than 300.
2.11-0
Query Processing 563
5.18 AS
The AS keyword is a field qualifier which defines a synonym for a field and any qualifying
information.
Format
where
synonym is the name by which the field and its qualifiers is to be known. This name
must not correspond to an existing entry in the file's dictionary or in the
VOC.
The AS keyword creates a synonym for field.name together with any field.qualifier. It is normally
only used in conjunction with a field.qualifier or to name an evaluated expression.
Example
This command processes records from the INVOICES file and reports the total of the multivalued
RECEIVED field . The report is displayed in descending order of total received amount. The AS
keyword is used to give the synonym AMT to the evaluated sum so that it can be referred to again
in the sort clause after the BY.DSND keyword without full expansion.
See also:
EVAL
2.11-0
564 OpenQM
5.19 ASSOC
The ASSOC keyword is a field qualifier to specify that the field is to be treated as part of a named
association.
Format
where
name is the name of the association in which field.name is to be included. The name
must be quoted to avoid its expansion as a phrase.
The ASSOC keyword causes field.name to be treated as part of the named association.
Example
This command processes records from the ORDERS file and reports the multivalued part numbers,
quantities and calculated line total value for each record. The evaluated expression is treated as a
member of the association LINE.ITEMS to which the other reported fields already belong.
See also:
ASSOC.WITH
2.11-0
Query Processing 565
5.20 ASSOC.WITH
The ASSOC.WITH keyword is a field qualifier to specify that the field is to be associated with
some other named field.
Format
where
The ASSOC.WITH keyword causes field.name to be treated as associated with field name.
Example
This command processes records from the ORDERS file and reports the multivalued part numbers,
quantities and calculated line total value for each record. The evaluated expression is treated as
associated with PART.NO.
See also:
ASSOC
2.11-0
566 OpenQM
5.21 AVERAGE
The AVERAGE field qualifier keyword causes a field to be reported together with its average
value. The synonym AVG may be used.
Format
where
The AVERAGE field qualifier keyword is placed before the field name to which it applies and
causes the query processor to report the value of the field for each record processed and also to
report the average value at the end of the report. Used with breakpoints, the AVERAGE keyword
will also report the average value of the field at each breakpoint.
If the field is defined as multivalued, the AVERAGE keyword operates on each value in turn.
The AVERAGE keyword operates only on numeric data. Non-numeric values are ignored.
The NO.NULLS keyword can be used to prevent null values being included in the calculation of
the average value.
Example
The sentence
would produce a display such as that below in which the average value of the VALUE field is
included at the end of the report.
2.11-0
Query Processing 567
5.22 BETWEEN
The BETWEEN selection clause operator compares a field or evaluated expression against two
other fields, evaluated expressions or literal values, testing whether the value of the first item lies
between the other two values.
Format
where
The BETWEEN selection clause operator returns true if field is greater than or equal to value1
and less than or equal to value2. The optional NO.CASE qualifier causes a case insensitive
comparison to be applied.
When applied to multivalued fields, the test is applied to each value in turn. Note that the query
LIST ORDERS WITH PART.NO BETWEEN 200 299
is not the same as
LIST ORDERS WITH PART.NO >= 200 AND PART.NO <= 299
if PART.NO is a multivalued field. The first query selects only those records which include part
numbers in the range 200 to 299. The second query selects those records which include a part
number that is greater than or equal to 200 and another part number that is less than or equal to
299.
2.11-0
568 OpenQM
5.23 BOXED
The BOXED display clause option causes the query processor to generate a boxed report. This
option is ignored if report destination is not a printer or file set in PCL mode.
Format
BOXED
The BOXED option draws a box around the page border as defined by the page width and depth
specified in the SETPTR command. The effective width of the page is reduced by two characters to
ensure that there is a margin between the text and sides of the box.
If the report includes a page heading or footing, these are separated from the body of the report by a
horizontal line.
Note: The quality of PCL implementations varies widely and this option may not give the expected
results on some printers. It is the application developer's responsibility to ensure that the printed
results are acceptable.
2.11-0
Query Processing 569
5.24 BREAK.ON
The BREAK.ON field qualifier keyword causes the query processor to display the named field,
generating a breakpoint whenever the field value changes.
Format
where
The BREAK.ON keyword appears before the field name and causes the query processor to
generate a breakpoint whenever the field value changes. The field is also printed as part of the
report. Queries using breakpoints should also sort on the breakpoint field(s).
The action taken at the breakpoint depends on the optional options component and whether any
field value accumulations (AVERAGE, CALC, MAX, MIN, PERCENTAGE or TOTAL) are
in use.
A breakpoint with no options and no field accumulations prints a line with two asterisks in the
column for the field causing the breakpoint followed by a blank line. If field accumulations are
present, subtotals are also printed for each accumulated column. A line of hyphens may appear
above the subtotals depending on the use of the U breakpoint control code.
The options text will be used in place of the default two asterisks when a breakpoint occurs. This
text may also contain control codes enclosed in single quotes. The available control codes are:
B{n} Start a new page, retaining the value of the breakpoint field for inclusion in the page
heading/footing by use of the B heading text option. The optional single digit qualifier,
n, allows collection of values from multiple breakpoints for inclusion in a composite
heading. If omitted, the value of n defaults to zero. Thus use of B alone is equivalent to
use of B0.
D Omit the subtotal line if there is only one line of detail for this breakpoint.
L Emit a blank line in place of the breakpoint. Any text in the options string will be
ignored.
N Resets page number to one at each breakpoint. This implies the P option if not used
with B or P.
O Only show the value of the breakpoint field on the first detail line within the breakpoint.
P Start a new page.
U If the PICK.BREAKPOINT.U mode of the OPTION command is in effect, this mode
inserts a line of hyphens above any subtotals, etc. If this option is not in effect, the line
of hyphens is produced unless the U mode is used.
V Print the breakpoint field value in place of the default two asterisks. The V control code
2.11-0
570 OpenQM
Pick Syntax
If the PICK.BREAKPOINT mode of the OPTION command is in effect, the options element of
the BREAK.ON appears after the field rather than before.
Examples
The command
===========
2930.79
7 records listed.
would produce
LIST SALES BY REGION BREAK.ON "Total"O"" REGION SALESMAN TOTAL
ORDER.V Page 1
SALES..... REGION SALESMAN ORDER VALUE
19887 North Roberts 279.40
19859 Sharp 384.43
19858 Sharp 845.50
19845 Harris 234.53
Total -----------
North 1743.86
2.11-0
Query Processing 571
===========
2930.79
7 records listed.
See also:
BREAK.SUP
2.11-0
572 OpenQM
5.25 BREAK.SUP
The BREAK.SUP field qualifier keyword causes the query processor to generate a breakpoint
whenever the field value changes. The field is not displayed in the report.
Format
where
The BREAK.SUP keyword appears before the field name and causes the query processor to
generate a breakpoint whenever the field value changes. Queries using breakpoints should also sort
on the breakpoint field(s).
The action taken at the breakpoint depends on the optional options component and whether any
field value accumulations (AVERAGE, CALC, MAX, MIN, PERCENTAGE or TOTAL) are
in use.
A breakpoint with no options and no field accumulations prints a line with two asterisks in the
column for the field causing the breakpoint followed by a blank line. If field accumulations are
present, subtotals are also printed for each accumulated column. A line of hyphens may appear
above the subtotals depending on the use of the U breakpoint control code.
The options item is as for BREAK.ON though the text will never appear and only some control
options are of use with BREAK.SUP. The useful control codes are:
B{n} Start a new page, retaining the value of the breakpoint field for inclusion in the page
heading/footing by use of the B heading text option. The optional single digit qualifier,
n, allows collection of values from multiple breakpoints for inclusion in a composite
heading. If omitted, the value of n defaults to zero. Thus use of B alone is equivalent to
use of B0.
D Omit the subtotal line if there is only one line of detail for this breakpoint.
L Emit a blank line in place of the breakpoint. Any text in the options string will be
ignored.
N Resets page number to one at each breakpoint. This implies the P option if not used
with B or P.
P Start a new page.
U If the PICK.BREAKPOINT.U mode of the OPTIONcommand is in effect, this mode
inserts a line of hyphens above any subtotals, etc. If this option is not in effect, the line
of hyphens is produced unless the U mode is used.
Combinations of control codes may be used together.
2.11-0
Query Processing 573
Pick Syntax
If the PICK.BREAKPOINT mode of the OPTION command is in effect, the options element of
the BREAK.SUP appears after the field rather than before.
Examples
The command
===========
2930.79
7 records listed.
would produce
2.11-0
574 OpenQM
===========
2930.79
7 records listed.
See also:
BREAK.ON
2.11-0
Query Processing 575
5.26 BY
The BY sort clause keyword causes the query processor to sort records prior to display or when
building a select list.
Format
BY {NO.CASE} field
where
field is the field name or evaluated expression to be used to determine the sort order.
The BY keyword causes records to be sorted into ascending order of the specified field. The
comparison is performed before conversion of the data to its display format. If the display format is
left justified, a left justified sort is performed. Conversely, if the display format is right justified, a
right justified sort is performed.
The optional NO.CASE keyword causes the sort to be performed in a case insensitive manner.
Effectively, all comparisons are done using an uppercase version of the data being compared.
If more than one sort clause is present, sort criteria are applied in the order in which they are
specified.
The command
is identical to
SORT BOOKS
Example
The command
See also:
BY.DSND, BY.EXP, BY.EXP.DSND
2.11-0
576 OpenQM
5.27 BY.DSND
The BY.DSND sort clause keyword causes the query processor to sort records prior to display or
when building a select list. The synonym BY-DSND may be used.
Format
where
field is the field name or evaluated expression to be used to determine the sort order.
The BY.DSND keyword causes records to be sorted into descending order of the specified field.
The comparison is performed before conversion of the data to its display format. If the display
format is left justified, a left justified sort is performed. Conversely, if the display format is right
justified, a right justified sort is performed.
The optional NO.CASE keyword causes the sort to be performed in a case insensitive manner.
Effectively, all comparisons are done using an uppercase version of the data being compared.
If more than one sort clause is present, sort criteria are applied in the order in which they are
specified.
Example
The command
See also:
BY, BY.EXP, BY.EXP.DSND
2.11-0
Query Processing 577
5.28 BY.EXP
The BY.EXP sort clause keyword applied to a multivalued field causes the query processor to
explode the multivalued items to form separate single valued records and to sort these into
ascending order prior to display or when building a select list.
Format
where
field is the field name or evaluated expression to be used to determine the sort order.
The BY.EXP keyword causes records to be sorted into ascending order of the values stored in the
specified field. The comparison is performed before conversion of the data to its display format. If
the display format is left justified, a left justified sort is performed. Conversely, if the display
format is right justified, a right justified sort is performed.
The optional NO.CASE keyword causes the sort to be performed in a case insensitive manner.
Effectively, all comparisons are done using an uppercase version of the data being compared.
If more than one sort clause is present, sort criteria are applied in the order in which they are
specified. If more than one exploded sort clause is present, they must all be on the same association.
Example
The command
The command
2.11-0
578 OpenQM
Adding an explosion limiter to this query to show only part numbers greater than 300:
LIST ORDERS PART.NO QTY LINE.TOTAL BY.EXP PART.NO > 300
would produce the report below.
See also:
BY, BY.DSND, BY.EXP.DSND, REPEATING
2.11-0
Query Processing 579
5.29 BY.EXP.DSND
The BY.EXP.DSND sort clause keyword applied to a multivalued field causes the query processor
to explode the multivalued items to form separate single valued records and to sort these into
descending order prior to display or when building a select list.
Format
where
field is the field name or evaluated expression to be used to determine the sort order.
The BY.EXP.DSND keyword causes records to be sorted into descending order of the values
stored in the specified field. The comparison is performed before conversion of the data to its
display format. If the display format is left justified, a left justified sort is performed. Conversely, if
the display format is right justified, a right justified sort is performed.
The optional NO.CASE keyword causes the sort to be performed in a case insensitive manner.
Effectively, all comparisons are done using an uppercase version of the data being compared.
If more than one sort clause is present, sort criteria are applied in the order in which they are
specified. If more than one exploded sort clause is present, they must all be on the same association.
Example
The command
The command
2.11-0
580 OpenQM
Adding an explosion limiter to this query to show only part numbers greater than 300:
LIST ORDERS PART.NO QTY LINE.TOTAL BY.EXP.DSND PART.NO > 300
would produce he report below.
See also:
BY, BY.DSND, BY.EXP
2.11-0
Query Processing 581
5.30 CALC
The CALC keyword prefixes an I-type field name or an evaluated expression and causes the
calculation to be performed on the total lines using accumulated values from the detail lines.
Format
CALC field
where
field is the I-type field or expression for which the calculation is to be performed.
The CALC keyword works in conjunction with the I-type TOTAL() function. During detail lines,
the TOTAL() function accumulates values which are then used on the subtotal and grand total lines
to calculate the value in the column to which the CALC keyword applies.
Example
The command
The average profit figure (23.81) is the average of the figures in the column above it. Perhaps what
we really want to show is the percentage profit selling for 16.00 something that cost us 13.00 (the
average cost and selling prices). To do this, the PROFIT expression is changed to
100 * (TOTAL(SELL) - TOTAL(COST)) / TOTAL(COST)
or, more simply,
100 * TOTAL(SELL - COST) / TOTAL(COST)
The command
LIST PARTS AVG COST AVG SELL CALC PROFIT
now produces
2.11-0
582 OpenQM
2.11-0
Query Processing 583
5.31 COL.HDG
The COL.HDG keyword defines an alternative column heading for reported data. The synonym
DISPLAY.NAME may be used.
Format
where
field is the field or expression to which the new column heading is to be applied.
text is the new column heading. This must be enclosed in single or double quotes.
The default column heading for reported data is the display name from the dictionary entry or, for
evaluated expressions, the expression. The COL.HDG field qualifier can be used to set an
alternative column heading.
The text may include the control tokens that control how the column heading is displayed. The
codes are enclosed in single quotes which implies that a column heading specification that uses the
codes must itself be enclosed in double quotes.
'L' appearing within text breaks the heading onto a new line at that point. This is
equivalent to use of a value mark in a dictionary heading definition.
'R' at the start of the heading text right aligns the heading.
'X' at the start of the heading text suppresses the dot fillers normally inserted into unused
columns of the heading.
If both R and X are to be used, they should be enclosed in a single set of quotes.
Examples
This command reports records from the INVOICES file where no payment has been recorded. The
AMT.DUE field has the column heading set to "Outstanding".
This command reports records from the SALES file. The heading for the CUST.NO field occupies
two lines. The column heading for VALUE is right justified with the normal dot filler suppressed.
2.11-0
584 OpenQM
5.32 COL.HDG.ID
The COL.HDG.ID keyword causes the query processor to use the display clause field names as the
default column headings.
Format
COL.HDG.ID
The query processor normally uses the display name entry from the dictionary as the column
heading in a report. Use of the COL.HDG.ID keyword causes use of the actual field name as the
column heading for all fields unless overridden by use of COL.HDG.
Example
The command
2.11-0
Query Processing 585
5.33 COL.HDR.SUPP
The COL.HDR.SUPP display clause keyword suppresses page and column headings. The
synonyms COL-HDR-SUPP, COL.HDR.SUP and COL-HDR-SUP can be used.
Format
COL.HDR.SUPP
The COL.HDR.SUPP keyword suppresses both the page heading (normally the command that
invoked the query processor) and the column headings derived from the dictionary display names or
COL.HDG keywords.
Example
The command
2.11-0
586 OpenQM
5.34 COL.SPACES
The COL.SPACES keyword determines the number of spaces inserted between columns of a
tabular report. The synonym COL.SPCS may be used.
Format
COL.SPACES n
where
Tabular reports are automatically adjusted to fit the available page space. The COL.SPACES
keyword allows a user specified column spacing to be used.
Example
The command
2.11-0
Query Processing 587
5.35 CONV
Format
where
conv.spec is the new conversion specification. This must be enclosed in single or double
quotes.
The default conversion for reported data is taken from the dictionary entry for field or, for
evaluated expressions, the first field referenced in the expression. The CONV field qualifier can be
used to set an alternative conversion specification.
Example
This command reports records from the ORDERS file where using a non-default conversion
specification for the ORDER.DATE field.
2.11-0
588 OpenQM
5.36 COUNT.SUP
The COUNT.SUP display option keyword suppresses display of the number of records listed or
selected at the end of the command.
Format
COUNT.SUP
Query processor commands normally displays the number of records listed or selected at the end of
the command. The COUNT.SUP keyword can be used to suppress this action.
Example
Compare the two commands and their displayed results shown below.
The first command shows the normal display of the count of records selected. The second command
includes the COUNT.SUP keyword to suppress this display.
2.11-0
Query Processing 589
5.37 COL.SUP
The COL.SUP display clause keyword suppresses column headings. The synonym COL-SUPP
can be used.
Format
COL.SUP
The COL.SUP keyword suppresses the column headings derived from the dictionary display names
or COL.HDG keywords. Used with LIST.ITEM or SORT.ITEM, this keyword suppress display
of field numbers.
Example
The command
2.11-0
590 OpenQM
5.38 CSV
The CSV display option keyword specifies that the report should be produced in CSV format.
Format
where
file id is a filename and record id pair identifying the destination for the output.
The CSV keyword produces a report in CSV (comma separated variable) format as used by many
software products. In this format, each item in the report is separated by a comma instead of the
usual tabular style of report. QM extends this format by allowing use of an alternative delimiter
character.
The mode option specifies the format rules to be applied. A mode value of 1 (the default if no mode
is given) produces output that conforms to the CSV format specification (RFC 4180). This requires
that items containing double quotes or the delimiter character are enclosed in double quotes with
embedded double quotes replace by two adjacent double quotes.
A mode value of 2 encloses all non-null values in double quotes except for numeric items that do
not contain a comma. Embedded double quotes are replaced by two adjacent double quotes.
A mode value of 3 encloses all values in double quotes. Embedded double quotes are replaced by
two adjacent double quotes.
The delimiter may be set to a tab character by use of the special syntax "<TAB>". Other
non-printing characters can be specified by use of the ^nnn notation where nnn is the three digit
character number from the ASCII character set.
Multivalued items will be split over multiple lines of CSV output. If an item is defined as single
valued in the dictionary (or by use of the SINGLE.VALUE keyword) but the corresponding data
contains value marks, the marks are treated as normal data characters and the entire multivalued
item, including the embedded value marks, will be output as a single element of the CSV output.
The TO option directs output to an operating system file by pathname. The AS option directs
output to a named record in a QM directory file. If the destination item already exists, the user will
be prompted to confirm whether it should be overwritten. The NO.QUERY option suppresses this
prompt, overwriting the existing file. The APPENDING option causes the output to be appended to
the output file if it already exists. The NO.QUERY and APPENDING options may not be used
together.
In normal usage, the page heading and record counts would probably need to be suppressed using
the HDR.SUP and COUNT.SUP keywords. The COL.SUP keyword can be used to suppress
column headings.
Examples
The command
LIST CUSTOMERS NAME TEL HDR.SUP COL.SUP COUNT.SUP CSV
would produce a display such as that below.
Note how the customer name in the second line has been quoted because it contains a comma.
This command constructs comma separated format report of the STOCK file into the
C:\STOCK.CSV file.
This command constructs comma separated format report of the STOCK file in a record named
SRK.RPT in the $HOLD file.
A command such as
LIST SALES ITEM.NO CSV
where ITEM.NO is multivalued might produce a report containing
26832,176
,218
,398
2.11-0
592 OpenQM
5.39 CUMULATIVE
The CUMULATIVE field qualifier keyword displays the cumulative value of a field.
Format
where
The CUMULATIVE field qualifier keyword is placed before the field name to which it applies and
causes the query processor to report the cumulative value of the field. A total line is also produced.
Used with breakpoints, the CUMULATIVE keyword will also report the total value of the field at
each breakpoint.
The CUMULATIVE keyword operates only on numeric data. Non-numeric values are ignored.
Example
The command
would produce a display such as that below in which the total value of the VALUE field is included
at the end of the report.
2.11-0
Query Processing 593
5.40 DBL.SPC
The DBL.SPC display option keyword causes records in a tabular report to be double spaced. The
synonym DBL-SPC may be used.
Format
DBL.SPC
The DBL.SPC keyword inserts a blank line between each record displayed in a tabular format
report. It has no effect in a vertical format report.
Example
The command
4 records listed.
2.11-0
594 OpenQM
5.41 DELIMITER
The DELIMITER display option keyword specifies the separating character(s) to be used in a
delimited report.
Format
file id is a filename and record id pair identifying the destination for the output.
A delimited report displays it output as a series of items separated by the given string instead of the
usual tabular style of report. The DELIMITER keyword causes the query processor to produce
this style of report and specifies the separator to be used. The output from a delimited report can,
for example, be structured with comma separators, sent to a file using the LPTR keyword and then
read into applications such as Microsoft Excel.
The string may contain tab characters by use of the special syntax "<TAB>". Other non-printing
characters can be included by use of the ^nnn notation where nnn is the three digit character
number from the ASCII character set.
Multivalued items will be split over multiple lines of delimited output. If an item is defined as single
valued in the dictionary (or by use of the SINGLE.VALUE keyword) but the corresponding data
contains value marks, the marks are treated as normal data characters and the entire multivalued
item, including the embedded value marks, will be output as a single element of the delimited
output.
The TO option directs output to an operating system file by pathname. The AS option directs
output to a named record in a QM directory file. If the destination item already exists, the user will
be prompted to confirm whether it should be overwritten. The NO.QUERY option suppresses this
prompt, overwriting the existing file. The APPENDING option causes the output to be appended to
the output file if it already exists. The NO.QUERY and APPENDING options may not be used
together.
In normal usage, the page heading and record counts would probably need to be suppressed using
the HDR.SUP and COUNT.SUP keywords. The COL.SUP keyword can be used to suppress
column headings.
Examples
The command
LIST INVOICES VALUE CUSTOMER.NAME DELIMITER "," HDR.SUP
2.11-0
Query Processing 595
COL.SUP COUNT.SUP
would produce a display such as that below.
74529,£1712.43,J McTavish
74273,£95.23,County Newspapers
63940,£141.00,R Bryant
74993,£9.29,Write Right Stationery
The command
LIST INVOICES VALUE CUSTOMER.NAME DELIMITER "<tab>" HDR.SUP
COUNT.SUP
would produce a display such as that below where the spacing is performed by tab characters.
A command such as
LIST SALES ITEM.NO DELIMITER ","
where ITEM.NO is multivalued might produce a report containing
26832,176
,218
,398
2.11-0
596 OpenQM
5.42 DET.SUP
The DET.SUP keyword (synonym DET-SUPP) suppresses reporting of detail lines, leaving only
page and column headers, totals, footers and the final record count.
Format
DET.SUP
The DET.SUP keyword removes all detail lines from a report. It allows easy reporting of totals
without the data that contributed to the totals.
When a query uses both DET.SUP and breakpoints, any column for which no breakpoint is defined
and no arithmetic field qualifier is in use will show the value of that field for the last record
processed within that breakpoint group. This is probably only meaningful when the value of the
field is the same for all records in the breakpoint group.
When used with report styles (see the STYLE option), subtotal lines will be reported using the
detail line style.
Example
The command
===========
2930.79
7 records listed.
Adding the DET.SUP keyword and omitting the salesman changes this report to be as below.
2.11-0
Query Processing 597
2.11-0
598 OpenQM
5.43 DISPLAY.LIKE
The DISPLAY.LIKE keyword is a field qualifier which causes the field to be displayed using the
attributes of another field defined in the dictionary.
Format
where
other.field is the field whose attributes are to be used when field.name is displayed.
The DISPLAY.LIKE keyword causes the attributes of other.field to be used when displaying
field.name. The attributes are the display name, conversion, format, single / multiple value flag and
association. The COL.HDG, CONV, FMT, SINGLE.VALUE, MULTI.VALUE, ASSOC and
ASSOC.WITH field qualifiers can be used to further modify the attributes.
Example
This command processes records from the INVOICES file and reports the record id (probably the
invoice number) and the date 90 days after that stored in the ISSUE.DATE field using the attributes
of the DUE.DATE field except for the column heading which is specifically set.
2.11-0
Query Processing 599
5.44 ENUMERATE
The ENUMERATE field qualifier keyword causes a field to be reported together with a count of
values. The synonym ENUM may be used.
Format
where
The ENUMERATE field qualifier keyword is placed before the field name to which it applies and
causes the query processor to report the value of the field for each record processed and also to
report the number of values at the end of the report. Used with breakpoints, the ENUMERATE
keyword will also report the number of values at each breakpoint.
If the field is defined as multivalued, the ENUMERATE keyword counts each value.
Example
The command
would produce a display such as that below in which the number of items in the VALUE field is
shown at the end of the report.
2.11-0
600 OpenQM
5.45 EQ
The EQ selection clause operator compares a field or evaluated expression against another field,
evaluated expression or literal value and tests for the first item being equal to the second. The
synonyms EQUAL and = can be used.
Format
where
value is the second field, evaluated expression or literal value to be compared. The
optional NO.CASE qualifier causes a case insensitive comparison to be applied.
The default behaviour of the query processor is that if field is defined as left justified in the
dictionary, an exact match string comparison is used. For right aligned fields (typically numeric
values) a numeric comparison will be used if the field content and value are both integer values.
The QUERY.STRING.COMP mode of the OPTION command can be used to apply string
character comparisons to all data.
Example
This command lists items found on the STOCK file with a QTY field of 100. If QTY is defined as
left justified, the content of this field must be the three digits 100 for the record to be included in the
report. If QTY is defined as right justified, records for which QTY holds any numeric data equal to
100 will be included (e.g. 0100).
If the PICK.WILDCARD option is enabled (see the OPTION command) and the value item is a
literal value, the interpretation is extended to include use of Pick style wildcard characters:
· A [ character at the start of the value replaces any number of leading characters. It is
equivalent to the … action of the LIKE operator.
· A ] character at the end of the value replaces any number of trailing characters. It is
equivalent to the … action of the LIKE operator.
· A ^ character within the value replaces a single character. It is equivalent to the 1X action
of the LIKE operator.
2.11-0
Query Processing 601
5.46 EVAL
The EVAL (or EVALUATE) keyword prefixes an expression to be evaluated and used as though
it were an I-type defined in the dictionary.
Format
EVAL expr
where
The EVAL keyword prefixes an expression which is handled as a temporary I-type. It may be used
as a field for display or in selection or sort clauses.
The expr string conforms to the same rules as I-type expressions. It is compiled by the query
processor for use within the command being executed but is not saved in the dictionary. Where the
value of expr is a constant, the expression is evaluated only once and then treated as a literal value.
The default display name used for an EVAL expression in the absence of a COL.HDG qualifier is
the expression itself.
The default display format and conversion are taken from the first field referenced by the
expression. If no fields are referenced, the format defaults to 10L with no conversion. Alternative
format or conversion may be specified with the FMT or CONV field qualifiers.
Example
This command processes records from the INVOICES file and reports the record id (probably the
invoice number) and the total of the RECEIVED field which is multivalued to allow for more than
one payment against an invoice.
See also:
AS
2.11-0
602 OpenQM
5.47 FMT
Format
where
fmt.spec is the new format specification. This must be enclosed in single or double
quotes.
The default format for reported data is taken from the dictionary entry for field or, for evaluated
expressions, the first field referenced in the expression. The FMT field qualifier can be used to set
an alternative format specification.
Example
This command reports records from the ORDERS file where using a non-default format
specification for the SITE.NAME field.
2.11-0
Query Processing 603
5.48 FOOTING
The FOOTING keyword defines a page footing for the report. The synonym FOOTER may be
used.
Format
FOOTING "text"
where
A page footing defined with the FOOTING keyword will appear at the bottom of each page of the
report. The footing text may contain control codes enclosed in single quotes to insert variable data
or to alter the appearance of the footing. These control codes are:
B{n} Insert data from the corresponding B control code in a BREAK.ON or BREAK.SUP
option string. The optional single digit qualifier, n, defaults to zero if omitted.
C Centres the current line of the footing text.
D Inserts the date. The default format is dd mmm yyyy (e.g. 24 Aug 2005) but can be
changed using the DATE.FORMAT command.
F{n} Inserts the file name in a field of n spaces. If n is omitted, a variable width is used.
G Inserts a gap. Spaces are inserted in place of the G control code to expand the text to
the width of the output device. If more than one G control code appears in a single line,
spaces are distributed as evenly as possible.
When a footing line uses both G and C, the footing is considered as a number of
elements separated by the G control options. The element that contains the C option
will be centered. The items either side of the centered element are processed separately
when calculating the number of spaces to be substituted for each G option.
Hn Sets horizontal position (column) numbered from one. Use of H with C or with a
preceding G token may have undesired results.
I{n} Inserts the record id in a field of n spaces. If n is omitted, a variable width is used.
L Inserts a new line at this point in the text.
N Suppresses pagination of the output to the display.
O Reverses the elements separated by G tokens in the current line on even numbered
pages. This is of use when printing double sided reports.
P{n} Insert page number. The page number is right justified in n spaces, widening the field if
necessary. If omitted, n defaults to four.
R{n} Same as I{n}.
S{n} Insert page number. The page number is left justified in n spaces, widening the field if
necessary. If omitted, n defaults to one.
T Inserts the time and date in the form hh:mm:ss dd mmm yyyy. The format of the date
component can be changed using the DATE.FORMAT command.
2.11-0
604 OpenQM
A single quote may be inserted in the footing by use of two adjacent single quotes in the text.
If more than one FOOTING definition is given in a single query, the first one is used. This allows a
query sentence to include a footing that will override an alternative footing in the default listing
phrase.
Example
The command
7 records listed.
SALES REPORT
26 Jun 2000
Confidential
See also:
HEADING
2.11-0
Query Processing 605
5.49 FORCE
Format
FORCE
A query report that finds no records to output normally shows only the zero record count. The
FORCE option causes the page and column headings to be displayed in this situation.
2.11-0
606 OpenQM
5.50 FROM
The FROM keyword specifies the select list to be used as a source of record ids for processing by
the query.
Format
FROM list.no
where
If the FROM keyword is not present, the query processor will automatically use the default list, list
0, if it is active. Otherwise, all records in the file are processed.
Example
This command lists items from the STOCK file using select list 4 as the source of record ids to be
processed.
2.11-0
Query Processing 607
5.51 GE
The GE selection clause operator compares a field or evaluated expression against another field,
evaluated expression or literal value and tests for the first item being greater than or equal to the
second. The synonyms >= and => can be used.
Format
where
value is the second field, evaluated expression or literal value to be compared. The
optional NO.CASE qualifier causes a case insensitive comparison to be applied.
The GE selection clause operator returns true if field is greater than or equal to value.
Example
This command lists items found on the STOCK file with a QTY field of 100 or over.
2.11-0
608 OpenQM
5.52 GRAND.TOTAL
Format
GRAND.TOTAL "text"
where
The GRAND.TOTAL text may include control options enclosed in single quotes. These are:
The default form of the grand total is to show a line of equals signs (=) above the total values. The
grand total text appears on the left of this line.
The U control option inverts inclusion of the underline. Without PICK.GRAND.TOTAL, this
mode omits the underline. With PICK.GRAND.TOTAL, the underline is shown.
Example
The command
7 records listed.
See also:
NO.GRAND.TOTAL
2.11-0
610 OpenQM
5.53 GT
The GT selection clause operator compares a field or evaluated expression against another field,
evaluated expression or literal value and tests for the first item being greater than the second. The
synonyms AFTER, GREATER and > can be used.
Format
where
value is the second field, evaluated expression or literal value to be compared. The
optional NO.CASE qualifier causes a case insensitive comparison to be applied.
The GT selection clause operator returns true if field is greater than value.
Example
This command lists items found on the STOCK file with a QTY field of over 100.
2.11-0
Query Processing 611
5.54 HDR.SUP
The HDR.SUP display clause keyword suppresses the default page heading. The synonyms
HDR-SUPP and SUPP can be used.
Format
HDR.SUP
The HDR.SUP keyword suppresses the default page heading (the command that invoked the query
processor). Any heading specified by use of the HEADING keyword will still be output.
Example
The command
2.11-0
612 OpenQM
5.55 HEADING
The HEADING keyword defines a page heading for the report. The synonym HEADER may be
used.
Format
HEADING "text"
where
A page heading defined with the HEADING keyword will appear at the top of each page of the
report in place of the default heading. Except when used with the SHOW verb, the heading text
may contain control codes enclosed in single quotes to insert variable data or to alter the appearance
of the heading. These control codes are:
B{n} Insert data from the corresponding B control code in a BREAK.ON or BREAK.SUP
option string. The optional single digit qualifier, n, defaults to zero if omitted.
C Centres the current line of the heading text.
D Inserts the date. The default format is dd mmm yyyy (e.g. 24 Aug 2005) but can be
changed using the DATE.FORMAT command.
F{n} Inserts the file name in a field of n spaces. If n is omitted, a variable width is used.
G Inserts a gap. Spaces are inserted in place of the G control code to expand the text to
the width of the output device. If more than one G control code appears in a single line,
spaces are distributed as evenly as possible.
When a heading line uses both G and C, the heading is considered as a number of
elements separated by the G control options. The element that contains the C option
will be centered. The items either side of the centered element are processed separately
when calculating the number of spaces to be substituted for each G option.
Hn Sets horizontal position (column) numbered from one. Use of H with C or with a
preceding G token may have undesired results.
I{n} Inserts the record id in a field of n spaces. If n is omitted, a variable width is used.
L Inserts a new line at this point in the text.
N Suppresses pagination of the output to the display.
O Reverses the elements separated by G tokens in the current line on even numbered
pages. This is of use when printing double sided reports.
P{n} Insert page number. The page number is right justified in n spaces, widening the field if
necessary. If omitted, n defaults to four.
R{n} Same as I{n}.
S{n} Insert page number. The page number is left justified in n spaces, widening the field if
necessary. If omitted, n defaults to one.
T Inserts the time and date in the form hh:mm:ss dd mmm yyyy. The format of the date
2.11-0
Query Processing 613
A single quote may be inserted in the heading by use of two adjacent single quotes in the text.
If more than one HEADING definition is given in a single query, the first one is used. This allows
a query sentence to include a heading that will override an alternative heading in the default listing
phrase.
Example
The command
SALES REPORT
26 Jun 2000
Confidential SALES..... REGION SALESMAN ORDER VALUE
19845 North Harris 234.53
19858 North Sharp 845.50
19859 North Sharp 384.43
19887 North Roberts 279.40
19830 South Smith 324.39
19886 South Abbott 397.23
19866 South Abbott 465.31
7 records listed.
See also:
FOOTING
2.11-0
614 OpenQM
5.56 ID.ONLY
The ID.ONLY keyword causes the query processor to ignore the default listing phrase and show
only record ids. The synonym ONLY may be used.
Format
ID.ONLY
Used with no field names on the command line, the ID.ONLY keyword causes the query processor
to ignore the default listing phrase (@ or @LPTR) and to show the record its only. If field names
are given on the command line this keyword has no effect.
For compatibility with other multivalue products, the ID.ONLY keyword may appear before the
file name in a query processor sentence. For example:
LIST ID.ONLY ORDERS
2.11-0
Query Processing 615
5.57 ID.SUP
The ID.SUP display option keyword causes the record id to be omitted from the report. The
synonym ID-SUPP may be used.
Format
ID.SUP
The record id is normally included automatically as the first item in a LIST or SORT report. The
ID.SUP keyword can be used to suppress this item either where it is not required or where it is
named explicitly in the command so that, for example, non-standard display attributes can be used
Used with LIST.ITEM or SORT.ITEM, the ID.SUP keyword suppresses display of the record id
above the data.
Example
The command
2.11-0
616 OpenQM
5.58 IN
The IN selection clause operator tests whether the content of a field is in a named select list.
Format
where
listname is the name of an item previously saved to the $SAVEDLISTS file that holds a
field mark delimited list of acceptable values for field. The optional NO.CASE
qualifier causes a case insensitive comparison to be applied. The list name should
be enclosed in quotes if it may clash with a dictionary or VOC item name.
filename is the name of a file containing a record that holds a field mark delimited list of
acceptable values for field. The optional NO.CASE qualifier causes a case
insensitive comparison to be applied. The quotes around the filename and id are
mandatory.
The IN selection clause operator causes the report output to contain only records where the content
of field is in the list identified by listname or filename and id. When applied field is multivalued, at
least one value must meet the condition. The EVERY qualifier can be used to test that all values
are in the list.
Example
This sequence of commands processes the COUNTRIES file to build a select list of country codes
that it then saves as CTRY. We could then go on to do
LIST CLIENTS WITH COUNTRY IN CTRY
to list only CLIENTS file records that had a valid country code.
2.11-0
Query Processing 617
5.59 LABEL
The LABEL keyword specifies the label template record name for LIST.LABEL and
SORT.LABEL.
Format
LABEL template.name
LABEL NO.DEFAULT
The first format of the LABEL keyword specifies the name of a label template record stored in the
dictionary of the file being processed or in the VOC.
The second format specifies that the default @LABEL record is not to be used. The query
processor will then prompt for the label page shape parameters.
2.11-0
618 OpenQM
5.60 LE
The LE selection clause operator compares a field or evaluated expression against another field,
evaluated expression or literal value and tests for the first item being less than or equal to the
second. The synonyms <= and =< can be used.
Format
where
value is the second field, evaluated expression or literal value to be compared. The
optional NO.CASE qualifier causes a case insensitive comparison to be applied.
The LE selection clause operator returns true if field is less than or equal to value.
Example
This command lists items found on the STOCK file with a QTY field of 100 or less.
2.11-0
Query Processing 619
5.61 LIKE
The LIKE selection clause operator compares a field or evaluated expression against another field,
evaluated expression or literal value and tests for the first item matching the pattern template given
by the second. The synonyms LIKE, MATCHES and MATCHING can be used.
Format
where
template is the field, evaluated expression or literal value representing the pattern
against which field is to be compared. The optional NO.CASE qualifier
causes a case insensitive comparison to be applied.
The LIKE selection clause operator returns true if field matches template.
The LIKE operator treats characters that do not correspond to any valid component of a pattern as
literal values which must be matched exactly. Thus it is possible to find all the QMBasic include
records (which have a suffix of .H) in the BP file by a command of the form
The initial three dots are a valid template component. The remaining two characters are not and are
hence treated as literals. It would be better to enter this as
to avoid confusion. In some cases quotes must be used to handle literal values which are also valid
components of a pattern template.
Example
This command lists items found on the STOCK file with a PRODUCT.CODE starting with A.
See also:
Pattern Matching
2.11-0
620 OpenQM
5.62 LOCKING
The LOCKING keyword locks the file during a report, preventing updates.
Format
LOCKING
The LOCKING keyword causes the query processor to take a file lock on the file named in the
query sentence. This prevents any other process from modifying the file during the report, ensuring
that the report reflects a snap shot view of the data at the point when the query began.
Files accessed using the TRANS() function in I-type dictionary records or using the T conversion
code will not be locked and hence may be modified during the report.
It is the user's responsibility to ensure that use of the lock in lengthy reports does not cause
operational problems. In particular, be aware that a user who leaves a query on a "Press return to
continue" prompt may severely affect the ability of other users to access the file.
2.11-0
Query Processing 621
5.63 LPTR
Format
LPTR { unit }
where
The LPTR keyword directs the query processor output to the specified print unit. It also changes
the way in which the default listing phrase operates. With this option, if no report fields are
specified on the command line, the query processor first looks for a phrase named @LPTR and
then, if this does not exist, it reverts to the @ phrase. This allows different default report formats
for the printer and the display.
A query using the LPTR option normally closes the printer at the end of the report. When using the
default print unit (printer 0), if the QUERY.MERGE.PRINT mode of the OPTION command is
active and the printer was already active (PRINTER ON) before the query command started, the
printer is left active at the end of the report. This allows an application program to embed a query
report into other data printed by the program.
2.11-0
622 OpenQM
5.64 LT
The LT selection clause operator compares a field or evaluated expression against another field,
evaluated expression or literal value and tests for the first item being less than the second. The
synonyms BEFORE, LESS and < can be used.
Format
where
value is the second field, evaluated expression or literal value to be compared. The
optional NO.CASE qualifier causes a case insensitive comparison to be applied.
The LT selection clause operator returns true if field is less than value.
Example
This command lists items found on the STOCK file with a QTY field of less than 100.
2.11-0
Query Processing 623
5.65 MARGIN
The MARGIN keyword specifies the width of a blank left margin to appear in the report output.
Format
MARGIN width
where
The MARGIN keyword allows a blank left margin to be produced at the edge of the report. It is
intended for use when the printed report is to be bound and thus requires clear space at the left edge.
2.11-0
624 OpenQM
5.66 MAX
The MAX field qualifier keyword causes a field to be reported together with its maximum value.
Format
where
The MAX field qualifier keyword is placed before the field name to which it applies and causes the
query processor to report the value of the field for each record processed and also to report the
maximum value at the end of the report. Used with breakpoints, the MAX keyword will also report
the maximum value of the field at each breakpoint.
If the field is defined as multivalued, the MAX keyword operates on each value in turn.
The MAX keyword operates on all types of data. Where the field holds non-numeric data, a string
comparison is performed.
Used with the SHOW verb, the MAX keyword specifies the maximum number of records allowed
in the resultant select list.
Example
The command
would produce a display such as that below in which the maximum value of the VALUE field is
repeated at the end of the report.
2.11-0
Query Processing 625
5.67 MIN
The MIN field qualifier keyword causes a field to be reported together with its minimum value.
Format
where
The MIN field qualifier keyword is placed before the field name to which it applies and causes the
query processor to report the value of the field for each record processed and also to report the
minimum value at the end of the report. Used with breakpoints, the MIN keyword will also report
the minimum value of the field at each breakpoint.
If the field is defined as multivalued, the MIN keyword operates on each value in turn.
The MIN keyword operates on all types of data. Where the field holds non-numeric data, a string
comparison is performed.
The NO.NULLS keyword can be used to prevent null values being included in the test for the
minimum value.
Used with the SHOW verb, the MIN keyword specifies the minimum number of records allowed in
the resultant select list.
Example
The command
would produce a display such as that below in which the minimum value of the VALUE field is
repeated at the end of the report.
2.11-0
626 OpenQM
4 records listed.
2.11-0
Query Processing 627
5.68 MULTI.VALUE
The MULTI.VALUE keyword is a field qualifier that forces the field to be processed as a
multivalued item. The synonym MULTIVALUED can be used.
Format
field MULTI.VALUE
where
The query processor verbs normally use the dictionary to determine whether a field should be
treated as single or multivalued. The MULTI.VALUE field qualifier forces the field to be
processed as a multivalued item regardless of the dictionary definition. It is normally only used with
an EVAL expression.
See also:
SINGLE.VALUE
2.11-0
628 OpenQM
5.69 NE
The NE selection clause operator compares a field or evaluated expression against another field,
evaluated expression or literal value and tests for the first item being not equal to the second. The
synonyms NOT, #, <> and >< can be used.
Format
where
value is the second field, evaluated expression or literal value to be compared. The
optional NO.CASE qualifier causes a case insensitive comparison to be applied.
The NE selection clause operator returns true if field is not equal to value.
The default behaviour of the query processor is that if field is defined as left justified in the
dictionary, an exact match string comparison is used. For right aligned fields (typically numeric
values) a numeric comparison will be used if the field content and value are both integer values.
The QUERY.STRING.COMP mode of the OPTION command can be used to apply string
character comparisons to all data.
Example
This command lists items found on the STOCK file with a non-zero QTY. If QTY is defined as left
justified, the content of this field must be the single digit 0 for the record to be included in the
report. If QTY is defined as right justified, records for which QTY holds any numeric data equal to
zero will be included (e.g. 00).
If the PICK.WILDCARD option is enabled (see the OPTION command) and the value item is a
literal value, the interpretation is extended to include use of Pick style wildcard characters:
· A [ character at the start of the value replaces any number of leading characters. It is
equivalent to the … action of the UNLIKE operator.
· A ] character at the end of the value replaces any number of trailing characters. It is
equivalent to the … action of the UNLIKE operator.
· A ^ character within the value replaces a single character. It is equivalent to the 1X action
of the UNLIKE operator.
2.11-0
Query Processing 629
5.70 NEW.PAGE
The NEW.PAGE display option keyword causes each record in a report to start on a new page.
Format
NEW.PAGE
2.11-0
630 OpenQM
5.71 NO
The NO selection clause operator tests whether a field or evaluated expression is null.
Format
WITH NO field
where
Example
This command lists items found on the STOCK file with a null SUPPLIER.CODE.
2.11-0
Query Processing 631
5.72 NO.CASE
The NO.CASE keyword used in the SEARCH verb specifies that the string comparison is to be
performed in a case insensitive manner.
Format
NO.CASE
The SEARCH verb is normally case sensitive in its comparison of the given search strings. The
NO.CASE option performs a case insensitive comparison.
The NO.CASE keyword can also be used as a qualifier with relational operators in the selection
clause. In tis context, the QUERY.NO.CASE mode of the OPTION command can be used to
imply case insensitivity.
See also:
ALL.MATCH, NO.MATCH, SEARCH
2.11-0
632 OpenQM
5.73 NO.GRAND.TOTAL
Format
NO.GRAND.TOTAL
The NO.GRAND.TOTAL phrase suppresses the grand total line. It is only of use when the query
includes breakpoints that produce subtotals.
Example
This is equivalent to
See also:
GRAND.TOTAL
2.11-0
Query Processing 633
5.74 NO.INDEX
The NO.INDEX keyword causes the query processor to ignore any index that would otherwise be
used to handle the selection clause of the query.
Format
NO.INDEX
Use of the NO.INDEX keyword may result in faster query processing where the selection clause
includes a large proportion of the records in the file.
2.11-0
634 OpenQM
5.75 NO.MATCH
The NO.MATCH keyword used in a SEARCH command specifies that the records to be selected
must contain none of the given search strings.
Format
NO.MATCH
Without this keyword, the SEARCH command builds a list of records containing any of the
supplied search strings. With NO.MATCH, the records must contain none of the supplied strings.
Example
SEARCH BP NONE.MATCH
String: STOCK.FILE
String: STK.F
String:
This command builds a list of records in the BP file containing neither of the given strings.
See also:
ALL.MATCH, NO.CASE, SEARCH
2.11-0
Query Processing 635
5.76 NO.NULLS
Format
NO.NULLS
1. With the query processor AVERAGE, ENUMERATE and MIN keywords, this keyword
suppresses use of null values when calculating averages, enumerations or minimum values.
2. With the query processor SAVING keyword, this keyword omits null field values from the
generated select list.
3. With the CREATE.INDEX command, it omit records with null field values from the
index.
2.11-0
636 OpenQM
5.77 NO.PAGE
The NO.PAGE display option keyword suppresses the normal page end prompt. The synonym
NOPAGE may be used.
Format
NO.PAGE
The LIST and SORT commands normally pause at the end of each page when output is directed to
the display. The NO.PAGE keyword suppresses this page end prompt.
2.11-0
Query Processing 637
5.78 NO.SPLIT
The NO.SPLIT keyword causes the query processor to avoid splitting records across pages where
possible.
Format
NO.SPLIT
The NO.SPLIT causes the query processor to start a new page when there is insufficient space on
the current page for the record about to be reported.
2.11-0
638 OpenQM
5.79 NOT.IN
The NOT.IN selection clause operator tests whether the content of a field is not in a named select
list.
Format
where
listname is the name of an item previously saved to the $SAVEDLISTS file that holds a
field mark delimited list of unacceptable values for field. The optional NO.CASE
qualifier causes a case insensitive comparison to be applied. The list name should
be enclosed in quotes if it may clash with a dictionary or VOC item name.
filename is the name of a file containing a record that holds a field mark delimited list of
unacceptable values for field. The optional NO.CASE qualifier causes a case
insensitive comparison to be applied. The quotes around the filename and id are
mandatory.
The NOT.IN selection clause operator causes the report output to contain only records where the
content of field is not in the list identified by listname. When applied field is multivalued, at least
one value must meet the condition. The EVERY qualifier can be used to test that all values are not
in the list.
Example
This sequence of commands processes the COUNTRIES file to build a select list of country codes
that it then saves as CTRY. We could then go on to do
LIST CLIENTS WITH COUNTRY NOT.IN CTRY
to list only CLIENTS file records that had an invalid country code.
2.11-0
Query Processing 639
5.80 OR
The OR selection clause operator links two selection criteria where either may be true for the record
to be selected.
Format
where
The OR selection clause operator returns true if either or both of condition.1 and condition.2 are
true.
The AND and OR operators are normally of equal priority and will be evaluated strictly left to
right. Brackets may need to be used to enforce evaluation in an different order. Thus a query such
as
LIST CLIENTS WITH REGION = 1 AND VALUE > 1000 OR REGION = 2
AND VALUE > 500
may need brackets to achieve the desired effect
LIST CLIENTS WITH (REGION = 1 AND VALUE > 1000) OR (REGION = 2
AND VALUE > 500)
Pick style multivalue database products give AND priority over OR such that the above query
would not need the brackets. This behaviour can be enabled in QM by use of the
QUERY.PRIORITY.AND mode of the OPTION command.
Example
This command lists items found on the STOCK file with a QTY field of over 100 or a REORDER
field of less than 300.
2.11-0
640 OpenQM
5.81 OVERLAY
The OVERLAY option specifies a catalogued subroutine to emit a graphical page overlay.
Format
OVERLAY subr.name
where
The OVERLAY option allows a report to include a graphical overlay to draw a form on each page
of a report directed to a printer or a file. This is equivalent to use of the OVERLAY option of the
SETPTR command except that it applies only to the one report.
The subr.name qualifier is the name of a catalogued subroutine that will emit the page overlay. This
subroutine takes a single argument, the print unit number, and should not perform any other action.
Example
This command lists the ORDERS file, overlaying each page with a graphical image generated by
the ORD.OV subroutine.
2.11-0
Query Processing 641
5.82 PAGESEQ
Format
PAGESEQ filename id
where
The PAGESEQ option provides a way in which successive uses of the same report can produce
sequentially numbered pages allowing, for example, separate monthly business reports to be
assembled into a single item. The option is ignored for reports directed to the screen.
The PAGESEQ option specifies the name of a file and a record within that file. This record should
contain a single field which holds the page number to be applied to the first page of the report. The
query processor will retain a lock on this record for the duration of the query and will update it on
completion to contain a value one greater than the number of the final page in the report.
If the control record does not exist, a default page number of 1 is used for the first page and the
record will be created when the query terminates.
Example
The command
would produce a report of the MONTHLY.INVOICES file, using the value in SEQFILE INV as
the start page number and updating this value on completion of the report.
2.11-0
642 OpenQM
5.83 PAN
The PAN keyword, used in reports directed to the display, permits the total width of the report to
exceed that of the display by allowing the user to pan columns.
Format
PAN
The PAN keyword causes the query processor to buffer the report page and allows the user to pan
columns using the left and right cursor key. The panning operation never displays only part of a
column.
The PAN keyword operates differently depending on where it is placed in the query sentence. If it
appears before or after all the displayed fields, the entire display is panned. If it appears between
displayed fields, only those fields following the keyword are panned; the remaining fields being
locked in position.
The L and R keys or Ctrl-B and Ctrl-F can be used in place of the cursor keys.
2.11-0
Query Processing 643
5.84 PERCENTAGE
The PERCENTAGE field qualifier keyword causes a field to be reported as a percentage of the
total of the value of the field in all selected records.
Format
where
The PERCENTAGE field qualifier keyword is placed before the field name to which it applies and
causes the query processor to report the value of the field for each record processed as a percentage
of the total value of the field in all selected records. The total percentage (always 100 unless the
data has changed during the query) is shown at the end of the report. Used with breakpoints, the
PERCENTAGE keyword will also report the percentage value at each breakpoint.
If the field is defined as multivalued, the PERCENTAGE keyword operates on each value in turn.
The PERCENTAGE keyword operates only on numeric data. Non-numeric values are treated as
zero.
Example
The command
4 records listed.
2.11-0
644 OpenQM
5.85 REQUIRE.INDEX
The REQUIRE.INDEX keyword causes the query processor to terminate the query unless it can
make use of an alternate key index.
Format
REQUIRE.INDEX
Use of the REQUIRE.INDEX keyword can help determine whether a query has been phrased in a
manner that can make use of an alternate key index.
2.11-0
Query Processing 645
5.86 REQUIRE.SELECT
The REQUIRE.SELECT keyword indicates that the query should only proceed if there is an
active select list.
Format
REQUIRE.SELECT
The REQUIRE.SELECT keyword is useful in automated queries from paragraphs, etc. where a
preceding SELECT might have found no items and hence not left an active list. The following
query would therefore process all records instead of none.
If no select list is active when a query using this keyword is initiated, an error message is displayed.
Example
The above sequence shows how the REQUIRE.SELECT keyword causes the query processor to
terminate the LIST operation when no records were found matching the selection criteria. Without
this keyword, the LIST would have reported all the customers.
2.11-0
646 OpenQM
5.87 REPEATING
The REPEATING keyword causes the query processor to repeat single valued data against further
values in other fields.
Format
REPEATING
In a report that includes multivalued fields, the value of any single valued items normally only
appears once. The REPEATING keyword duplicates the single valued items against each
multivalued element of other fields.
The decision as to whether an item is single or multivalued is based on the S/M flag in the D/I-type
dictionary definition or use of the equivalent field qualifiers, not by whether the data includes value
marks. This is to ensure that a multivalued field with only a single entry does not get repeated.
Example
A file containing a multivalued list of order numbers corresponding to each customer might produce
a report that includes the following section:
Customer Order No
1447 10045
1587 10051
10059
Customer Order No
1447 10045
1587 10051
1587 10059
See also:
BY.EXP
2.11-0
Query Processing 647
5.88 SAID
The SAID selection clause operator compares a field or evaluated expression against another field,
evaluated expression or literal value and tests for the first item having the Soundex phonetic code
given by the second. The synonyms SPOKEN and ~ can be used.
Format
where
The SAID selection clause operator returns true if the Soundex phonetic code for field is value.
The Soundex phonetic code for a word is made up from the first letter of the word in upper case
followed by three digits which are found by examination of further characters of the word according
to the following table.
0 A E H I O U W Y
1 B F P V
2 C G J K Q S X Z
3 D T
4 L
5 M N
6 R
Other letters are ignored. Consecutive letters that result in the same value result in only a single
character. If the result is less than four characters long, zeros are added to fill the remaining
positions. Thus the word SOUNDEX encodes to S532.
Example
This command names in the STAFF file that sound like Reed (Read, Reid, etc).
2.11-0
648 OpenQM
5.89 SAMPLE
The SAMPLE selection clause keyword causes only a limited number of records to be selected or
displayed. The synonym FIRST can be used in place of SAMPLE.
Format
SAMPLE {n}
where
The SAMPLE keyword causes selection or listing of records to terminate after the given number of
records have been found. Sampling occurs after selection criteria but before sorting. Thus it cannot
be used to show, for example, only the first three records in sorted order of the whole file.
Example
This command lists the first 5 items found on the STOCK file that have a QTY field of over 100.
2.11-0
Query Processing 649
5.90 SAMPLED
The SAMPLED selection clause keyword causes only a proportion of records to be selected or
displayed.
Format
SAMPLED {n}
where
The SAMPLED keyword causes only every n'th record meeting the selection criteria (if any) to be
selected or listed.
Example
This command lists every fifth item found on the STOCK file with a QTY field of over 100.
2.11-0
650 OpenQM
The SAVING clause can be used in a SELECT or SSELECT command to save the content of a
field in place of the record id.
Format
where
UNIQUE specifies that duplicate values are not to be repeated in the saved list.
MULTI.VALUE specifies that values and subvalues in the field are to be saved as separate
list entries. The alternative spelling, MULTIVALUED, may be used.
The SAVING clause changes the action of SELECT or SSELECT to save the content of a field
(D or I-type) or evaluated expression into the target select list in place of the record id. It is
normally used to saved fields which are ids of records in some other file.
Use of the UNIQUE keyword suppresses multiple inclusion of the same field value in the list.
For compatibility with other products, the SAVING clause normally treats value marks and
subvalue marks as part of the data without applying any special meaning. Use of the
MULTI.VALUE keyword causes each value or subvalue to be inserted in the list as a separate
entry.
Example
This command creates a save list of all the site references appearing in the invoices file. The
UNIQUE keyword ensures that site references only appear once regardless of the number of
invoices that refer to them.
2.11-0
Query Processing 651
5.92 SCROLL
The SCROLL keyword used in a report directed to the display enables scrolling back through
report pages.
Format
SCROLL { pages }
where
pages The pages qualifier is retained for backward compatibility but the value of pages is
not significant except that a value of zero will disable scrolling, perhaps enabled by
use of the SCROLL keyword in the $QUERY.DEFAULTS record.
Use of the SCROLL keyword allows paging back through a displayed report. The following
options are available at the end of page prompt:
A Abort. The query is terminated, returning to the command prompt. The ON.ABORT
paragraph will be executed, if it exists.
Q Quit. The query is terminated, returning to the menu or paragraph from which the
query was initiated or to the command prompt.
N Next. The next page of the report is shown. The cursor down key or ctrl-N can also be
used.
P Previous. The previous page of the report is shown. The cursor up key, ctrl-P or ctrl-Z
can also be used.
n Page number. The specified page number is shown. Note that when used with the N
breakpoint option which resets page numbers, the numbering used by scroll is the
physical page number within the report which may be different from the page number
printed in the heading or footing.
C Continue. Used when the display is showing a saved page, this continues with the first
unseen page.
S Suppress pagination. The query continues with no further screen pagination.
2.11-0
652 OpenQM
5.93 SINGLE.VALUE
The SINGLE.VALUE keyword is a field qualifier that forces the field to be processed as a
single-valued item.
Format
field SINGLE.VALUE
where
The query processor verbs normally use the dictionary to determine whether a field should be
treated as single or multivalued. The SINGLE.VALUE field qualifier forces the field to be
processed as a single-valued item regardless of the dictionary definition. It is normally only used
with an EVAL expression.
See also:
MULTI.VALUE
2.11-0
Query Processing 653
5.94 STRINGS
The STRINGS keyword used in a SEARCH command specifies the file and record from which the
search strings are to be taken.
Format
Without this keyword, the SEARCH command prompts for the strings for which it is to search.
The STRINGS keyword allows these strings to be taken from a file.
The file should be formatted such that each field represents a separate search string. Take care to
avoid blank lines as these will be taken as being search strings.
Example
This command builds a list of records in the BP file containing any of the strings found in the
PROGS record of the SRCH.DATA file.
See also:
NO.CASE, ALL.MATCH NO.MATCH, SEARCH
2.11-0
654 OpenQM
5.95 STYLE
The STYLE keyword selects the report style to be used, overriding any style selected using the
REPORT.STYLE or SETPTR commands or the QMBasic SETPU statement.
Format
STYLE name
where
name is the name of a VOC style record. Use of STYLE NONE will disable use of any
style selected using the REPORT.STYLE or SETPTR commands or the
QMBasic SETPU statement.
Each line of a report falls into one of the following classifications: Heading, Column heading,
Detail, Subtotal, Total, Footing, Other. Report styles allow users to attribute each of these
classifications a colour for a displayed report or a font weight for a report directed to a PCL printer.
An additional style, Exit, is used to determine how the screen is left on exit from the query
processor. If this is absent, the query processor sends the terminfo sgr0 code to turn off all display
attributes.
Report styles are defined using an X-type VOC record where fields 2 onwards consist of a line
classification, foreground colour, background colour and font weight in the form:
Heading=Bright blue,Black,Bold
Only the first character of the line classification name is used. Thus the above line could be written
as
H=Bright blue,Black,Bold
Any non-alphabetic characters are ignored. Thus Bright Green can also be written as, for example,
Bright.Green, Bright-Green or BrightGreen. Numeric colour values of 0 to 15 can be used where
these correspond to the order of the colour names above.
Note that the colour palette used by AccuTerm may need to be amended from its default settings to
improve the rendering of the non-bright colours.
Font weights are taken from the list defined in SYSCOM $PCLDATA which defaults to:
Ultra-Thin, Extra-Thin, Thin, Extra-Light, Light, Demi-Light, Semi-Light, Medium,
Semi-Bold, Demi-Bold, Bold, Extra-Bold, Black, Extra-Black, Ultra-Black
Any non-alphabetic characters are ignored in the same way as for colour names. Numeric font
weight values in the range -7 to +7 can be used where these correspond to the order of the font
weight names above.
2.11-0
Query Processing 655
Any classification not defined in the style record, or any omitted component within a classification,
takes on the values of the Other classification which itself defaults to White foreground, Black
background, Medium font weight if not defined.
When the DET.SUP keyword is used, subtotals are reported using the detail line style.
Example
X
H=Bright Blue,,Bold
S=Blue
T=Bright Red,,Bold
See also:
REPORT.STYLE
2.11-0
656 OpenQM
The TO keyword used in a SELECT, SSELECT or SEARCH command specifies the select list
to be created.
Format
TO list.no
where
If the TO keyword is not present, the default list, list 0, will be created.
Example
This command builds a list of records in the STOCK file with the COST field greater than 100,
placing the resultant record ids in select list 4.
2.11-0
Query Processing 657
5.97 TO (REFORMAT)
The TO keyword used in a REFORMAT command specifies the name of the output file.
Format
TO new.file.name
TO DATA
where
new.file.name is the name of an existing file into which the REFORMAT output is to be
written.
If the TO keyword is not present, the REFORMAT command prompts for the file name.
Use of TO DATA causes the query processor to create a dynamic array containing the output. This
can be accessed via the @DATA variable. Each "record" in this array is separated by an item mark
character (char 255) and the fields within the item correspond to the display clause elements in the
REFORMAT command.
Examples
This command constructs a new file, CUST.BY.ZIP, keyed by zip code and containing two data
fields, the customer number and name. Note that if two or more customers share the same zip code,
the record will be overwritten by the second and subsequent items.
This is the same command executed from within a QMBasic program, directing the output to the
@DATA variable. The loop after the EXECUTE then extracts each item mark delimited entry and
processes it.
2.11-0
658 OpenQM
5.98 TOTAL
The TOTAL field qualifier keyword causes a field to be reported together with its total value.
Format
where
The TOTAL field qualifier keyword is placed before the field name to which it applies and causes
the query processor to report the value of the field for each record processed and also to report the
total value at the end of the report. Used with breakpoints, the TOTAL keyword will also report the
total value of the field at each breakpoint.
If the field is defined as multivalued, the TOTAL keyword operates on each value in turn.
The TOTAL keyword operates only on numeric data. Non-numeric values are ignored. If the
values are a mixture of numerics and non-numerics, the total of the numerics will be reported. If all
the values are non-numeric, zero will be reported.
When used with breakpoints, the NO.GRAND.TOTAL keyword can be used to suppress the
grand total line, leaving only the subtotals for each breakpoint.
Example
The command
would produce a display such as that below in which the total value of the VALUE field is included
at the end of the report.
2.11-0
Query Processing 659
5.99 UNLIKE
The UNLIKE selection clause operator compares a field or evaluated expression against another
field, evaluated expression or literal value and tests for the first item not matching the pattern
template given by the second. The synonym NOT.MATCHING can be used.
Format
where
template is the field, evaluated expression or literal value representing the pattern
against which field is to be compared. The optional NO.CASE qualifier
causes a case insensitive comparison to be applied.
Example
This command lists items found on the STOCK file with a PRODUCT.CODE not starting with A.
See also:
Pattern Matching
2.11-0
660 OpenQM
5.100 USING
The USING clause allows a query to be processed using the dictionary of another file.
Format
where
The query processor uses the dictionary of the file being reported until the USING clause is
encountered. All subsequent command line items are parsed using the specified dictionary. It is
therefore usual to place the USING clause immediately after the query file name.
Example
This command lists an archive file of customer data using the dictionary of the main CUSTOMERS
file.
2.11-0
Query Processing 661
5.101 VERTICALLY
The VERTICALLY display option keyword causes a vertical format report to be produced. The
synonym VERT may be used.
Format
The LIST and SORT commands normally produce a tabular report unless the total width of the
data to be reported exceeds that of the display or printer to which it is directed. The
VERTICALLY keyword forces a vertical format report regardless of display width. A blank line
is produced between each record in the report.
The default action of the query processor is to show the field heading text as a left justified 12
character wide column, effectively using a format code of ".L#12". The optional FMT qualifier to
the VERTICAL keyword can be used to change this. Note that the default code uses a mask rather
than "12.L" which would insert text marks if the name was longer than 12 characters.
Examples
The command
Including the VERTICALLY keyword would modify the display format to become
Invoice...74273
Value..... £95.23
Customer..County Newspapers
Invoice...63940
Value..... £141.00
Customer..R Bryant
3 records listed.
2.11-0
662 OpenQM
Adding a format code to the VERTICALLY keyword reduces the name width as below.
Invoice. : 74273
Value... : £95.23
Customer : County Newspapers
Invoice. : 63940
Value... : £141.00
Customer : R Bryant
3 records listed.
2.11-0
Query Processing 663
5.102 WHEN
Format
WHEN condition
where
A selection clause specifies criteria governing which records are processed by the command. If
omitted, all records are processed. The WHEN clause performs selection on exploded values from
within the named multivalued field, showing only the selected value of the named field and all
associated fields
Field comparisons are performed using the internal format of field1, converting the field2 or value
item to this format if required. Thus a field holding an internal date, for example, may be compared
with the more natural external form of the date. For example,
will list all invoice records with an issue date after 12 October 1996.
Example
The command
2.11-0
664 OpenQM
to find only orders containing part 100 might produce a report such as
3 records listed.
For the same data, use of the WHEN keyword to select only part 100 with a query such as
3 records listed.
2.11-0
Query Processing 665
5.103 WITH
Format
where
rel.op is AND or OR
A selection clause specifies criteria governing which records are processed by the command. If
omitted, all records are processed.
The relational operators may be followed by the keyword NO.CASE to apply a case insensitive
comparison. This also occurs if the QUERY.NO.CASE mode of the OPTION command is in
effect.
The EVERY keyword indicates that every value or subvalue of field1 must match field2 in the
manner defined by the operator. For example, the command
LIST EXAM.RESULTS STUDENTS SUBJECTS WITH EVERY GRADE = "A"
might be used to report a list of students achieving grade A in every examination. The SUBJECTS
and GRADE fields in this example are a pair of associated multivalued fields recording examination
subjects and grades.
The AND and OR operators may be used to build complex conditions. For example,
2.11-0
666 OpenQM
The AND and OR operators are of equal priority and, if both appear in a single WITH clause, are
evaluated left to right. Brackets may be used to modify the evaluation sequence. For example,
LIST STOCK WITH QTY < REORDER AND (SUPPLIER = 26 OR WAREHOUSE
= 14)
A query may contain more than one WITH clause. There is normally an implied AND relationship
between these clauses. Thus the command
LIST STOCK WITH QTY < REORDER WITH SUPPLIER = 26
is identical in effect to
LIST STOCK WITH QTY < REORDER AND SUPPLIER = 26
The WITH.IMPLIES.OR mode of the OPTION command changes the effect of multiple WITH
clauses to have an implied OR between the clauses so that the above query with two WITH clauses
is equivalent to.
LIST STOCK WITH QTY < REORDER OR SUPPLIER = 26
Field comparisons are performed using the internal format of field1, converting the field2 or value
item to its internal form if a conversion code is present. Thus a field holding an internal date, for
example, may be compared with the more natural external form of the date. For example,
LIST INVOICES WITH ISSUE.DATE > "12 OCT 96"
will list all invoice records with an issue date after 12 October 1996.
This leads to a potential problem if the conversion code is not "reversible", where data converted
from internal form to external form cannot be converted back again. As an example, a date
conversion that returns just the month in which the date lies is not reversible. An internal date of
15171 (14 July 2009) would convert to "July" but this cannot be converted back to the original
date.
The date conversions are defined such that a date with no year is assumed to be in the current year
and a date with no day number is assumed to refer to the first day of the month. Thus a query of the
form
LIST SALES WITH MONTH = "July"
is actually asking for orders placed on the first of July in the current year.
Short forms
The query processor offers a variety of short forms for selection clause elements.
2.11-0
Query Processing 667
In each of the following examples, the second query is an abbreviated form of the first
LIST ORDERS WITH DATE AFTER '31 DEC 99' AND DATE BEFORE '1 JAN
01'
LIST ORDERS WITH DATE AFTER '31 DEC 99' AND BEFORE '1 JAN 01'
Implicit OR relation
A relational operator followed by a series of values tests each of the values against the given field in
an implicit OR relationship.
2.11-0
668 OpenQM
5.104 WITHOUT
Format
Example
This is equivalent to
LIST ORDERS WITH NO PAYMENT.DATE
2.11-0
Part
6
QMBasic
670 OpenQM
6 QMBasic
There are times when the powerful facilities available using the standard commands of QM are not
sufficient to meet application demands. For these occasions, the QMBasic programming language
provides a very easy to use means of developing components of the application. User written
programs can be mixed with standard commands to give maximum capabilities with minimum
development costs.
QMBasic is not difficult to learn. As the name implies, it has its origin in the Basic language found
on many personal computers, however, the powerful string handling and screen formatting
functions make development extremely fast. QMBasic has very high compatibility with the
equivalent languages found in other similar data management products but also has some major
extensions such as object oriented programming.
QMBasic Overview
Variable Names and Values
Scalars, Matrices and Dynamic Arrays
Objects
Common Blocks
Labels
Expressions and Operators
Assignment Statements
Type Conversion
Matrix file i/o
Sequential file i/o
Multivalue functions
Object oriented programming
Compiler Directives
Limits
QMBasic Statements by Name
2.11-0
QMBasic 671
QM applications are written using QMBasic. Unlike many other programming languages, the
individual source modules are not linked together to form a single executable program but remain
separate items that are loaded into memory dynamically when they are first needed. This approach
generally results in lower memory usage and easier maintenance.
The program modules are stored as simple text records in directory files where each field of the
record represents a line of the program (a transformation that corresponds exactly to how directory
file records are stored by the underlying operating system). Although you may place your program
modules in any directory file you wish or scatter them over several files, by convention
programmers often use a file named BP (Basic Programs). The BASIC and RUN commands will
look here for programs by default if no file name is given in the commands.
Throughout all documentation, the word program is used to refer to all of the above module types
unless the context explicitly states otherwise.
Before a program can be executed, the source form written by the developer must be compiled
(translated into corresponding executable program modules) using the BASIC command. The
executable items are written to records of the same name as the source but in a file with a .OUT
suffix added. For example, the compiled version of a program stored as MYPROG in BP will be in
MYPROG in the BP.OUT file. Programs may be executed directly from the .OUT file or may be
moved into the system catalogue using the CATALOGUE command. Subroutines, functions and
class modules must be catalogued before use.
Often, it is useful to place QMBasic source code elements that are used in more than one program
in a separate record which is read during compilation as though it was part of the main program. In
particular, common data structures or names representing keys to subroutines may be handled in
this way to ensure that all components of the application have a common view of the information
instead of needing to make changes in many places. The SYSCOM file is an example of this
technique with records containing keys and other values that you may need in many programs. The
QMBasic $INCLUDE directive described later in this section is used to direct the compiler to
include text from another record. Include records may be stored in any file and are not separately
compiled as the text is imported into other programs. It is recommended that a suffix of .H is used
2.11-0
672 OpenQM
on include record names as the compiler will automatically skip these when using a select list. This
suffix has its origins in the C programming language where it is used to denote a "header file" that
serves the same purpose as QMBasic include records.
A QMBasic program has a very simple to understand format. The program is made up of a series
of statements. Each statement normally corresponds to a single line of source program text though
it is possible to place multiple statements on a single line by separating them with semicolons. Some
statements have a syntax which allows them to span multiple lines without special action. Any
statement that includes a comma in its syntax may start a new line immediately after the comma.
Other statements may be split over multiple lines by ending each line except the last with a tilde (~)
character. Note that continuation lines are handled before any other analysis of the line and
therefore a comment that ends with a tilde will be treated as continuing on the next line.
Lines commencing with an asterisk or an exclamation mark are treated as comments and ignored by
the compiler. Comments can be included on the same line as a source program statement by using a
semicolon to start a new statement followed by an asterisk or an exclamation mark. Blank lines and
leading spaces are ignored by the compiler.
The compiler is not case sensitive in language keywords. By default, variable names are also case
insensitive but this can be altered using the $MODE directive or the $BASIC.OPTIONS record.
PROGRAM name
SUBROUTINE name(arg1,arg2,...)
FUNCTION name(arg1,arg2,...)
and
CLASS name
A program ends with an END statement. Only blank lines and comments may follow this final
END. For compatibility with other multivalue database products there is a compiler option to make
this final END optional.
2.11-0
QMBasic 673
Variable names must commence with a letter and may contain letters, digits, periods (full stops),
percentage signs and dollar signs. Names may also contain underscore characters but not as the last
character of the name. Users are discouraged from defining names containing dollar signs for their
own purposes as these are reserved to identify system functions and constants. Except as indicated
elsewhere, there is no restriction on the length of a name though very long names may appear
truncated in debugging information.
Although QMBasic imposes few restrictions on the choice of names, it is advisable to avoid using
names which correspond to QMBasic statements, functions and keywords. The only reserved names
which may not be usable in some contexts are
AND GOSUB ON
BEFORE GOTO OR
BY GT REPEAT
CAPTURING IN RETURNING
CAT LE SETTING
DO LOCKED STEP
ELSE LT THEN
EQ MATCH TO
FROM MATCHES TRAPPING
GE NE UNTIL
GO NEXT WHILE
QMBasic variables are type variant, that is, that they may hold, for example, an integer value at
one point in time and a character string later on. The actual form in which the data is held is
determined by how it was assigned. If a variable is set to contain a string of digits and is
subsequently used in an arithmetic calculation, the value is converted internally to a numeric form
without affecting the variable itself. If this arithmetic calculation was performed many times in a
loop, it may be worth forcing a type conversion to prevent repeated temporary conversions. For this
reason, QMBasic programs often contain apparently redundant looking statements of the form
Numeric values may are held as integers wherever possible, conversion to floating point format
occurring when the result of an arithmetic operation is non-integer or when the value is too large to
be stored as an integer.
A variable holding a string of no characters is referred to as a null string and is treated as a special
case in many operations. Users familiar with SQL type environments should take care to distinguish
the multivalue database meaning of the word null from its SQL meaning.
A string variable may hold any number of characters. The actual total limit for all strings in a
program is imposed by the disk space available for paging and is typically many megabytes.
Although QMBasic avoids copying strings unnecessarily whenever it can, operations involving very
2.11-0
674 OpenQM
A variable may hold many other types of information. For example, a file variable holds a
reference to an open file and is used in all statements that refer to that file. A subroutine variable
contains a fast reference to a catalogued subroutine that has been loaded into memory. Users cannot
directly create subroutine variables; they are the result of transforming a string variable holding the
subroutine name when it is first called. Until otherwise determined, variables are initially
unassigned. Reference to an unassigned variable (where no value has yet been stored) will cause a
run time error as an aid to program debugging. This can be changed to become a warning message
by use of the UNASS.WARNING mode of the OPTION command.
Constants
Numeric constants are written as a sequence of digits, optionally preceded by a sign or containing
a decimal point. If a sign is used, there must be no space between it and the first digit.
QMBasic also allows hexadecimal numbers in equated tokens and most expressions. These are
written with a prefix of 0x as used in the C programming language (e.g. 0x23 is decimal 35).
String constants are sequences of characters enclosed by delimiters. Valid delimiter characters are
the single quote ('), the double quote (") and the backslash (\). The delimiter at the start and end of
the string value must be the same but there is no difference in the internal treatment of the
delimiters.
The compiler imposes no limit on the length of a string literal value though it may not extend from
one line to the next. Very long strings can be constructed by concatenating component substrings.
The mark characters are available as @FM, @VM, @SM, @TM and @IM. These are described in
a later section.
2.11-0
QMBasic 675
QMBasic provides support for both scalar and matrix variables. A scalar variable is a simple
value referenced by its name alone. It may contain data of any type.
A matrix variable is a one or two dimensional array of values. Matrices must be declared by use of
the DIMENSION (more usually DIM) statement. Because memory for matrices is allocated
dynamically, the DIM statement must be executed at program run time before the variable is used
in any other way.
A single dimensional matrix is effectively a two dimensional matrix with one column. Thus
references of the forms A(B) and A(B,1) are totally interchangeable.
By default, all matrices have an additional element, the zero element, which is used by some
QMBasic statements. This is referred to as A(0) or B(0,0). The $MODE compiler directive can be
used to create Pick style matrices which do not have a zero element. Note that, in a two dimensional
matrix, this is a single element, not a complete row 0 and column 0.
The elements of a matrix may be of differing types (numbers, strings, file variables, etc).
A variable holding a string value may be considered as a dynamic array, the mark characters being
used to divide it into fields, values and subvalues. Such a string may correspond to a record in a
data file or may be totally internal to the program. Special operations are provided in QMBasic to
manipulate dynamic arrays. These include sorted and unsequenced searching, insertion, deletion,
replacement and extraction as well as some extremely powerful operations to build or decompose
dynamic arrays.
A dynamic array in which each field, value or subvalue contains a numeric value is known as a
numeric array. Many of the arithmetic operations operate on numeric arrays by processing
corresponding elements in turn. For example, a statement
A = B + C
adds B and C together, storing the result in A. Where B and C are simple numeric values or strings
that can be converted to numbers, this operation behaves as in most other computer languages. If B
and C are dynamic arrays the operation handles each corresponding pair of values in turn.
The result of this operation would be to set A to 6FM8VM10FM12. The effect of operations on numeric
arrays where the placement of fields, values and subvalues do not match exactly is determined by
the use of the REUSE() function.
2.11-0
676 OpenQM
Variables are normally available to all statements within a single QMBasic program or subroutine.
Although the language provides an internal subroutine call through the GOSUB statement, this
does not automatically bring in the concept of the internal subroutine having its own variables or
any other aspect of variable scope found in other languages.
QMBasic extends the language definition by adding the concept of variables that are private to an
internal subroutine. This is achieved by use of the LOCAL statement and the associated
PRIVATE variable declaration statement. Variables declared in this way are private to the one
internal subroutine and cannot be accessed by other parts of the program. Furthermore, they are
stacked if the subroutine calls itself, either directly or indirectly via another intermediate subroutine.
For more information, see the description of the LOCAL statement.
QMBasic provides common blocks for data which is to be shared between two or more programs.
These are declared by a statement of the form
COMMON /name/ var1, var2, var3,...
where name is the name by which the common block is to be known. A common block may contain
any number of variables and is created when it is first referenced. It remains in existence until the
user leaves QM. Once a common block is created, subsequent programs using the same common
block name within the same process access the same data. The number of variables in the common
block may not be increased by later definition but programs can define fewer variables than in the
actual common block. Normally, the structure of a common block is best defined in an include file
so that the same definition is used by all parts of the application.
Where programs use separate COMMON statements to reference the same block, note that the
variables are defined by their position in the list, not the names used. Thus it would be valid (but
not a good idea) for one program to have
COMMON /MYCOMMON/ A, B, C
and another program
COMMON /MYCOMMON/ D, E, F
where the data stored in B by the first program would be visible to the second program as E.
The name of a common block must conform to the same rules as a variable name. There is also an
unnamed common (sometimes known as blank or unlabelled common) which is defined by a
COMMON statement without a name:
COMMON A, B, C
This operates in exactly the same way except that each command processor level has its own
unnamed common. Thus, an EXECUTE statement used to run one program from within another
would result in a new unnamed common block being created for the executed program, the original
being restored on return.
The variables in a common block are initialised to integer zero when the block is created. It is thus
possible to include QMBasic code to perform further initialisation just once by statements of the
form
2.11-0
QMBasic 677
do initialisation tasks
INITIALISED = @TRUE
END
Note how the names of the variables within the common block may extend from one line to the next.
The compiler will continue the common block definition over multiple lines wherever the line ends
with a comma.
COMMON/MYCOMMON/ VAR1
COMMON/MYCOMMON/ VAR2
COMMON/MYCOMMON/ VAR3
...etc...
The compiler assumes that definitions of variables with the same common block name are a
continuation of the previous definitions.
Common blocks may also contain matrices. These are defined by including the row and column
bounds in the COMMON statement, for example
Except when using Pick style matrices, the size of a matrix in common may be changed by a later
DIM statement. The size given in the COMMON declaration is the initial size of the matrix.
The matrix in the example above may be made smaller by a statement such as
DIM MAT1(2,1)
or made larger by a statement such
DIM MAT1(99,9)
It will then keep the changed row and column bounds, within the current program and in any other
program that shares the common block, regardless of the row and column bounds specified in the
COMMON statement. This allows matrices to be freely shared between programs, with their
dimensions being changed as needed.
Pick style matrices are of fixed size and cannot be redimensioned dynamically.
2.11-0
678 OpenQM
QMBasic - Labels
Any statement of a QMBasic program may be labelled. A label may take one of three formats; a
name of the same format as a variable name followed by a colon, a sequence of digits and periods
followed by a colon, or a sequence of digits and periods with no trailing colon.
REDISPLAY:
100
12.9.6:
The label must appear as the first item on the source line. Labels and variables may have the same
name though this may lead to some confusion when maintaining a program.
Statements that reference the label (e.g. GOSUB) may optionally include the colon after the label
name. This is not recommended as it can make using an editor to search for a label in a program
more difficult as the search will also find references to the label.
Numeric labels are provided for compatibility with other products. Use of numeric labels is
discouraged as the "names" do not impart any information about the role of the label. For example,
a statement such as
GOSUB 9600
gives the reader no clue about the action performed by the subroutine at label 9600 whereas
GOSUB GET.CUSTOMER.ID
suggests what the subroutine does.
2.11-0
QMBasic 679
A QMBasic expression consists of one or more data items (constants or variables) linked by
operators.
var(r,c)[s,n]
where r and c are expressions which evaluate to the desired matrix index values.
where conditional.expression is evaluated to determine whether the overall value is that of expr.1
or expr.2.
The boolean (true/false) values used by QMBasic are that any value other than zero or a null string
is treated as true, zero or a null string being treated as false. An expression returning a boolean
value returns the integer value 1 for true, zero for false. The boolean values are available as
@TRUE and @FALSE for use in programs.
The substring extraction operation x[s,n] extracts n characters starting at character s of the string x.
Character positions are numbered from one. Thus
A = "abcdefghijkl"
Z = A[5,3]
sets Z to the string "efg".
If the bounds of the substring extend beyond the end of the string from which it is to be extracted,
the result is truncated. Trailing spaces are not added to make up the shortfall. A start position of
less than one is treated as one.
The trailing substring extraction operation x[n] extracts the last n characters of the string x. Thus
A = "abcdefghijkl"
2.11-0
680 OpenQM
Z = A[3]
sets Z to the string "jkl".
If the length of the substring to be extracted is greater than the length of the source string, the entire
source string is returned.
The third form of substring extraction, known as group extraction, is of the form var[d,s,n]. It
treats var as being made up of a series of sections delimited by character d and returns n
consecutive sections, starting at section s. See the FIELD() function for an alternative syntax.
The field extraction operator x<f,v,s> extracts field f, value v, subvalue s from the source string x.
If s is omitted or zero, field f, value v is extracted. If v is omitted or zero, field f is extracted. Thus
x<2> extracts field 2
x<2,7> extracts field 2, value 7
x<2,7,3> extracts field 2, value 7, subvalue 3
The operators of QMBasic are set out in the table below. The numbers in the right hand column are
the operator precedence, the lower valued operators taking precedence in execution. Operations of
equal precedence are processed left to right with the exception of the exponentiation operator which
is processed right to left. Round brackets may be used to alter the order of execution or to improve
readability of complex expressions.
+ Unary plus 0
- Unary minus 0
~ Unary bitwise not 0
<> Dynamic array extraction 1
[] Substring extraction 1
** or ^ Exponentiation (raising to power) 2
* Multiplication 3
/ Division 3
// Integer division 3
+ Addition 4
- Subtraction 4
Implicit format (See FMT() function) 5
: Concatenation 6
< Less than 7
> Greater than 7
= Equal to 7
# Not equal to 7
<= Less than or equal to 7
>= Greater than or equal to 7
MATCHES Pattern match (see below) 7
AND Logical AND 8
2.11-0
QMBasic 681
OR Logical OR 8
.& Bitwise logical AND 8
.! Bitwise logical OR 8
The following alternative logical and relational operator formats may be used
< LT
> GT
= EQ
# NE <> ><
<= LE =< #>
>= GE => #<
MATCHES MATCH
AND &
OR !
The relational operators are defined such that, if the two items to be compared can both be treated
as numbers, a simple numeric comparison is performed. If one or both items cannot be treated as
numbers, they are compared as left aligned character strings. The COMPARE() function can be
used to force a string comparison.
Note: The language syntax includes an ambiguity with the use of the < and > characters as both
relational operators and in dynamic array references. For example, the statement
A = B<C> + 0
could be extracting field C from dynamic array B and adding zero to it (to force it to be stored as a
numeric value) or it could be testing whether B is less than C and the result of this comparison is
greater than zero. In cases such as this, the compiler looks at the overall structure of the statement
and takes the most appropriate view. Use of brackets when mixing relational operators with field
references will always avoid possible misinterpretation.
The MATCHES operator matches a string against a pattern consisting of one or more
concatenated items from the following list.
The values n and m are integers with any number of digits. m must be greater than or equal to n.
2.11-0
682 OpenQM
The 0A, nA, 0N, nN and "string" patterns may be preceded by a tilde (~) to invert the match
condition. For example, ~4N matches four non-numeric characters such as ABCD (not a string
which is not four numeric characters such as 12C4).
A null string matches patterns ..., 0A, 0X, 0N, their inverses (~0A, etc) and "".
The 0X and n-mX patterns match against as few characters as necessary before control passes to
the next pattern. For example, the string ABC123DEF matched against the pattern 0X2N0X
matches the pattern components as ABC, 12 and 3DEF.
The 0N, n-mN, 0A, and n-mA patterns match against as many characters as possible. For example,
the string ABC123DEF matched against the pattern 0X2-3N0X matches the pattern components as
ABC, 123 and DEF.
The pattern string may contain alternative templates separated by value marks. The MATCHES
operator tries each template in turn until one is a successful match against the string.
See also:
Pattern Matching
2.11-0
QMBasic 683
= Simple assignment
+= Add expr to original value
-= Subtract expr from original value
*= Multiply original value by expr
/= Divide original value by expr
:= Concatenate expr as string to original value
&= Bitwise AND with original value
!= Bitwise OR with original value
Substring Assignment
Two alternative implementations are provided for compatibility with various Pick style multivalue
environments. Use of the PICK.SUBSTR option of the $MODE compiler directive extends the
definition above such that the original string is extended if the region to be overwritten extends
beyond the end of the current string value.
Use of the PICK.SUBSTR.ASSIGN option of the $MODE compiler directive changes the
behaviour of substring assignment considerably. If the value of s is negative, the new contents of
var are formed by copying the value or expr, adding -s spaces, skipping n characters of the original
value of var and copying the remainder. If the value of s is greater than or equal to zero, the new
2.11-0
684 OpenQM
value of var is formed by copying s-1 characters of the original value of var, adding spaces if
necessary, skipping n characters, inserting the value of expr and then copying any remaining
characters from the original var.
If the value of expr is longer than the substring to be set, the trailing characters are lost. If the value
of expr is shorter than the substring to be set, the remainder is filled with spaces.
The two $MODE compiler directive settings described above do not affect trailing substring
assignment.
Delimited substring assignment replaces or inserts a portion of a string which is divided into
substrings by use of a delimiter character. This character does not have to be one of the mark
characters. The first character of string d is taken as the delimiter character. Starting at substring i,
n substrings are replaced by the value of the assignment expression. For full details of delimited
substring assignment, see the description of the FIELDSTORE statement.
Field Assignment
Field (or value, or subvalue) assignment replaces an existing field (or value, or subvalue) with the
result of the expression. If the specified field, value or subvalue does not already exist within the
string, mark characters are added as necessary. When adding a new field at the end of a string, the
syntax
Z<-1> = expr
can be used. The QMBasic language will add a new field to receive the result. Similarly, the
operations
Z<5,-1> = expr
Z<5,3,-1> = expr
would add a new value or subvalue to the end of existing data.
The way in which the append operation is performed depends on the setting of the
COMPATIBLE.APPEND option of the $MODE compiler directive.
By default, QM prefixes the appended data with a field, value or subvalue mark unless the string,
field or value in which the item is being appended is completely null.
Thus, if S = "ABCFMDEFVMFMXYZFM"
S<-1> = "ghi" sets S to "ABCFMDEFVMFMXYZFMFMGHI"
S<1,-1> = "ghi" sets S to "ABCVMGHIFMDEFVMFMXYZFM"
S<2,-1> = "ghi" sets S to "ABCFMDEFVMVMGHIFMXYZFM"
2.11-0
QMBasic 685
Setting the COMPATIBLE.APPEND mode modifies the behaviour such that a mark character is
not inserted if the final element of the portion of the dynamic array to which data is being appended
is null. This is the how other multivalue database products work and results in
S<-1> = "ghi" sets S to "ABCFMDEFVMFMXYZFMGHI"
S<1,-1> = "ghi" sets S to "ABCVMGHIFMDEFVMFMXYZFM"
S<2,-1> = "ghi" sets S to "ABCFMDEFVMGHIFMXYZFM"
This same rule applies to the INS statement and the INSERT() and REPLACE() functions.
Dictionary I-type expressions that use INSERT() or REPLACE() always adopt the default QM
behaviour.
Note that the S<-1> syntax should not be used when working with an association because it can
lose the relation between the members of the association. Suppose we are working with an inventory
in which we are associating a part number, description, and a comment. Every item has a part
number and description but the comment is not always present. If we write
PART.NO<-1> = part number
DESCRIPTION<-1> = description
COMMENT<-1> = text
the COMMENT field will not not be updated as expected if the text item is a null string. Next time
these items are updated, the associations may get out of step.
To avoid this problem, use the field assignment or the REPLACE() function in code such as this:
PART.NO<N> = part number
DESCRIPTION<N> = description
COMMENT<N> = text
where N is the dynamic array filed position to be updated. This will ensure that any null values are
inserted correctly, so that the association between the values will also be correctly maintained.
2.11-0
686 OpenQM
QMBasic variables are of variant type, the stored type being determined by the context in which the
value was set and conversion being carried out on a temporary basis wherever necessary to perform
processing. For example, the following program fragment
A = 962
S = A[2,1]
would result in A containing the integer value 962 and S containing the digit 6 as a string. The type
conversion from integer to string is implicit in the use of the substring extraction on the second line.
Where a variable is accessed a very large number of times, there may be performance benefits to be
obtained from ensuring that it is stored in an appropriate type thus minimising implicit temporary
conversions. The QMBasic language does not have any specific type conversion functions as the
automatic type variant nature of the language is adequate for most purposes. Where a variable is to
be forced to be a number, this can be achieved by adding zero
A = A + 0
or, more typically, combined with some other operation such as
NUM.INVOICES = CLI.REC<C.INV.CT> + 0
2.11-0
QMBasic 687
File Processing
QMBasic programs usually need to access database files. This section discusses the various
techniques available. Further information can be found by following the links to detailed sections.
Directory files also allow data to be processed in a line by line manner or as a simple byte stream.
There are also special program operations to simplify reading and writing comma separated data as
used, for example, by some spreadsheet packages. For more information on this style of access, see
sequential file i/o.
Opening Files
Before a file can be processed, it must be opened. This is normally done using the OPEN statement,
identifying the file by referencing the name of the corresponding F-type VOC record. By having this
level of indirection, the physical location of the file can be changed without affecting the
application; all that is necessary is to edit the VOC record to reference the new file location. There
are three special file name syntaxes available to reference files in other accounts without needing a
Q-type VOC record:
Implicit Q-pointer account:file
Implicit QMNet pointer server:account:file
Pathname PATH:pathname
Because these syntaxes potentially weaken the security provided by the VOC indirection, their
availability is determined by a system configuration parameter, FILERULE.
It is also possible for an application to open files directly by pathname using the OPENPATH
statement. This should only be used where the normal VOC indirection is not appropriate.
A typical application may open many files simultaneously and it is therefore necessary to have a
way to determine which file is being referenced by subsequent data transfer operations. This link is
provided by the OPEN and OPENPATH statements setting up a file variable which is then used
in other operations on the same file. The file remains open so long as the file variable remains in
place. Overwriting the file variable will implicitly close the file that it referenced. Exit from the
program will discard local variables and hence close the file.
Most applications adopt a convention for the names of variables. Many examples in this
documentation use a convention where the file name is contracted to three of four characters and a
suffix of .F is added to form the file variable name. Thus a file named ORDERS might be
referenced via a file variable named ORD.F. It is common to continue the convention into other
variables so that, for example, ORDERS file record ids would be stored in ORD.ID and records
would be read from the file into the ORD.REC variable. These are examples only. There is no
restriction on naming imposed by QM itself.
2.11-0
688 OpenQM
A file variable may be copied, just like any other variable. In this case, the file remains open until
the last file variable referencing it is discarded or overwritten.
There are two factors that limit the number of files that can be open at one time. Firstly, QM has an
internal file table that contains a reference to every distinct file open on the system by all QM
processes. The size of this table is set by the NUMFILES configuration parameter. If several users
all open the same file, that only requires one entry in the table. If a program attempts to open a file
when the table is full, the operation will fail, taking the ELSE clause to allow the program to report
an error. The LIST.FILES command can be used to monitor how close a system is to reaching this
configuration limit.
The second limit is imposed by the operating system. On some systems this may be configurable, on
others it is fixed. QM tries to hide this limit by implementing a mechanism whereby, if the limit is
reached, the file that has not been accessed for longest is closed internally to make room for the new
file. Subsequent access to the file that has been closed will automatically reopen it, probably closing
something else to make space. Although this mechanism is totally automatic and gives the developer
the illusion that there is no limit, the impact on performance can be quite serious. It is strongly
recommended that any limit imposed by the operating system is set to an appropriate value.
Opening a file is a complex process. Although QM maintains a file cache to improve the situation,
developers should avoid continually re-opening the same file. One useful way to achieve this is to
place the file variable in a common block so that is is not discarded when the program or subroutine
exits. By using this technique it is possible for a program to open all of its main data files as it
starts up and to keep them open for the entire life of the application. Keeping large numbers of files
open will require careful configuration of NUMFILES and the corresponding operating system
parameters.
Programs read data using the QMBasic READ statement. With a hashed file, the internal
processing of this statement applies the hashing process to read just the group that would contain
the requested record and then locates the record within that group. If it is not found, it is not in the
file and there is no need to look elsewhere. This process ensures that hashed files give best
performance. For a directory file, QM uses operating system functions to locate and read the
requested item. This will not give the performance of hashed files as it requires a scan of the
directory to locate the item.
The READ statement returns a variable that contains a dynamic array representing the data of the
requested record. The program can then use the various dynamic array operations such as field
extraction to access the data in the record.
If the record is to be updated by the application, it is essential to ensure that other processes cannot
update the record at the same time. This protection is provided by QM's locking mechanisms and
corresponding QMBasic statements, most importantly READU. A program should never write or
delete a record unless it owns a lock to protect it. There is a configuration parameter,
MUSTLOCK, that allows administrators to enforce strong locking rules. Unfortunately, this
cannot be made the default behaviour as there is much software which does not use locking because
the developer knew that there could never be an interaction with other processes.
A data record is written to the file using the QMBasic WRITE statement. If the record already
exists in the file, the new version replaces the previous one. If the record does not already exist, the
write operation adds it to the file. The record lock is automatically released when the write
2.11-0
QMBasic 689
completes.
A data record is deleted from the file using the QMBasic DELETE statement. The record lock is
automatically released after the record has been deleted.
The QMBasic statements named above work with dynamic arrays. There is an alternative style of
file i/o that uses dimensioned matrices. For details, see Matrix File I/O.
The READ statement requires that the program knows the id of the record it needs to read. To
process a file sequentially or to process only records that meet a specific condition, programs use a
select list. This list may be generated by executing a query processor SELECT operation or by use
of the QMBasic SELECT statement. Whichever method is used, the program then reads items
from the list using the READNEXT statement, typically in a loop that then uses READ or one of
its locking variants to process each record from the list.
Building a select list requires the system to traverse the entire file, examining every record. For
situations where only a small number of records are to be selected, an alternate key index can give
substantial performance improvements. Effectively, this is a set of pre-built select lists based on the
content of a specific field or the result of evaluating an I-type expression. The index is
automatically updated whenever a change is made to the file. The cost of this additional update on
write is usually significantly outweighed by the performance improvement of being able to go
directly to the desired set of records.
Most of the QMBasic file handling statements have an optional ON ERROR clause. This is rarely
needed by applications but allows a program to trap an error that would otherwise cause QM to
abort the program. If an ON ERROR clause is present, the program can take its own recovery
action or display alternative diagnostic messages. Developers should avoid using the ON ERROR
clause simply to condition an ABORT statement as this will usually give less diagnostic
information than would have appeared if no ON ERROR clause had been present.
Examples
This short program opens the CLIENTS file and then enters a loop in which it prompts for a client
number, reads the client record and displays the content of field 2. The loop continues until the user
enters a blank client number.
2.11-0
690 OpenQM
This example shows why direct use of field numbers in programs is a bad idea. Anyone reading this
program has no idea what information about the client is being displayed. A better approach is to
use the EQUATE statement to define names for each field (typically in an include record). The
data display statement might then become
DISPLAY CLI.REC<CLI.NAME>
which suggests to anyone reading the program that it is displaying the client's name. The
GENERATE command can be used to construct an include record of field names from the file
dictionary rather than having to maintain two separate descriptions of the data.
SELECT @VOC TO 1
LOOP
READNEXT ID FROM 1 ELSE EXIT
READ VOC.REC FROM @VOC, ID THEN
IF VOC.REC[1,1] = 'F' THEN
OPEN ID TO TEST.F ELSE
DISPLAY 'File ' : ID : ' cannot be opened'
END
END
END
REPEAT
This program uses the system defined file variable @VOC to reference the VOC instead of opening
it explicitly. The SELECT statement builds a list of all records in the file into select list 1 which is
then processed in the loop. For each item in the list, the record is read from the VOC and, if it is an
F-type record, the program attempts to open the file. If it cannot be opened, an error message is
displayed.
Note the use of EXIT to exit from the loop when the list is exhausted. Some multivalue
environments do not support this statement and require developers to devise alternative exit schemes
that are generally not as efficient.
Note also that the file opened to variable TEST.F is not explicitly closed. Each OPEN will
implicitly close the previous file as the file variable is overwritten. The final file opened will remain
open until the program terminates.
This program has needed to include a test to process only F-type VOC records. Alternatively, the
program could use the query processor to build a list of F-type records and then process all records
in this list:
Although this approach may look simpler and does not require the unwanted records to be read, it is
actually less efficient than the first method as the query processor will need to read every record and
the loop then re-reads the records of interest. In the previous example, use of the QMBasic
SELECT actually only sets a pointer to the start of the file and the subsequent READNEXT reads
2.11-0
QMBasic 691
each group when it needs to process the first record from the group, effectively reading the file only
once. This exposes an interesting problem that is highlighted in the next example.
The above program might be used to convert a CLIENTS file to add a zero on the front of each
record id, perhaps to allow more clients on a system where the application requires fixed length ids.
Because it is the READNEXT that actually traverses the file rather than the SELECT statement,
new records written to higher numbered groups would be seen by a later READNEXT and get
processed for a second time. For example, if the record for client number 1234 was in group 6 and
the new version of this record with id 01234 hashed to group 10, it would appear in the list
constructed when processing reaches group 10 and the record would be renamed once more to
become 001234.
Although programs that might suffer from this problem are rare, we need to force completion of the
record selection before entering the loop. One way to do this would be to use the query processor
SELECT instead of the QMBasic equivalent:
EXECUTE 'SELECT CLIENTS TO 1'
Note the use of RECORDLOCKU to set an update lock on the record to be added to the file.
Although this is probably strictly unnecessary in this example because the new record will not
already exist, it does ensure compliance with the locking rules.
2.11-0
692 OpenQM
QMBasic has two styles of file i/o that may be freely mixed within an application. Using READ
and WRITE to transfer data using dynamic arrays is simpler and usually faster for programs that
do little processing of the data. For programs that perform a significant amount of processing of the
data in a record, it may be worth the cost of breaking the fields into separate elements of a
dimensioned matrix using MATREAD and MATWRITE.
These statement have the same locking variants as their dynamic array counterparts. They also
share an almost identical syntax where the prefix MAT is used to select the matrix version of the
operation and the variable representing the database record must be a dimensioned array. For
example, the dynamic array read:
READ var FROM filevar, id
becomes
MATREAD array FROM filevar, id
The MATREAD statement places each field of the record into a separate element of the array,
keeping values and subvalues together as these are instances of the same data item.
For example, if a record has three fields, the second of which is multivalued:
AFMB1VMB2FMC
using MATREAD to read this into a three element (plus the zero element) matrix would result in:
0
1 A
2 B1VMB2
3 C
The MATWRITE operation joins together each element of the matrix, inserting field marks
between them and writes this to the file.
If the matrix has more elements than there are fields in the record, the excess elements are set to null
strings:
0
1 A
2 B1VMB2
3 C
4
5
The INMAT() function can be used to determine how many fields the record had. The
MATWRITE operation ignores all trailing empty fields so that above situation would not write
two empty fields at the end of the record.
2.11-0
QMBasic 693
If the matrix has fewer elements than there are fields in the record, the zero element is used to store
the excess data. Consider the a record with five fields and an array with three elements:
0 DFME
1 A
2 B1VMB2
3 C
The MATWRITE operation adds the contents of the zero element to the record formed from the
remaining elements of the matrix, reconstructing the correctly formed data. The zero element thus
acts as an "overflow bucket" allowing programs that did not expect to find the excess data to
function correctly.
Pick style matrices do not have a zero element. In this case, the excess data is stored in the final
element of the matrix:
1 A
2 B1VMB2
3 CFMDFME
This is likely to cause the program to malfunction if it updates element 3 where it expected only to
find the third field of the database record. To avoid this, Pick style programmers usually ensure that
the matrix has at least one more element than they expect it to need, effectively moving the
"overflow bucket" to the end of the matrix.
2.11-0
694 OpenQM
Directory files are so called because they are represented by an operating system directory. The
records in these files are represented by operating system files in the directory. These files do not
give the high performance of hashed files but they allow access to the data from outside of QM.
They are therefore particularly useful for data interchange.
Records in directory files are sometimes very large and may consist of a number of lines of textual
information with a fixed layout. In such cases, it may be useful to process the data line by line. QM
provides statements to perform sequential reading or writing of text data. These can only be used
with directory files.
An item is opened for sequential processing using the OPENSEQ statement. This has two forms,
one that opens a record in a directory file by name:
OPENSEQ file, id TO filevar
the other opens a file by pathname:
OPENSEQ pathname TO filevar
In both forms, the statement takes the optional ON ERROR, LOCKED, THEN and ELSE
clauses. At least one of the THEN and ELSE clauses must be present. Because the OPENSEQ
operation is effectively opening a record, it applies a lock to this record to prevent other users
overwriting it.
The OPENSEQ statement will take the ELSE clause for three reasons:
· The file does not exist.
· The file exists but is not a directory file.
· The file exists as a directory file but the record does not exist.
The last of these three situations would be an error in a program that is intending to read the item
but is usually not an error in a program that will write to the item. The STATUS() function can be
used to determine which of the above three conditions exist as discussed in the detailed OPENSEQ
statement description.
OPENSEQ also has options to open the item in read-only mode, append to an existing item, or
overwrite an existing item.
The QMBasic statements that can be used to access the sequential item are:
READSEQ Read text line by line
READBLK Read a given number of bytes
WRITESEQ Write text line by line
WRITESEQF Write text line by line, flushing to disk before continuing
WRITEBLK Write a given number of bytes
READCSV Read comma separated variable (CSV) format data
WRITECSV Write comma separated variable format data
SEEK Position within the sequential item
NOBUF Suppress buffering
WEOFSEQ Write end of file (truncate the item)
CLOSESEQ Close the sequential item, flushing buffers and releasing the lock.
2.11-0
QMBasic 695
Examples
This short program reads lines from a text file, C:\PRICES. Each line within this file has a stock
part number in the first five characters and a new price in external format in the next eight
characters. For each line, the program reads the corresponding STOCK file record and updates field
STK.PRICE to contain the internal form of the price value. The token STK.PRICE would typically
be defined in an include record.
This program is a variation on the first example where the import data contains comma separated
items as might have been written by a spreadsheet tool such as Excel. The READCSV statement
reads the first two comma separated items in each line of text into STK.ID and PRICE. Any
additional values on the line are discarded.
2.11-0
696 OpenQM
END
REPEAT
This program creates a text item in C:\EXPORT.CSV where each line contains the stock part
number, the price and the quantity on hand as a comma separated list suitable for import into
spreadsheets such as Excel.
2.11-0
QMBasic 697
For compatibility with other environments, QMBasic supports the concept of the default file
variable but, because use of this feature can result in mis-typed programs compiling without errors
but not functioning correctly, it must be enabled by use of the STDFIL or STDFIL.SHARED
option of the $MODE compiler directive or the equivalent setting in the $BASIC.OPTIONS
record.
The default file variable allows a program to open a file without referencing a specific variable
name.
When using the STDFIL.SHARED option of $MODE, the default file variable is an implied
reference to the @STDFIL variable. All programs and subroutines executed at the same command
processor level share a single default file variable. It is therefore important that an application uses
this feature with care. @STDFIL is maintained separately for each command processor level. Thus
a program that uses the default file variable can use the QMBasic EXECUTE statement to run a
sperate program that uses the default file variable to reference a different file. On return from the
EXECUTE, @STDFIL references the original file.
When using the STDFIL option of $MODE instead of STDFIL.SHARED, the default file variable
is maintained separately for each program or subroutine. The @STDFIL variable is local to the
program in which it is referenced.
A single application can validly include a mix of programs that use both modes but use of both
STDFIL and STDFIL.SHARED together in a single program is equivalent to use of STDFIL.
When this feature is enabled, the syntax of many of the QMBasic statements that access files is
modified to allow the file variable to be omitted. The revised syntax for use with the default file
variable is as shown below but not referenced elsewhere in this manual.
CLEARFILE {ON ERROR statement(s)}
CLOSE {ON ERROR statement(s)}
DELETE record.id {ON ERROR statement(s)}
DELETEU record.id {ON ERROR statement(s)}
FILELOCK {ON ERROR statement(s)} {LOCKED statement(s)}
FILEUNLOCK {ON ERROR statement(s)}
OPEN {dict.expr, } filename {READONLY} {ON ERROR statement(s)}
OPENPATH pathname {READONLY} {ON ERROR statement(s)}
MATREAD mat FROM record.id {ON ERROR statement(s)} {THEN statement(s)} {ELSE
statement(s)}
MATREADL mat FROM record.id {ON ERROR statement(s)} {LOCKED statement(s)}
{THEN statement(s)} {ELSE statement(s)}
MATREADU mat FROM record.id {ON ERROR statement(s)} {LOCKED statement(s)}
{THEN statement(s)} {ELSE statement(s)}
MATWRITE mat TO record.id {ON ERROR statement(s)}
MATWRITEU mat TO record.id {ON ERROR statement(s)}
2.11-0
698 OpenQM
READ rec FROM record.id {ON ERROR statement(s)} {THEN statement(s)} {ELSE statement
(s)}
READL rec FROM record.id {ON ERROR statement(s)} {LOCKED statement(s)} {THEN
statement(s)} {ELSE statement(s)}
READU rec FROM record.id {ON ERROR statement(s)} {LOCKED statement(s)} {THEN
statement(s)} {ELSE statement(s)}
RELEASE , record.id {ON ERROR statement(s)} [Note comma before record.id]
SELECT (TO list} {ON ERROR statement(s)}
SELECTN (TO list} {ON ERROR statement(s)}
SELECTV (TO list} {ON ERROR statement(s)}
WRITE rec TO record.id {ON ERROR statement(s)}
WRITEU rec TO record.id {ON ERROR statement(s)}
QM does not support use of the default file variable with READV, WRITEV and the locking
related variants of these statements.
2.11-0
QMBasic 699
Multivalue Functions
The QMBasic language has many functions that provide multivalued equivalents of their more
commonly used single valued counterparts. In each case, these work element by element through the
dynamic arrays passed into the functions, performing the operation on each element in turn to
produce an equivalent dynamic array of results.
A contains ABCFMDEFFMGHI
and
B contains 123FM456FM789
There are also a number of multivalued logical functions. These provide equivalents to the
relational operators and other functions that return boolean values.
For example, the GTS(arr1, arr2) function takes two dynamic arrays and returns a new dynamic
array of true / false values indicating whether the corresponding elements of arr1 are greater than
those of arr2.
2.11-0
700 OpenQM
C = GTS(A, B)
Returns C as 0FM0VM1VM1FM0
The IFS() function returns a dynamic array constructed from elements chosen from two other
dynamic arrays depending on the content of a third dynamic array.
where
The IFS() function examines successive elements of control.array and constructs a result array
where elements are selected from the corresponding elements of either true.array or false.array
depending on the control.array value.
Example
A contains 1VM0VM0VM1VM1VM1VM0
B contains 6VM2VM3VM4VM9VM6VM3
C contains 2VM8VM5VM0VM3VM1VM3
D = IFS(A, B, C)
2.11-0
QMBasic 701
Used in combination, and often with REUSE(), these functions can give very elegant solutions to
apparently complex problems. For example, to determine how many elements of a dynamic array
contain a value greater than four:
N = SUM(GTS(X, REUSE(4))
2.11-0
702 OpenQM
QMBasic includes support for object orientated programming. Users familiar with other object
oriented languages will find that QM offers many of the same concepts but, because they are
integrated into an existing programming environment, there may be some significant differences in
usage.
What is an Object?
An object is a combination of data and program operations that can be applied to it. An object is
defined by a class module, a QMBasic program that is introduced by the CLASS statement and
contains the definitions of persistent data items and public subroutine and functions. An object is a
run time instance of the class, instantiated by use of the OBJECT() function
OBJ = OBJECT("MYCLASS")
where "MYCLASS" is the catalogue name of the class module. The OBJ variable becomes a
reference to an instance of the class.
A second use of the OBJECT() function with the same catalogue name will create a second
instance of the object. On the other hand, copying the object variable creates a second reference to
the same instance.
In other program types, data is stored either in local variables that are discarded on return from the
program, or in common blocks that persist and may be shared by many programs. A class module
has the additional concept of persistent data that is related to the particular instance of the object
and is preserved across repeated entry to the object. If an object is instantiated more than once, each
instantiation has its own version of the persistent data.
PRIVATE and PUBLIC variables are set to unassigned when the object is instantiated.
Another important difference between class modules and other program types is that a class module
usually has multiple entry points, each corresponding to a public function or public subroutine.
Indeed, simply calling the class module by its catalogue name will generate a run time error.
Just as with conventional QMBasic functions and subroutines, a public function must return a value
to its caller whereas a public subroutine does not (though it can do so by updating its arguments).
2.11-0
QMBasic 703
...processing...
RETURN Z
END
where XX is the function name, A, B and C are the arguments (optional), and Z is the value to be
returned to the caller.
The number of arguments in a public function or subroutine is normally limited to 32 but this can
be increased using the MAX.ARGS option of the CLASS statement.
Both styles of public routine allow use of the VAR.ARGS qualifier after the argument list to
indicate that it is of variable length. Argument variables for which the caller has provided no value
will be unassigned. The ARG.COUNT() function can be used to find the actual number of
arguments passed. A special syntax of three periods (...) used as the final argument specifies that
unnamed scalar arguments are to be added up to the limit on the number of arguments. These can
be accessed using the ARG() function and the SET.ARG statement. See the PUBLIC statement
for more details of this feature.
Sometimes an application developer may wish a public variable to be visible to users of the class
for reading but not for update. Although this could be achieved by use of a dummy PUBLIC
SUBROUTINE that ignores updates or reports an error, public variables may be defined as
read-only by including the READONLY keyword after the variable declaration:
PUBLIC A READONLY
or
PUBLIC B(5) READONLY
Referencing an Object
References to an object require two components, the object variable and the name of a property or
method within that object. The syntax for such a reference is
2.11-0
704 OpenQM
OBJ->PROPERTY
or, if arguments are required,
OBJ->PROPERTY(ARG1, ARG2, ...)
Any argument may reference a whole matrix by prefixing the matrix name with the keyword MAT,
for example
OBJ->CALC(CLIENT, MAT CLI.REC, TOTVAL)
This dual role of public variables and functions or subroutines makes it very easy to write a class
module in which, for example, a property value may be retrieved without execution of any program
statements inside the object but setting the value executes a subroutine to validate the new value.
All object, property and public routine names are case insensitive.
Public variables may be dimensioned arrays. Subscripts for index values are handled in the usual
way:
OBJ->MODE(3) = 7
where MODE has been defined as a single dimensional array. If MODE has an associated public
subroutine, the indices are passed via the arguments and the new value as the final argument. Thus,
if MODE was defined as
PUBLIC SUBROUTINE MODE(A,B)
the above statement would pass in A as 3 and B as 7.
Other object oriented languages usually provide methods, subroutines that can be executed from
calling programs to do some task. QMBasic class modules do this by using public subroutines. The
calling program uses a statement of the form:
OBJ->RESET
where RESET is the name of the public subroutine representing the method. Again, arguments are
allowed:
OBJ->RESET(5)
2.11-0
QMBasic 705
This leads to an apparent syntactic ambiguity between assigning values to public properties and
execution of methods. Actually, there is no ambiguity but the following two statements are
semantically identical:
OBJ->X(2,3)
OBJ->X(2) = 3
All of the above examples have used literal (constant) property names. QMBasic allows expressions
as property names in all contexts using a syntax
OBJ->(expr)
where expr is an expression that evaluates to the property name.
The ME Token
Sometimes an object needs to reference itself. The reserved data name ME can be used for this
purpose:
ME->RESET
When an object is instantiated using the OBJECT() function, part of this process checks whether
there is a public subroutine named CREATE.OBJECT and, if so, executes it. This can be used, for
example, to preset default values in public and private variables. Up to 32 arguments may be
passed into this subroutine by extending the OBJECT() call to include these after the catalogue
name of the class module.
An object remains in existence until the last object variable referencing it is discarded or
overwritten. At this point, the system checks for a public subroutine named DESTROY.OBJECT
and, if it exists, it is executed. This subroutine is guaranteed to be executed, even if the object
variable is discarded as part of a program failure that causes an abort. The only situation where an
object can cease to exist without this subroutine running to completion is if the
DESTROY.OBJECT subroutine itself aborts.
2.11-0
706 OpenQM
The optional UNDEFINED public subroutine and/or public function can be used to trap references
to the object that use property names that are not defined. This handler is executed if a program
using the object references a name that is not defined as a public item. The first argument will be
the undefined name. Any arguments supplied by the calling program will follow this. The
ARG.COUNT() and ARG() functions can be used to help extract this data in a meaningful way.
Inheritance
Sometimes it is useful for one class module to incorporate the properties and methods of another.
This is termed inheritance.
Use of the INHERITS clause of the CLASS statement effectively inserts declaration of a private
variable of the same name as the inherited class (removing any global catalogue prefix character)
and adds
name = OBJECT(inherited.class)
INHERIT name
to the CREATE.OBJECT subroutine.
Alternatively, inheritance can be performed during execution of the object by direct use of the
INHERIT statement.
The name search process that occurs when an object is referenced scans the name table of the
original object reference first. If the name is not found, it then goes on to scan the name tables of
each inherited object in the order in which they were inherited. Where an inherited object has itself
inherited further objects, the lower levels of inheritance are treated as part of the object into which
they were inherited. If the name is not found, the same search process is used to look for the
undefined name handler.
Syntax Summary
2.11-0
QMBasic 707
There is a sample QMBasic class module named INDEX.CLS in the BP file of the QMSYS
account, catalogued as !INDEX.CLS. This class allows an application to scan an index one record
id at a time instead of one indexed value at a time. Full details of its use and internal operation can
be found in the source code.
See also:
CLASS, DISINHERIT, INHERIT, OBJECT(), PRIVATE, PUBLIC.
2.11-0
708 OpenQM
QMBasic includes a set of functions that allow network connections to be established with other
systems or other software on the same system.
What is a Socket?
A socket is one end of a bidirectional link between two software components across a network or
within the same system. A socket is established using a network address (typically written as four
dot separated values such as 193.118.13.11) and a port number. These can be considered as being
much like a telephone number and extension. The network address identifies the device on the
network to which a connection is to be established and the port number identifies a service within
that device.
Just as we can look up a telephone number in a directory, so the internet has domain name servers
that fulfil the same role, allowing users to reference a network destination by name instead of its
number. For example, www.openqm.com translates to 81.31.112.103.
There is a central registry of standard port numbers (e.g. 23 for a telnet connection or 80 for a web
server) but these are not rigidly enforced. By default, QM uses ports 4242 and 4243 for terminal
and QMClient connections respectively.
A socket may be established in two modes; stream and datagram. A stream connection represents a
channel over which a succession of messages may be passed in each direction until connection is
broken by one participant. A datagram connection consists of a single message and response pair
after which the connection is broken.
There are also two protocols used to manage the internal structure of a message; TCP (transmission
control protocol) and UDP (user datagram protocol). These are usually paired up with the
corresponding socket modes such that TCP is used over stream connections and UDP over
datagram connections but the underlying network system allows variations.
Creating a stream connection is very easy. Although one end of this connection is likely to be
something other than a QMBasic program, the example below is based on two QMBasic programs
communicating across a network.
The server process (the one that is waiting for an incoming connection) starts listening by using a
sequence of the form:
The CREATE.SERVER.SOCKET() call listens for incoming TCP stream connections on port
4000. The first argument in this function has been specified as a null string to listen on all local
addresses. A specific address can be specified if required. SRVR.SKT becomes a socket variable
that is effectively monitoring for incoming connections. This is then used in a call to
2.11-0
QMBasic 709
Once a connection has been established, data can be read or written using READ.SOCKET() and
WRITE.SOCKET().
This example simply echoes the data back to the other end of the connection. The
SKT$BLOCKING flag specifies that READ.SOCKET() should wait for incoming data rather
than returning immediately if there is no data waiting. Note that this waits for any data, not the full
100 bytes specified as the limit. It may be necessary to perform several reads to assemble the data
sent from the other end of the connection.
Finally, the connection can be terminated using CLOSE.SOCKET(), remembering that the server
socket also needs to be closed when no new connections are to be handled. Like all QMBasic
variables, if a program terminates and a socket variable is discarded, the socket will be closed
automatically.
CLOSE.SOCKET SKT
CLOSE.SOCKET SRVR.SKT
The client program that wants to connect to this server would be of the form
Datagram Connections
A datagram connection is typically used to send a single message to a server which returns a single
response and then closes the connection. The domain name servers mentioned above use this form
of data exchange when looking up a name.
2.11-0
710 OpenQM
CLOSE.SOCKET SKT
Socket Tracing
Socket tracing enables an application to create a diagnostic report of all data transmitted in either
direction via a socket. Tracing is enabled by use of the SKT$INFO.TRACE mode of the
SET.SOCKET.MODE() function, passing in the pathname of the log file to be created. Any
existing data in this log file will be overwritten. Tracing remains active until the socket is closed or
a further call to SET.SOCKET.MODE() sets the log file pathname to a null string.
The log consists of a simple text file in with entries tagged as SEND or RECV to indicate the
direction of data transfer. Each entry shows the data in both hexadecimal and character form.
If an application needs to work with multiple simultaneous socket connections, handling input on
each socket as it occurs, the SELECT.SOCKET() function provides a way to wait for an event on
any of a collection of sockets.
See also:
ACCEPT.SOCKET.CONNECTION, CLOSE.SOCKET, CREATE.SERVER.SOCKET(),
OPEN.SOCKET(), READ.SOCKET(), SELECT.SOCKET(), SERVER.ADDR(),
SET.SOCKET.MODE(), SOCKET.INFO(), WRITE.SOCKET()
2.11-0
QMBasic 711
Compiler directives control the way in which the compiler processes the QMBasic source programs.
They do not result directly in executable statements.
2.11-0
712 OpenQM
The $CATALOGUE directive (or the American spelling $CATALOG) causes automatic
cataloguing of a program after successful compilation.
Format
where
name is the name to be used when the program is added to the catalogue.
The $CATALOGUE directive causes the compiler to add the program to the system catalogue
with the given call name if the compilation is successful. If name is omitted, the source record name
is used. When using this default name, an error will be reported if the name is not the same as the
name specified in the PROGRAM, SUBROUTINE, FUNCTION or CLASS statement.
If the name does not follow the normal QMBasic name construction rules (e.g. a Pick user exit such
as 50BB) it should be enclosed in quotes. The rules for catalogue name format are described with
the CATALOGUE command.
Automatic cataloguing can also be performed using the CATALOGUE entry in the
$BASIC.OPTIONS record as described under the BASIC command. Use of the $CATALOGUE
compiler directive will override any alternative settings specified in the $BASIC.OPTIONS record.
See also:
$NO.CATALOGUE, $BASIC.OPTIONS
2.11-0
QMBasic 713
Format
$DEBUG
The $DEBUG directive is an alternative to use of the DEBUGGING keyword to the BASIC
command. The $DEBUG directive must appear before any executable statements in the program.
During development, it is often useful to compile the entire application in debug mode. There is a
small performance overhead running debug mode programs so it is recommended that production
versions of the application should be compiled without this mode.
See also:
QMBasic debugger
2.11-0
714 OpenQM
The $DEFINE directive is used to associate a value with a symbolic name at compile time. The
standard include records in the SYSCOM file contain many examples of $DEFINE.
Format
where name is the symbol to be used in the program and value is a constant.
If the defined name is also a built-in function or statement, that function or statement becomes
inaccessible.
The token QM is automatically defined and may be used with $IFDEF to determine whether a
program is being compiled on the QM database. The token QM.WINDOWS, QM.LINUX,
QM.FREEBSD, QMMAC, QMAIX or QMPDA is defined corresponding to the underlying
operating system. Because these are only relevant at compile time, take care when using them in
programs that may be moved between platforms. The SYSTEM(1010) function can be used to
determine platform type at run time.
See $IFDEF for an example of use of define tokens to control conditional compilation, allowing a
single source stream to be used in different multivalue environments.
See also:
EQUATE
2.11-0
QMBasic 715
Format
$EXECUTE "command"
This directive can be useful, for example, when program generated include records are used.
2.11-0
716 OpenQM
Format
$IFDEF name
...statements...
$ELSE
...statements...
$ENDIF
The $ELSE and associated statements are optional. Statements conditioned by the $IFDEF
directive are ignored if name has not been defined by a previous $DEFINE directive. Statements
under the $ELSE directive are ignored if name has been defined by a previous $DEFINE directive.
The $IFNDEF directive provides the inverse action of $IFDEF, compiling the following statements
if name has not been defined.
$IFDEF and $IFNDEF statements may be nested to any depth though nesting more than two deep
can make program maintenance very difficult.
Portable Software
One use of conditional compilation is to allow a single source stream to be compiled in different
multivalue environments rather than having to maintain separate source streams. When compiling
on QM, the name QM is always defined thus a construct such as
$IFDEF QM
SETLEFT 'DATE' FROM INV.F
LOOP
SELECTRIGHT 'DATE' FROM INV.F SETTING DT
UNTIL STATUS()
READLIST IDS THEN GOSUB PROCESS
REPEAT
$ENDIF
might be used scan an alternate key index on QM. The same program might contain an equivalent
for UniVerse
$IFDEF UV
BSCAN DT, IDS FROM INV.F USING 'DATE' RESET THEN
LOOP
GOSUB PROCESS
BSCAN DT, IDS FROM INV.F USING 'DATE' ELSE EXIT
REPEAT
END
$ENDIF
though UniVerse does not define the UV token automatically. This would need to be done in the
source code, probably as part of a platform specific include record.
2.11-0
QMBasic 717
See also:
$DEFINE
2.11-0
718 OpenQM
The $INCLUDE directive is used to direct the compiler to include text from another record.
Include records may be in either directory or dynamic files.
Format
For compatibility with some other systems, $INSERT may be used as a synonym for $INCLUDE.
Examples
The first example includes record ERR.H from the SYSCOM file. The second example, which has
no file name specified, includes MYKEYS.H from the same file as the source program.
Use of a .H suffix is recommended on include records as these will be skipped automatically by the
compiler when using a select list.
The file name in the first $INCLUDE in this example is not strictly necessary as the compiler will
always look in SYSCOM if no file name is given and the include record is not found in the same file
as the source program.
Because directory files on non-Windows platforms have case sensitive record names, the compiler
will look for the record name as entered and then, if it has not been found, in uppercase. Thus
programs may be written in either upper or lowercase if the records are always stored with
uppercase name. The standard include records in the SYSCOM file follow this rule.
Include files may be nested (one included from within another) though this can lead to difficulties
when maintaining complex programs and is discouraged.
For compatibility with other multivalue databases, the $INCLUDE directive can also be written
without the $ prefix. Used in this way, it must be the only statement on the source line and must not
contain any tokens that have been defined using $DEFINE or EQUATE.
2.11-0
QMBasic 719
The $LIST directive can be used to start, suspend and resume generation of a listing of the
program and any associated error messages.
Format
$LIST {ON}
$LIST OFF
The listing is directed to a record of the same name as the program source but with a suffix of .LIS.
Any existing listing record is deleted by the compiler at the start of compilation regardless of
whether a new listing is to be produced.
A $LIST ON directive in the main program starts generation of a listing record from that point
onwards. The compiler LISTING option is equivalent to a $LIST ON at the start of the program.
A $LIST OFF directive stops generation of the listing record. If this is on an include record, listing
will resume on return to the source or include record from which it was entered.
A $LIST ON directive in an include record only resumes generation of the listing record if listing
was active when processing of the include record began.
2.11-0
720 OpenQM
The $MODE directive enables language options for improved compatibility with other multivalue
databases.
Format
where
option is the feature to be turned on. Multiple comma separated option names may be
given.
Prefixing a mode name (other than DEFAULT) with a minus sign turns off the named option.
Default modes can be set by creating a record named $BASIC.OPTIONS in the source file or in the
VOC. Details of how to do this can be found with the description of the BASIC command.
Examples
$MODE TRAP.UNUSED
FUNCTION INV.CLI(INV.REC)
CLEINT.NO = INV.REC<4>
IF CLIENT.NO = '' THEN CLIENT.NO = INV.REC<18>
RETURN CLIENT.NO
END
2.11-0
722 OpenQM
The above program contains a typographical error in the spelling of the first use of CLIENT.NO.
Because it has been compiled with the TRAP.UNUSED option, the compiler will display a warning
message that the CLEINT.NO variable is assigned but never used.
PROGRAM INVOICE
FOR I = 1 TO 3
NEXT I
DISPLAY "I on exit = " : I
END
The above program displays the loop exit value as being 3 whereas the program below uses the
FOR.STORE.BEFORE.TEST mode and displays the loop exit value as being 4.
$MODE FOR.STORE.BEFORE.TEST
PROGRAM INVOICE
FOR I = 1 TO 3
NEXT I
DISPLAY "I on exit = " : I
END
2.11-0
QMBasic 723
The $NO.CATALOGUE directive (or the American spelling $NO.CATALOG) overrides any use
of the CATALOGUE option in the $BASIC.OPTIONS record.
Format
$NO.CATALOGUE
See also:
$CATALOGUE, $BASIC.OPTIONS
2.11-0
724 OpenQM
$NO.XREF
The $NO.XREF directive specifies that a QMBasic program is to be compiled without the
cross-reference tables.
Format
$NO.XREF
The $NO.XREF directive is equivalent to use of the NO.XREF option to the BASIC command.
The cross-reference tables are used by QM to identify source code line numbers and the names of
variables when reporting errors. Compiling a program without the cross-reference tables means that
error messages are not able to show line numbers or the name of the variable involved.
The QMBasic debugger also uses the cross-reference tables. The $NO.XREF option is ignored if a
program is compiled in debug mode.
See also:
BASIC, $BASIC.OPTIONS
2.11-0
QMBasic 725
The $NOCASE.STRINGS directive compiles the program using case insensitive string operations.
Format
$NOCASE.STRINGS
This directive must appear before any executable statements in the program source and applies to
the entire program module.
Selecting case insensitive string mode affects the relational operators (=, #, <, >, <=, >=), their
multivalue function equivalents (EQS(), NES(), LTS(), GES(), LES(), GES()), the CHANGE(),
CONVERT(), COUNT(), DCOUNT(), FIELD(), INDEX() and SWAP() functions and the
CONVERT, FIND, FINDSTR and LOCATE statements.
2.11-0
726 OpenQM
The $PAGE directive inserts a page break in the compiler listing record.
Format
$PAGE
The $PAGE directive can be used to improve readability of the record generated by use of the
LISTING option to the BASIC command or the $LIST compiler directive.
2.11-0
QMBasic 727
The $QMCALL compiler directive controls access to a catalogued subroutine via QMClient.
Format
$QMCALL
QMClient includes the ability to restring which catalogued subroutines may be called directly by the
client interface.
For processes running with the QMCLIENT configuration parameter set to 2, this directive makes
the subroutine in which it appears available for calling using the QMClient API QMCall function.
This subroutine may then call other subroutines that may or may not include this compiler directive.
By using the QMCLIENT configuration parameter and this directive, it is possible to restrict the
actions of a QMClient session thus allowing tighter control of QMClient security.
2.11-0
728 OpenQM
Format
$STOP {message}
where
The $STOP directive causes the QMBasic compiler to terminate compilation of the current
program. It is most likely to be used inside a $IFDEF conditional compilation structure to recognise
that the program is inappropriate to the system being compiled.
Example
$IFDEF QM
$STOP Program not applicable to QM
$ENDIF
The above example appears in the QMSAVE program in the BP file of the QMSYS account. This
program is issued in source form for use in environments other than QM.
2.11-0
QMBasic 729
This scheme provides access to a virtually unlimited number of files but can have severe
performance effects when many files are used in frequent rotation.
Maximum precision
14 decimal places
2.11-0
730 OpenQM
Program Control
ABORT Abort to command prompt
ABORTE Abort to command prompt with Pick style message handling
ABORTM Abort to command prompt with Information style message
handling
CALL Call an external subroutine
CASE Perform statements according to multiple conditions
CHAIN Terminate program and execute a command
CONTINUE Continue next iteration of a loop
ENTER Synonym for CALL
EXECUTE Execute a command
EXIT Leave a loop
FOR / NEXT Iterative loop construct
GET(ARG.) Retrieve command line arguments
GO / GOTO Jump to a label
GOSUB Enter an internal subroutine
IF / THEN / ELSE Perform conditional statements
LOCAL Declares an internal subroutine or function that has private local
variables
LOOP / REPEAT Define a loop to be repeated
NAP Suspend program for a short period
ON GOSUB Jump to one of a list of labels selected by value
ON GOTO Enter one of a list of internal subroutines selected by value
OS.EXECUTE Execute an operating system command
PAUSE Pause execution until awoken by another process
PERFORM Synonym for EXECUTE
REMOVE.BREAK.HANDLER Deactivate a break handler subroutine
RETURN Return from CALL or GOSUB
2.11-0
QMBasic 731
2.11-0
732 OpenQM
String Handling
ALPHA() Test if string holds only alphabetic characters
ASCII() Convert an EBCDIC string to ASCII
CATS() Concatenate elements of a dynamic array
CHANGE() Replace substring in a string
CHAR() Get ASCII character for a given collating sequence value
COL1() Start of substring position from FIELD()
COL2() End of substring position from FIELD()
COMPARE() Compare strings
COMPARES() Multivalued variant of COMPARE()
CONVERT Substitute characters with replacements
CONVERT() Substitute characters with replacements
COUNT() Count occurrences of substring in string
COUNTS() Multivalued variant of COUNT()
CROP() Remove redundant mark characters
CSVDQ() Dequote a CSV string
DCOUNT() Count delimited substrings in string
DECRYPT() Decrypt text
DEL Delete a field, value or subvalue
DELETE() Delete a field, value or subvalue
DOWNCASE() Convert string to lowercase
DPARSE Split elements of a delimited string
DPARSE.CSV Split elements of a CSV format delimited string
DQUOTE() Synonym for QUOTE()
DQUOTES() Synonym for QUOTES()
EBCDIC() Convert an ASCII string to EBCDIC
ENCRYPT() Encrypt data
EXTRACT() Extract a field, value or subvalue
FIELD() Extract delimited fields
FIELDS() Multivalued variant of FIELD()
FIELDSTORE() Replace or insert delimited fields
FIND Find a string in a dynamic array element
FINDSTR Find a substring in a dynamic array element
FMT() Format a string
FMTS() Format a dynamic array
FOLD() Break a string into sections, splitting at spaces where possible
FOLDS() Multivalued variant of FOLD()
GETREM() Get remove pointer position
ICONV() Perform input conversion
ICONVS() Perform input conversion on a dynamic array
2.11-0
QMBasic 733
2.11-0
734 OpenQM
File Handling
BEGIN TRANSACTION Start a new transaction
CLEARFILE Clear a file, deleting all records and releasing disk space
CLOSE Close a file
CLOSESEQ Close a record opened for sequential access
COMMIT Commit transaction updates
CREATE Create an empty sequential file record
CREATE.FILE Create a file
DELETE Delete record from a file
DELETESEQ Delete an operating system file
DELETEU Delete record from a file preserving locks
DFPART() Access a part file within a distributed file
DIR() Return the contents of a directory
END TRANSACTION Terminate a transaction
FCONTROL() Perform control action on an open file
FILE Open a file and access data by field name
FILE.EVENT() Create a file event monitoring variable
FILEINFO() Return information about an open file
FILELOCK Lock a file
FILEUNLOCK Unlock a file
FLUSH Flush sequential file data to disk
FLUSH.DH.CACHE Flush dynamic file cache
GET.PORT.PARAMS() Get serial port parameters
MARK.MAPPING Control field mark translation in directory files
MATREAD Read a record, parsing into a matrix
MATREADCSV Read a CSV format text item into a matrix
MATREADL Read a record setting a read lock, parsing into a matrix
MATREADU Read a record setting an update lock, parsing into a matrix
MATWRITE Write a record from matrix elements
MATWRITEU Write a record from matrix elements, retaining any lock
NOBUF Turn off buffering for a record opened using OPENSEQ
OPEN Open a file
OPENPATH Open a file by pathname
OPENSEQ Open a record for sequential access
OSDELETE Delete a file by pathname
OSREAD Read a file by pathname
OSWRITE Write a file by pathname
OUTERJOIN() Fetch data from a file using an "outer join"
READ Read a record from a file
READBLK Read bytes from a sequential file
READCSV Read a CSV format text item
READL Read a record from a file, setting a read lock
2.11-0
QMBasic 735
2.11-0
736 OpenQM
2.11-0
QMBasic 737
Socket Interface
ACCEPT.SOCKET.CONNECTION() Accept an incoming connection on a server socket
CLOSE.SOCKET Close a socket
CREATE.SERVER.SOCKET() Open a server socket
OPEN.SOCKET() Open a socket connection
READ.SOCKET() Read data from a socket
SELECT.SOCKET() Monitor events on multiple sockets
SERVER.ADDR() Find the IP address for a given server name
SET.SOCKET.MODE() Set mode of a socket
SOCKET.INFO() Retrieve information about a socket
WRITE.SOCKET() Write data to a socket
Miscellaneous
ARG() Returns an argument variable based on its argument list position
ARG.COUNT() Returns the number of arguments passed into a subroutine
ARG.PRESENT() Test for presence of an argument in a subroutine or function
ASSIGNED() Test whether variable is assigned
CATALOGUED() Check catalogue entry
CHECKSUM() Calculate a checksum value for a supplied data item
CHILD() Test if a phantom process is still running
CONFIG() Returns the value of a configuration parameter
CONNECT.PORT() Connect a serial port to a phantom process
DEBUG Enter debugger
DTX() Convert a number to hexadecimal
ENV() Retrieve an operating system environment variable
GET.MESSAGES() Retrieve messages from the message queue
GETNLS() Get national language support parameter value
INMAT() Return status of matrix operations
ITYPE() Execute a compiled I-type
LOCK Set task lock
LOGMSG Add an entry to the system error log
NULL No operation
OBJECT() Instantiates an object
OBJINFO() Returns information about an object variable
OS.ERROR() Return operating system error information
PRECISION Set number of decimal places in numeric conversion
PROCREAD Read data from the PROC primary input buffer
PROCWRITE Write data to the PROC primary input buffer
REMARK Alternative syntax for comments
SENTENCE() Returns the command line that started the current program
SET.ARG Sets an argument variable based on its argument list position
SET.EXIT.STATUS Set final exit status value
SETNLS() Set national language support parameter value
STATUS() Return status from previous operation
SYSTEM() Return system information
TCLREAD Returns the sentence that started the current program
TESTLOCK Test state of a task lock
UNASSIGNED() Test whether variable is unassigned
UNLOCK Release task lock
XTD() Convert a hexadecimal number
2.11-0
738 OpenQM
2.11-0
QMBasic 739
2.11-0
740 OpenQM
2.11-0
QMBasic 741
EXP() Exponential
EXTRACT() Extract a field, value or subvalue
FCONTROL() Perform control action on an open file
FIELD() Extract delimited fields
FIELDS() Multivalued variant of FIELD()
FIELDSTORE() Replace or insert delimited fields
FILE Open a file and access data by field name
FILE.EVENT() Create a file event monitoring variable
FILEINFO() Return information about an open file
FILELOCK Lock a file
FILEUNLOCK Unlock a file
FIND Find a string in a dynamic array element
FINDSTR Find a substring in a dynamic array element
FLUSH Flush sequential file data to disk
FLUSH.DH.CACHE Flush dynamic file cache
FMT() Format a string
FMTS() Format a dynamic array
FOLD() Break a string into sections, splitting at spaces where possible
FOLDS() Multivalued variant of FOLD()
FOOTING Set footing text
FOR / NEXT Iterative loop construct
FORMLIST Create a numbered select list from a dynamic array
FORMLISTV Create a select list variable from a dynamic array
FUNCTION Declare function name and arguments
GES() Multivalued greater than or equal to test
GET Synonym for PUBLIC FUNCTION
GET(ARG.) Retrieve command line arguments
GET.MESSAGES() Retrieve messages from the message queue
GET.PORT.PARAMS() Get serial port parameters
GETLIST Restore a saved select list
GETNLS() Get national language support parameter value
GETPU() Get a characteristic of a print unit
GETREM() Get remove pointer position
GO / GOTO Jump to a label
GOSUB Enter an internal subroutine
GTS() Multivalued greater than test
HEADING Set heading text
HUSH Suppress or enable display output
ICONV() Perform input conversion
ICONVS() Perform input conversion on a dynamic array
IDIV() Integer division
IF / THEN / ELSE Perform conditional statements
IFS() Multivalued conditional expression
IN Read a single byte from the terminal with an optional timeout
INDEX() Locate occurrence of substring within a string
INDEXS() Multivalued equivalent of INDEX()
INDICES() Return information about alternate key indices
INHERIT Inherit an object
INMAT() Return status of matrix operations
INPUT Input a string from the keyboard or data queue
INPUT @ Input a string from the keyboard or data queue
INPUTCLEAR Synonym for CLEARINPUT
INPUTCSV Input CSV format data
INPUTERR Synonym for PRINTERR
2.11-0
742 OpenQM
2.11-0
QMBasic 743
2.11-0
744 OpenQM
2.11-0
QMBasic 745
2.11-0
746 OpenQM
2.11-0
QMBasic 747
@(x,y) Function
Format
where
arg provides qualifying information for use with some mode values.
The @(x, y) functions return string values which can be used in the same way as any other strings.
They only take effect when the string is used in a CRT, DISPLAY or PRINT statements directed
to the display. The actual value returned by the function is a control code to be sent to the terminal
and is dependant on the type of terminal in use (see the TERM command).
When output is directed to a printer or to a file for later printing rather than to the display, escape
sequences relevant to the printer may be used for formatting, etc. Because the @(x,y) function
returns codes specific for the terminal in use, it is unlikely that these codes are relevant for printers.
Some functions are extensions to the standard terminal capability definitions and may require use of
AccuTerm with terminal type that have a -at suffix or QMTerm in qmterm mode.
Cursor Positioning
The @(col {, line}) format specifies that subsequent output is to appear at the given column and,
optionally, line position. Columns and lines are numbered from zero where the top left of the screen
is line 0, column 0. The effect of attempting to move to a cursor position outside the display area is
undefined.
Some terminal emulations (e.g. vpa2-at) may not handle cursor positions correctly if set to a large
screen size such as 132 column width. This is not a defect in QM but is caused by limitations of the
control codes used by these terminals.
Use of the @(col {, line}) function disables screen pagination (automatic display of the "Press
return to continue" prompt after each screen of output). Pagination remains disabled until the
program executes the PRINTER RESET statement or return to the command prompt.
Use of the EXECUTE statement enables screen pagination, executes the command(s) and then
restores pagination to its state when the EXECUTE was performed.
2.11-0
748 OpenQM
Special Functions
@(x, y) functions with negative values of x are used to provide a variety of control functions. These
are largely in common with the functions defined for other systems. The token names shown in the
table below are defined in the KEYS.H include record in the SYSCOM file.
Functions not supported by the terminal device in use return a null string and hence will be ignored.
Note that individual terminal types may place restrictions on use of display attributes such as
flashing, underline, colour, etc. For example, although each attribute has a corresponding start and
end control code pair, many terminals can only apply a single attribute to any particular screen
region.
Display attributes are also implemented in two fundamentally distinct ways. Most modern terminals
maintain an attribute for each character position on the display and data is stored by the terminal
using the currently active attributes regardless of any intervening cursor movements. On some other
terminals, the code sent by an @() function to set or clear an attribute occupies a character position
on the screen. Starting at the top left of the screen and working row by row through each character
position, the attributes of any particular character are determined by the most recent attribute
setting encountered.
For example,
DISPLAY @(-1):@(-15):'ABC':@(-16):'DEF'
on a terminal that stores the attribute for each character position would result in a display of
ABCDEF
whereas a terminal that uses a character cell to store the attribute would display
ABC DEF
2.11-0
QMBasic 749
Descriptions
2.11-0
750 OpenQM
colour.
IT$CUB (Backspace)
The cursor moves left by the number of positions specified in the second argument which defaults to
one or until the left edge of the screen is reached.
2.11-0
QMBasic 751
The number of lines specified in the second argument (default value one) are deleted at the current
cursor position. Blank lines are inserted at the bottom of the screen.
IT$BLACK 0
IT$BLUE 1
IT$GREEN 2
IT$CYAN 3
IT$RED 4
IT$MAGENTA 5
IT$BROWN 6
IT$WHITE 7
IT$GREY 8
IT$BRIGHT.BLUE 9
2.11-0
752 OpenQM
IT$BRIGHT.GREEN 10
IT$BRIGHT.CYAN 11
IT$BRIGHT.RED 12
IT$BRIGHT.MAGENTA 13
IT$YELLOW 14
IT$BRIGHT.WHITE 15
Some terminal emulators provide the ability to map these colour values to an alternative colour
palette. The terminfo COLOURMAP setting can be used to translate the internal QM values listed
above to an alternative set relevant to a specific terminal emulator.
Examples
2.11-0
QMBasic 753
This statement displays the value of the STATUS() function in bright red. Further output to the
display will continue to be in this colour until the foreground colour is reset.
2.11-0
754 OpenQM
ABORT
The ABORT statement terminates the current program, returning to the command prompt.
ABORTE and ABORTM provide compatibility with other multivalue database products.
Format
ABORT {message}
where
If an ON.ABORT paragraph is defined in the VOC, this will be executed before the command
prompt is issued.
The program location at which the abort was generated will be reported unless the
SUPPRESS.ABORT.MSG option has been set using the OPTION command.
Because ABORT terminates all active programs, menus, paragraphs, etc., it should only be used to
handle error conditions.
where
message evaluates to the id of a record in the ERRMSG file which holds the message to
be displayed. If this id is numeric, it will be copied to
@SYSTEM.RETURN.CODE.
See the ERRMSG statement for a description of the ERRMSG file message format.
The ABORTE statement always uses Pick style message handling and the ABORTM statement
always uses Information style message handling, regardless of the setting of the PICK.ERRMSG
option.
2.11-0
QMBasic 755
Examples
This statement aborts to the command prompt if the value of the variable NO.OF.ENTRIES is
zero. No error message is printed. ABORT statements without error text messages can result in
difficult diagnostic work to locate faults.
This program fragment attempts to open a file named STOCK.FILE. If the open fails, the program
displays an error message and aborts to the command prompt.
See also:
ERRMSG, STOP
2.11-0
756 OpenQM
ABS()
The ABS() function returns the absolute (positive) value of a numeric expression.
The ABSS() function is similar to ABS() but operates on successive elements of a dynamic array,
returning a similarly structured dynamic array of results.
Format
ABS(expr)
where
The ABS() function returns the absolute value of expr. If expr is positive or zero, the value of
ABS(expr) is expr. If expr is negative, the value of ABS(expr) is -expr.
If expr is a numeric array (a dynamic array where all elements are numeric), the ABS() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Examples
DIFF = ABS(A - B)
This statement assigns DIFF to the difference in value of A and B. The result is positive regardless
of which value is the greater.
A contains 11FM-2VM-8VM4
B = ABSS(A)
B now contains 11FM2VM8VM4
2.11-0
QMBasic 757
ACCEPT.SOCKET.CONNECTION()
Format
ACCEPT.SOCKET.CONNECTION(srvr.skt, timeout)
where
If the action is successful, the function returns a socket variable that can be used to read and write
data using the READ.SOCKET() and WRITE.SOCKET() functions. The STATUS() function
will return zero.
If the socket cannot be opened, the STATUS() function will return an error code that can be used to
identify the cause of the error. If no connection arrives before the timeout period expires, the error
code will be ER$TIMEOUT as defined in the SYSCOM ERR.H include record.
Example
This program fragment creates a server socket, waits for an incoming connection, reads a single
data packet from this connection and then closes the sockets.
See also:
Using Socket Connections, CLOSE.SOCKET, CREATE.SERVER.SOCKET(),
OPEN.SOCKET(), READ.SOCKET(), SELECT.SOCKET(), SERVER.ADDR(),
SET.SOCKET.MODE(), SOCKET.INFO(), WRITE.SOCKET()
2.11-0
758 OpenQM
ACOS()
Format
ACOS(expr)
where
The ACOS() function returns the arc-cosine of expr. Angles are measured in degrees.
If expr is a numeric array (a dynamic array where all elements are numeric), the ACOS() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Examples
This statement finds the angle with cosine equal to the value of ADJ / HYP and assigns this to
variable ANGLE.
See also:
ASIN(), ATAN(), COS(), SIN(), TAN()
2.11-0
QMBasic 759
ALPHA()
The ALPHA() function tests whether a string contains only alphabetic characters.
Format
ALPHA(string)
where
The ALPHA() function returns true (1) if string contains only alphabetic characters (A to Z, a to
z). The function returns false (0) for a null string or a string that contains non-alphabetic
characters.
Example
LOOP
DISPLAY "Enter surname ":
INPUT NAME
WHILE NOT(ALPHA(NAME))
PRINTERR "Name is invalid"
REPEAT
This program fragment prompts for and inputs a name. If the name is null or contains
non-alphabetic characters, an error message is displayed and the prompt is repeated.
See also:
Pattern matching, NUM()
2.11-0
760 OpenQM
ANDS()
The ANDS() function performs a logical AND operation on successive elements of a dynamic
array, returning a similarly structured dynamic array of results.
Format
ANDS(expr1, expr2)
where
The ANDS() function performs the logical AND operation between corresponding elements of the
two dynamic arrays and constructs a similarly structured dynamic array of results as its return
value. An element of the returned dynamic array is 1 if both of the corresponding elements of expr1
and expr2 are true. Any value other than zero or a null string is treated as true.
The REUSE() function can be applied to either or both expressions. Without this function, any
absent trailing values are taken as false.
Examples
A contains 1VM1SM0VM0VM1FM0VM1
B contains 1VM0SM1VM0VM1FM1VM0
C = ANDS(A, B)
See also:
EQS(), GES(), GTS(), IFS(), LES(), LTS(), NES(), NOTS(), ORS(), REUSE()
2.11-0
QMBasic 761
ARG ()
The ARG() function returns and argument value based on its position in the argument list. It is
intended for use with subroutines declared with the VAR.ARGS option.
Format
ARG(n)
where
Subroutines declared with the VAR.ARGS option may have a variable number of arguments.
Although each argument must have a name assigned to it in the SUBROUTINE statement, it is
often useful to be able to process a series of arguments by indexing this list.
The ARG() function returns the value of argument n. The actual number of arguments passed may
be determined using the ARG.COUNT() function. Use of an argument position value less than one
or greater than the number of arguments causes the program to abort.
Example
The above function returns the average of the supplied arguments. Because this function is declared
with the VAR.ARGS option, the ARG.COUNT() function is used to determine the actual number
of arguments and the ARG() function is used to access each argument by its position.
See also:
ARG.COUNT(), ARG.PRESENT(), SET.ARG
2.11-0
762 OpenQM
ARG.COUNT()
The ARG.COUNT() function returns the number of arguments passed into the current subroutine.
It is intended for use with subroutines declared with the VAR.ARGS option.
Format
ARG.COUNT()
When a program calls a subroutine that has been declared with the VAR.ARGS option, the actual
number of arguments passed may be fewer than the number of argument variables in the subroutine
definition. The unused argument variables will be left unassigned. The ARG.COUNT() function
allows a subroutine to determine the number of arguments that have been passed. See the ARG()
function for a way to access arguments by their position in the argument list.
When used in a function, the value returned by ARG.COUNT() excludes the hidden return
argument.
Example
The above function returns the average of the supplied arguments. Because this function is declared
with the VAR.ARGS option, the ARG.COUNT() function is used to determine the actual number
of arguments and the ARG() function is used to access each argument by its position.
See also:
ARG(), ARG.PRESENT(), SET.ARG
2.11-0
QMBasic 763
ARG.PRESENT()
The ARG.PRESENT() function tests whether an argument variable was passed by the caller of a
subroutine or function declared with the VAR.ARGS option.
Format
ARG.PRESENT(var)
where
When a program calls a subroutine or function that has been declared with the VAR.ARGS option,
the actual number of arguments passed may be fewer than the number of argument variables in the
subroutine definition. The unused argument variables will be left unassigned. The
ARG.PRESENT() function allows the subroutine or function to test whether the argument was
passed by the caller. Use of default values for missing arguments does not affect the value returned
by this function.
Example
The above subroutine increments a counter stored in field 2 of a VOC X-type record. If the CT
argument is present in the call to this subroutine, the previous value of the counter is returned via
this argument.
See also:
ARG(), ARG.COUNT(), SET.ARG
2.11-0
764 OpenQM
ASCII()
Format
ASCII(expr)
where
The ASCII() function returns the ASCII equivalent of the supplied EBCDIC string. Characters that
have no ASCII equivalent are returned as question marks.
See also:
EBCDIC()
2.11-0
QMBasic 765
ASIN()
Format
ASIN(expr)
where
The ASIN() function returns the arc-sine of expr. Angles are measured in degrees.
If expr is a numeric array (a dynamic array where all elements are numeric), the ASIN() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
This statement finds the angle with sine equal to the value of OPP / HYP and assigns this to
variable ANGLE.
See also:
ACOS(), ATAN(), COS(), SIN(), TAN()
2.11-0
766 OpenQM
ASSIGNED()
Format
ASSIGNED(var)
where
All QMBasic variables except those in common blocks are initially unassigned. Any attempt to use
the contents of the variable in an expression would cause a run time error until such time as a value
has been stored in it. The ASSIGNED() function allows a program to test whether a variable has
been assigned, returning true (1) if it is assigned or (0) if it is unassigned.
Example
This program fragment validates an account code. The use of the ASSIGNED() function prevents
an abort if the variable has not been assigned.
See also:
UNASSIGNED()
2.11-0
QMBasic 767
ATAN()
Format
ATAN(expr)
where
The ATAN() function returns the arc-tangent of expr. Angles are measured in degrees.
If expr is a numeric array (a dynamic array where all elements are numeric), the ATAN() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
This statement finds the angle with tangent equal to the value of OPP / ADJ and assigns this to
variable ANGLE.
See also:
ACOS(), ASIN(), COS(), SIN(), TAN()
2.11-0
768 OpenQM
BEGIN TRANSACTION
Format
BEGIN TRANSACTION
{statements}
COMMIT / ROLLBACK
...
END TRANSACTION
A transaction is a group of updates that must either be performed in their entirety or not at all. The
BEGIN TRANSACTION statement starts a new transaction. All updates until a corresponding
END TRANSACTION are cached and only applied to the database when a COMMIT statement
is executed. Execution of the program then continues at the statement following the END
TRANSACTION.
The ROLLBACK statement discards any cached updates and continues at the statement following
the END TRANSACTION. A rollback is implied if the program executes the END
TRANSACTION directly.
Testing the value of the STATUS() function immediately after the END TRANSACTION
statement will return 0 if the transaction committed successfully, ER_COMMIT_FAIL if an error
occurred during the commit action, or ER_ROLLBACK if the transaction was rolled back.
Deletes and writes inside a transaction will fail unless the program holds an update lock on the
record or the file. All locks obtained inside the transaction are retained until the transaction
terminates and are then released. Locks already owned when the transaction begins will still be
present after the transaction terminates, even if the record is updated or deleted within the
transaction.
Closing a file inside a transaction appears to work in that the file variable is destroyed though the
actual close is deferred until the transaction terminates and any updates have been applied to the
file. Rolling back the transaction will not reinstate the file variable.
Updates to sequential records opened using OPENSEQ are not affected by transactions.
Example
2.11-0
QMBasic 769
BEGIN TRANSACTION
READU CUST1.REC FROM CUST.F, CUST1.ID ELSE ROLLBACK
CUST1.REC<C.BALANCE> -= TRANSFER.VALUE
WRITE CUST1.REC TO CUST.F, CUST1.ID
The above program fragment transfers money between two customer accounts. The updates are
only committed if the entire transaction is successful.
2.11-0
770 OpenQM
BINDKEY()
The BINDKEY() function sets, removes, queries, saves or restores key bindings.
Format
BINDKEY(key.string, action)
where
key.string The character sequence for the key to be bound, unbound or queried.
The BINDKEY() function used with an action value in the range 0 to 255 binds the key sequence
in key.string to the given action value. This is the underlying mechanism of the KEYEDIT,
KEYEXIT and KEYTRAP statements used to set up keys for special handling by INPUT@ and
INPUTFIELD. If successful, the function returns true (1) and the STATUS() function would
return zero. If an error occurs, the function returns false(0) and the STATUS() function can be
used to find the cause of the error:
1 Invalid key.string
2 Invalid action
3 Key.string conflicts with an existing binding
An action value of -1 removes any defined binding for key.string. Used in this mode, the function
always returns true (1) even if there was no binding for this key.string.
An action value of -2 returns the action number bound to the given key.string. If there is no
binding, the function returns -1.
An action value of -3 returns a string that contains all defined key bindings. The value of key.string
is ignored. Programs should make no assumption about the format of this string as it may change
between releases of QM.
An action value of -4 restores the bindings define in a key.string that was returned by a previous
call to BINDKEY() with an action of -3. This action also restores the state of lone Esc key
handling to its setting at the time when the key bindings were saved.
Actions -5 and -6 control whether the KEYCODE() function returns char(27) on detection of an
incoming Escape character that is not closely followed by further characters. When this mode is
enabled (which is the default), the Esc is returned by KEYCODE() if no further characters are
received within 200mS. When disabled, the Esc is always treated as the start of a control sequence
and KEYCODE() will wait for further characters. These two action codes return true (1) if lone
Esc key handling was previously enabled, or false (0) if it was previously disabled.
2.11-0
QMBasic 771
Because retrieval of a key binding returns -1 if the key is not bound, it is easy to save and restore a
single key binding:
OLD.BINDING = BINDKEY(KEY.STRING, -2)
IF BINDKEY(KEY.STRING, NEW.ACTION) THEN ...
To restore the original binding, unbinding the key if there was no previous binding:
X = BINDKEY(KEY.STRING, OLD.BINDING)
Note that key bindings set using BINDKEY() are lost on return to the command processor. This
ensures that private bindings do not interfere with programs run later in the process. Persistent
bindings can be set by modifying the terminfo database.
See also:
INPUT@, INPUTFIELD, KEYCODE(), KEYEDIT, KEYEXIT, KEYTRAP
2.11-0
772 OpenQM
BITAND()
The BITAND() function forms the bitwise logical AND of two integer values.
Format
BITAND(expr1, expr2)
where
The BITAND() function converts expr1 and expr2 to 32 bit integers and performs a bit-by-bit
logical AND to form a new integer value as the result.
The value of each bit in the result is 1 if same bit position in both of expr1 and expr2 is 1.
Example
IF BITAND(N, 1) THEN N += 1
This statement adds one to N if the least significant bit is 1. The effect is to round N to an even
integer.
See also:
BITNOT(), BITOR(), BITRESET(), BITSET(), BITTEST(), BITXOR(), SHIFT()
2.11-0
QMBasic 773
BITNOT()
The BITNOT() function forms the bitwise logical NOT of an integer value.
Format
BITNOT(expr)
where
The BITNOT() function converts expr to a 32 bit integer and forms a result value by inverting
each bit.
Example
N = BITNOT(A)
See also:
BITAND(), BITOR(), BITRESET(), BITSET(), BITTEST(), BITXOR(), SHIFT()
2.11-0
774 OpenQM
BITOR()
The BITOR() function forms the bitwise logical OR of two integer values.
Format
BITOR(expr1, expr2)
where
The BITOR() function converts expr1 and expr2 to 32 bit integers and performs a bit-by-bit
logical OR to form a new integer value as the result.
The value of each bit in the result is 1 if same bit position in one or both of expr1 and expr2 is 1.
Example
FLAGS = BITOR(FLAGS, 8)
This statement sets the bit with integer value 8 in the FLAGS variable.
See also:
BITAND(), BITNOT(), BITRESET(), BITSET(), BITTEST(), BITXOR(), SHIFT()
2.11-0
QMBasic 775
BITRESET()
Format
BITRESET(expr, bit)
where
The BITRESET() function converts expr to a 32 bit integer and turns off (sets to 0) the bit
identified by bit to form a new integer value as the result. Bits are numbered from 0 to 31 from the
least significant end of the value. The effect of this function with a bit value outside this range is
undefined.
Example
FLAGS = BITRESET(FLAGS, 2)
See also:
BITAND(), BITNOT(), BITOR(), BITSET(), BITTEST(), BITXOR(), SHIFT()
2.11-0
776 OpenQM
BITSET()
Format
BITSET(expr, bit)
where
The BITSET() function converts expr to a 32 bit integer and turns on (sets to 1) the bit identified
by bit to form a new integer value as the result. Bits are numbered from 0 to 31 from the least
significant end of the value. The effect of this function with a bit value outside this range is
undefined.
Example
FLAGS = BITSET(FLAGS, 2)
See also:
BITAND(), BITNOT(), BITOR(), BITRESET(), BITTEST(), BITXOR(), SHIFT()
2.11-0
QMBasic 777
BITTEST()
The BITTEST() function tests the state of a specified bit in an integer value.
Format
BITTEST(expr, bit)
where
The BITTEST() function converts expr to a 32 bit integer and tests the state of the bit identified
by bit, returning true (1) if it is set and false (0) if it is reset. Bits are numbered from 0 to 31 from
the least significant end of the value. The effect of this function with a bit value outside this range is
undefined.
Example
This statement clears the screen if bit 2 is set in the FLAGS variable.
See also:
BITAND(), BITNOT(), BITOR(), BITRESET(), BITSET(), BITXOR(), SHIFT()
2.11-0
778 OpenQM
BITXOR()
The BITXOR() function forms the bitwise logical exclusive-OR of two integer values.
Format
BITXOR(expr1, expr2)
where
The BITXOR() function converts expr1 and expr2 to 32 bit integers and performs a bit-by-bit
logical exclusive-OR to form a new integer value as the result.
The value of each bit in the result is 1 if same bit position in one and only one of expr1 and expr2 is
1.
Example
FLAGS = BITXOR(FLAGS, 8)
This statement inverts the bit with integer value 8 in the FLAGS variable.
See also:
BITAND(), BITNOT(), BITOR(), BITRESET(), BITSET(), BITTEST(), SHIFT()
2.11-0
QMBasic 779
BREAK
The BREAK statement allows the action of the break key to be disabled during program execution.
Format
where
QM maintains a break inhibit counter which is set to zero before the command prompt is first
displayed. This counter is incremented by the BREAK OFF statement and decremented by
BREAK ON though it cannot become negative. Use of the break key whilst the counter is non-zero
will not cause a break action to occur. Instead, the break is remembered and will be handled when
the counter returns to zero. Multiple use of the break key will not result in more than one break
event being handled. The BREAK CLEAR statement cancels any deferred break event.
The BREAK expr format of this statement is equivalent to BREAK OFF if the value of expr is
zero, BREAK ON if expr is positive and BREAK CLEAR if expr is negative.
Example
BREAK OFF
GOSUB UPDATE.FILES
BREAK ON
This program fragment inhibits use of the break key while the internal subroutine UPDATE.FILES
is executed.
See also:
BREAK command, SET.BREAK.HANDLER, REMOVE.BREAK.HANDLER
2.11-0
780 OpenQM
CALL, ENTER
The CALL statement calls a catalogued subroutine. The ENTER statement is a synonym for
CALL unless the PICK.ENTER option of the $MODE directive is used.
Format
where
@var is the name of a variable holding the name of the subroutine to be called.
Direct calls
Placing the subroutine name in the CALL statement is referred to as a direct call. QM will search
for the subroutine as described below when any CALL statement referencing the subroutine is first
executed in the program or subroutine. For CALL statements which occur within catalogued
subroutines the search will take place every time the calling subroutine itself is called. QM includes
an object code caching mechanism to minimise the performance impact of this repeated search.
Indirect calls
Executing a CALL statement using a variable to hold the subroutine name is referred to as an
indirect call. In this case, QM will search for the subroutine as described below when the first
CALL statement is executed. Indirect calls allow an application to call a subroutine where the
name of the routine was not known at compile time. This might be of use, for example, in menu
systems.
When an indirect call is executed, the variable containing the subroutine name is modified to
become a subroutine reference. This can still be used as a string in the program but also contains a
pointer to the memory resident copy of the subroutine. The subroutine will remain in memory so
long as one or more subroutine references point to it. Overwriting the variable will destroy the
subroutine link and may make the subroutine a candidate for removal from the object code cache.
One advantage of indirect calls is that, by placing the variable in a common block where it is
accessible by all modules of the application and will not be discarded, the catalogue search need
only be performed once even when the CALL is in a subroutine which itself may be called many
times. A direct call works in a similar way but the variable in which the subroutine reference is
placed is local to the program containing the CALL and is thus lost when the program terminates.
2.11-0
QMBasic 781
Subroutines to be executed using CALL must be placed in the catalogue using the CATALOGUE
command or the equivalent automated cataloguing from within the QMBasic compiler.
Subroutine names must conform to the QMBasic name formats except that two special prefix
characters are allow. An exclamation mark prefix character is used on all standard globally
catalogued subroutines provided as part of QM that are intended for user use. An asterisk prefix
may be used on user written globally catalogued subroutines for compatibility with other products.
Unless the subroutine name commences with one of the global catalogue prefix characters, QM
goes through a series of steps when a CALL statement searches for a subroutine:
· The local catalogue is checked. This consists of a VOC record of the form
Field 1 V
Field 2 CS
Field 3 Runfile pathname
· The private catalogue file is checked.
· The global catalogue is checked.
Note that subsequent calls to the same subroutine where the subroutine reference has not been reset
will continue to use the original catalogued routine even if it has been deleted from the catalogue or
replaced.
The argument list may contain up to 255 items. If a subroutine has no arguments, the brackets may
be omitted.
Each argument is
A constant CALL SUB("MY.FILE")
An expression CALL SUB(X + 7)
A variable name CALL SUB(X)
An indexed matrix element name CALL SUB(A(5,2))
A matrix name prefixed by MAT CALL SUB(MAT A)
Where the argument is a reference to a variable, a matrix element or a whole matrix, the subroutine
may update the values in these variables. Except when passing a whole matrix, the calling program
can effectively prevent this by forcing the argument to be passed by value rather than by reference
by enclosing it in brackets, thus making the argument into an expression.
If the FORCE.RELOAD mode of the OPTION command is in effect, this mechanism is extended
such that all subroutine link variables are reset. The next call to the subroutine will reload the object
code. This allows dynamic modification of an application in a production environment but carries
the risk that a simple loop such as
FOR I = 1 TO 5
CALL MYSUB
2.11-0
782 OpenQM
NEXT I
might call a different version of MYSUB from one iteration of the loop to the next.
Note that the event causes all subroutine links to be reset, not just those for the program that has
been compiled or catalogued. Note also that the FORCE.RELOAD option must be set in the QM
session that is to perform the reload, not necessarily in the session that compiles or catalogues the
program.
By default, the ENTER statement is a synonym for CALL. Use of the PICK.ENTER option of
the $MODE compiler directive causes ENTER to behave in the same way as its equivalent in Pick
style multivalue database products.
In this mode, use of ENTER terminates the current program and replaces it with the named
program. This new program may not take arguments. If the ENTER statement is performed in a
program that was started using the EXECUTE statement, or a subroutine called from such a
program, the ENTER does not discard the program containing the EXECUTE.
Examples
This program fragment declares a common block to hold subroutine call references. When the
program is first executed, the conditional statements will be performed as common block variables
are initially zero. This path sets the name of the subroutine SUBR1 into common variable SUB1.
Later in the program, perhaps in a different subroutine from that in which the common was
initialised, a statement of the form
will call the SUBR1, changing the common variable to be a subroutine reference for fast access on
subsequent calls.
would call the same subroutine but does not use the common block variable. If this call was in a
subroutine, the catalogue search would be performed for the first call each time the calling
subroutine is entered.
See also:
CATALOGUE
2.11-0
QMBasic 783
CASE
The CASE statement provides conditional execution dependant on the result of expression
evaluation.
Format
BEGIN CASE
CASE expr
statement(s)
CASE expr
statement(s)
END CASE
where
The expressions are evaluated in turn until one evaluates to true. The statements associated with
that test expression are then executed and control passes to the statement following the END CASE
. Only one of the statement groups is executed. If none of the test expressions evaluates to true, no
statements are executed.
It is frequently useful to execute a default set of statements where no specific test expression results
in non-zero result. This can be achieved by a case of the form
CASE 1
which makes use of the fact that 1 is the value of the boolean True. This must be the final element
of the CASE statement.
Example
N = DCOUNT(ITEMS, @VM)
BEGIN CASE
CASE N = 0
DISPLAY "There are no items"
CASE N = 1
DISPLAY "There is 1 item"
CASE 1
DISPLAY "There are " : N : " items"
END CASE
This program fragment displays a message indicating the number of values in the ITEMS variable.
Note the use of the CASE 1 construct.
2.11-0
784 OpenQM
CATALOGUED()
The CATALOGUED() function determines whether a subroutine can be found using the search
process described for the CALL statement.
Format
CATALOGED(name)
where
Where a subroutine name appears in more than one catalogue form, the search order is as in the list
above and the value returned reflects the first entry found.
The return value from the CATALOGUED() function can be treated as a boolean (true/false)
value if the application merely wants to determine if a subroutine is catalogued and does not need to
know in which format.
Example
See also:
CATALOGUE, CALL
2.11-0
QMBasic 785
CATS()
Format
CATS(string1, string2)
where
The CATS() function returns the result of concatenating corresponding dynamic array components
(fields, values and subvalues) from the supplied strings.
The REUSE() function can be applied to either or both expressions. Without this function, any
absent trailing values are taken as null strings.
Examples
S1 = "ABC":@fm:"DEF"
S2 = "123":@vm:"456":@fm:"789"
X = CATS(S1,S2)
Note that this example has both field and value marks. The above code fragment concatenates
elements of the two strings yielding a result in X of "ABC123VM456FMDEF789"
S1 = "ABC":@fm:"DEF"
S2 = "123":@fm:"456":@fm:"789"
X = CATS(S1,S2)
This example concatenates elements of the two strings yielding a result in X of "ABC123FMDEF456
FM789"
S1 = "ABC":@fm:"DEF"
S2 = "123":@fm:"456":@fm:"789"
X = CATS(REUSE(S1),S2)
Adding the REUSE() function to the previous example gives a result in X of "ABC123FMDEF456FM
DEF789"
2.11-0
786 OpenQM
CHAIN
The CHAIN statement terminates the current program and executes a command.
Format
CHAIN expr
where
The current program terminates immediately, discarding local variables but retaining named
common variables. The command defined by expr is executed as though it replaced the sentence
which invoked the program in which the CHAIN statement occurs. If this sentence is in a
paragraph, the remainder of the paragraph will be executed when the CHAIN'ed program
terminates.
The exact behaviour of CHAIN when executed from a program started by a PROC depends on the
VOC record type of the target item referenced by expr. If this is a further PROC, any stacked
PROCs leading up to the program that performed the CHAIN are discarded. If the target is not a
PROC, control will return to the PROC that executed the program performing the CHAIN when
the chained command terminates.
CHAIN is provided primarily for compatibility with other systems. The same effect can usually be
better achieved using EXECUTE.
Examples
This program fragment terminates the current program and executes PROGRAM2 in its place.
2.11-0
QMBasic 787
CHANGE()
The CHANGE() function replaces occurrences of a substring within a string by another substring.
The synonym SWAP() can be used.
Format
where
The CHANGE() function replaces the specified occurrences of old within string by new.
If old is a null string, the function returns string unchanged. If new is a null string, all occurrences
of old are removed.
If the $NOCASE.STRINGS compiler directive is used, matching of old against string is case
insensitive.
Examples
See also:
CONVERT()
2.11-0
788 OpenQM
CHAR()
The CHAR() function returns the character with a given ASCII value.
Format
CHAR(seq)
where
The CHAR() function returns a single character string containing the ASCII character with value
seq. It is the inverse of the SEQ() function.
Only the least significant 8 bits of the integer value of seq are used. Values outside the range 0 to
255 may behave differently on other systems and should not be relied on.
Example
DISPLAY CHAR(7):
This statement outputs character 7 of the ASCII character set to the display. Character 7 is the
BELL character and causes the audible warning to sound. This is similar to use of the
@SYS.BELL variable except that CHAR(7) is not affected by use of the BELL OFF verb and will
always work.
See also:
SEQ()
2.11-0
QMBasic 789
CHECKSUM()
Format
CHECKSUM(data)
where
The CHECKSUM() function calculates a checksum value for the supplied data item. Note that the
algorithm used by QM may be different from that of other multivalue products and hence may yield
a different result for the same data.
Example
DISPLAY CHECKSUM(REC)
This statement displays a checksum value for the data in the REC variable.
See also:
MD5()
2.11-0
790 OpenQM
CHILD()
The CHILD() function tests whether a phantom process started from the current session is still
running.
Format
CHILD(userno)
where
The CHILD() function allows a process that started a phantom process to determine whether the
phantom is still running. The userno argument is the user number of the phantom process as
returned by the PHANTOM command via the @SYSTEM.RETURN.CODE variable.
The CHILD() function returns true (1) if there is a phantom process running with the given user
number that was started by the process in which the CHILD() function is executed. In all other
cases, the function returns false (0). The CHILD() function cannot be used to test the state of
phantoms started by other sessions.
Example
This program fragment starts a phantom to run the END.OF.MONTH program, does some further
processing, and then tests whether the phantom is still active.
See also:
LIST.PHANTOMS, PHANTOM, !PHLOG(), STATUS
2.11-0
QMBasic 791
CLASS
Format
where
limit is the maximum number of arguments allowed in public function and subroutines
within the class module. This defaults to 32 and cannot exceed 255.
class.list is a comma separated list of the catalogue names of classes to be inherited by this
class. These should not be enclosed in quotes.
The CLASS statement must appear before any executable statements. For more details, see Object
Oriented Programming.
The name need not be related to the name of the source record though it is recommended that they
are the same as this eases program maintenance. The name must comply with the QMBasic name
format rules.
A class module contains the components of a QMBasic object. The general structure of this is
CLASS name
PUBLIC A, B(3), C
PRIVATE X, Y, Z
The MAX.ARGS option can be used to increase the default limit on the number of arguments
permitted in a public function or subroutine within the class module. This has a small effect on
performance and should only be used where the default value of 32 needs to be exceeded.
2.11-0
792 OpenQM
The INHERITS option causes the named class or classes to be inherited automatically by this class
when it is instantiated.
See also:
Object oriented programming, DISINHERIT, INHERIT, OBJECT(), OBJINFO(), PRIVATE,
PUBLIC.
2.11-0
QMBasic 793
CLEAR
Format
CLEAR
All local variables, including all elements of matrices, are set to zero. Files associated with local file
variables will be closed. The value of variables in common areas are not affected.
Subroutine arguments that are passed by reference will set the corresponding variable in the calling
program to zero.
See also:
CLEARCOMMON
2.11-0
794 OpenQM
CLEARCOMMON
The CLEARCOMMON statement sets all variables in the unnamed common area to zero. Used
with a common block name, it clears the named common.
Format
CLEARCOMMON {name}
If name is omitted, all variables in the unnamed common area are set to zero. Other variables are
not affected.
If name is present, it must be the name of a common block defined in the program. All variables in
this common block will be cleared.
Examples
COMMON A,B,C
CLEARCOMMON
All variables in the unnamed common area (A, B and C) are set to zero.
COMMON /MYDATA/P,Q,R
CLEARCOMMON MYDATA
All variables in the MYDATA common block (P, Q and R)are set to zero.
See also:
CLEAR, COMMON
2.11-0
QMBasic 795
CLEARDATA
The CLEARDATA statement clears any data stored by previous DATA statements or DATA
verbs and not yet processed by INPUT statements.
Format
CLEARDATA
The data queue is cleared. Any keyboard type-ahead is not affected by this statement. The
CLEARDATA statement is most useful when recovering from error situations where the data
queue could cause problems.
Example
ERROR.LABEL:
CLEARDATA
ABORT "A fatal error has occurred"
This program fragment could be used to ensure that the data queue is empty when aborting at some
error condition.
See also:
CLEAR.DATA command
2.11-0
796 OpenQM
CLEARFILE
The CLEARFILE statement clears a file previously opened using the OPEN statement, deleting
all records.
Format
where
The file associated with the file variable will be cleared. All records are deleted from the file,
contracting the file to its minimum modulus size and releasing disk space.
The ON ERROR clause is executed if the file cannot be cleared for any reason. The STATUS()
function may be used to find the cause of such an error.
Note that the CLEARFILE statement executes the clear file trigger function, not the delete trigger
function if one is defined.
Example
This program fragment opens a file, clears it and then closes the file.
2.11-0
QMBasic 797
CLEARINPUT
The CLEARINPUT statement clears any keyboard data that has been entered but not yet
processed by INPUT or KEYIN() statements.
Format
CLEARINPUT
CLEAR INPUT
Any type-ahead data is cleared. Data stored by the DATA statement is not affected.
Example
ERROR.LABEL:
CLEARINPUT
ABORT "A fatal error has occurred"
This program fragment could be used to ensure that data entered at the keyboard is cleared when
aborting at some error condition.
2.11-0
798 OpenQM
CLEARSELECT
Format
CLEARSELECT {list.no}
CLEARSELECT ALL
CLEARSELECT var
where
list.no evaluates to the number of the select list to be cleared. If omitted, select list zero is
cleared.
Select lists are numbered from 0 to 10. Where no list number is specified, the default is to use select
list 0.
The CLEARSELECT statement clears the specified numbered select list if it was active. Use of
the ALL keyword causes all select lists to be cleared.
Example
CLEARSELECT 2
2.11-0
QMBasic 799
CLOSE
The CLOSE statement closes a file previously opened using the OPEN or OPENPATH
statement.
Format
where
The file associated with the file variable will be closed. Any other file variable which refers to the
same file, either from a separate OPEN or from copying the file variable, will be unaffected.
The ON ERROR clause is provided for source program compatibility with other systems and will
never be executed by QMBasic programs.
Files do not always need to be closed explicitly. Local variables are released when a program or
subroutine returns and files associated with local file variables are closed automatically. File
variables in common areas will not be affected.
Closing a file inside a transaction destroys the file variable but defers the actual close until the
transaction ends. Rolling back the transaction will not reinstate the file variable.
Example
This program fragment opens a file, processes it and then closes the file.
2.11-0
800 OpenQM
CLOSE.SOCKET
Format
CLOSE.SOCKET skt
where
See also:
Using Socket Connections, ACCEPT.SOCKET.CONNECTION,
CREATE.SERVER.SOCKET(), OPEN.SOCKET(), READ.SOCKET(),
SELECT.SOCKET(), SERVER.ADDR(), SET.SOCKET.MODE(), SOCKET.INFO(),
WRITE.SOCKET()
2.11-0
QMBasic 801
CLOSESEQ
Format
where
file.var is the file variable previously associated with the directory file record or device
by use of the OPENSEQ statement.
The ON ERROR clause is provided for source program compatibility with other systems and will
never be executed by QMBasic programs.
The CLOSESEQ and CLOSE statements can be interchanged without adverse effect in QMBasic
programs, however, care should be taken to use the correct statement if portability to other systems
is required.
Example
CLOSESEQ STOCK.LIST
This statement closes a directory file record previously opened using OPENSEQ and associating it
with STOCK.LIST as the file variable.
See also:
CREATE, NOBUF, OPENSEQ, READBLK, READSEQ, SEEK, WEOFSEQ WRITEBLK,
WRITESEQ, WRITESEQF
2.11-0
802 OpenQM
COL1()
The COL1() function returns the character position immediately preceding the substring extracted
by the last FIELD() function.
Format
COL1()
The COL1() function is used after a FIELD() function to find the character position of the
character immediately preceding the extracted substring.
The value of the COL1() function is maintained on a per-program basis. If an external subroutine
is called between the FIELD() and COL1() functions, the value returned relates to the last use of
FIELD() in the current program. Any FIELD() functions executed by the subroutine will have no
effect on the COL1() value.
Example
S = "A*BB*CCC*DDDD*EEEEE"
X = FIELD(S, "*", 3, 2)
N = COL1()
This program fragment extracts the string "CCC*DDDD" to variable X. The COL1() function
returns 5 and assigns this to N.
See also:
COL2(), FIELD()
2.11-0
QMBasic 803
COL2()
The COL2() function returns the character position immediately following the substring extracted
by the last FIELD() function.
Format
COL2()
The COL2() function is used after a FIELD() function to find the character position of the
character immediately following the extracted substring.
The value of the COL2() function is maintained on a per-program basis. If an external subroutine
is called between the FIELD() and COL2() functions, the value returned relates to the last use of
FIELD() in the current program. Any FIELD() functions executed by the subroutine will have no
effect on the COL2() value.
Example
S = "A*BB*CCC*DDDD*EEEEE"
X = FIELD(S, "*", 3, 2)
N = COL2()
This program fragment extracts the string "CCC*DDDD" to variable X. The COL2() function
returns 14 and assigns this to N.
See also:
COL1(), FIELD()
2.11-0
804 OpenQM
COMMON
Format
where
The COMMON statement is used to define variables as being in common blocks, that is, memory
areas that may be used to pass data between different programs and subroutines.
The variable names may extend over multiple lines by splitting the statement after a comma. For
example
COMMON/VARS/ VAR1
COMMON/VARS/ VAR2
COMMON/VARS/ VAR3
COMMON/VARS/ VAR4
The compiler assumes that definitions of variables with the same common block name are a
continuation of previous definitions in the same block.
Common blocks are identified by the name that is used in the COMMON statement. The name of a
common block must conform to the same rules as a variable name. Multiple programs in the same
process using the same name share the same variables. Named common blocks are created on the
first reference to the name and remain in existence until exit from QM. There is also a common
block with no name (unnamed common) which may be referred to by a COMMON statement of
the form
The unnamed common block is associated with a single command and is discarded on termination
of the command that created it. Use of the EXECUTE statement saves and removes any current
unnamed common and restores it on completion of the executed command.
A common block may contain any number of variables but the number of variables may not be
increased by later redefinition. It is valid for a program to define fewer variables than in the original
common block declaration. This is useful if a new item has been added at the end of a common
block but not all programs have yet been recompiled.
2.11-0
QMBasic 805
Variables within a common block are referenced internally by position, not by name. Thus it would
be possible (though not recommended) for different programs to use different names when accessing
the same common block. Normally, the structure of a common block is best defined in an include
record so that the same definition is used by all parts of the application.
By default, the variables in a common block are initialised to integer zero when the block is created.
It is thus possible to include QMBasic code to perform further initialisation just once by statements
of the form
For compatibility with some other systems, the UNASSIGNED.COMMON option of the $MODE
compiler directive can be used to specify that common blocks are to be created with their
component variables left unassigned instead of being set to zero. This directive only affects the
program that actually creates the common block (i.e. the first program executed that references the
common). It has no effect if the common has already been created. It is possible for an application
to mix assigned and unassigned common by careful placement of the $MODE directive.
Common blocks may contain matrices. These are defined by including the row and column bounds
in the COMMON statement, for example
QM supports two styles of matrix with different characteristics. The $MODE compiler directive
can be used to select Pick style matrices.
The default style of matrix includes a zero element and is resizeable. A common block declared as
COMMON A,B(3),C
has three variables, one of which is a matrix:
A matrix of this type in a common block can be redimensioned by a later DIM statement.
Pick style matrices do not have a zero element and cannot be resized. A matrix of this type in a
common block is equivalent to a series of simple variables:
2.11-0
806 OpenQM
Although not recommended, three programs could use very different views of the same five element
common block when using Pick style matrices:
COMMON A,B(3),C
COMMON X(2),Y,Z(2)
COMMON P,Q,R,S,T
See also:
CLEARCOMMON
2.11-0
QMBasic 807
COMPARE(), COMPARES()
The COMPARE() function compares two strings using the same rules as the LOCATE statement
and the SORT verb. The COMPARES() function is similar but operates on a multivalued list of
strings.
Format
where
justification evaluates to a string where the first character is "L" for left justified
comparison or "R" for right justified comparison. If omitted or invalid, left
justification is used.
For a left justified comparison, characters are compared one by one and the function return value is
determined by the relative ASCII character set positions of the characters at which the first
mismatch occurs. If the strings are of different lengths and match up to the end of the shorter, the
longer string is treated as the greater.
For a right justified comparison, the COMPARE() function behaves as though sufficient spaces
were inserted at the start of the shorter string to match the length of the longer string. Characters are
then compared one by one and the function return value is determined by the relative ASCII
character set positions of the characters at which the first mismatch occurs.
The COMPARE() function is not affected by the setting of the $NOCASE.STRINGS compiler
directive and can therefore be used to force a case sensitive comparison in otherwise case insensitive
programs..
The COMPARES() function treats string1 as a dynamic array, comparing each element in turn
with string2 and returning a similarly structured dynamic array of results.
Examples
A = 0
B = '00'
DISPLAY A = B
DISPLAY COMPARE(A,B)
2.11-0
808 OpenQM
In the above example, use of the relational equals operator will see A and B as equal because both
items can be treated as numbers. B is converted to a number (0) and a numeric comparison is
performed. Use of the COMPARE() function always treats the items as character strings. A is
converted to a string and the two items are compared as left aligned strings, reporting that they are
unequal.
DIM ITEM(100)
ITEMS = 0
LOOP
INPUT NEW.ITEM
WHILE LEN(NEW.ITEM)
* Find position to insert new item
I = 1
LOOP
WHILE I <= ITEMS
IF COMPARE(NEW.ITEM, ITEM(I)) < 0 THEN EXIT
I += 1
REPEAT
This program fragment creates a matrix, ITEMS, and then enters a loop to read NEW.ITEM values
from the keyboard until a blank line is entered. Each item read is inserted into the matrix in its
correct position to maintain the matrix in ascending collating sequence order. Additional statements
to detect and handle matrix overflow would be useful in a full application.
A = 'AAA':@VM:'BBB':@FM:'CCC'
X = COMPARES(A, 'BBB')
The above program fragment returns X as "-1VM0FM1". Note how the mark characters used to
delimit A have been replicated in X.
2.11-0
QMBasic 809
CONFIG()
Format
CONFIG(param)
where
The CONFIG() function can be used to retrieve the value of configuration parameters defined in
the QM configuration file. The STATUS() function will return zero if successful.
Configuration parameters that may be repeated within the configuration file (e.g. STARTUP) are
returned as a dynamic array with each entry as a separate field. This does not apply to parameters
that are defined as additive numeric values (e.g. NETFILES) where the composite result is returned.
If param is not recognised as a configuration parameter name, the function returns a null string and
the STATUS() function will return ER$NOT.FOUND.
Example
GS = CONFIG("GRPSIZE")
This statement returns the value of the GRPSIZE configuration parameter, the default group size
used when creating a dynamic file.
2.11-0
810 OpenQM
CONNECT.PORT()
The CONNECT.PORT() function converts a phantom process into an interactive session, using a
serial port as its terminal device.
Format
where
parity specifies the parity setting for the connection (0 = none, 1 = odd, 2 = even).
The CONNECT.PORT() function enables an application to start a phantom process that then uses
a serial port as though it were a terminal device. The function returns true (1) if successful, false (0)
if it fails. The STATUS() function can be used to determine the cause of failure.
Once the connection has been created, the process changes from a phantom to an interactive session
and can use the normal QMBasic terminal i/o statements such as INPUT and PRINT to access the
port. If the program exits to the command processor, the connection can be used in exactly the same
way as if the user had logged in over the serial port. To terminate the session from within a
program, execute the QUIT command.
Because this function converts the phantom process into an interactive user, the process consumes a
licence. The CONNECT.PORT() function will fail if the user limit has been reached.
Example
This program fragment, used in a phantom process, connects to the device on the COM1 port as the
command source, converting the process into an interactive session.
2.11-0
QMBasic 811
CONTINUE
Format
CONTINUE
The CONTINUE statement is equivalent to a jump to the REPEAT or NEXT statement of the
innermost loop structure.
Example
LOOP
REMOVE ITEM FROM STOCK SETTING DELIM
...processing statements...
WHILE DELIM
IF ITEM[1,1] = "A" THEN CONTINUE
...further statements...
REPEAT
This program fragment processes items extracted from the STOCK dynamic array. If the value of
ITEM commences with "A", the section marked ...further statements... is omitted.
See also:
EXIT, FOR/NEXT, LOOP/REPEAT
2.11-0
812 OpenQM
CONVERT
The CONVERT statement and CONVERT() function replace selected characters by others in a
string. The CONVERT statement performs this conversion in-situ; the CONVERT() function
leaves the source string unchanged and returns the modified value.
Format
where
The statement
S = CONVERT(X, Y, S)
is equivalent to
CONVERT X TO Y IN S
Characters taken from the from.string and to.string define character translations to be performed.
Each occurrence of a character from from.string in var (or src.string) is replaced by the character
in the same position in to.string. If to.string is shorter than from.string, characters for which there
is no replacement character are deleted. If to.string is longer than from.string the surplus characters
are ignored.
If a character appears more than once in from.string only the first occurrence is used.
If the $NOCASE.STRINGS compiler directive is used, matching of from.string against var is case
insensitive.
Examples
S = "ABCDEFGHIJK"
CONVERT "CGAGJ" TO "123" IN S
This program fragment replaces all occurrences of the letter "C" in S by "1", "G" by "2" and "A" by
"3". The second occurrence of "G" in the from.string is ignored. The letter "J" is deleted from S.
The result of this operation is to set S to "3B1DEF2HIK".
2.11-0
QMBasic 813
This statement prints the string S with all spaces replaced by # characters.
LOOP
INPUT ISBN,13_:
UNTIL CONVERT('0123456789X-', '', ISBN) = ''
INPUTERR 'Invalid ISBN'
REPEAT
The loop above verifies that the data entered by the user contains only digits, the letter X and
hyphens. The CONVERT() function is used to return a copy of the input data with all valid
characters removed. If the result string is not null, it must contain an invalid character.
See also:
CHANGE()
2.11-0
814 OpenQM
COS()
Format
COS(expr)
where
The COS() function returns the cosine of expr. Angles are measured in degrees.
If expr is a numeric array (a dynamic array where all elements are numeric), the COS() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
This statement finds the length of the adjacent side of a right angled triangle from the length of the
hypotenuse and the angle between these two sides.
See also:
ACOS(), ASIN(), ATAN(), SIN(), TAN()
2.11-0
QMBasic 815
COUNT()
The COUNT() function counts occurrences of a substring within a string. The COUNTS()
function is similar to COUNT() but operates on successive elements of a dynamic array, returning
a similarly structured dynamic array of results.
Format
COUNT(string, substring)
COUNTS(string, substring)
where
The COUNT() function counts occurrences of substring within string. Substrings may not overlap,
thus
S = "ABABABABABAB"
N = COUNT(S, "ABA")
sets N to 3.
Programs compiled with the $NOCASE.STRINGS compiler directive use case insensitive string
comparisons in the COUNT() and COUNTS() functions.
Example
See also:
DCOUNT()
2.11-0
816 OpenQM
CREATE
The CREATE statement creates an empty directory file record after a previous OPENSEQ has
reported that the record did not exist.
Format
CREATE file.var
{ON ERROR statement(s)}
{THEN statement(s)}
{ELSE statement(s)}
where
file.var is the file variable associated with the record by a previous OPENSEQ
statement.
The ON ERROR clause is taken in the event of a fatal error that would otherwise cause the
program to abort.
At least one of the THEN and ELSE clauses must be present. The THEN clause is executed if the
operation is successful. The ELSE clause is executed if the CREATE operation fails.
Example
This program fragment attempts to open a sequential file record. If the OPENSEQ fails because
the record does not exist, an empty record is created.
See also:
CLOSESEQ, NOBUF, OPENSEQ, READBLK, READCSV, READSEQ, SEEK,
WEOFSEQ, WRITEBLK, WRITECSV, WRITESEQ, WRITESEQF
2.11-0
QMBasic 817
CREATE.FILE
Format
where
minmod is the minimum modulus value. For compatibility with the CREATE.FILE
command, the synonym MINIMUM.MODULUS may be used.
Example
This statement creates a dynamic hash file with group size 4 (4096 bytes) as the C:\MYFILE
directory.
2.11-0
818 OpenQM
CREATE.SERVER.SOCKET
Format
where
addr is the address on which to listen for incoming connections. This may be an IP
address or a host name. A null string implies listen on any local address.
flags is a flag value formed from the additive values below. For compatibility with
earlier releases, this may be omitted and defaults to a TCP stream connection. The
token values are defined in the SYSCOM KEYS.H include record.
Socket type, one of:
SKT$STREAM A stream connection (default)
SKT$DGRM A datagram type connection
Protocol, one of:
SKT$TCP Transmission Control Protocol (default)
SKT$UDP User Datagram Protocol
If the action is successful, this function returns the socket variable associated with the new server
port and the STATUS() function returns zero.
If unsuccessful, the STATUS() function returns an error code that can be used to determine the
cause of failure.
Example
This program fragment creates a server socket, waits for an incoming connection, reads a single
data packet from this connection and then closes the sockets.
See also:
2.11-0
QMBasic 819
2.11-0
820 OpenQM
CROP()
Format
CROP(string)
where
string evaluates to the string from which mark characters are to be removed.
The CROP() function removes redundant mark characters from string. These are all mark
characters after the final non-mark character, trailing subvalue marks within each value and trailing
value marks within each field.
Example
REC = CROP(REC)
2.11-0
QMBasic 821
CSVDQ()
Format
CSVDQ(string {, delimiter})
where
delimiter is the delimiter character separating the elements of the string. This defaults to a
comma if omitted.
The CSVDQ() function dequotes a CSV string, removing outer double quotes, handling embedded
quotes and returning the result as a dynamic array where each element of the original string is
represented by a separate field. This is in accordance with the CSV format specification (RFC
4180).
Example
S = 'ABC,"DEF","GHI,JKL","MN""O"'
DISPLAY CSVDQ(S)
See also:
READCSV, WRITECSV
2.11-0
822 OpenQM
DATA
The DATA statement adds one or more items to the input data queue
Format
where
Where multiple expr clauses are present, they may be spread over successive lines by inserting a
newline between a comma and the subsequent item. Any number of expr clauses may be present.
The INPUT statement takes data provided by DATA statements in preference to reading from the
keyboard. Keyboard input is only used if there is no data from DATA statements remaining to be
processed. The KEYIN() function always takes its input from the keyboard.
The data stream generated by successive DATA statements is held in the @DATA.PENDING
variable which may be read by programs. This variable contains the individual data items separated
by item marks. For this reason, DATA statement items should not include item marks as these will
be taken as separators.
Example
123
456
789
and then echo data typed at the keyboard until a blank line is entered.
See also:
CLEARDATA, DATA command
2.11-0
QMBasic 823
DATE()
The DATE() function returns the internal value of the current date.
Format
DATE()
The DATE() function returns the day number of the current date within the user's time zone. Day
numbers are defined such that 31 December 1967 is day zero. Date values representing dates earlier
than this are negative.
Example
INVOICE.REC<7> = DATE()
This statement assigns field 7 of INVOICE.REC with the internal date value of the current day.
See also:
@DATE, EPOCH(), TIME()
2.11-0
824 OpenQM
DCOUNT()
Format
DCOUNT(string, delimiter)
where
The DCOUNT() function counts substrings delimited by delimiter within string. Substrings may
not overlap, thus
S = "ABABABABABABA"
N = DCOUNT(S, "BAB")
sets N to 4.
If string is null, DCOUNT() returns zero. In all other cases, DCOUNT() returns a value one
greater than the COUNT() function applied to the same string.
Programs compiled with the $NOCASE.STRINGS compiler directive use case insensitive string
comparisons in the DCOUNT() function.
Example
See also:
COUNT()
2.11-0
QMBasic 825
DEBUG
Format
DEBUG
The DEBUG statement enters debug mode for the program in which it was executed and all
programs called by it. This statement causes a compile time warning but is otherwise ignored if the
program is not complied with the DEBUGGING option or use of the $DEBUG compiler directive.
Example
The above statement would enter the debugger if the user running the program is logged is as
mjones.
See also:
QMBasic debugger
2.11-0
826 OpenQM
DECRYPT()
The DECRYPT() function decrypts data that has been encrypted for secure storage or
transmission.
Format
DECRYPT(data, key)
where
The DECRYPT() function applies the AES 128 bit encryption algorithm to the supplied data and
returns the decrypted text. The key string may be up to 64 characters in length and may contain any
character. It is automatically transformed into a form that is useable by the AES algorithm. For
optimum data security, the key should be about 16 characters.
The encrypted data is structured so that it can never contain characters from the C0 control group
(characters 0 to 31) or the mark characters. As a result of this operation, the encrypted data is
slightly longer than the resultant decrypted data.
Example
FUNCTION LOGIN()
OPEN 'USERS' TO USR.F ELSE
DISPLAY 'Cannot open USERS file'
RETURN @FALSE
END
DISPLAY 'User name: ' :
INPUT USERNAME, 20_:
READ USER.REC FROM USR.F THEN
FOR I = 1 TO 3
DISPLAY 'Password: ' :
INPUT PW,20_: HIDDEN
IF PW = DECRYPT(USR.REC<1>, 'MySecretKey') THEN RETURN
@TRUE
DISPLAY 'Password incorrect'
NEXT I
END
RETURN @FALSE
END
The above function prompts for a user name and password, validating these against a record in the
USERS file. The password field of this file is encrypted.
See also:
Data encryption, ENCRYPT()
2.11-0
QMBasic 827
DEFFUN
Format
DEFFUN name {(arg1 {,arg2 ...})} {CALLING "subr" | LOCAL} {VAR.ARGS} {KEY
key}
where
The DEFFUN statement defines a function that may be called from within the program. The
DEFFUN statement must appear before the first reference to the function. If the function name
matches the name of a built in function, any references to name before the DEFFUN will call the
intrinsic function and references after the DEFFUN will call the declared function.
If the LOCAL keyword is not present, the function must correspond to a catalogued item. A call to
this function call is effectively translated to a call to a subroutine with an additional hidden first
argument through which the result is returned. The optional CALLING component of the
DEFFUN statement allows the catalogue name of the function to be different from the name of the
function itself.
Use of the LOCAL keyword indicates that this function is internal to the program module and will
be defined later in the source by use of the LOCAL FUNCTION statement.
The argument names used in the DEFFUN statement are for documentation purposes only and have
no significance within the program except that the compiler counts them to verify correct use of the
function. The variables used in the actual call to the function are determined by the use of the
function. An argument may be defined to be a whole matrix in which case it should be prefixed by
the keyword MAT in the DEFFUN argument list.
The function is used in the same way as the intrinsic functions described in this manual. Although it
is not recommended, a function can update its argument variables.
The VAR.ARGS option indicates that compiler should not check the number of arguments in calls
to the function. It is of use with functions that take variable length argument lists. This option
cannot be used with local function.
The KEY option passes the key value as an additional argument before the first one named in calls
to the function. This enables construction of multiple functions that call a single catalogued item
with a mode key as the first argument. The !PCL() function provided in the BP file of the QMSYS
account uses this feature to implement the various PCL functions defined in the SYSCOM PCL.H
include record.
2.11-0
828 OpenQM
Example
DEFFUN MATMAX(MAT A)
DIM VALUES(100)
...
MAX = MATMAX(MAT VALUES)
The program fragment above uses the MATMAX() function to find the maximum value of all the
elements of matrix VALUES.
See also:
FUNCTION, LOCAL
2.11-0
QMBasic 829
DEL
The DEL statement and DELETE() function delete a field, value or subvalue from a dynamic
array.
Format
where
value evaluates to the number of the value to be deleted. If omitted or zero, the entire
field is deleted.
subvalue evaluates to the number of the subvalue to be deleted. If omitted or zero, the
entire value is deleted.
The specified field, value or subvalue is deleted from the dynamic array. The DEL statement
assigns the result to the dyn.array variable. The DELETE() function returns the result without
modifying dyn.array.
Example
DEL ITEMS<1,N>
S = DELETE(ITEMS, 1, N)
This statement is similar to the previous example except that the result is assigned to S, leaving
ITEMS unchanged.
See also:
EXTRACT(), FIND, FINDSTR, INS, INSERT(), LISTINDEX(), LOCATE, LOCATE(),
REPLACE()
2.11-0
830 OpenQM
DELETE
The DELETE statement deletes a record from an open file. The DELETEU statement is similar
but it preserves locks.
Format
where
The specified record is deleted from the file. No error occurs if the record does not exist.
If the process performing the DELETE had a read or update lock on the record, the lock is
released. The DELETEU statement preserves any lock. Within a transaction, the lock is retained
until the transaction terminates and then released regardless of which statement is used. Attempting
to delete a record in a transaction will fail if the process does not hold an update lock on the record
or the file.
The STATUS() function can be used to determine the cause of execution of the ON ERROR
clause. A fatal error occurring when no ON ERROR clause is present will cause an abort to occur.
Example
This statement deletes the record whose id is in ITEM.ID from the file associated with file variable
STOCK.
2.11-0
QMBasic 831
DELETELIST
The DELETELIST statement deletes a select list from the $SAVEDLISTS file.
Format
DELETELIST name
where
The DELETELIST statement restores the previously saved select list identified by name from the
$SAVEDLISTS file. No error occurs if the list does not exist.
2.11-0
832 OpenQM
DELETESEQ
Format
where
filename evaluates to the VOC name of the directory file holding the record to be
deleted.
The DELETESEQ statement deletes the operating system file identified by filename and id or by
pathname. It is primarily intended as a counterpart to OPENSEQ but can be used to delete any
operating system file.
The ELSE clause will be executed for conditions that most likely relate to user or programming
errors such as the item to delete not existing or not having access rights to delete it. The STATUS()
function can be used to determine the cause of the error.
The ON ERROR clause will be executed if an internal error occurs during the delete and should
only be included if the program needs to continue execution rather than taking the default action of
aborting at such an error. The STATUS() function can be used to determine the cause of the error.
The NO.MAP option is relevant only to directory files and suppresses the normal translation of
restricted characters in record ids. See directory files for more information.
Note that DELETESEQ takes no part in the locking system. If locking is required, the directory
containing the file to be deleted must be opened as a directory type file and standard file processing
statements used.
2.11-0
QMBasic 833
DFPART()
The DFPART() function returns a file variable that references an individual part of a distributed
file.
Format
DFPART(dist.file, part)
where
The DFPART() function allows a QMBasic program to refer to a specific part within a distributed
file. It is of use, for example, with FILEINFO() to obtain details of a specific part or when
constructing programs that need to merge index entries from multiple part files.
A list of part numbers can be obtained using the FILEINFO() function with key FL$PARTS.
These part numbers can then be used with DFPART() to access the individual part files. If the part
argument does not reference a valid part number, the program will abort with a run time error.
Examples
The above program reports the modulo values for each part file in the ORDERS distributed file.
The index scanning operations are not available for distributed files because the indices are separate
for each part file. The above program effectively merges index data from each part file within the
ORDERS distributed file. In this example, LIST is created as a list ids for records where the
2.11-0
834 OpenQM
2.11-0
QMBasic 835
DIMENSION
The DIMENSION statement is used to set the dimensions of a matrix. The short form DIM may
be used in place of DIMENSION.
Format
where
A matrix variable is a one or two dimensional array of values. Matrices must be declared by use of
the DIMENSION statement. The DIMENSION statement must be executed at program run time
before the variable is used in any other way.
DIMENSION A(10)
DIMENSION B(5,8)
By default, all matrices have an additional element, the zero element, which is used by some
QMBasic statements. This is referred to as A(0) or B(0,0).
The elements of a matrix may hold data of differing types (numeric, string, file variable, etc).
A matrix may be redimensioned at any time by a further DIMENSION statement though the
number of dimensions cannot be changed. Existing values of matrix elements will be retained in the
redimensioned matrix by copying elements on a row by row basis. If the matrix is enlarged , the
newly created elements will be unassigned. If it is smaller than before, any values in the excess
elements are discarded.
The $MODE compiler directive can be used to select Pick style matrices which do not have a zero
element and cannot be redimensioned.
The INMAT() function may be used to check on the success of a DIMENSION statement. A
sequence such as
DIMENSION A(N)
IF INMAT() THEN ABORT "Insufficient memory"
will cause the program to abort if there is insufficient memory to hold the matrix. The INMAT()
function used in this way returns 0 if the DIMENSION statement was successful, 1 if it failed.
With the memory sizes found on modern systems, this test is probably totally unnecessary and
2.11-0
836 OpenQM
usually omitted.
The INMAT() function can also be used to find the current dimensions of a matrix. For a single
dimensional matrix, this function returns the number of elements excluding the zero element. For a
two dimensional matrix, the function returns the row and column dimensions separated by a value
mark.
Examples
N = DCOUNT(REC, @FM)
DIM A(N)
MATPARSE A FROM REC, @FM
This program fragment creates an array with the correct number of elements to receive the result of
a MATPARSE operation on dynamic array REC and then performs the MATPARSE.
This program fragment creates two matrices and reports their sizes. For the second use of
INMAT(), the CHANGE() function has been use to replace the value mark in the returned data
with a comma. The program output would be
3
2,3
See also:
INMAT(), MAT, MATBUILD, MATREAD, MATREADCSV, MATPARSE, MATWRITE
2.11-0
QMBasic 837
DISINHERIT
Format
DISINHERIT object
where
The DISINHERIT statement removes a previously inherited object from the name search used
when locating the variable or public function/subroutine for an object reference.
See also:
Object oriented programming, CLASS, INHERIT, OBJECT(), OBJINFO(), PRIVATE,
PUBLIC.
2.11-0
838 OpenQM
DISPLAY
The DISPLAY statement sends data to the display. The synonym CRT can be used in place of
DISPLAY.
Format
DISPLAY {print.list}
where
The print.list contains any number of items (including zero) but must all appear on a single source
program line. The individual items are expressions which can be evaluated and represented as
strings.
Where multiple items are present, they are separated by commas. The DISPLAY statement will
replace the comma by a TAB character, causing display to align to the next horizontal tabulation
column, initially set to columns 0, 10, 20, 30, etc. The same effect can be achieved by inserting
TAB characters in the data to be displayed.
A colon as the final token on the source line is not treated as a concatenation operator but as a
special symbol which causes the normal line feed and carriage return at the end of the DISPLAY
action to be suppressed.
When data is output to the display, QM will pause at the end of the screen and ask for confirmation
to continue.
Entering A will cause an abort to occur. Entering Q will quit from the current program or
command. Entering S will continue display and suppress this prompt at the end of subsequent
pages. Any other character causes display to continue up to the next prompt.
Pagination may be suppressed by use of any @(x, y) cursor positioning function. Note that this
does not have to be sent to the screen; use of the function is sufficient. Thus a statement such as
DUMMY = @(0,0)
will suppress pagination even though nothing is displayed by this statement. Pagination may be
turned on again by use of the PRINTER RESET statement.
Examples
This statement displays the literal string "Error code " and the value of the STATUS() function.
The cursor is then positioned at the start of the next line.
2.11-0
QMBasic 839
This program fragment displays a prompt for a product code to be entered. Note the use of the
trailing colon to suppress the line feed so that the cursor is left after the prompt ready for the
INPUT statement.
FOR I = 1 TO 10
DISPLAY I, RATE(I), TOTAL(I)
NEXT I
This example displays a three column table, lining up the columns with horizontal tabulation
positions.
See also:
@(x,y), PRINT
2.11-0
840 OpenQM
DIR()
Format
DIR(pathname)
where
The DIR() function returns a dynamic array with one field per entry in the specified directory. Each
field contains two items separated by value marks:
Value 1 The item name. On platforms with case insensitive file names, the text returned
preserves the casing used by the underlying operating system.
Value 2 The item type. This is F for a file or D for a directory.
Value 3 File modes. On Windows and PDA systems, this is a collection of letters
representing the file attributes:
A = archive
C = compressed
H = hidden
R = read only
S = system
T = temporary
On other platforms, this value contains the file permissions as a decimal value.
Applications should not assume that this structure will remain unchanged. Additional values may
appear in future releases.
Example
FILES = DIR('C:\MYDIR')
NUM.FILES = DCOUNT(FILES, @FM)
FOR I = 1 TO NUM.FILES
IF FILES<I,2> = 'F' THEN DISPLAY FILES<I,1>
NEXT I
The above example lists all the files in C:\MYDIR, omitting subdirectories.
2.11-0
QMBasic 841
DIV()
Format
DIV(dividend, divisor)
where
The DIV() function returns the quotient from dividing dividend by divisor.
2.11-0
842 OpenQM
DOWNCASE()
The DOWNCASE() function returns a string with all letters converted to lower case.
Format
DOWNCASE(string)
where
The DOWNCASE() function returns the value of string with all letters converted to lower case. If
string is a variable rather than an expression, the value of the variable is not affected.
Example
REF.NO = "A12F635"
PRINT DOWNCASE(REF.NO)
See also:
UPCASE()
2.11-0
QMBasic 843
The DPARSE splits the elements of a delimited string into other variables. DPARSE.CSV is
similar but unquotes strings according to the rules in the CSV standard.
Format
where
delimiter evaluates to the substring delimiter. If this is more than one character, only the
first character is used.
var1,var2,... is a list of variables to receive the elements extracted from string. These may
be simple variables, matrix elements or field, value or subvalue references.
The DPARSE statement extracts successive elements delimited by delimiter within string into the
listed variables. A statement such as
DPARSE S, ",", A, B, C
is equivalent to
A = FIELD(S, ",", 1)
B = FIELD(S, ",", 2)
C = FIELD(S, ",", 3)
DPARSE.CSV extends this action by removing quotes that have been applied to meet the CSV
standard. CSV format allows optional double quotes around items and specifies that these must be
present when the item contains the delimiting character or a double quote. In the latter case, the
embedded double quote will be represented by two adjacent double quotes.
Examples
LOOP
READSEQ LINE FROM SEQ.F ELSE EXIT
STOCK.REC = ""
DPARSE LINE, ",", PART.NO, STOCK.REC<1>, STOCK.REC<2>
...Processing...
REPEAT
S = 'abc,"de""f"'
DPARSE S, ',', A, B
DISPLAY A,B
DPARSE.CSV S, ',', A, B
2.11-0
844 OpenQM
DISPLAY A,B
2.11-0
QMBasic 845
DTX()
Format
DTX(expr {, expr})
where
The DTX() function converts the supplied expr value to hexadecimal. If the converted value is
shorter than min.width, leading zeros are added.
Examples
In each example, the DISPLAY statement is followed by the output that it would produce. Note
that DTX() treats the value as an unsigned 32 bit quantity and hence negative numbers will always
appear as 8 hexadecimal digits.
DISPLAY DTX(87)
57
DISPLAY DTX(87,4)
0057
DISPLAY DTX(-21,4)
FFFFFFEB
See also:
XTD()
2.11-0
846 OpenQM
EBCDIC()
Format
EBCDIC(expr)
where
The EBCDIC() function returns the EBCDIC equivalent of the supplied ASCII string. The action
of this function with non-ASCII characters is undefined.
See also:
ASCII()
2.11-0
QMBasic 847
ECHO
Format
ECHO OFF
ECHO ON
ECHO expr
where
Keyboard input is normally echoed to the display when it is processed by an INPUT statement. Use
of ECHO OFF will suppress this echo until a subsequent ECHO ON statement. Typically,
ECHO OFF is used to prevent display of passwords, etc. Turning off echo does not suppress
display of the input prompt character, if enabled (see PROMPT).
The ECHO expr format of this statement is equivalent to ECHO ON if the value of expr is
non-zero and ECHO OFF if expr is zero.
Example
This program fragment requests entry of a password with echoing inhibited. The HIDDEN option
of the INPUT statement may be a better way to do this as it echoes asterisks back to the terminal.
See also:
INPUT, INPUT @
2.11-0
848 OpenQM
ENCRYPT()
Format
ENCRYPT(data, key)
where
The ENCRYPT() function applies the AES 128 bit encryption algorithm to the supplied data and
returns the encrypted text. The key string may be up to 64 characters in length and may contain any
character. It is automatically transformed into a form that is useable by the AES algorithm. For
optimum data security, the key should be about 16 characters.
The encrypted data is post-processed so that it can never contain characters from the C0 control
group (characters 0 to 31) or the mark characters. As a result of this operation, the encrypted data
is slightly longer than the original source data.
Example
FUNCTION LOGIN()
OPEN 'USERS' TO USR.F ELSE
DISPLAY 'Cannot open USERS file'
RETURN @FALSE
END
DISPLAY 'User name: ' :
INPUT USERNAME, 20_:
READ USER.REC FROM USR.F THEN
FOR I = 1 TO 3
DISPLAY 'Password: ' :
INPUT PW,20_: HIDDEN
IF ENCRYPT(PW, 'MySecretKey') = USR.REC<1> THEN RETURN
@TRUE
DISPLAY 'Password incorrect'
NEXT I
END
RETURN @FALSE
END
The above function prompts for a user name and password, validating these against a record in the
USERS file. The password field of this file is encrypted.
See also:
Data encryption, DECRYPT()
2.11-0
QMBasic 849
END
The END statement terminates a program, subroutine or a block of statements conditioned by the
THEN, ELSE, LOCKED or ON ERROR keywords.
Format
END
When used to terminate a program or subroutine, the END statement may not be followed by any
further executable statements; only comments and blank lines are allowed. An END statement is not
mandatory at the end of a program, subroutine or function but lack of an END will cause a warning
message to be displayed as this may be symptomatic of a structural problem elsewhere in the
program.
The compiler will generate a RETURN statement at the end of the program or subroutine which
will be executed if there is no RETURN or other program flow control statement immediately prior
to the END. For compatibility with other mutlivalue database products, the IMPLIED.STOP
option of the $MODE compiler directive can be used to insert a STOP in place of a return in
program, subroutine or function modules. Class modules always insert an implied RETURN
regardless of the setting of this mode.
The END statement is also used to terminate a group of conditional statements. For details of the
use of END in this way, see the description of the QMBasic statement to which the conditional
element applies.
Example
This program fragment reads a record from a file, displays its record id and calls an internal
subroutine to process the record. The two indented statements are both conditioned so that they only
occur if the read was successful.
2.11-0
850 OpenQM
ENV()
Format
ENV(var.name)
where
var.name is the name of the variable to be retrieved.
The ENV() function retrieves the named operating system environment variable, returning its value.
If the variable is not defined or var.name is invalid a null string is returned.
This function always returns a null string on the PDA version of QM.
In general, environment variables do not change during the life of a QM session. For example, on a
Linux system, the PWD environment variable stores the current working directory pathname.
Within QM, use of ENV('PWD') will return the value of the environment variable passed to the QM
process when it started. Using LOGTO, which effectively changes the current working directory,
will not affect the value of the PWD environment variable within QM. A shell process started
using SH after the LOGTO will see the new value of PWD as environment variables are
maintained separately for each Linux process.
2.11-0
QMBasic 851
EPOCH()
The EPOCH() function returns the internal value of the current date and time in epoch format.
Format
EPOCH()
The EPOCH() function returns the current date and time in time zone independent epoch format, as
a number of seconds since 1 January 1970 UTC. This is equivalent to use of the SYSTEM(1035)
function.
Because epoch values are defined to be 32 bit integers, there is a limitation that they can only
represent times between 13 December 1901 and 19 January 2038. This is a widely recognised issue,
potentially more widespread than the "millennium bug", that will require changes to operating
systems and run time libraries.
Example
TIMESTAMP = EPOCH()
This statement assigns the TIMESTAMP variable with the current date and time in epoch format.
See also:
DATE(), TIME(), Date, Times and Epoch Values, EPOCH(), MVDATE(), MVDATE.TIME(),
MVEPOCH(), MVTIME(), SET.TIMEZONE
2.11-0
852 OpenQM
EQS()
The EQS() function processes two dynamic arrays, returning a similarly structured result array
indicating whether corresponding elements are equal.
Format
EQS(expr1, expr2)
where
The EQS() function compares corresponding elements of the dynamic arrays expr1 and expr2,
returning a similarly structured dynamic array of true / false values indicating the results of the
comparison.
The REUSE() function can be applied to either or both expressions. Without this function, any
absent trailing values are taken as false.
Example
A contains 11FM0VM14VMABCFM2
B contains 12FM0VM14VMACBFM2
C = EQS(A, B)
See also:
ANDS(), GES(), GTS(), IFS(), LES(), LTS(), NES(), NOTS(), ORS(), REUSE()
2.11-0
QMBasic 853
EQUATE
The EQUATE statement, often abbreviated to EQU, defines a symbolic name to represent a
constant or reference to a matrix element.
Format
where
name is the name to be attached to the value or matrix reference.
value is a number or a quoted string.
variable is the name of a variable (scalar or matrix) or an @-variable.
matrix is the name of a matrix.
index1 is a number representing the first index to matrix.
index2 is a number representing the second index to a two dimensional matrix.
dyn.array is the name of a variable holding a dynamic array.
field is a number representing the field position within dyn,array.
value is a number representing the value position within dyn,array.
subvalue is a number representing the subvalue position within dyn,array.
seq is a character sequence number.
The EQUATE statement defines a name that can be used later within the program as a reference to
a constant, matrix element, dynamic array element, character value or QMBasic source construct.
EQUATE statements are often placed in include records so that the same values can be
incorporated into many programs without duplication.
All variants of the EQUATE statement except LITERALLY can alternatively be written using
the $DEFINE compiler directive.
2.11-0
854 OpenQM
constant value. The EQUATE statement can be used to eliminate constants for state variables,
field positions, etc from the main body of a program. Subsequent changes to the value thus only
require a single amendment and recompilation of all programs using name.
Multiple tokens may be equated on a single line by separating each definition by a comma. For
example:
EQUATE LOW TO 12, HIGH TO 20
An equated token may not be used within the same source line as its definition. For example
EQUATE NAME TO CLIENT.REC(1) ; NAME = ""
will not recognise the use of NAME in the second statement as being a reference to
CLIENT.REC(1)
If the equated name is also a built-in function or statement, that function or statement becomes
inaccessible.
Examples
EQUATE ADDRESS TO 1
EQUATE TEL.NO TO 2
...
READ REC FROM DATA.FILE, ID THEN
PRINT "Address: " : REC<ADDRESS>
PRINT "Telephone: " : REC<TEL.NO>
END
The above program fragment attaches name to two fields of a data record and then uses these when
the data is extracted for printing.
2.11-0
QMBasic 855
This program fragment achieves the same as the previous example but uses the MATREAD
statement to separate the fields of the record read from the file into the elements of matrix REC.
The names defined in the EQUATE statements are then used to reference elements of this matrix
The above example uses an equated token, VALUE, to represent the calculation of COST * QTY.
When executed, this example would display the value 28.
See also:
$DEFINE, GENERATE
2.11-0
856 OpenQM
ERRMSG
The ERRMSG statement displays a Pick style message from the ERRMSG file.
Format
where
msg.id evaluates to the id of a record in the ERRMSG file which holds the message to be
displayed. If this id is numeric, it will be copied to @SYSTEM.RETURN.CODE.
A standard Pick ERRMSG file is supplied with QM. Many of the messages in this file are
irrelevant on QM. Users may modify this to add new messages or to change existing ones. QM only
uses this file through ERRMSG, STOP or ABORT statements in user written programs.
The ERRMSG file entry consists of one or more fields, each prefixed by an action code. The
message is built up and displayed by processing each code in turn. The codes are:
A{n} Display the next argument left aligned in a field of n characters. If n is omitted, the
argument is displayed without any additional spaces.
B Sound the terminal "bell".
D Outputs the system date in the form dd mmm yyyy.
E Outputs the msg.id enclosed in square brackets.
Htext Outputs the given text.
L{n} Outputs n newlines. The value of n defaults to 1 if omitted.
R{n} Display the next argument right aligned in a field of n characters. If n is omitted,
the argument is displayed without any additional spaces.
Sn Displays n spaces.
T Outputs the system time in the form hh:mm:ss.
The component parts of the message are output with no insertion of newlines except as explicitly
specified in the ERRMSG entry.
See also:
ABORT, STOP
2.11-0
QMBasic 857
EXECUTE
The EXECUTE statement enables a QMBasic program to execute any command. The synonym
PERFORM can be used in place of EXECUTE.
Format
where
src.list is a select list variable holding a list to be passed into the executed command as list
0. For compatibility with other multivalue environments, the PASSLIST clause is
ignored if src.list is omitted.
tgt.list is a variable to receive a returned select list. This variable may be used in a
subsequent READNEXT to extract items from the list.
The EXECUTE statement creates a new command level by starting a new version of the command
processor and passing it the command line to be executed. On completion of the command, the
command processor returns control to the calling program.
The value in expr may contain several commands delimited by field marks. These will be processed
as a paragraph and may include DATA and LOOP constructs, etc.
An abort occurring in the command(s) processed by the EXECUTE statement is normally trapped
by the command processor. The TRAPPING ABORTS qualifier to the EXECUTE statement
causes aborts to return to the program issuing the EXECUTE without execution of the optional
ON.ABORT paragraph. The @ABORT.CODE variable may be used to determine whether the
command caused an abort to occur. This variable is initially zero and is reset to zero only by the
EXECUTE statement.
The CAPTURING clause captures output that would otherwise have gone to the terminal or
phantom log file, saving it in the named variable with field marks in place of newlines.
PASSLIST and RTNLIST are used with Pick style select list variables. The PASSLIST clause
passes the list in the named select list variable into the executed command as list 0. The RTNLIST
clause returns the content of the default select list in the named variable, removing the active
2.11-0
858 OpenQM
The STACKLIST option saves the current state of the default select list (list 0) before executing
the command and restores the list on return to the program, thus allowing the executed command to
use the default select list internally. This option cannot be used with either PASSLIST or
RTNLIST.
The unnamed common area is saved by the EXECUTE statement and the new command level may
define a new structure for this area. On return from the EXECUTE statement, the original
unnamed common area is restored. Named common areas are not affected by the EXECUTE
statement. Except as influenced by the PASSLIST and RTNLIST options described above, the
numbered select lists are carried into the executed command and any changes will be visible on
return.
Application designers should carefully consider the possible impact of EXECUTE inside a
transaction.
If the executed command directly or indirectly changes account by performing a LOGTO, the
process will continue to run in the new account on return from the EXECUTE. Setting the
STACKED.ACCOUNT mode of the OPTION command causes the system to revert to the
previous account on completion of the EXECUTE.
Examples
This statement performs the LIST command from within the calling program. Control is returned to
the program once the LIST command is complete.
2.11-0
QMBasic 859
EXIT
Format
EXIT
The EXIT statement is equivalent to a jump to the statement following the REPEAT or NEXT
statement of the innermost loop structure.
Example
LOOP
REMOVE ITEM FROM STOCK SETTING DELIM
...processing statements...
WHILE DELIM
IF ITEM[1,1] = "A" THEN EXIT
...further statements...
REPEAT
This program fragment processes items extracted from the STOCK dynamic array. If the value of
ITEM commences with "A", the program exits from the loop.
See also:
CONTINUE, FOR/NEXT, LOOP/REPEAT, WHILE, UNITL
2.11-0
860 OpenQM
EXP()
The EXP() function returns the exponential (the natural anti-log) of a value.
Format
EXP(expr)
where
The EXP() function returns the exponential of expr, that is, the mathematical constant e raised to
the power expr. The value of e is about 2.71828.
If expr is a numeric array (a dynamic array where all elements are numeric), the EXP() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
N = EXP(X)
See also:
LN()
2.11-0
QMBasic 861
EXTRACT()
The EXTRACT() function extracts a field, value or subvalue from a dynamic array.
Format
where
value evaluates to the number of the value to be extracted. If omitted or zero, the
entire field is extracted.
subvalue evaluates to the number of the subvalue to be extracted. If omitted or zero, the
entire value is extracted.
The specified field, value or subvalue is extracted from the dynamic array and returned as the result
of the EXTRACT() function. This function is identical in effect to the alternative syntax of
dyn.array<field {, value {, subvalue}}>
Example
AMOUNT.DUE = EXTRACT(INVOICE.REC, 3)
This statement extracts field 3 from INVOICE.REC, assigning the result to variable
AMOUNT.DUE.
See also:
DEL, DELETE(), FIND, FINDSTR, INS, INSERT(), LISTINDEX(), LOCATE, LOCATE(),
REPLACE()
2.11-0
862 OpenQM
FCONTROL()
Format
where
The FCONTROL() function performs the action defined by action against the file open as fvar.
The action values are listed below using the tokens defined in the SYSCOM KEYS.H include
record:
FC$SYNC (1)
Controls or reports the state of forced writes for a dynamic hashed file. See synchronous
(forced write) mode in the section that discussed dynamic files for more details.
If qualifier is false (0), forced writes are disabled. If qualifier is true (1), forced writes are
enabled. For all values of qualifier, the previous state of forced writes is returned as the result
of the function.
Note that, if the file is open to multiple file variables within the one process, this action affects
all writes to the file regardless of which file variable is used.
Example
This program fragment opens the AUDIT file and sets forced write mode. The same effect could
have been achieved with the SYNC option to the OPEN statement.
See also:
OPEN, OPENPATH
2.11-0
QMBasic 863
FIELD()
The FIELD() function returns one or more delimited substrings from a string. The FIELDS()
function is similar to FIELD() but operates on a multivalued string, returning a similarly structured
dynamic array of results.
Format
where
occurrence evaluates to the position of the substring to be extracted. If less than one, the
first substring is extracted.
The FIELD() function extracts count substrings starting at substring occurrence from string.
Substrings within string are delimited by the first character of delimiter. If delimiter is a null
string, the entire string is returned.
If the value of occurrence is greater than the number of delimited substrings in string, a null string
is returned.
If the value of count is greater than the number of delimited substrings in string starting at
substring occurrence, the remainder of string is returned. Additional delimiters are not inserted.
The COL1() and COL2() functions can be used to find the character positions of the extracted
substring.
Use of the $NOCASE.STRINGS compiler directive makes the delimiter case insensitive.
Example
A = "1*2*3*4*5"
S = FIELD(A, '*', 2, 3)
2.11-0
864 OpenQM
See also:
COL1(), COL2(), FIELDSTORE()
2.11-0
QMBasic 865
FIELDSTORE()
Format
where
delimiter evaluates to a string, the first character of which is used as the delimiter
separating the substrings within string. A null delimiter string will cause a run
time error.
The value returned by the FIELDSTORE() function is the result of the replacement.
S = FIELDSTORE(S, d, i, n, rep.string)
S[d, i, n] = rep.string
The action of FIELDSTORE() depends on the values of i and n and the number of substrings
within rep.string.
If the value of the position expression, i, is less than one, a value of one is assumed. If there are
fewer than i delimited substrings present in string, additional delimiters are added to reach the
required position.
If the value of the number of substrings expression, n, is positive, n substrings are replaced by the
same number of substrings from rep.string. If rep.string contains fewer than n substrings,
additional delimiters are inserted.
If the value of the number of substrings expression, n, is zero or negative, n substrings are deleted
from string and the whole of rep.string is inserted regardless of the number of substrings that it
contains.
2.11-0
866 OpenQM
Use of the $NOCASE.STRINGS compiler directive makes the delimiter case insensitive.
Example
S = 1*2*3*4*5
A = FIELDSTORE(S, "*", 2, 3, "A*B")
B = FIELDSTORE(S, "*", 2, 3, "A*B*C")
C = FIELDSTORE(S, "*", 2, 3, "A*B*C*D")
D = FIELDSTORE(S, "*", 2, 0, "A*B")
E = FIELDSTORE(S, "*", 2, -3, "A*B")
This program fragment performs the FIELDSTORE() function on the string S using different
values for rep.string and n. The results are
See also:
FIELD()
2.11-0
QMBasic 867
FILE
The FILE statement provides a way to reference data in files using field names defined in the
dictionary.
This statement is provided for compatibility with other systems and its use is discouraged.
Format
where
The FILE statement opens the named files for processing in the current program. The QMBasic
compiler will process the associated dictionary to allow use of field names as described below. Note
that any change to the dictionary may require the program to be recompiled.
Note that the FILE statement has no error handling clause. If the file cannot be opened, any
subsequent access to it will fail.
After a file has been opened using the FILE statement, a record can be read using a modified form
of the READ statement:
READ name FROM id
where name is the file name in the FILE statement and id is the key of the record to be read. This
form of the READ statement take the same optional clauses as a normal READ. The locking
variants (READL and READU) are also supported.
After a record has been read, data from that record can be accessed using a construct:
name(field)
where name is the file name and field is a field name defined in the dictionary. Note that QMBasic
restricts this construct such that field must be a D-type item or an A or S-type item with no
correlative. Calculated values are not supported.
Records may be written to the file using a modified form of the WRITE (or WRITEU) statement:
WRITE name TO id
where name is the file name in the FILE statement and id is the key of the record to be written.
Apart from the above special cases, use of name in a file handling statement or function refers to
the file variable associated with the file. Use of name in any other context refers to the dynamic
array that will be used implicitly by READ or WRITE statements.
Use of the FILE statement is not recommended in new developments as it requires that the file is
opened separately in every program that will access it rather than using a file variable in a common
block for best performance. The syntax of the associated statements is also likely to be confusing as
the same name references either the file variable or the data depending on its context.
2.11-0
868 OpenQM
Example
FILE 'ORDERS'
READ ORDERS FROM ORDER.NO THEN
DISPLAY ORDERS(CUSTOMER.NO)
END
This program fragment opens the ORDERS file, reads the record for a given order number and
displays the customer number from this record.
2.11-0
QMBasic 869
FILE.EVENT
The FILE.EVENT() function creates a file event monitoring variable (Windows only).
Format
FILE.EVENT(path, event)
where
The FILE.EVENT() function allows a program to wait for a change within the Windows file
system. It can be used, for example, to wait until a new file is created within a directory without
needing to write a loop that periodically compares the directory content with a previously recorded
list of items.
Path is the pathname of the directory to which the monitoring is to be applied. Event is any
combination of the following additive tokens defined in the SYSCOM KEYS.H record:
FE$FILE.NAME Any file name change in the watched directory or sub-tree.
Changes include renaming, creating, or deleting a file name.
FE$DIR.NAME Any directory-name change in the watched directory or sub-tree.
Changes include creating or deleting a directory.
FE$ATTRIBUTES Any attribute change in the watched directory or sub-tree.
FE$SIZE Any file-size change in the watched directory or sub-tree. The
operating system detects a change in file size only when the file is
written to the disk. For operating systems that use extensive
caching, detection occurs only when the cache is sufficiently
flushed.
FE$LAST.WRITE Any change to the last write time of files in the watched directory
or sub-tree. The operating system detects a change to the last
write-time only when the file is written to the disk. For operating
systems that use extensive caching, detection occurs only when the
cache is sufficiently flushed.
FE$LAST.ACCESS Any change to the last access time of files in the watched
directory or sub-tree. The operating system detects a change to the
last write-time only when the file is written to the disk. For
operating systems that use extensive caching, detection occurs
only when the cache is sufficiently flushed.
FE$CREATION Any change to the creation time of file in the watched directory or
sub-tree.
FE$SECURITY Any security-descriptor change in the watched directory or subtree
causes a change notification wait operation to return.
FE$SUBTREE Apply monitoring to the specified directory and all sub-directories.
2.11-0
870 OpenQM
If the FILE.EVENT() function is successful, it returns a value that can be stored in a variable as a
file event monitoring action for use with WAIT.FILE.EVENT() and STATUS() will be zero. Use
of the returned value in any other way will appear to be a number.
2.11-0
QMBasic 871
FILEINFO()
Format
FILEINFO(file.var, key)
where
Values for the key to the FILEINFO() function are defined in the KEYS.H record in the SYSCOM
file. These are
2.11-0
872 OpenQM
2.11-0
QMBasic 873
Example
This program fragment checks whether a file variable is associated with a dynamic file and, if not,
aborts.
See also:
STATUS
2.11-0
874 OpenQM
FILELOCK
Format
where
The FILELOCK statement sets a file lock which prevents other users from obtaining read or
update locks on records within the file or a file lock on the whole file. File access operations that do
not obtain locks are can still be performed by other users. These are CLEARFILE, DELETE,
DELETEU, MATREAD, MATWRITE, MATWRITEU, READ, READV, WRITE,
WRITEU, WRITEV and WRITEVU. Correct application design avoids accidental deletion or
overwriting of locked records.
A file lock does not prevent access by the user that owns the lock.
The LOCKED clause is executed if another user holds a file lock or a read or update lock on any
record in the file. The STATUS() function will return the user id of a process holding a lock. If the
LOCKED clause is omitted, the program will wait for any lock to be released.
The THEN and ELSE clauses are both optional and neither need be present. The THEN clause
will be executed if the file lock is successfully obtained. The ELSE clause will be executed if the
lock cannot be obtained for a reason other than it being held by some other user. There are currently
no conditions that would execute the ELSE clause.
Example
FILELOCK STOCK
SELECT STOCK
TOTAL = 0
LOOP
READNEXT ID ELSE EXIT
READ REC FROM STOCK, ID ELSE ABORT "Cannot read " : ID
TOTAL += REC<QTY>
REPEAT
FILEUNLOCK STOCK
This program fragment obtains a file lock on the file open as STOCK and then reads all records
from the file, forming a total of the values in the QTY field. The lock prevents other users obtaining
update locks when they might be updating this field in some record. The lock ensures that the total
2.11-0
QMBasic 875
value represents a true picture of the file when the file lock was obtained. The lock is released on
leaving the main processing loop.
See also:
Locking, FILEUNLOCK
2.11-0
876 OpenQM
FILEUNLOCK
The FILEUNLOCK statement releases a file lock previously obtained using the FILELOCK
statement.
Format
The FILEUNLOCK statement releases a file lock, making the file available to other users. Read
and update locks on records from the file are not affected.
The ON ERROR clause is executed in the event of a fatal error. The STATUS() function will
return an error code giving the cause of the error.
Where the ON ERROR clause is not taken, the STATUS() function returns 0 if the file was
previously locked by this user, ER$LCK if the lock is held by another user or ER$NLK if no user
holds the lock.
The THEN and ELSE clauses are both optional and neither need be present. The THEN clause
will be executed if the file lock is successfully released. The ELSE clause will be executed if the
lock cannot be released. Currently, this will only occur if the lock is not owned by the process
executing the FILEUNLOCK.
Example
FILELOCK STOCK
SELECT STOCK
TOTAL = 0
LOOP
READNEXT ID ELSE EXIT
READ REC FROM STOCK, ID ELSE ABORT "Cannot read " : ID
TOTAL += REC<QTY>
REPEAT
FILEUNLOCK STOCK
This program fragment obtains a file lock on the file open as STOCK and then reads all records
from the file, forming a total of the values in the QTY field. The lock prevents other users obtaining
update locks when they might be updating this field in some record. The lock ensures that the total
value represents a true picture of the file when the file lock was obtained. The lock is released on
leaving the main processing loop.
See also:
Locking, FILELOCK
2.11-0
QMBasic 877
FIND
The FIND statement searches a dynamic array for a given string in any position.
Format
where
field is the variable to receive the field number at which string is found.
value is the variable to receive the value number at which string is found. If
omitted, only the field position is returned
subvalue is the variable to receive the subvalue number at which string is found. If
omitted, only the field and, optionally, value positions are returned
The FIND statement searches dyn.array for a field, value or subvalue equal to string. If found, the
position of string within dyn.array is returned in the field, value, and subvalue variables and the
THEN clause is executed. If not found or dyn.array is a null string, the field, value, and subvalue
variables are unchanged and the ELSE clause is executed.
Use of the $NOCASE.STRINGS compiler directive makes the comparison case insensitive.
Example
See also:
DEL, DELETE(), EXTRACT(), FINDSTR, INS, INSERT(), LISTINDEX(), LOCATE,
2.11-0
878 OpenQM
LOCATE(), REPLACE()
2.11-0
QMBasic 879
FINDSTR
The FINDSTR statement searches a dynamic array for a given substring in any position.
Format
where
field is the variable to receive the field number at which string is found.
value is the variable to receive the value number at which string is found. If
omitted, only the field position is returned
subvalue is the variable to receive the subvalue number at which string is found. If
omitted, only the field and, optionally, value positions are returned
The FINDSTR statement searches dyn.array for a field, value or subvalue containing string. This
need not be the entire field, value or subvalue. If found, the position of string within dyn.array is
returned in the field, value, and subvalue variables and the THEN clause is executed. If not found
or dyn.array is a null string, the field, value, and subvalue variables are unchanged and the ELSE
clause is executed.
Use of the $NOCASE.STRINGS compiler directive makes the comparison case insensitive.
Example
See also:
2.11-0
880 OpenQM
2.11-0
QMBasic 881
FLUSH
The FLUSH statement flushes the internal buffers for a directory file record previously opened for
sequential access.
Format
FLUSH file.var
{THEN statement(s)}
{ELSE statement(s)}
where
file.var is the file variable associated with the record by a previous OPENSEQ
statement.
At least one of the THEN and ELSE clauses must be present. The THEN clause is executed if the
operation is successful. The ELSE clause is executed if the FLUSH operation fails.
The sequential file buffers are automatically flushed periodically during file usage and on closing
the file. The FLUSH statement allows the programmer to ensure that data is flushed to disk at a
given point in the program
Example
LOOP
LINE = REMOVE(LIST, CODE)
WRITESEQ LINE TO SEQ.F ELSE ABORT "Write error"
WHILE CODE
REPEAT
FLUSH SEQ.F ELSE ABORT "Flush error"
This program fragment writes a series of text lines extracted from LIST to a sequential file and then
flushes the buffers to verify that the data has been written to disk.
See also:
CLOSESEQ, NOBUF, READBLK, READCSV, READSEQ, SEEK, WEOFSEQ,
WRITEBLK, WRITECSV, WRITESEQ, WRITESEQF
2.11-0
882 OpenQM
FLUSH.DH.CACHE
Format
To improve performance of applications that repeatedly open and close the same files, closing a
dynamic hashed file does not immediately close it at the operating system level. Instead, the file is
moved into a cache of recently closed files from where it can be reopened at the application level
very quickly. The size of this cache is determined by the DHCACHE configuration parameter. On
reaching this limit, the oldest file in the cache is closed at the operating system level.
Sometimes an application may do something that will fail if the file is still open in the cache,
perhaps in another process. Built-in QM operations such as using OSDELETE to delete a file will
automatically flush the cache in all QM processes. Where the operation is not a built-in part of QM,
the FLUSH.DH.CACHE statement can be used to cause all QM processes to close files that are in
their cache.
Note that this action is asynchronous and it may take a few seconds for the request to be handled in
all other QM processes. The FLUSH.DH.CACHE statement will wait for other processes to
acknowledge that they have seen the request, with a timeout after four seconds. The NO.WAIT
qualifier causes the program to continue without waiting.
When used with the LOCAL option, only the file cache of the process in which this statement
appears is flushed.
Excessive use of the FLUSH.DH.CACHE statement can have a detrimental effect on performance.
2.11-0
QMBasic 883
FMT()
The FMT() function performs data formatting according to a format template. It is typically used to
convert data for display or printing. The FMTS() function is identical to FMT() except that it
works on each element of a dynamic array in turn, returning the result in a similarly delimited
dynamic array.
Format
FMT(expr, fmt.spec)
FMTS(expr, fmt.spec)
where
The FMT() function sets the STATUS() function value to indicate whether the operation was
successful. Possible values are
0 Successful formatting.
1 Data to format was too long or invalid for the format specification.
2 The format specification was invalid.
Operations that result in a non-zero STATUS() value return expr as the function result.
Shortform Notation
For compatibility with other systems, the FMT() function action can also be performed in QMBasic
programs (but not in I-type dictionary entries) by use of a shortform notation in which the expr and
fmt.spec are simply written next to each other with no operator in between.
Thus
X = FMT(A, '8R')
can be written as
X = A '8R'
2.11-0
884 OpenQM
The FOLD() function breaks a string into field mark delimited sections no longer than a given
width, placing breaks on spaces where possible.
Format
where
The FOLD() function breaks string into sections, placing the delim character between each section.
Each section is at most width characters in length with the break from one section to the next
occurring at a space where possible.
The width argument may be multivalued. In this case, the first value specifies the width for the first
fragment of the result, the second value specifies the width for the second fragment of the result and
so on. If there are more fragments in the result than there are width specifications, the final width is
used for the remaining data.
The delim argument is optional. If omitted, a field mark is used by default. Specifying delim as a
null string uses a value mark as the delimiter.
The FOLDS() function is similar to FOLD() but works on each field, value or subvalue of string
separately, returning a similarly structured dynamic array of folded strings
Example
The quick
brown fox
jumps over
the lazy
dog
2.11-0
QMBasic 885
FOOTING
The FOOTING statement defines text to be printed or displayed at the foot of each page of output.
Format
where
print.unit identifies the logical print unit in the range -1 to 255 to which the footing text
is to be applied. If omitted, the default print unit (unit 0) is used.
text is the footing text. This may include control tokens as described below.
The FOOTING statement defines the text of a page footing and, optionally, control information
determining the manner in which the text is output. A page footing is output whenever the bottom of
the page is reached or on execution of a PAGE statement to terminate the current page.
The footing text may include the following control tokens enclosed in single quotes. Multiple tokens
may appear within a single set of quotes.
D Inserts the date. The default format is dd mmm yyyy (e.g. 24 Aug 2005) but can be
changed using the DATE.FORMAT command.
G Insert a gap. Spaces are inserted in the footing line at the position of each G control
token such that the overall length of the line is the same as the printer unit width. A
single use of the G token will right justify the subsequent text. Multiple G tokens will
distribute spaces as evenly as possible.
When a footing line uses both G and C, the footing is considered as a number of
elements separated by the G control options. The element that contains the C option
will be centered. The items either side of the centered element are processed separately
when calculating the number of spaces to be substituted for each G option.
Hn Sets horizontal position (column) numbered from one. Use of H with C or with a
preceding G token may have undesired results.
O Reverses the elements separated by G tokens in the current line on even numbered
pages. This is of use when printing double sided reports.
Pn Insert page number. The page number is right justified in n spaces, widening the field if
necessary. If omitted, n defaults to four.
Sn Insert page number. The page number is left justified in n spaces, widening the field if
2.11-0
886 OpenQM
T Inserts the time and date in the form hh:mm:ss dd mmm yyyy. The format of the date
component can be changed using the DATE.FORMAT command.
Unrecognised control tokens are ignored. A quotation mark may be inserted in the printed text by
using two adjacent quotation marks in the text string.
There is no limit to the length of a footing text. Each line will be truncated at the width of the print
unit. The effect of using a footing which will not fit on to the physical page is undefined.
See the RUN command for a discussion of how the page end pause on output to the screen may be
affected by setting a page footing.
See also:
HEADING, PAGE
2.11-0
QMBasic 887
FOR / NEXT
The FOR / NEXT statement defines a group of statements to be executed with an iterative control
variable.
Format
where
start.expr evaluates to the value to be placed in var for the first iteration of the loop.
limit.expr evaluates to the value beyond which var must not pass.
The first form of the FOR / NEXT statement executes statement(s) for values of var from
start.expr to limit.expr in increments of step.expr. If step.expr is positive, the loop continues while
the value of var is less than or equal to limit.expr. If step.expr is negative, the loop continues while
the value of var is greater than or equal to limit.expr. The value of var on leaving the loop is the
last value for which the loop was executed or start.expr if the initial value was already out of range.
The value of var should not be changed within the loop as this may lead to unexpected results.
Use of non-integer values for start.expr, limit.expr and step.expr is not recommended where
rounding errors in incrementing var and the loop termination comparison may lead to unexpected
effects.
2.11-0
888 OpenQM
For best performance, limit.expr and step.expr should be constants or simple variable references as
they are evaluated for every iteration of the loop. In the unlikely case that limit.expr or step.expr
use the value of var, note that these expressions are evaluated before the first cycle of the loop
assigns the start value to var.
The second form of the FOR / NEXT statement executes the loop for each of the supplied values
of var in turn. The value of var on leaving the loop will be the final value for which the loop was
executed. The values to be assigned to var may be constants or expressions.
The third form of the FOR / NEXT statement executes the loop for each mark character delimited
value in string. This form of FOR / NEXT is broadly equivalent to using the REMOVE statement
to extract successive values from string. The value of string is copied to an internal variable at the
start of the loop and hence changing it inside the loop will have no effect. The value of var on
leaving the loop will be the final value for which the loop was executed.
If var is present in the NEXT statement it must be the same var as in the FOR statement at the
head of the loop. Use of var in the NEXT statement aids program readability and is checked by the
compiler for correct matching of FOR and NEXT statements.
The WHILE, UNTIL and EXIT statements can be used with the FOR / NEXT loop to provide
another loop termination control. The CONTINUE statement causes a jump to the start of the next
iteration.
FOR / NEXT loops may be nested to any depth. Jumping to a label within a FOR / NEXT loop
from outside may have undefined effects.
The FOR / NEXT construct is semantically different in the various multivalue database
environments. Some, including QM, test the end condition of the loop before storing the updated
control variable such that a loop
FOR I = 1 TO 10
would exit with I set to 10. Others store the value before testing the end condition such that this
same loop would exit with I set to 11.
The FOR.STORE.BEFORE.TEST option of the $MODE compiler directive can be used to modify
the behaviour of FOR / NEXT constructs to store the new value of the control variable before
testing for the end condition. For ease of maintenance and portability, it is recommended that
programs should not rely on the value of the control variable after the loop has terminated.
Examples
FOR I = 1 TO 10 STEP 2
DISPLAY I
NEXT I
This program fragment displays the values 1, 3, 5, 7 and 9. The final value of I on leaving the loop
is 9.
FOR I = 1 TO 20
2.11-0
QMBasic 889
This program fragment displays elements of matrix A. The loop terminates if an element is found
with a negative value.
FOR I = 1, 7, 22
DISPLAY I
NEXT I
This program fragment walks though the values in SALES.REC<S.ITEM>, displaying each value.
Note that the actual mark character separating the items in the list is not significant and cannot be
determined from within the loop.
See also:
CONTINUE, EXIT, LOOP/REPEAT, WHILE, UNITL
2.11-0
890 OpenQM
FORMLIST, FORMLISTV
The FORMLIST statement creates a numbered select list from a dynamic array. The
FORMLISTV statement is similar but creates a select list variable.
Format
where
list.no evaluates to the select list number. If omitted, select list zero is created.
Any existing select list list.no or in var is cleared and a new list is created from the elements of
dyn.array. This list may be separated by field marks, item marks or a mixture of both.
Examples
This program fragment reads a list from record OVERDUE of file ACCOUNTS and creates select
list zero from the elements of this list.
This program fragment is again similar but creates MYLIST as a select list variable.
See also:
READLIST
2.11-0
QMBasic 891
FUNCTION
Format
where
The FUNCTION statement must appear before any executable statements. The brackets are
optional if there are no arguments. The FUNCTION statement may be split over multiple lines by
breaking after a comma.
The name used in a FUNCTION statement need not be related to the name of the source record
though it is recommended that they are the same as this eases program maintenance. The name must
comply with the QMBasic name format rules.
A function is a special form of subroutine. It returns a value to the calling program and can be
referenced in a QMBasic statement in the same way as the intrinsic functions described in this
manual, without the need for an explicit CALL statement. The FUNCTION statement is
equivalent to a SUBROUTINE statement with an additional hidden argument at the start which is
used to return the result.
The number of arguments in calls to the function must be the same as in the FUNCTION statement
unless the function is declared with the VAR.ARGS option. When VAR.ARGS is used, any
arguments not passed by the caller will be unassigned. The ARG.COUNT() function can be used
to determine the actual number of arguments passed, excluding the hidden return argument. The
ARG.PRESENT() function can be used to test for the presence of an optional argument by name.
FUNCTION CREDIT.RATING(CLIENT, CLASS, CODE) VAR.ARGS
In this example, if the calling program supplies only one argument, the CLASS and CODE
variables will be unassigned. If the calling program provides two arguments, the CODE variable
will be unassigned.
When using VAR.ARGS, default values may be provided for any arguments by following the
argument name with an = sign and the required numeric or string value. For example,
FUNCTION CREDIT.RATING(CLIENT, CLASS = 1, CODE = "Standard")
VAR.ARGS
In this example, if the calling program supplies only one argument, the CLASS variable will default
to 1 and the CODE variable will default to "Standard". If the calling program provides two
2.11-0
892 OpenQM
arguments, the default value for CLASS is ignored and the CODE variable defaults to "Standard".
Function arguments are normally passed by reference such that changes made to the argument
variable inside a subroutine will be visible in the caller's variable referenced by that argument. A
function call allows arguments to be passed by value by enclosing them in brackets. The
FUNCTION statement also supports this dereferencing syntax. For example
FUNCTION CREDIT(P, (Q))
If dereferencing is used with the default argument syntax described above, the default value is
placed inside the parenthesis. For example,
FUNCTION INVOICE(P, (Q = 7)) VAR.ARGS
An argument may refer to a whole matrix. In this case the argument variable name must be
preceded by the keyword MAT and there must be a DIM statement following the function
declaration to indicate whether this is a one or two dimensional matrix. Alternatively, the
dimensions may be given after the variable name in the FUNCTION statement. In either case, the
actual dimension values are counted by the compiler but otherwise ignored. Use of a dimension
value of one emphasises to readers of the program that the value is meaningless. A matrix passed as
an argument cannot be redimensioned in the function.
Programs that use the function must include a DEFFUN statement to define the function template.
Example
FUNCTION MATMAX(MAT A)
DIM A(1)
MAX = A(1)
N = INMAT(A)
FOR I = 1 TO N
IF A(I) > MAX THEN MAX = A(I)
NEXT I
RETURN MAX
END
This function scans a one dimensional matrix and passes back the value of the largest element. The
first two lines could alternatively be written as
See also:
DEFFUN
2.11-0
QMBasic 893
GES()
The GES() function processes two dynamic arrays, returning a similarly structured result array
indicating whether elements of the first array are greater than or equal to corresponding elements of
the second array.
Format
GES(expr1, expr2)
where
The GES() function compares corresponding elements of the dynamic arrays expr1 and expr2,
returning a similarly structured dynamic array of true / false values indicating the results of the
comparison.
The REUSE() function can be applied to either or both expressions. Without this function, any
absent trailing values are taken as zero.
Example
A contains 11FM0VM14VMABCFM2
B contains 12FM0VM14VMACBFM2
C = GES(A, B)
See also:
ANDS(), EQS(), GTS(), IFS(), LES(), LTS(), NES(), NOTS(), ORS(), REUSE()
2.11-0
894 OpenQM
GET(ARG.)
Format
The GET(ARG.) statement allows a program to retrieve command line arguments. This statement
is provided for compatibility with other systems. The !PARSER() subroutine provides a more
powerful way to process command arguments.
The command line is considered to be formed from a number of tokens separated by spaces. Spaces
within quoted strings are treated as part of the string. The GET(ARG.) statement, used without the
argno element or with argno less than one, returns the value of the next command line argument in
var. Specifying a positive and non-zero value for argno retrieves the specified argument.
The THEN and ELSE clauses are both optional. If present, the THEN clause will be executed if
the argument is retrieved successfully. The ELSE clause is executed if the argument was not
present in the command line.
If the program is started using the RUN or DEBUG commands, the argument data is each
argument following the program record name. If the program is started by reference to its name
within the catalogue, the argument data is everything after the catalogue name.
The command arguments and the current position within them are stacked on a per-command
processor level basis.
Examples
PROGRAM TEST
GET(ARG.) A
GET(ARG.) B
GET(ARG.) C
DISPLAY A
DISPLAY B
DISPLAY C
END
2.11-0
QMBasic 895
2.11-0
896 OpenQM
GET.MESSAGES()
The GET.MESSAGES() function returns any messages currently queued for display.
Format
GET.MESSAGES()
Use of GET.MESSAGES() removes the messages from the queue so that they are not displayed on
return to the command prompt. Normally, the application that uses GET.MESSAGES() would
handle display of the messages.
Messages submitted with the IMMEDIATE option of the MESSAGE command appear on the
screen immediately and cannot be retrieved with the GET.MESSAGES() function.
2.11-0
QMBasic 897
GET.PORT.PARAMS()
The GET.PORT.PARAMS() function retrieves the communications parameters for a serial port.
This function is not available on the PDA version of QM.
Format
GET.PORT.PARAMS(fvar)
where
fvar is the file variable from the OPENSEQ statement that was used to open the port.
The GET.PORT.PARAMS() function returns a dynamic array containing the following data:
Programs should be written to allow for the possibility of additional fields being added in future
releases.
Example
2.11-0
898 OpenQM
GETLIST
The GETLIST statement restores a select list from the $SAVEDLISTS file.
Format
where
list.no is the select list number to which it is to be restored. If omitted, this defaults to
zero.
The GETLIST statement restores the previously saved select list identified by name from the
$SAVEDLISTS file. The disk copy is not removed by this operation.
The @SELECTED variable can be examined to determine the number of items in the list.
At least one of the THEN and ELSE clauses must be present. If the list is successfully restored,
the THEN clause is executed. If the list does not exists or cannot be restored for any other reason,
the ELSE clause is executed.
See also:
SAVELIST
2.11-0
QMBasic 899
GETNLS()
The GETNLS() function returns the value of a national language support parameter.
Format
GETNLS(key)
where
The GETNLS() function returns the value of the named national language support parameter. NLS
parameter name tokens are defined in the KEYS.H include record.
See also:
Conversion codes, Format codes, OCONV()
2.11-0
900 OpenQM
GETPU()
Format
GETPU(key, unit)
where
2.11-0
QMBasic 901
The GETPU() function returns the print unit characteristic specified by key. It is closely related to
the !GETPU() subroutine.
The PU$DEFINED key should be used to determine if a print unit has been defined. Use of any
other key value for an undefined print unit will create it with all settings at their default values.
Example
MODE = GETPU(PU$MODE, 3)
The above statement gets the mode of print unit 3, storing it in MODE.
See also:
SETPU
2.11-0
902 OpenQM
GETREM()
The GETREM() function returns the remove pointer position into a string.
Format
GETREM(string)
where
string is the string for which the remove pointer position is to be returned.
The GETREM() function returns the offset of the remove pointer into string. It is typically used
with SETREM to save and restore the remove pointer position. The remove pointer is positioned
on the mark character preceding the next fragment to be extracted. It is reset to zero when a new
value is assigned to the string.
Example
RMV.PTR = GETREM(S)
GOSUB PROCESS.DATA
SETREM RMV.PTR ON S
The above code fragment saves the remove pointer associated with string S and restores it after
execution of subroutine PROCESS.DATA which might change this remove pointer.
See also:
REMOVE, SETREM
2.11-0
QMBasic 903
GOSUB
Format
GOSUB label{:}
GOSUB label{:}(args)
where
label is the label attached to the statement at the start of the internal subroutine.
args is a comma separated list of arguments to a subroutine defined with the LOCAL
SUBROUTINE statement.
The optional colon after the label has no effect on the action of the statement.
The program continues execution at the given label, saving the location of the GOSUB for a later
RETURN which will resume execution at the statement following the GOSUB. See also the
RETURN TO statement for details of alternate returns.
QMBasic defines two styles of internal subroutine. A conventional internal subroutine, as found in
other multivalue database products, has no formal start or end. The label may be any label defined
within the program or subroutine. It is the programmer's responsibility to ensure that internal
subroutines return correctly. Variables referenced in the internal subroutine are accessible across
the entire program module, requiring great care from the programmer to ensure that data in one part
of the module is not accidentally altered elsewhere by use of the same name. Loop counters in
FOR/NEXT loops are a good example of where this frequently happens. Calling this style of
internal subroutine recursively is possible but of limited use because the variables in one invocation
will be overwritten by the next.
The second style, referred to in QMBasic terminology as a local subroutine, is introduced by the
LOCAL statement and is terminated by END. Local subroutines may have arguments and may
have private local variables that are not visible outside the subroutine which are stacked if the
subroutine is called recursively.
Examples
This program fragment checks if the value of STOCK.LEVEL has fallen to the
REORDER.LEVEL and, if so, calls internal subroutine REORDER.
2.11-0
904 OpenQM
END
RETURN
END
The above local subroutine takes a record id and the amount by which a field is to be updated, reads
the corresponding record and applies the update. A real program would include statements to handle
the case where the record is not found.
2.11-0
QMBasic 905
GOTO
Format
GOTO label{:}
GO {TO} label{:}
where
The trailing colon is optional and has no effect on the action of the statement.
The program continues execution at the given label. The label may be any label defined within the
program or subroutine. Excessive use of GOTO and labels in place of other language constructs
(e.g. LOOP/REPEAT) can make programs difficult to maintain.
Example
This program fragment checks if the first character of REC is "A". If not, it jumps to label
ERROR.
2.11-0
906 OpenQM
GTS()
The GTS() function processes two dynamic arrays, returning a similarly structured result array
indicating whether elements of the first array are greater than corresponding elements of the second
array.
Format
GTS(expr1, expr2)
where
The GTS() function compares corresponding elements of the dynamic arrays expr1 and expr2,
returning a similarly structured dynamic array of true / false values indicating the results of the
comparison.
The REUSE() function can be applied to either or both expressions. Without this function, any
absent trailing values are taken as zero.
Example
A contains 11FM0VM14VMABCFM2
B contains 12FM0VM14VMACBFM2
C = GTS(A, B)
See also:
ANDS(), EQS(), GES(), IFS(), LES(), LTS(), NES(), NOTS(), ORS(), REUSE()
2.11-0
QMBasic 907
HEADING
The HEADING statement defines text to be printed or displayed at the top of each page of output.
Format
where
print.unit identifies the logical print unit in the range -1 to 255 to which the heading text
is to be applied. If omitted, the default print unit (unit 0) is used.
text is the heading text. This may include control tokens as described below.
The HEADING statement defines the text of a page heading and, optionally, control information
determining the manner in which the text is output. A page heading is output whenever the first line
of output on a page is about to be printed or displayed. The HEADING statement normally causes
subsequent output to appear on a new page. The NO.EJECT option defers the new heading until
the start of the next page. The HEADING.NO.EJECT option of the $MODE compiler directive
can be used to make NO.EJECT the default.
The heading text may include the following control tokens enclosed in single quotes. Multiple tokens
may appear within a single set of quotes.
D Insert the current date in the form dd mmm yyyy (e.g. 25 MAR 2006)
G Insert a gap. Spaces are inserted in the heading line at the position of each G control
token such that the overall length of the line is the same as the printer unit width. A
single use of the G token will right justify the subsequent text. Multiple G tokens will
distribute spaces as evenly as possible.
When a heading line uses both G and C, the heading is considered as a number of
elements separated by the G control options. The element that contains the C option
will be centered. The items either side of the centered element are processed separately
when calculating the number of spaces to be substituted for each G option.
Hn Sets horizontal position (column) numbered from one. Use of H with C or with a
preceding G token may have undesired results.
O Reverses the elements separated by G tokens in the current line on even numbered
pages. This is of use when printing double sided reports.
Pn Insert page number. The page number is right justified in n spaces, widening the field if
necessary. If omitted, n defaults to four.
2.11-0
908 OpenQM
Sn Insert page number. The page number is left justified in n spaces, widening the field if
necessary. If omitted, n defaults to one.
Unrecognised control tokens are ignored. A quotation mark may be inserted in the printed text by
using two adjacent quotation marks in the text string.
There is no limit to the length of a heading text. Each line will be truncated at the width of the print
unit. The effect of using a heading which does not leave sufficient space for at least one line of text
is undefined.
See the RUN command for a discussion of how the page end pause on output to the screen may be
affected by setting a page heading.
See also:
FOOTING, PAGE
2.11-0
QMBasic 909
HUSH
Format
where
The HUSH ON statement causes all output sent to the display by CRT, DISPLAY or PRINT
statements to be suppressed. The HUSH OFF statement re-enables display.
The HUSH expr format of this statement is equivalent to HUSH ON if the value of expr is
non-zero and HUSH OFF if expr is zero.
The optional SETTING clause saves the previous state of display output control in var which can
be used later to revert to that state. Alternatively, the previous state can be obtained using the
STATUS() function immediately after the HUSH statement. In either case, the value is 1 if output
was suppressed or 0 if it was enabled.
Example
HUSH ON
EXECUTE "SELECT STOCK.FILE WITH QTY > 50"
HUSH OFF
This program fragment suppresses display while the SELECT statement is executed. Use of the
query processor COUNT.SUP option might be better as it would not hide any errors.
2.11-0
910 OpenQM
ICONV()
The ICONV() function performs input conversion. Data is converted from its external
representation to the internal form. This function is typically used to convert data entered at the
keyboard. The ICONVS() function is identical to ICONV() except that it works on each element of
a dynamic array, returning the result in a similarly delimited dynamic array.
Format
ICONV(expr, conv.spec)
ICONVS(expr, conv.spec)
where
The ICONV() function converts the value of expr to its internal representation according to the
conversion codes in conv.spec. The result of ICONV() is stored internally as a string regardless of
whether the value is a number or not except for the MO and MX conversions which always produce
an integer value.
The ICONV() function sets the STATUS() function value to indicate whether the conversion was
successful. Possible values are
0 Successful conversion.
1 Data to convert was invalid for the conversion specification. A null string is returned
for all codes except ML and MR which result of conversion of the leading numeric
portion of the input data or the entire input data if there is no leading numeric portion.
2 The conversion code was invalid. A null string is returned.
3 The day number in a date conversion was beyond the end of the month. The returned
value will be extended into the following month (e.g. 31 June becomes 1 July). This
feature can be suppressed using the NO.DATE.WRAPPING option.
See also:
Conversion codes, OCONV()
2.11-0
QMBasic 911
IDIV()
The IDIV() function divides one integer by another and returns an integer result.
Format
IDIV(dividend, divisor)
where
Both arguments to the IDIV() function are converted to integers. The function returns the result of
the division as an integer rounded towards zero.
Example
X = 7
Y = 2
Z1 = X / Y
Z2 = IDIV(X, Y)
This program fragment shows the difference between the division operator and the IDIV() function.
Z1 will be set to 3.5 and Z2 will be set to 3.
See also:
RDIV()
2.11-0
912 OpenQM
IF /THEN / ELSE
Format
IF expr
{THEN statement(s)}
{ELSE statement(s)}
where
At least one of the THEN and ELSE clauses must be present. If both are used, the THEN clause
must be first. An IF statement with just an ELSE clause is syntactically valid but likely to be
difficult to understand.
The statement(s) under the THEN clause are executed if the value of expr is non-zero. The
statement(s) under the ELSE clause are executed if the value of expr is zero.
Where the keyword THEN or ELSE is followed by an executable statement on the same line, the
condition applies to that statement. If there is nothing else or only a comment on the line, the
conditioned statement(s) must appear on subsequent lines terminated by an END statement. For
example:
Alternatively, this could be written using semicolons to separate the conditioned statements:
Use of this format is discouraged as the semantics differ across multivalue database products.
The above program fragment might be used to compare the quantity in an order (QTY) with the
quantity on hand (QOH), taking different paths dependant on whether there is sufficient stock. Note
the need for the END to terminate the THEN clause as, unlike some other programming languages,
the END pairs up with the THEN or ELSE and not with the IF.
2.11-0
QMBasic 913
IFS()
The IFS() function returns a dynamic array constructed from elements chosen from two other
dynamic arrays depending on the content of a third dynamic array.
Format
where
The IFS() function examines successive elements of control.array and constructs a result array
where elements are selected from the corresponding elements of either true.array or false.array
depending on the control.array value.
Example
A contains 1VM0VM0VM1VM1VM1VM0
B contains 11VM22VM3VM4VM91VM36VM7
C contains 14VM61VM2VM0VM35VM18VM3
D = IFS(A, B, C)
See also:
ANDS(), EQS(), GES(), GTS(), LES(), LTS(), NES(), NOTS(), ORS(), REUSE()
2.11-0
914 OpenQM
IN
The IN statement reads a single byte from the terminal with an optional timeout.
Format
where
var is the variable to receive the input character value. This is the ASCII character
number, not the character itself.
The IN statement reads a single byte from the terminal, returning the character value in var. Unless
the character is a non-printing control code, it is echoed to the terminal.
If a timeout is specified, the program will continue execution if no input is received after this
period. The var will be set to zero if a timeout occurs.
The optional THEN and ELSE clauses can be used with the timeout to determine whether input
was received.
See also:
INPUT, KEYIN(), KEYREADY()
2.11-0
QMBasic 915
INDEX()
The INDEX() function returns the position of a specified occurrence of a substring within a string.
The INDEXS() function is similar to INDEX() but operates on each element of a dynamic array
element separately, locating the required occurrence of substring and returning a similarly
structured dynamic array of results.
Format
where
The INDEX() function locates the specified occurrence of substring within string and returns its
character position.
If occurrence is less than one or the desired occurrence of substring is not found, the INDEX()
function returns zero.
Use of the $NOCASE.STRINGS compiler directive makes the comparison case insensitive.
Examples
N = INDEX(S, "*", 3)
This statement assigns N with the character position of the third asterisk in variable S.
S = "ABABABABABAB"
N = INDEX(S, "ABA", 2)
sets N to 5.
2.11-0
916 OpenQM
INDICES()
Format
where
The first form of the INDICES() function returns a field mark delimited list of alternate key index
names for the file referenced via file.var.
The second form of the INDICES() function returns a dynamic array resembling a dictionary
record for the index named by the index.name argument. This dynamic array is broadly similar to
the original dictionary record used to create the index except that field 1 is extended to include
additional flags as a multivalued list.
Example
2.11-0
QMBasic 917
INDEX.NAMES = INDICES(FVAR)
NUM.INDICES = DCOUNT(INDEX.NAMES, @FM)
FOR I = 1 TO NUM.INDICES
NAME = INDEX.NAMES<I>
CRT NAME : ' Type ' : INDICES(FVAR, NAME)[1,1]
NEXT I
The above program displays a list of alternate key index names and their type.
2.11-0
918 OpenQM
INHERIT
The INHERIT statement used in a class module makes the public variables, functions and
subroutines of another object visible as part of this object.
Format
INHERIT object
where
object is an object variable returned from a previous use of the OBJECT() function.
The process of searching for a public variable, function or subroutine scans the object referenced in
the statement that initiated the scan and then all inherited objects in the order in which they were
inherited. Where an inherited object has itself inherited other objects, the scan treats these inherited
names as part of the directly inherited object.
See also:
Object oriented programming, CLASS, DISINHERIT, OBJECT(), OBJINFO(), PRIVATE,
PUBLIC.
2.11-0
QMBasic 919
INMAT()
The INMAT() function provides qualifying information after certain statements are executed.
Format
INMAT({mat})
where
Used without a mat matrix name, the INMAT() function returns information relating to the last use
of the following statements
Further details of the information returned by INMAT() in each case is documented with the
relevant statement.
Used with a matrix name, the INMAT() function returns the current dimensions of the matrix. If
mat is a single dimensional matrix, INMAT() returns the number of elements, excluding the zero
element. If mat is a two dimensional matrix, INMAT() returns the number of rows and columns as
two values separated by a value mark.
Examples
DIM A(N)
IF INMAT() THEN ABORT "Insufficient memory"
This program fragment dimensions matrix A and tests whether it was successful. If not, the
program aborts. With memory sizes found on modern computer systems, dimensioning a matrix is
very unlikely to fail and this test is usually omitted.
N = INMAT(A)
FOR I = 1 TO N
A(I) += 1
NEXT I
This program fragment adds one to each element of matrix A. The INMAT() function is used
because the matrix was dimension elsewhere and hence its size is not known.
2.11-0
920 OpenQM
INPUT
The INPUT statement enables entry of data from the keyboard or from previously stored DATA
statements.
Format
where
HIDDEN echoes characters back to the screen as asterisks for password type fields.
TIMEOUT wait Sets a timeout period in seconds. If input is not received in this time, the
INPUT terminates, leaving var unchanged. The keywords FOR or
WAITING can be used in place of TIMEOUT for compatibility with
other environments.
The optional THEN and ELSE clauses used with TIMEOUT allow a program to determine
whether the input timed out. Successful input executes the THEN clause. A timeout will execute
the ELSE clause.
The INPUT statement reads data from the DATA queue or, if there is no stored data, from the
keyboard.
Keyboard Input
When taking input from the keyboard, the current prompt character will be displayed prior to
reading data. The values stored for printing characters are the ASCII characters associated with the
key. Non-printing characters result in other stored character values.
If no length expression is included, data characters are stored until the return key is pressed.
If length is specified, up to that number of characters may be entered after which input is
automatically terminated as though the return key had been pressed, any subsequent key entries
being retained for the next INPUT statement. The return key is not stored as part of the input data.
The optional underscore component of the statement suppresses the automatic input termination
when length characters have been entered. Any number of characters may be entered but only
length characters will be displayed.
The optional colon causes the carriage return and line feed output when the return key is used or on
reaching the input length limit to be suppressed.
2.11-0
QMBasic 921
The INPUT statement recognises the backspace key, allowing this to be used to correct data entry
errors. The terminfo system allows the code sent by the backspace key to be redefined from its
default char(8). If an alternative, single byte definition is used, INPUT will honour this, otherwise
char(8) is used as the backspace.
Where the data queue is not empty, the INPUT statement reads the item at the head of this queue,
copying it verbatim to var with no processing of any embedded control characters. The length
expression is ignored. The prompt character is not displayed. Unless the NO.ECHO.DATA mode
of the $MODE compiler directive is enabled, the item is displayed as though it had been typed.
The INPUT statement may be used to test whether there are characters waiting to be read from the
keyboard or the data queue by using a negative length value. For example, the statement
INPUT S, -1
Use of Pipes
QM recognises input from pipes as a special case. Programs that process data from a pipe can read
the data using the same QMBasic statements and functions as for keyboard input. If the end of the
data is reached, a subsequent INPUT will return a null string. The STATUS() function will return
ER$EOF.
Examples
INPUT ACCOUNT.NO, 10
This statement reads data into ACCOUNT.NO with a maximum length of 10 characters.
This program fragment displays a query message on the bottom line of the screen and reads a
response. Note the trailing colon in the INPUT statement to suppress the line feed which would
cause the screen to roll up as output was to the bottom line of the display.
2.11-0
922 OpenQM
INPUT @
The INPUT @ statement enables entry of data from the keyboard at a specific screen position or
from previously stored DATA statements.
Format
INPUT @(x, y) {,} {:} var {, length} {_} {:} {format} {modes}
{THEN statement(s)}
{ELSE statement(s)}
where
x, y are the screen position (column and line) at which input is to occur.
format is the format specification to the used for initial display of var and to
redisplay the data on completion of input.
The comma after the cursor position is optional and has no effect on the operation of the statement.
2.11-0
QMBasic 923
The optional THEN and ELSE clauses used with TIMEOUT allow a program to determine
whether the input timed out. Successful input executes the THEN clause. A timeout will execute
the ELSE clause.
The INPUT @ statement reads data from the DATA queue or, if there is no stored data, from the
keyboard.
Keyboard Input
When reading from the keyboard, the current prompt character will be displayed to the left of the
given input position. No prompt is displayed if the input column position, x, is zero or if the prompt
has been disabled using the PROMPT statement. The prompt character will be removed from the
screen on completion of the input.
If the colon character before var is present, the original contents or var are displayed in the input
area and entry commences in overlay mode. If the colon character before var is not present, entry
commences in insert mode with a blank field.
The values stored for printing characters are the ASCII characters associated with the key.
Non-printing characters result in stored character values as listed under Character Values for
Terminal Input.
If no length expression is included, data characters are stored until the return key is pressed.
If length is specified, up to that number of characters may be entered after which input is
automatically terminated as though the return key had been pressed, any subsequent key entries
being retained for the next INPUT statement. The return key is not stored as part of the input data.
The INPUT @ statement may not behave correctly if the length of the input field causes it to
extend over multiple lines and the terminal in use does not automatically wrap from one line to the
next when displaying long text output.
The optional underscore component of the statement suppresses the automatic input termination
when length characters have been entered. Any number of characters may be entered but only
length characters will be displayed.
The optional colon causes the carriage return and line feed output when the return key is used or on
reaching the input length limit to be suppressed.
Ctrl-A Home Position the cursor at the start of the input data
2.11-0
924 OpenQM
Ctrl-E End Position the cursor at the end of the input data
When the return key is pressed to terminate input, if a format is specified, the data is redisplayed
using this mask to apply format rules such as right justification.
Where the data queue is not empty, the INPUT @ statement reads the item at the head of this
queue, copying it verbatim to var with no processing of any embedded control characters. The
length expression is ignored. The item is displayed as though it had been typed but the prompt
character is not displayed.
Use of the STATUS() function after an INPUT @ statement returns zero unless input was
terminated by a key defined using the KEYEXIT or KEYTRAP statements.
Use of Pipes
QM recognises input from pipes as a special case. Programs that process data from a pipe can read
the data using the same QMBasic statements and functions as for keyboard input. If the end of the
data is reached, a subsequent INPUT @ will return a null string. The STATUS() function will
return ER$EOF.
Examples
This program fragment displays the current value of ACCOUNT.NO with a suitable annotation and
accepts input. Pressing the RETURN key alone will retain the original value as displayed. The
PROMPT statement has been used to suppress display of the prompt character.
2.11-0
QMBasic 925
This program fragment inputs a value for the PRICE variable, redisplaying it right justified on
completion of input.
See also:
BINDKEY(), INPUTFIELD, KEYCODE(), KEYEDIT, KEYEXIT, KEYTRAP
2.11-0
926 OpenQM
INPUTCSV
The INPUTCSV statement enables entry of CSV format data from the keyboard or from
previously stored DATA statements.
Format
where
var1 var2, ... are the variables to receive the input data.
The INPUTCSV statement reads CSV format data from the DATA queue or, if there is no stored
data, from the keyboard. This data is then parsed into the named variables.
If there are insufficient data items entered to populate all the named variables, any unused variables
are set to null strings. If there are more data items entered than the number of variables, the excess
data is discarded.
Keyboard Input
When taking input from the keyboard, the current prompt character will be displayed prior to
reading data. The values stored for printing characters are the ASCII characters associated with the
key. Non-printing characters result in other stored character values.
The INPUTCSV statement recognises the backspace key, allowing this to be used to correct data
entry errors. The terminfo system allows the code sent by the backspace key to be redefined from its
default char(8). If an alternative, single byte definition is used, INPUTCSV will honour this,
otherwise char(8) is used as the backspace.
Where the data queue is not empty, the INPUTCSV statement reads the item at the head of this
queue, copying it verbatim to var with no processing of any embedded control characters. The item
is displayed as though it had been typed.
Example
This statement parses the entered data into the PROD.NO and QTY variables.
See also:
PRINTCSV, READCSV, WRITECSV
2.11-0
QMBasic 927
INPUTFIELD
The INPUTFIELD statement enables entry of data from the keyboard at a specific screen position
or from previously stored DATA statements. It differs from INPUT @ in that it terminates on
entry of any control character not recognised as an editing key. This allows application software to
capture and handle control and function keys.
Format
INPUTFIELD @(x, y) {,} {:} var, length {_} {:} {format} {modes}
{THEN statement(s)}
{ELSE statement(s)}
where
x, y are the screen position (column and line) at which input is to occur.
format is the format specification to the used for initial display of var and to
redisplay the data on completion of input.
2.11-0
928 OpenQM
The comma after the cursor position is optional and has no effect on the operation of the statement.
The optional THEN and ELSE clauses used with TIMEOUT allow a program to determine
whether the input timed out. Successful input executes the THEN clause. A timeout will execute
the ELSE clause.
The INPUTFIELD statement reads data from the DATA queue or, if there is no stored data, from
the keyboard.
The INPUTFIELD statement works similarly to the INPUT @ statement except that entry of any
control character not recognised as an editing function (see INPUT @) terminates data entry. The
STATUS() function can be used to determine the key that caused exit. This will return zero for the
return key and the internal key code for any other key.
When the return key is pressed to terminate input, if a format is specified, the data is redisplayed
using this mask to apply format rules such as right justification.
Keyboard Input
When reading from the keyboard, the current prompt character will be displayed to the left of the
given input position. No prompt is displayed if the input column position, x, is zero or if the prompt
has been disabled using the PROMPT statement. The prompt character will be removed from the
screen on completion of the input.
If the colon character before var is present, the original contents or var are displayed in the input
area and entry commences in overlay mode. If the colon character before var is not present, entry
commences in insert mode with a blank field.
The values stored for printing characters are the ASCII characters associated with the key.
Non-printing characters result in stored character values as listed under Character Values for
Terminal Input.
If no length expression is included, data characters are stored until the return key is pressed.
If length is specified, up to that number of characters may be entered after which input is
automatically terminated as though the return key had been pressed, any subsequent key entries
being retained for the next INPUT statement. The return key is not stored as part of the input data.
The INPUTFIELD statement may not behave correctly if the length of the input field causes it to
extend over multiple lines and the terminal in use does not automatically wrap from one line to the
next when displaying long text output.
The optional underscore component of the statement suppresses the automatic input termination
when length characters have been entered. Any number of characters may be entered but only
2.11-0
QMBasic 929
The optional colon causes the carriage return and line feed output when the return key is used or on
reaching the input length limit to be suppressed.
Where the data queue is not empty, the INPUT @ statement reads the item at the head of this
queue, copying it verbatim to var with no processing of any embedded control characters. The
length expression is ignored. The item is displayed as though it had been typed.
See also:
BINDKEY(), INPUT@, KEYCODE(), KEYEDIT, KEYEXIT, KEYTRAP
2.11-0
930 OpenQM
INS
The INS statement and INSERT() function insert a field, value or subvalue into a dynamic array.
Format
where
field evaluates to the number of the field before which insertion is to occur.
value evaluates to the number of the value before which insertion is to occur. If
omitted or zero, value 1 is assumed.
subvalue evaluates to the number of the subvalue before which insertion is to occur. If
omitted or zero, subvalue 1 is assumed.
The string is inserted before the specified field, value or subvalue of the dynamic array. The INS
statement assigns the result to the dyn.array variable. The INSERT() function returns the result
without modifying dyn.array.
A negative value of field, value or subvalue causes the next item at this level to be appended. For
example,
INS X BEFORE S<3, -1>
appends X as a new value at the end of field 3 of S. See the description of the S<f,v,sv> assignment
operator for a discussion of how QM appends items.
Additional delimiters will be added to reach the specified field, value and subvalue unless the string
to be inserted is null. Absent fields, values and subvalues are assumed to be null so there is no need
to insert additional marks in this case.
Setting the COMPATIBLE.APPEND option of the $MODE compiler directive modifies the
behaviour such that a mark character is not inserted if the final element of the portion of the
dynamic array to which data is being appended is null.
Example
This program fragment locates PART.NO in a sorted list PARTS and, if it is not already present,
inserts it.
2.11-0
QMBasic 931
See also:
DEL, DELETE(), EXTRACT(), FIND, FINDSTR, LISTINDEX(), LOCATE, LOCATE(),
REPLACE()
2.11-0
932 OpenQM
INT()
Format
INT(expr)
where
The INT() function returns the integer part of expr. Any fractional part after rounding in
accordance with the INTPREC configuration parameter is discarded such that INT(1.9), for
example, evaluates to 1.
If expr is a numeric array (a dynamic array where all elements are numeric), the INT() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
N = INT(A / B)
This statement finds the integer part of the quotient of A / B and assigns this to N. The IDIV()
function provides an alternative way to achieve this but is specific to QMBasic.
2.11-0
QMBasic 933
ITYPE()
The ITYPE() function executes a compiled I or C-type dictionary record or an A or S-type with a
correlative.
Format
ITYPE(itype)
where
The ITYPE() function evaluates expression compiled as part of the given I-type dictionary record
and returns its result. C-type and A/S-type records with correlatives can also be evaluated using this
function.
The working environment for the ITYPE() function must be established by setting @ID to the key
of the record being processed and @RECORD to the record data if these are used by the
expression. These variables are also used internally by the query processor to store the id and data
for the current record. If the expression evaluated by the ITYPE() function calls a subroutine that
modifies these variables, the original values must be saved and reinstated if the dictionary item is to
be usable within the query processor.
The dictionary record must have been compiled before the ITYPE() function is used.
If the byte ordering of the object code in the itype variable is not the same as that of the machine on
which it is being executed, it will be converted automatically and the itype variable will be modified
to contain the converted object code so that a subsequent call to the ITYPE() function will not
repeat the conversion.
The ITYPE() function can also be used to evaluate D-type items and A or S type items that do not
include a correlative. Although the performance of this use of the function will be significantly
lower than simple field extraction in the calling program, it may allow some programs that do not
require best performance to adopt a generalised interface for all dictionary record types that return
data item values.
Example
This program fragment reads dictionary record "AGE" to IREC. This might, perhaps, be an I-type
to calculate a person's age from their date of birth. The @RECORD variable is set to the data to be
processed and the ITYPE() function is used to execute the I-type.
2.11-0
934 OpenQM
KEYCODE()
Format
KEYCODE({timeout})
The KEYCODE() function pauses program execution until a key is pressed. The character
associated with that key is returned as the value of the function. The character is not echoed to the
display.
The optional timeout parameter specifies a period in seconds after which the function will return if
no input is received. In this case the returned value is a null string and the STATUS() function will
return ER$TIMEOUT.
A null string is also returned when taking input from a pipe if the piped data stream is exhausted. In
this case the STATUS() function will return ER$EOF. The value returned by the STATUS()
function is not significant unless KEYCODE() has returned a null string.
The KEYCODE() function differs from KEYIN() in that it uses the terminfo database to identify
certain special keys and returns the character representing the internal representation of that key as
defined in the KEYIN.H include record in the SYSCOM file. The special keys recognised by this
function are:
Function keys F1 to F12
Left, right, up and down cursor keys
Page up and Page down keys
Home and End
Insert and Delete
Backtab
Mouse
Use of the Escape key will return char(27) if no further characters are received within 200mS. This
mechanism can be disabled using the BINDKEY() function.
The mouse code is returned when the mouse control prefix sequence defined in the terminfo
database is detected. The way in which mouse clicks are handled varies considerably between
different terminal emulators and will almost certainly require device specific programming. The
following code sample works for the AccuTerm emulator in its vt100 mode if the terminfo kmous
key is defined as "\E[101~".
C = KEYCODE()
IF SEQ(C) = K$MOUSE THEN
S = ''
LOOP
C = KEYIN()
2.11-0
QMBasic 935
UNTIL C = 'R'
S := C
REPEAT
ROW = MATCHFIELD(S, '0X0N;0N', 2)
COL = MATCHFIELD(S, '0X0N;0N', 4)
END
Stylus taps are enabled on a PDA using the @(IT$STYLUS) function. When enabled, a stylus tap
sends char(200) (K$MOUSE) followed by the column and row coordinates, separated by a comma
and terminated by a carriage return. The following function extends KEYCODE to recognise stylus
taps, returning the mouse code to the caller and leaving the screen coordinates in a common block.
FUNCTION KEY()
$CATALOGUE KEY
$INCLUDE KEYS.H
$INCLUDE KEYIN.H
DISPLAY @(IT$STYLUS,1):
K = KEYCODE()
DISPLAY @(IT$STYLUS,0):
IF SEQ(K) = K$MOUSE THEN
ECHO OFF
INPUT S ;* Get coordinate data
HUSH OFF
STYLUS.COL = MATCHFIELD(S, '0N","0N', 1)
STYLUS.ROW = MATCHFIELD(S, '0N","0N', 3)
END
RETURN K
END
2.11-0
936 OpenQM
KEYEDIT
The KEYEDIT statement defines editing keys for use with INPUT @.
Format
where
action identifies the editing action to be performed when the key is pressed. This may be:
2 Cursor left
3 Return
4 Backspace
6 Cursor right
7 Insert character (treated as action 13)
8 Delete character
13 Toggle insert mode
A negative action value removes the key binding specified by key.
key identifies the key to be bound to the given action. This is specified as a numeric
value:
1 to 31 Use the control key with this character value. Ctrl-A is 1, Ctrl-B is
2, etc.
32 to 159 Use the Escape key followed a character value of key - 32 (e.g.
Esc-A is 97).
160+ Use a sequence of up to four characters constructed from the bytes
sent by the key to be trapped starting from the low order byte plus
160. See below for an example.
The KEYEDIT statement adds user defined alternative key bindings to the standard set used by
the INPUT @ statement. These may validly replace default bindings. The newly bound keys remain
in effect until either they are rebound by a further KEYEDIT statement or the process returns to
the command prompt.
The INPUT @ statement checks for keys bound via the terminfo system or KEYEDIT before
using the standard default bindings.
The F2 key of a vt100 terminal using the vt100-at definition with AccuTerm sends a three character
sequence of "Esc O Q". The hexadecimal values of these characters are 1B, 4F, 51. The key value
is formed by concatenating bytes with these character values in reverse order and adding 160. The
simplest way to do this is
2.11-0
QMBasic 937
See also:
BINDKEY(), INPUT@, INPUTFIELD, KEYCODE(), KEYEXIT, KEYTRAP
2.11-0
938 OpenQM
KEYEXIT
The KEYEXIT statement defines exit keys for use with INPUT @.
Format
where
action is a user defined value in the range 1 to 255 to be returned by the STATUS()
function following an INPUT @ that is terminated by use of the key defined by
key.
A negative action value removes the key binding specified by key.
key identifies the key to be bound to the given action. This is specified as a numeric
value:
1 to 31 Use the control key with this character value. Ctrl-A is 1, Ctrl-B is
2, etc.
32 to 159 Use the Escape key followed a character value of key - 32 (e.g.
Esc-A is 97).
160+ Use a sequence of up to four characters constructed from the bytes
sent by the key to be trapped starting from the low order byte plus
160. See below for an example.
The KEYEXIT statement defines one or more keys that will terminate an INPUT @ statement.
When any of these keys in pressed the INPUT @ returns with the input data as entered up to the
moment when this key was used. The STATUS() function will return the value defined by action
for the key.
See the KEYTRAP statement for a method to return the original data.
The F2 key of a vt100 terminal using the vt100-at definition with AccuTerm sends a three character
sequence of "Esc O Q". The hexadecimal values of these characters are 1B, 4F, 51. The key value
is formed by concatenating bytes with these character values in reverse order and adding 160. The
simplest way to do this is
KEY = XTD('514F1B') + 160
See also:
BINDKEY(), INPUT@, INPUTFIELD, KEYCODE(), KEYEDIT, KEYTRAP
2.11-0
QMBasic 939
KEYIN()
The KEYIN(), KEYINC() and KEYINR() functions read a single keystroke from the keyboard.
Format
KEYIN({timeout})
KEYINC({timeout})
KEYINR({timeout})
The KEYIN() function pauses program execution until a key is pressed. The character associated
with that key is returned as the value of the function. The character is not echoed to the display.
The KEYINC() function is identical except that the case of alphabetic characters is inverted in case
inversion has been enabled.
The KEYINR() function reads a single character with no internal processing. In particular, null
characters are not removed and char(10) and char(13) are passed through without any special
handling.
The KEYINR() function is redundant from release 2.1-8 as QM now honours the setting of the
telnet binary mode parameter. The function will be retained as a synonym for KEYIN() for the
foreseeable future.
KEYIN(), KEYINC() and KEYINR() do not take data from the DATA statement queue.
The optional timeout parameter specifies a period in seconds after which the function will return if
no input is received. In this case the returned value is a null string and the STATUS() function will
return ER$TIMEOUT. The timeout value may be fractional to specify timeouts of less than one
second. Values less than 10mS or greater than 24 hours may not behave correctly.
A null string is also returned when taking input from a pipe if the piped data stream is exhausted. In
this case the STATUS() function will return ER$EOF. The value returned by the STATUS()
function is not significant unless KEYIN() has returned a null string.
Character Values
The printing characters and control characters are all represented by their normal ASCII characters.
Other keystrokes such as the function keys, ALT sequences and special keys (Home, Delete, cursor
moves, etc) are represented by characters with values of 128 and upwards. Click here for a table of
key code values.
See also:
IN, KEYCODE(), KEYREADY()
2.11-0
940 OpenQM
KEYREADY()
Format
KEYREADY()
The KEYREADY() function tests whether characters have been typed at the keyboard, returning
true if characters are waiting to be processed, false if not. It differs from use of the INPUT
statement with a negative length value in that KEYREADY() checks the keyboard only whereas
INPUT checks the keyboard and the DATA statement queue.
KEYREADY() always returns true when using piped input. The end of file condition can only be
determined by a subsequent attempt to read data from the pipe.
Data detected by KEYREADY() may be read by a subsequent use of either KEYIN() or INPUT.
See also:
IN, KEYIN()
2.11-0
QMBasic 941
KEYTRAP
The KEYTRAP statement defines trap keys for use with INPUT @.
Format
where
action is a user defined value in the range 1 to 255 to be returned by the STATUS()
function following an INPUT @ that is terminated by use of the key defined by key
.
A negative action value removes the key binding specified by key.
key identifies the key to be bound to the given action. This is specified as a numeric
value:
1 to 31 Use the control key with this character value. Ctrl-A is 1, Ctrl-B is
2, etc.
32 to 159 Use the Escape key followed a character value of key - 32 (e.g.
Esc-A is 97).
160+ Use a sequence of up to four characters constructed from the bytes
sent by the key to be trapped starting from the low order byte plus
160. See below for an example.
The KEYTRAP statement defines one or more keys that will terminate an INPUT @ statement.
When any of these keys in pressed the INPUT @ returns with the original value of the input
variable. The STATUS() function will return the value defined by action for the key.
See the KEYEXIT statement for a method to return the input data as entered up to the moment
when this key was used.
The F2 key of a vt100 terminal using the vt100-at definition with AccuTerm sends a three character
sequence of "Esc O Q". The hexadecimal values of these characters are 1B, 4F, 51. The key value
is formed by concatenating bytes with these character values in reverse order and adding 160. The
simplest way to do this is
KEY = XTD('514F1B') + 160
See also:
BINDKEY(), INPUT@, INPUTFIELD, KEYCODE(), KEYEDIT, KEYEXIT
2.11-0
942 OpenQM
LEN()
The LEN() function returns the length of a string. The LENS() function is similar to LEN() but
operates on successive elements of a dynamic array, returning a similarly structured dynamic array
of results.
Format
LEN(string)
where
The LEN() function returns the length of string including any trailing spaces.
Example
LOOP
DISPLAY "Enter account number: "
INPUT ACCOUNT.NO
WHILE LEN(ACCOUNT.NO) # 6
PRINTERR "Invalid account number"
REPEAT
This program fragment prompts for and inputs an account number. If it is not six characters in
length, an error is displayed and the prompt is repeated.
2.11-0
QMBasic 943
LES()
The LES() function processes two dynamic arrays, returning a similarly structured result array
indicating whether elements of the first array are less than or equal to corresponding elements of the
second array.
Format
LES(expr1, expr2)
where
The LES() function compares corresponding elements of the dynamic arrays expr1 and expr2,
returning a similarly structured dynamic array of true / false values indicating the results of the
comparison.
The REUSE() function can be applied to either or both expressions. Without this function, any
absent trailing values are taken as zero.
Example
A contains 11FM0VM14VMABCFM2
B contains 12FM0VM14VMACBFM2
C = LES(A, B)
See also:
ANDS(), EQS(), GES(), GTS(), IFS(), LTS(), NES(), NOTS(), ORS(), REUSE()
2.11-0
944 OpenQM
LISTINDEX()
Format
where
The LISTINDEX() function returns the position of item in the delimited list. If it is not found, the
function returns zero.
See the LOCATE statement for a more powerful way of searching dynamic arrays.
Examples
This program fragment extracts the suffix from a Windows style file name and checks whether it is
TXT, DOC or PDF. If so, the document name is displayed.
Used as an expression in a dictionary I-type item, this example searches field PROD.NO for an
entry containing PART and extracts the corresponding entry from the QTY field. If the item is not
found, a null string is returned.
See also:
DEL, DELETE(), EXTRACT(), FIND, FINDSTR, INS, INSERT(), LOCATE, LOCATE(),
REPLACE()
2.11-0
QMBasic 945
LN()
Format
LN(expr)
where
The LN() function returns the natural log of expr. It is the inverse of the EXP() function.
If expr is a numeric array (a dynamic array where all elements are numeric), the LN() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
N = LN(X)
See also:
EXP()
2.11-0
946 OpenQM
LOCAL
The LOCAL statement introduces an internal function or subroutine that may have private local
variables.
Format
where
When passing a whole matrix as an argument to a local function or subroutine, a DIM statement
can be used within the body of the local function or subroutine to redimension the matrix. This is
not the same behaviour as applying DIM to a matrix passed as an argument to an external
subroutine where the DIM statement merely specifies the number of dimensions, the actual
dimension values being ignored.
Further local variables that are private to the function or subroutine may be defined by immediately
following the LOCAL statement by one or more PRIVATE statements. These contain a comma
separated list of variable names which may be simple scalar items or matrices where the dimension
values are numeric constants. Any variables referenced in the local function or subroutine but not
declared as private are considered as having scope across the entire program module.
Functions and subroutines declared using LOCAL must be terminated with an END statement.
The private variables declared using the PRIVATE statement have scope from the LOCAL
statement until the corresponding END statement. Variables referenced in the main body of the
program and in conventional internal subroutines are accessible unless they have the same name as
a locally defined variable.
A local function must be defined using the DEFFUN statement with the LOCAL option before its
first use in the program.
All labels within the local subroutine are private. It is not possible to jump into a subroutine
declared with LOCAL except by using a GOSUB or ON GOSUB to its unique entry point.
Similarly, it is not possible to jump to a label outside the local subroutine. Use of the
RETURN TO statement is prohibited within a local subroutine.
If a local subroutine is called recursively, either directly or indirectly via some other intermediate
2.11-0
QMBasic 947
subroutine, the local variables are stacked and the new invocation has its own private local
variables.
There is a small performance cost by comparison to use of conventional internal subroutines due to
the dynamic allocation of variables but this should be negligible in most applications.
When using the QMBasic debugger, local variables have a name formed from the subroutine name
and variable name separated by a colon.
Examples
The above program fragment represents a local subroutine that scans a list, checking that each entry
corresponds to a record in a file. By using LOCAL and three local variables, all risk of overwriting
valuable data in variables of the same names in the main body of the program is removed.
The above local function takes a file name as its argument and gets the next sequential record id
from a record stored in the corresponding dictionary, returning this as the value of the function. The
dictionary will automatically be closed when the DICT.F variable is discarded on return from the
function.
2.11-0
948 OpenQM
LOCATE
The LOCATE statement searches a dynamic array for a given field, value or subvalue. The
LOCATE() function provides similar capabilities and is particularly suited to use in dictionary
I-type items.
Format
This statement has three different syntaxes / semantics for compatibility with other systems.
Default style
LOCATE string IN dyn.array<field {,value {, subvalue}}> {BY order} {SETTING var}
{THEN statement(s)}
{ELSE statement(s)}
Pick style
LOCATE(string, dyn.array{, field {, value {, start }}}; var {; order})
{THEN statement(s)}
{ELSE statement(s)}
where
2.11-0
QMBasic 949
The LOCATE statement searches for fields, values or subvalues within a dynamic array. The
semantics of this operation depend on the style selected as described below.
Default Style
The default style of LOCATE is as found in products such as Prime Information, PI/open and
with certain mode settings in UniVerse and Unidata.
If only field is specified, LOCATE searches for a field that matches string. If field and value are
specified but subvalue is omitted, LOCATE searches for a value within the specified field that
matches string. If field, value and subvalue are specified, LOCATE searches for a subvalue within
the specified field and value that matches string.
Searching commences at the starting position defined in the IN clause. If a match is found, var is
set to its field, value or subvalue position as appropriate to the level of the search. If no match is
found, var is set to the position at which a new item should be inserted. For an unordered
LOCATE this will be such that it would be appended.
Note that the syntax actually reads incorrectly. A LOCATE statement such as
LOCATE DT IN DATES<1> SETTING POS THEN ...
is not searching in DATES<1> at all. It is searching starting at DATES<1>.
UniVerse Style
Pick and Reality systems and the UniVerse database running in Ideal, Pick, Reality or IN2 flavour
uses the IN clause to identify the item to be searched, not the starting position. The starting position
is assumed to be the first item in the data but may specified explicitly in the command by including
the start item.
Pick Style
The original Pick database used a very different syntax which can be used in QM without any
special mode settings. Note that despite the presence of brackets, this is a statement and should not
be confused with the LOCATE() function described below.
In all three styles, the THEN clause is executed if the string is found in dyn.array. The ELSE
clause is found if the string is not found.
In QMBasic, unlike other multivalue environments, the SETTING clause is optional. If omitted,
the THEN or ELSE clause is executed as described above but no positional information is
returned.
Note that this syntax, as found in Information style multivalue products, is actually illogical. The
IN clause does not specify the data within which to search. Instead it specifies the start position for
2.11-0
950 OpenQM
the search. The alternative syntax enabled by the UV.LOCATE compiler mode and described below
is more logical. This syntax is found in Pick, Reality and some flavours of UniVerse.
The optional BY clause allows selection of an ordering rule. The order must evaluate to a two
character string, which is
DL Descending, left justified. Similar to AL except that the list is held in descending
collating sequence.
DR Descending, right justified. Similar to AR except that the list is held in descending
collating sequence.
The ordering string must be in upper case. Left aligned ordering is faster than right aligned and
should be used for textual data. Right aligned ordering is useful for numeric data such as internal
format dates where the left aligned ordering would lead to sequencing problems (for example, 17
May 1995 is day 9999, 18 May 1995 is day 10000. Use of a left aligned ordering would place these
dates out of calendar order).
The LOCATE() function works like the Information style described above but returns the position
at which the item was found as its result value, zero if it was not found. Although the order
argument can be used to specify the expected ordering and has the impact described above for
numeric data, this function does not provide a way to identify where an item should be inserted if it
is not found. The LOCATE() function is particularly suited to use in dictionary I-type items.
The result of a LOCATE statement or LOCATE() function with a specific ordering when applied
to a dynamic array which does not conform to that ordering is undefined and likely to lead to
misbehaviour of the program at run time.
Use of the $NOCASE.STRINGS compiler directive makes the comparison case insensitive. When
used with a BY clause, the sorting is effectively as though both string and dyn.array are in
uppercase.
Examples
Default style:
LOCATE PART.NO IN PARTS<1> BY "AL" SETTING I ELSE
INS PART.NO BEFORE PARTS<I>
END
This program fragment locates PART.NO in a sorted list PARTS and, if it is not already present,
inserts it.
2.11-0
QMBasic 951
UniVerse style:
LOCATE PART.NO IN PARTS BY "AL" SETTING I ELSE
INS PART.NO BEFORE PARTS<I>
END
This is the same as the first example but reworked to use UniVerse style.
Function stye:
I = LOCATE(PART.NO, PARTS, 1; "AL")
This statement performs the same search as the previous example but can only be used to find the
position of an existing item, not to determine where a new item should be inserted to maintain the
correct sort order.
See also:
DEL, DELETE(), EXTRACT(), FIND, FINDSTR, INS, INSERT(), LISTINDEX(),
REPLACE()
2.11-0
952 OpenQM
LOCK
Format
where
The THEN and ELSE clauses are both optional. Neither is required.
Task locks provide a means of synchronising the activities of multiple processes without using locks
on records in data files. The LOCK statement attempts to acquire the lock identified by lock.num.
The THEN clause is executed if the lock was available or was already held by this process.
The ELSE clause is executed if the lock is held by another process. If no ELSE clause is present,
the LOCK statement waits for the lock to become available. This wait can be interrupted by using
the break key.
The STATUS() function returns zero if the lock was free when the LOCK statement was executed.
Otherwise it returns the user number of the process that held the lock. This will be the user number
of the current process if it already owned the lock.
There is no means for a program to determine which task locks are held by the user except by
attempting to acquire each lock in turn and checking the value of the STATUS() function. Beware
that unlike read, update and file locks, task locks are only automatically released on leaving QM,
not on return to the command prompt.
Examples
LOCK 7 THEN
...processing statements...
UNLOCK 7
END
ELSE ABORT "Cannot obtain task lock"
This program fragment obtains task lock 7, performs some critical processing and then releases the
lock. The program aborts if the lock is not available.
LOCK 7
This statement attempts to obtain task lock 7 but, unlike the previous example, waits for the lock to
become free if it is owned by another user.
2.11-0
QMBasic 953
See also:
CLEAR.LOCKS, LOCK (Command), LIST.LOCKS, TESTLOCK(), UNLOCK
2.11-0
954 OpenQM
LOGMSG
The LOGMSG statement adds a line to the system error log. This statement has no effect on the
PDA version of QM.
Format
LOGMSG text
where
QM includes the option to maintain a log of system error messages in a file named errlog in the
QMSYS account. The LOGMSG statement can be used by application software to write messages
into this file. If the error log is disabled, the LOGMSG statement will be ignored.
Although programs can write to this file using the sequential file handling statements, the internal
buffering mechanism used by these statements is likely to result in loss of messages. Programs
should, therefore, use on the LOGMSG statement to write messages.
Example
The above program fragment logs a message in the system error log if the NEXT.ORDER record
cannot be found in the VOC
See also:
LOGMSG command
2.11-0
QMBasic 955
LOOP / REPEAT
Format
LOOP
{statement(s)}
{WHILE expr}
{UNTIL expr}
{statement(s)}
REPEAT
where
There may be any number of WHILE or UNTIL statements within the loop appearing at any
position relative to other statements.
Execution of the statements within the loop continues repeatedly until either the expression
associated with a WHILE statement evaluates to zero or the expression associated with an UNTIL
statement evaluates to a non-zero value.
The loop may also be terminated by an EXIT statement as detailed in its own description.
The CONTINUE statement may be used to commence the next iteration of the loop without
execution of any intervening statements.
Example
LOOP
REMOVE ITEM FROM ITEM.LIST SETTING MORE
DISPLAY "Item id " : ITEM
WHILE MORE
REPEAT
This program fragment displays the elements of the dynamic array ITEM.LIST.
See also:
CONTINUE, EXIT, FOR/NEXT, WHILE, UNITL
2.11-0
956 OpenQM
LOWER()
The LOWER() function converts mark characters in a string to the next lower level mark.
Format
LOWER(string)
where
The LOWER() function replaces mark characters according to the following table:
Original Replacement
Item mark Field mark
Field mark Value mark
Value mark Subvalue mark
Subvalue mark Text mark
Text mark Text mark (unchanged)
Example
This statement reads active select list zero to LIST and then saves it in field 4 of REC. Because a
select list contains field marks, the LOWER() function is used to demote each mark character to
the next lowest mark.
See also:
RAISE()
2.11-0
QMBasic 957
LTS()
The LTS() function processes two dynamic arrays, returning a similarly structured result array
indicating whether elements of the first array are less than corresponding elements of the second
array.
Format
LTS(expr1, expr2)
where
The LTS() function compares corresponding elements of the dynamic arrays expr1 and expr2,
returning a similarly structured dynamic array of true / false values indicating the results of the
comparison.
The REUSE() function can be applied to either or both expressions. Without this function, any
absent trailing values are taken as zero.
Example
A contains 11FM0VM14VMABCFM2
B contains 12FM0VM14VMACBFM2
C = LTS(A, B)
See also:
ANDS(), EQS(), GES(), GTS(), IFS(), LES(), NES(), NOTS(), ORS(), REUSE()
2.11-0
958 OpenQM
MARK.MAPPING
The MARK.MAPPING statement determines how field marks are handled when reading or writing
from a directory file.
Format
where
Data written to directory files usually has field marks translated to newlines. On reading, the
reverse translation is performed to recover the original data. Records storing binary information
may contain bytes that appear to be field marks and these will be translated, possibly causing data
corruption.
Use of MARK.MAPPING file.var, OFF will suppress this mark mapping process until a
subsequent MARK.MAPPING file.var, ON statement or the file is closed.
Example
2.11-0
QMBasic 959
MAT
The MAT statement assigns a value to all elements of a matrix, copies one matrix to another, or
tests for equivalent matrices.
Format
where
The first format of this statement copies the value of expr into all elements of matrix. The zero
element is set to a null string.
The second format copies elements from matrix1 to matrix2 row by row. If the number of columns
differs, the copy behaves as depicted below.
Source: Target:
1 2 1 2 3
1 A B 1 A B C
2 C D 2 D E F
3 E F
If src.matrix has more elements than matrix, the excess elements are ignored. If src.matrix has
fewer elements than matrix, the remaining elements of matrix are unchanged.
A single dimensional matrix can be copied to a two dimensional matrix and vice versa.
The third syntax tests whether the content of matrix1 is the same as the content of matrix2.
Although most likely to be used as part of an IF statement as shown above, the
MAT matrix1 = MAT matrix2
component of this statement may be used anywhere that a boolean value is appropriate.
Examples
DIM A(25)
MAT A = 0
2.11-0
960 OpenQM
The above program fragment dimensions matrix A to have 25 elements and sets them all to zero.
This program fragment dimensions two matrices, sets values into matrix A and then creates a single
dimensional copy of A in matrix B.
2.11-0
QMBasic 961
MATBUILD
The MATBUILD statement constructs a dynamic array from the elements of a matrix.
Format
where
start.expr evaluates to the index of the first matrix element to be used. If omitted or less
than one, this defaults to one.
end.expr evaluates to the index of the last matrix element to be used. If omitted or less
than one, this defaults to the number of elements in the matrix.
delimiter evaluates to the delimiter to be used between elements of mat. This may be
more than one character. If omitted, this defaults to the field mark.
The MATBUILD statement constructs a dynamic array by concatenating elements of mat from
element start.expr to the last non-null element before element end.expr. The delimiter is inserted
between each element. With the default style of matrix, if the zero element of mat is non-null, a
delimiter followed by the content of the zero element is appended to the end of the resultant
dynamic array. Pick style matrices do not have a zero element. See the COMMON and
DIMENSION statements for more details.
Example
This statement constructs dynamic array REC from the elements of matrix A, separating each
element by a value mark.
See also:
MATPARSE
2.11-0
962 OpenQM
MATCHESS
The MATCHESS() function compares each element of a dynamic array with a pattern template,
returning an equivalently structured dynamic array of true/false values. Note the spelling of this
function name with the trailing S to "pluralise" the name in common with other multivalue function
names.
Format
MATCHESS(dyn.arr, pattern)
where
The MATCHESS() function matches each element of dyn.arr against pattern and returns a
dynamic array of true/false values indicating the result of each comparison.
The pattern string consists of one or more concatenated items from the following list.
The values n and m are integers with any number of digits. m must be greater than or equal to n.
The 0A, nA, 0N, nN and "string" patterns may be preceded by a tilde (~) to invert the match
condition. For example, ~4N matches four non-numeric characters such as ABCD (not a string
which is not four numeric characters such as 12C4).
A null string matches patterns ..., 0A, 0X, 0N, their inverses (~0A, etc) and "".
The 0X and n-mX patterns match against as few characters as necessary before control passes to
the next pattern. For example, the string ABC123DEF matched against the pattern 0X2N0X
matches the pattern components as ABC, 12 and 3DEF.
2.11-0
QMBasic 963
The 0N, n-mN, 0A, and n-mA patterns match against as many characters as possible. For example,
the string ABC123DEF matched against the pattern 0X2-3N0X matches the pattern components as
ABC, 123 and DEF.
The pattern string may contain alternative templates separated by value marks. The
MATCHESS() function tries each template in turn until one is a successful match against string.
Example
VAR = "123":@VM:"ABC:@FM:"456"
X = MATCHESS(VAR, "3N")
See also:
Pattern Matching
2.11-0
964 OpenQM
MATCHFIELD
The MATCHFIELD() function extracts a portion of a string that matches a pattern element.
Format
where
The MATCHFIELD() function matches string against pattern and returns the portion of string
that matches the element'th component of pattern.
The pattern string consists of one or more concatenated items from the following list.
The values n and m are integers with any number of digits. m must be greater than or equal to n.
The 0A, nA, 0N, nN and "string" patterns may be preceded by a tilde (~) to invert the match
condition. For example, ~4N matches four non-numeric characters such as ABCD (not a string
which is not four numeric characters such as 12C4).
A null string matches patterns ..., 0A, 0X, 0N, their inverses (~0A, etc) and "".
The 0X and n-mX patterns match against as few characters as necessary before control passes to
the next pattern. For example, the string ABC123DEF matched against the pattern 0X2N0X
matches the pattern components as ABC, 12 and 3DEF.
2.11-0
QMBasic 965
The 0N, n-mN, 0A, and n-mA patterns match against as many characters as possible. For example,
the string ABC123DEF matched against the pattern 0X2-3N0X matches the pattern components as
ABC, 123 and DEF.
The pattern string may contain alternative templates separated by value marks. The
MATCHFIELD() function tries each template in turn until one is a successful match against
string.
The element argument determines which component of string is returned as the MATCHFIELD()
function result. For example,
MATCHFIELD("ABC123DEF", "0X2N0X", 2)
The MATCHFIELD() function returns a null string if no component of pattern matches string.
Example
TEL.NO = "01604-709200"
LOCAL.NO = MATCHFIELD(TEL.NO, "0N'-'0N", 3)
This program fragment extracts the local part of a telephone number (709200 in this case). Note
that the literal element counts as a component of the string when identifying each element.
If the delimiter is multiple characters but not quoted, each character is counted as a separate
element:
See also:
Pattern Matching
2.11-0
966 OpenQM
MATPARSE
The MATPARSE statement breaks a delimited string into component substrings, assigning each to
an element of a matrix.
Format
where
mat is the matrix into which the substrings are to be assigned. This matrix must
already have been dimensioned.
delimiter evaluates to the delimiter that separates substrings within string. If omitted, a
field mark is used.
The MATPARSE statement operates in one of three ways depending on the length of the delimiter
string.
If delimiter is a null string, each character of string is assigned to a separate element of mat. If
both string and delimiter are null, no elements are assigned.
If delimiter is a one character string, each substring of string delimited by delimiter is assigned to a
separate element of mat. The delimiter character is not stored in mat.
If delimiter is more than one character long, each substring of string delimited by any character of
delimiter is assigned to a separate element of mat. The next element is assigned the character that
delimited the items. Where two or more occurrences of the same delimiter character occur within
string with no other intervening characters, only a single element of mat is used to receive the
multiple delimiters.
In all cases, the INMAT() function will return the number of elements assigned. Unused elements
are set to null strings.
With the default style of matrix, where there are insufficient elements in mat to receive the parsed
string, the remaining unparsed data is stored in the zero element of mat. In this case, the INMAT()
function will return zero.
Pick style matrices do not have a zero element. Any excess data is stored in the final element of the
matrix and the INMAT() function returns zero to indicate this condition. See the COMMON and
DIMENSION statements for more details.
Example
2.11-0
QMBasic 967
DIM A(30)
MATPARSE A FROM S, @FM
This program fragment assigns successive fields of string S to elements of matrix A. If there are
more than 30 fields, the remaining fields and delimiting mark characters are stored in A(0).
See also:
MATBUILD
2.11-0
968 OpenQM
MATREAD
The MATREAD statement reads a record from a file, assigning each field to an element of a
matrix.
The MATREADL statement is similar to MATREAD but sets a read lock on the record. The
MATREADU statement sets an update lock on the record.
Format
where
mat is the matrix into which fields are to be assigned. This matrix must already
have been dimensioned.
The LOCKED clause is not valid with the MATREAD statement. At least one of the THEN and
ELSE clauses must be present.
Each field of the record is assigned to a separate element of mat. If mat is two dimensional, its
elements are assigned row by row. The INMAT() function will return the number of elements
assigned. Unused elements are set to null strings.
With the default style of matrix, where there are fewer elements in mat than the number of fields in
the record, the remaining data is stored in the zero element of mat. In this case, the INMAT()
function will return zero.
Pick style matrices do not have a zero element. Any excess data is stored in the final element of the
matrix and the INMAT() function returns zero to indicate this condition. See the COMMON and
DIMENSION statements for more details.
2.11-0
QMBasic 969
Example
DIM ITEMS(30)
MATREAD ITEMS FROM ITEM.FILE, "ITEM.LIST" ELSE
ABORT "ITEM.LIST record not found"
END
IF INMAT() THEN DISPLAY INMAT() : " items read"
ELSE ABORT "Too many items"
This program fragment reads a record from a file, assigning fields to elements of matrix ITEMS. If
there are more than 30 fields, the program aborts, otherwise it displays the number of items read.
2.11-0
970 OpenQM
MATREADCSV
The MATREADCSV statement reads a CSV format line of text from a directory file record
previously opened for sequential access and parses it into the elements of a dimensioned matrix.
Format
where
matrix is the dimensioned matrix to receive the data read from the file.
file.var is the file variable associated with the record by a previous OPENSEQ
statement.
A line of text is read from the file. It is then parsed according to the CSV format rules, placing the
elements into successive elements of the matrix. If successful, the THEN clause is executed and
the STATUS() function would return zero.
If there are fewer data items in the line of text than the number of variables supplied, the remaining
elements of the matrix will be set to null strings. If the line of text has more data items than the
number of elements in the matrix, the excess data is placed in the zero element as for MATPARSE.
If there are no further fields to be read, the ELSE clause is executed and the STATUS() function
would return ER$RNF (record not found). The target matrix will be unchanged.
Example
DIM DETAILS(10)
LOOP
MATREADCSV DETAILS FROM DELIVERY.F ELSE EXIT
GOSUB PROCESS.DELIVERY.DETAILS
REPEAT
This program fragment reads CSV format lines of text from the record open for sequential access
via the DELIVERY.F file variable into elements of the DETAILS matrix. It then calls the
PROCESS.DELIVERY.DETAILS subroutine to process the new item. The loop terminates when
the ELSE clause is executed when all fields have been processed.
See also:
2.11-0
QMBasic 971
2.11-0
972 OpenQM
MATWRITE
The MATWRITE statement builds a record from successive elements of a matrix and writes this
to a file.
The MATWRITEU statement is similar but preserves any lock on the record being written.
Format
where
If the zero element of mat is a null string or unassigned, assembly of the dynamic array terminates
after the last non-null element of mat. No trailing null fields will be written for later unassigned
elements of mat.
If the zero element of mat contains data, all elements of mat are used and the zero element is
concatenated as the final field of the record.
Pick style matrices do not have a zero element. See the COMMON and DIMENSION statements
for more details.
If the ON ERROR clause is taken, the STATUS() function can be used to determine the cause of
the error. Otherwise, for the MATWRITE statement, the STATUS() function returns 0 if the
record was locked by this process prior to the MATWRITE or ER$NLK if it was not locked. The
STATUS() function value is undefined after a successful MATWRITEU statement.
Example
2.11-0
QMBasic 973
This program fragment writes a record built from elements of matrix ITEMS. If it was locked prior
to the MATWRITE, a message is displayed.
2.11-0
974 OpenQM
MAX()
Format
MAX(a, b)
where
The MAX() function compares the values a and b, returning the greater value. If either value
cannot be treated as a number, a character by character comparison from the left end is performed
until a difference is found, returning the "alphabetically last" item.
Example
A = 6
B = 8
C = MAX(A, B)
See also:
MIN()
2.11-0
QMBasic 975
MAXIMUM()
Format
MAXIMUM(dyn.array)
where
The MAXIMUM() function returns the greatest numeric value in dyn.array. Non-numeric and null
elements of dyn,array are ignored. If the entire dynamic array is null, a null string is returned.
Example
S = '61':@VM:'42':@FM:'71':@VM:'57'
CRT MAXIMUM(S)
This program fragment searches S for the largest numeric value and displays the result (71).
2.11-0
976 OpenQM
MD5()
The MD5() function returns the 32 digit hexadecimal message digest value for a given string.
Format
MD5(string)
where
The MD5() function provides a more comprehensive validation process than use of the
CHECKSUM() function. The returned value is a 32 digit hexadecimal string.
Example
DISPLAY MD5('The quick brown fox jumps over the lazy dog')
See also:
CHECKSUM()
2.11-0
QMBasic 977
MIN()
Format
MIN(a, b)
where
The MIN() function compares the values a and b, returning the lesser value. If either value cannot
be treated as a number, a character by character comparison from the left end is performed until a
difference is found, returning the "alphabetically first" item.
Example
A = 6
B = 8
C = MIN(A, B)
See also:
MAX()
2.11-0
978 OpenQM
MINIMUM()
Format
MINIMUM(dyn.array)
where
The MINIMUM() function returns the lowest numeric value in dyn.array. Non-numeric and null
elements of dyn,array are ignored. If the entire dynamic array is null, a null string is returned.
Example
S = '61':@VM:'42':@FM:'71':@VM:'57'
CRT MINIMUM(S)
This program fragment searches S for the largest numeric value and displays the result (42).
2.11-0
QMBasic 979
MOD()
The MOD() function returns the modulus value of one value divided by another. The MODS()
function is similar to MOD() but operates on successive elements of two dynamic arrays, returning
a similarly structured dynamic array of results.
Format
MOD(dividend, divisor)
where
The MOD() function returns the modulus value of dividing dividend by divisor. This is defined as
where the FLOOR() function returns the highest integer with value not greater than its argument.
For example, FLOOR(-3.7) is -4. (FLOOR() is not part of QMBasic. It is used here only to explain
the action of the MOD() function).
The MOD() function differs from the REM() function when one of its arguments is negative. The
following table shows the result of the MOD() function.
The MODS() function operates on corresponding elements of two dynamic arrays, returning a
similarly structured dynamic array of results. For arrays of differing structure, the structure of the
result depends on whether the QMB.REUSE function is used.
Example
N = MOD(T, 30)
2.11-0
980 OpenQM
See also:
REM(), ROUNDDOWN(), ROUNDUP()
2.11-0
QMBasic 981
MVDATE()
The MVDATE() function returns the multivalue style date value (days since 31 December 1967)
for a supplied epoch value using the currently selected time zone.
Format
MVDATE(epoch.value)
where
An epoch value represents a moment in time. The MVDATE() function returns the date part of this
as relevant to the currently selected time zone.
Example
T = 1234567890
SET.TIMEZONE 'GMT'
DISPLAY MVDATE(T)
SET.TIMEZONE 'Pacific/Wake'
DISPLAY MVDATE(T)
The dates differ because this moment in time was 23:31:30 on 13 February 2009 in the GMT time
zone but it was 11:31:30 on 14 February 2009 in the Pacific/Wake time zone.
See also:
Date, Times and Epoch Values, EPOCH(), MVDATE.TIME(), MVEPOCH(), MVTIME(),
SET.TIMEZONE
2.11-0
982 OpenQM
MVDATE.TIME()
The MVDATE.TIME() function returns the multivalue style date and time values (days since 31
December 1967 and seconds since midnight) for a supplied epoch value using the currently selected
time zone.
Format
MVDATE.TIME(epoch.value)
where
An epoch value represents a moment in time. The MVDATE.TIME() function returns the date and
time parts of this as relevant to the currently selected time zone. The two parts are separated by an
underscore.
Example
T = 1234567890
SET.TIMEZONE 'GMT'
DISPLAY MVDATE.TIME(T)
SET.TIMEZONE 'Pacific/Wake'
DISPLAY MVDATE.TIME(T)
The dates differ because this moment in time was 23:31:30 on 13 February 2009 in the GMT time
zone but it was 11:31:30 on 14 February 2009 in the Pacific/Wake time zone.
See also:
Date, Times and Epoch Values, EPOCH(), MVDATE(), MVEPOCH(), MVTIME(),
SET.TIMEZONE
2.11-0
QMBasic 983
MVEPOCH()
The MVEPOCH() function returns the epoch value corresponding to a multivalue style date and
time combination (days since 31 December 1967 and seconds since midnight) using the currently
selected time zone.
Format
MVEPOCH(time.string)
MVEPOCH(date, time)
where
time.string is the multivalue style date and time values separated by an underscore.
An epoch value represents a moment in time. The MVEPOCH() function converts the supplied
date and time values to the corresponding epoch value using the currently selected time zone.
If the time.string or date and time represents a moment in time that cannot be converted to an epoch
value, the function returns a null string.
For most time values, the MVEPOCH() function will correctly handle daylight saving time. There
is an one hour period when the clocks are moved backwards where the same external time value will
correspond to two alternative epoch values. It is not defined which of the two will be returned by
this function in this situation.
Example
S = '15021_41490'
SET.TIMEZONE 'Pacific/Wake'
DISPLAY MVEPOCH(S)
See also:
Date, Times and Epoch Values, EPOCH(), MVDATE(), MVDATE.TIME(), MVTIME(),
SET.TIMEZONE
2.11-0
984 OpenQM
MVTIME()
The MVTIME() function returns the multivalue style time value (seconds since midnight) for a
supplied epoch value using the currently selected time zone.
Format
MVTIME(epoch.value)
where
An epoch value represents a moment in time. The MVTIME() function returns the time part of this
as relevant to the currently selected time zone.
Example
T = 1234567890
SET.TIMEZONE 'GMT'
DISPLAY MVTIME(T)
SET.TIMEZONE 'Pacific/Wake'
DISPLAY MVTIME(T)
The times differ because this moment in time was 23:31:30 on 13 February 2009 in the GMT time
zone but it was 11:31:30 on 14 February 2009 in the Pacific/Wake time zone.
See also:
Date, Times and Epoch Values, EPOCH(), MVDATE(), MVDATE.TIME(), MVEPOCH(),
SET.TIMEZONE
2.11-0
QMBasic 985
NAP
The NAP statement causes the program in which it is executed to pause for a given number of
milliseconds.
Format
NAP time
where
If the value of time is less than 5000, the program pauses for the given number of milliseconds.
This sleep cannot be interrupted by the quit key.
If the value of time is 5000 or greater, the value is truncated to whole seconds and the program
enters an interruptable sleep for that period.
The actual sleep time may vary from that specified due to process scheduling actions within the
operating system.
See also:
SLEEP
2.11-0
986 OpenQM
NEG()
The NEG() function returns the arithmetic inverse of a value. The NEGS() function is similar to
NEG() but operates on successive elements of a dynamic array, returning a similarly structured
dynamic array of results
Format
NEG(expr)
where
If expr is a numeric array (a dynamic array where all elements are numeric), the NEG() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
N = NEG(A)
2.11-0
QMBasic 987
NES()
The NES() function processes two dynamic arrays, returning a similarly structured result array
indicating whether corresponding elements are not equal.
Format
NES(expr1, expr2)
where
The NES() function compares corresponding elements of the dynamic arrays expr1 and expr2,
returning a similarly structured dynamic array of true / false values indicating the results of the
comparison.
The REUSE() function can be applied to either or both expressions. Without this function, any
absent trailing values are taken as zero.
Example
A contains 11FM0VM14VMABCFM2
B contains 12FM0VM14VMACBFM2
C = NES(A, B)
See also:
ANDS(), EQS(), GES(), GTS(), IFS(), LES(), LTS(), NOTS(), ORS(), REUSE()
2.11-0
988 OpenQM
NOBUF
The NOBUF statement turns off buffering for a record opened using OPENSEQ.
Format
NOBUF file.var
{THEN statement(s)}
{ELSE statement(s)}
where
file.var is the file variable associated with the record by a previous OPENSEQ
statement.
Normally, QM buffers data for records opened using OPENSEQ. The NOBUF statement turns off
this buffering such that READBLK will read the exact number of bytes specified and READSEQ
will read byte by byte until a line feed character is found. WRITEBLK, WRITESEQ and
WRITESEQF will write data without intermediate buffering.
Using unbuffered processing will result in lower performance than normal operation but may be
useful, for example, when the item opened using OPENSEQ is actually a device or a pipe rather
than a file system data record.
See also:
CLOSESEQ, CREATE, OPENSEQ, READBLK, READCSV, READSEQ, SEEK,
WEOFSEQ, WRITEBLK, WRITECSV, WRITESEQ, WRITESEQF
2.11-0
QMBasic 989
NOT()
The NOT() function returns the logical inverse of its argument. The NOTS() function is similar to
NOT() but operates on successive elements of a dynamic array, returning a similarly structured
dynamic array of results.
Format
NOT(expr)
where
The NOT() function returns the logical inverse of expr. If expr is zero (or a null string which
equates to zero), the NOT() function returns true (1). If expr is non-zero, the NOT() function
returns false (0).
Example
This statement causes the program to jump to label ERROR if S is not numeric.
See also:
ANDS(), EQS(), GES(), GTS(), IFS(), LES(), LTS(), NES(), ORS(), REUSE()
2.11-0
990 OpenQM
NULL
Format
NULL
The NULL statement is useful to satisfy the requirements of QMBasic syntax where no specific
action is required. No object code is generated by this statement.
Example
This statement reads the record "INVOICE.LIST" from the file open as file variable
CONTROL.FILE. The READ statement must have either or both of the THEN and ELSE
clauses. If the record is not found, REC will be set to a null string by the READ statement and the
ELSE clause will be executed. As no further action is required, this clause is simply a NULL
statement.
2.11-0
QMBasic 991
NUM()
The NUM() function tests whether a string can be converted to a number. The NUMS() function is
similar to NUM() but operates on successive elements of a dynamic array, returning a similarly
structured dynamic array of results.
Format
NUM(string)
where
The NUM() function returns true (1) if the string can be converted to a number. The function
returns false (0) for a string which cannot be converted to a number. A null string is a valid
representation of zero and hence causes NUM() to return true.
Example
LOOP
DISPLAY "Enter part number ":
INPUT PART.NO
UNTIL LEN(PART.NO) AND NUM(PART.NO)
PRINTERR "Part number is invalid"
REPEAT
This program fragment prompts for and inputs a part number. If the data entered is null or cannot
be converted to a number, an error message is displayed and the prompt is repeated.
2.11-0
992 OpenQM
OBJECT()
Format
OBJECT(cat.name, {args...})
where
cat.name is the name of the catalogued CLASS module defining the object.
args are optional arguments that will be passed into the CREATE.OBJECT subroutine.
The OBJECT() function loads the catalogued class module defined by cat.name and creates an
object that references it. The function returns and object reference that should be stored in a
program variable.
OBJ = OBJECT("MYOBJECT")
If the class module includes a public subroutine named CREATE.OBJECT this is executed as part
of object instantiation.
Copying an object reference variable creates a second reference to the same object, not a new
instantiation of the same object.
The object remains in existence until the last variable referencing it is overwritten or discarded. At
this point, if the class module includes a public subroutine named DESTROY.OBJECT, it will be
executed.
See also:
Object oriented programming, CLASS, DISINHERIT, INHERIT, OBJINFO(), PRIVATE,
PUBLIC.
2.11-0
QMBasic 993
OBJINFO()
Format
OBJINFO(var, key)
where
The OBJINFO() function returns information about an object variable based on the key value
supplied.
See also:
CLASS, OBJECT
2.11-0
994 OpenQM
OCONV()
The OCONV() function performs output conversion. Data is converted from its internal
representation to the external form. This function is typically used to convert data for display or
printing. The OCONVS() function is identical to OCONV() except that it works on each element
of a dynamic array, returning the result in a similarly delimited dynamic array.
Format
OCONV(expr, conv.spec)
OCONVS(expr, conv.spec)
where
The OCONV() function converts the value of expr to its external representation according to the
conversion codes in conv.spec.
The OCONV() function sets the STATUS() function value to indicate whether the conversion was
successful. Possible values are
0 Successful conversion.
1 Data to convert was invalid for the conversion specification.
2 The conversion code was invalid.
Conversions that result in a non-zero STATUS() value return the string that failed to convert as the
function result. For an OCONV() function where conv.spec is not multivalued or where the first
stage of a multiple conversion fails, the function would return expr. If one or more stages of a
multivalued conv.spec have been completed, the returned value is the result of the last successful
stage.
Examples
DT = 14992
DISPLAY OCONV(DT, 'D2')
The above example converts a date from internal format as a value 14992 to its external form as 16
JAN 09.
DT = 14992VM14000
S = OCONVS(DT, 'D2')
2.11-0
QMBasic 995
The above example converts a multivalued list of internal format dates to an equivalent multivalued
list of external form dates. Variable S is set to
16 JAN 09VM30 APR 06
See also:
Conversion codes, ICONV()
2.11-0
996 OpenQM
ON GOSUB
The ON GOSUB statement enters one of a list of internal subroutines depending on the value of an
expression.
Format
where
label1... are statement labels. The trailing colons are optional and have no effect on the
behaviour of the statement.
The ON GOSUB statement may be written over multiple lines by inserting a newline after the
comma separating two labels.
Execution of the program continues at label1 if the value of expr (converted to an integer) is 1,
label2 if it is 2 and so on. By default, a value less than one will use label1 and a value greater than
the number of labels in the list will use the last label. The PICK.JUMP.RANGE option of the
$MODE directive can be used to invoke the Pick style behaviour where an out of range value
continues execution at the statement following the ON GOSUB.
Example
ON X GOSUB SUBR1,
SUBR2,
SUBR3
This program fragment enters one of three internal subroutines depending on the value of variable
X. If X could not be guaranteed to hold a valid value (1 to 3), error checking statements should be
included to ease debugging of program errors.
2.11-0
QMBasic 997
ON GOTO
The ON GOTO statement jumps to one of a list of labels depending on the value of an expression.
Format
where
label1... are statement labels. The trailing colons are optional and have no effect on the
behaviour of the statement.
The ON GOTO statement may be written over multiple lines by inserting a newline after the
comma separating two labels.
Execution of the program continues at label1 if the value of expr (converted to an integer) is 1,
label2 if it is 2 and so on. By default, a value less than one will use label1 and a value greater than
the number of labels in the list will use the last label. The PICK.JUMP.RANGE option of the
$MODE directive can be used to invoke the Pick style behaviour where an out of range value
continues execution at the statement following the ON GOTO.
Example
This program fragment jumps to one of three labels depending on the value of variable ACTION. If
ACTION could not be guaranteed to hold a valid value (1 to 3), error checking statements should
be included to ease debugging of program errors.
2.11-0
998 OpenQM
OPEN
The OPEN statement opens a directory file or dynamic file, associating it with a file variable.
Format
where
dict.expr evaluates to DICT to open the dictionary portion of the file or to a null
string to open the data portion. If omitted or any other value, the data
portion is opened.
options control the manner in which the file is opened and may be any combination
of:
NON.TRANSACTIONAL Ignore transaction boundaries
NO.MAP Suppress id character
translations in directory files
READONLY Disable file updates
SYNC Force write all file updates
file.var is the name of the variable to hold the file reference for use in later
operations on this file.
A file opened by the OPEN statement may be referenced using the file variable in subsequent
statements that operate on the file. The file remains open so long as the file variable remains intact.
Overwriting this variable or discard of the variable on return from a subroutine will implicitly close
the file. QM has limited support for the concept of a default file variable as found in some other
multivalue products.
The optional NON.TRANSACTIONAL clause indicates that updates to the file are not to be
treated as part of any transaction within which they occur.
The NO.MAP option is relevant only to directory files and suppresses the normal translation of
restricted characters in record ids. See directory files for more information.
The optional READONLY clause opens the file for read only access. Any attempt to write will
fail.
The SYNC option causes updates to the file to be flushed to disk after every write. This will have a
severe impact on performance if the file is updated frequently. See synchronous (forced write) mode
2.11-0
QMBasic 999
If the file is opened successfully, the THEN clause is executed. If the open fails the ELSE clause is
executed and the STATUS() function may be used to determine the cause of the failure.
The ON ERROR clause is taken only in the case of serious errors such as damage to the file's
internal control structures. The STATUS() function will contain an error number. If no ON
ERROR clause is present, a fatal error results in an abort.
QM allows more files to be open than the underlying operating system limit. This is achieved by
automatically closing files at the operating system level if the limit is reached, retaining information
to reopen them automatically when the next access to the file occurs. This process allows greater
freedom of application design but has a performance penalty if a large number of files are used
frequently.
For dynamic files, the INMAT() function used immediately after the OPEN returns the modulus of
the file.
Example
This statement opens a file with VOC name STOCK.FILE. If the open fails, the program aborts
with an error message.
See also:
OPENPATH, OPENSEQ
2.11-0
1000 OpenQM
OPENPATH
The OPENPATH statement opens a directory file or dynamic file by pathname, associating it with
a file variable.
Format
where
options control the manner in which the file is opened and may be any combination
of:
NON.TRANSACTIONAL Ignore transaction boundaries
NO.MAP Suppress id character
translations
READONLY Disable file updates
SYNC Force write all file updates.
file.var is the name of the variable to hold the file reference for use in later
operations on this file.
A file opened by the OPENPATH statement may be referenced using the file variable in
subsequent statements that operate on the file. The file remains open so long as the file variable
remains intact. Overwriting this variable or discard of the variable on return from a subroutine will
implicitly close the file. QM has limited support for the concept of a default file variable as found in
some other multivalue products.
The optional NON.TRANSACTIONAL clause indicates that updates to the file are not to be
treated as part of any transaction within which they occur.
The NO.MAP option is relevant only to directory files and suppresses the normal translation of
restricted characters in record ids. See directory files for more information.
The optional READONLY clause opens the file for read only access. Any attempt to write to the
file will fail.
The SYNC option causes updates to the file to be flushed to disk after every write. This will have a
severe impact on performance if the file is updated frequently. See synchronous (forced write) mode
in the section that discussed dynamic files for more details.
If the file is opened successfully, the THEN clause is executed. If the open fails the ELSE clause is
2.11-0
QMBasic 1001
executed and the STATUS() function may be used to determine the cause of the failure.
The ON ERROR clause is taken only in the case of serious errors such as damage to the file's
internal control structures. The STATUS() function will contain an error number. If no ON
ERROR clause is present, a fatal error results in an abort.
QM allows more files to be open than the underlying operating system limit. This is achieved by
automatically closing files at the operating system level if the limit is reached, retaining information
to reopen them automatically when the next access to the file occurs. This process allows greater
freedom of application design but has a performance penalty if a large number of files are used
frequently.
For dynamic files, the INMAT() function used immediately after the OPENPATH returns the
modulus of the file.
Example
This statement opens the skeleton NEWVOC file in the QMSYS directory using Windows
pathname syntax. If the open fails, the program aborts with an error message.
See also:
OPEN, OPENSEQ
2.11-0
1002 OpenQM
OPENSEQ
The OPENSEQ statement opens a record of a directory file, a device or a pipe for sequential
access.
Format
where
file.name evaluates to the VOC name of the directory file holding the record to be
opened.
The named record is opened and associated with file.var for later operations.
The optional READONLY clause opens the item for read only access. Any attempt to write will
fail.
Use of APPEND causes the OPENSEQ statement to position at the end of any existing data in the
record such that subsequent write operations will append new data. Use of OVERWRITE
truncates the record to remove any existing data.
If the record already exists, the THEN clause is executed. An update lock will be set on this record
unless the record is read-only in which case a shared read lock is set.
If the record does not already exist, the ELSE clause is executed and the STATUS() function
2.11-0
QMBasic 1003
returns zero. The record will have been locked and use of WRITESEQ, WRITESEQF,
WRITEBLK, WEOFSEQ or CREATE with the returned file.var will create the record.
Alternatively, the lock can be released using RELEASE or closing the file.var
The ELSE clause is also executed if the specified item cannot be opened due to an error. The
STATUS() function will contain the error code.
The LOCKED clause is executed if the record is already locked by another process.
The ON ERROR clause is executed if a fatal error occurs when opening the record. The
STATUS() function will return an error code relating to the problem.
The NOBUF option causes the file, device or pipe opened by OPENSEQ to be accessed in an
unbuffered mode. This is likely to degrade performance compared to use of the default buffered
mode but allows, for example, two processes to read from the same pipe.
The NO.MAP option is relevant only to directory files and suppresses the normal translation of
restricted characters in record ids. See directory files for more information.
A record open for sequential access may be read and written using READSEQ and WRITESEQ
respectively. The WRITESEQF statement provides a forced write and WEOFSEQ sets an end of
file marker. The record should be closed using CLOSESEQ though it will be closed automatically
when the program in which the file variable lies terminates.
The second form of OPENSEQ may be used to open a serial port by using the device name as
pathname. On Windows, this name is COM1, COM2, etc. On PDAs. the Windows device name
must be followed by a colon. On other platforms, it is the device driver name.
To open a floppy disk drive (e.g. a Pick style account save) specify the pathname as "A:" on
Windows or use the device driver name (probably /dev/fd0) on Linux.
Examples
This program fragment opens the record STOCK.LIST of directory file STOCKS. If it fails to
either open an existing record or to create a new record, the program aborts.
This program fragment opens the operating system file in C:\TEMP\IMPORT.DATA for sequential
processing.
See also:
CLOSESEQ, CREATE, NOBUF, READBLK, READCSV, READSEQ, SEEK, WEOFSEQ,
WRITEBLK, WRITECSV, WRITESEQ, WRITESEQF
2.11-0
1004 OpenQM
OPEN.SOCKET()
Format
where
addr is the address of the system to which a connection is to be established. This may be
an IP address or a host name.
flags is a flag value formed from the additive values below. The token values are defined
in the SYSCOM KEYS.H include record.
Socket type, one of:
SKT$STREAM A stream connection (default)
SKT$DGRM A datagram type connection
Protocol, one of:
SKT$TCP Transmission Control Protocol (default)
SKT$UDP User Datagram Protocol
Blocking mode, one of:
SKT$BLOCKING Sets the default mode of data transfer as
blocking.
SKT$NON.BLOCKING Sets the default mode of data transfer as
non-blocking.
The OPEN.SOCKET() function opens a connection to the server with the given address and port
number.
If the action is successful, the function returns a socket variable that can be used to read and write
data using the READ.SOCKET() and WRITE.SOCKET() functions. The STATUS() function
will return zero.
If the socket cannot be opened, the STATUS() function will return an error code that can be used to
determine the cause of the error.
Example
This program fragment opens a connection to port 3000 of IP address 193.118.13.14, sends the
data in DATA and then closes the socket.
2.11-0
QMBasic 1005
See also:
Using Socket Connections, ACCEPT.SOCKET.CONNECTION, CLOSE.SOCKET,
CREATE.SERVER.SOCKET(), READ.SOCKET(), SELECT.SOCKET(),
SERVER.ADDR(), SET.SOCKET.MODE(), SOCKET.INFO(), WRITE.SOCKET()
2.11-0
1006 OpenQM
ORS()
The ORS() function performs a logical OR operation on successive elements of a dynamic array,
returning a similarly structured dynamic array of results.
Format
ORS(expr1, expr2)
where
The ORS() function performs the logical OR operation between corresponding elements of the two
dynamic arrays and constructs a similarly structured dynamic array of results as its return value.
An element of the returned dynamic array is 1 if either or both of the corresponding elements of
expr1 and expr2 are true. Any value other than zero or a null string is treated as true.
The REUSE() function can be applied to either or both expressions. Without this function, any
absent trailing values are taken as false.
Example
A contains 1VM1SM0VM0VM1FM0VM1
B contains 1VM0SM1VM0VM1FM1VM0
C = ORS(A, B)
See also:
ANDS(), EQS(), GES(), GTS(), IFS(), LES(), LTS(), NES(), NOTS(), REUSE()
2.11-0
QMBasic 1007
OS.ERROR()
The OS.ERROR() function returns the error number associated with the last recorded operating
system level error.
Format
OS.ERROR()
Some actions that return errors via the STATUS() function are related to errors from operating
system calls. The OS.ERROR() function returns the value of the most recent operating system
error. The QM error codes for which this is valid are all marked with "os.error" in the SYSCOM
ERR.H include record. The value returned by OS.ERROR() at other times is meaningless.
The values returned by OS.ERROR() are defined by the operating system and program
development libraries. They are outside the control of QM and are documented with the operating
system. In general Linux, FreeBSD, AIX and Mac users can find these in the errno.h include record
in /usr/include though this file then includes a variety of further include records. Windows users can
find error numbers on the MSDN area of Microsoft's web site but they are scattered over several
pages.
The !ERRTEXT() subroutine will automatically insert this value into relevant expanded error
messages.
2.11-0
1008 OpenQM
OS.EXECUTE
The OS.EXECUTE statement executes an operating system command. This function is not
available on the PDA version of QM.
Format
where
The CAPTURING clause captures output that would otherwise have gone to the terminal or
phantom log file, saving it in the named variable with field marks in place of newlines.
The OS.EXECUTE statement returns two error codes. The STATUS() function returns a
non-zero value if QM detected an error and was unable to execute the command. For a zero
STATUS() value, the OS.ERROR() function returns the termination status of the executed
command. The interpretation of this value will depend on the command being executed.
Example
This statement uses the operating system MKDIR command to create a directory named
TEMPDIR.
2.11-0
QMBasic 1009
OSDELETE
Format
OSDELETE path
where
The OSDELETE statement provides a simple way for a program to delete an operating system file
by pathname. No error will be reported if the action fails.
OSDELETE takes no part in the locking system. It is up to the application developer to ensure that
concurrency issues are handled appropriately.
Example
OSDELETE 'C:\FAXLOG'
See also:
OSREAD, OSWRITE
2.11-0
1010 OpenQM
OSREAD
Format
where
The OSREAD statement provides a simple way for a program to read the content of an operating
system file by pathname rather than having to open the parent directory with OPENSEQ and then
using READBLK to read the data.
The data read from the specified file is transferred to var with no modification. In particular, note
that the translation of newlines to field marks that occurs when reading from directory files does not
happen with this statement.
OSREAD takes no part in the locking system. It is up to the application developer to ensure that
concurrency issues are handled appropriately.
The ELSE clause is executed if the read fails because, for example, the pathname does not
reference an existing file. Attempting to read an item larger than 1Gb will take the ELSE clause.
The STATUS() function will indicate the cause of the error and the OS.ERROR() function will
provide further information for operating system level errors.
The ON ERROR clause is executed for serious fault conditions such as the inability to read the
data from the file for reasons outside of QM. The STATUS() function will return an error number
and the OS.ERROR() function will provide further information about the operating system level
error. If no ON ERROR clause is present, an abort would occur at these types of error.
Example
This statement reads the content of an operating system file with pathname C:\FAXLOG and, if
found, executes a subroutine to process this data.
See also:
2.11-0
QMBasic 1011
OSDELETE, OSWRITE
2.11-0
1012 OpenQM
OSWRITE
Format
where
The OSWRITE statement provides a simple way for a program to write an operating system file
by pathname rather than having to open the parent directory with OPENSEQ and then using
WRITEBLK to write the data.
The data is written to the specified file with no modification. In particular, note that the translation
of field marks to newlines that occurs when writing to directory files does not happen with this
statement. Any existing data in the file will be overwritten, truncating the file if the old content was
larger than the new data.
OSWRITE takes no part in the locking system. It is up to the application developer to ensure that
concurrency issues are handled appropriately.
The ON ERROR clause is executed for serious fault conditions such as the inability to write the
data to the file. The STATUS() function will return an error number and the OS.ERROR()
function will provide further information about the operating system level error. If no ON ERROR
clause is present, an abort would occur at these types of error.
Example
This statement writes the content variable FAXDATA to an operating system file with pathname
C:\FAXLOG.
See also:
OSDELETE, OSREAD
2.11-0
QMBasic 1013
OUTERJOIN()
The OUTERJOIN() function returns the record ids of records in a file where a field holds a
specified value.
Format
where
file.name evaluates to the name of the file from which data is to be retrieved. The
optional DICT prefix specifies that the dictionary portion of the file is to be
used. Alternatively, the file.name expression may include the uppercase word
DICT before the actual file name and separated from it by a single space.
field.name is the name of the field in file.name that determines the record ids to be
returned. There must be an alternate key index on this field.
The OUTERJOIN() function uses an alternate key index on field.name to return a value mark
delimited list of record ids of records in the specified file that contain the given value.
This function is mainly intended for use in dictionary I-type expressions where the equivalent
programming built around SELECTINDEX cannot be used.
Examples
The above expression used in a dictionary I-type item retrieves a list of orders record ids for a given
customer.
The above program displays a list of customer numbers in the CUSTOMERS file and a list of the
orders placed by each customer.
2.11-0
1014 OpenQM
PAGE
Format
where
print.unit evaluates to the print unit number on which the action is to occur. If omitted,
print unit zero is used.
page.no evaluates to the page number to be used for the new page. If omitted, the page
number is incremented from its current value.
The PAGE statement causes the footing to be printed at the end of the current page and advances to
the next page. The heading will be printed if further output is directed to the print unit. The PAGE
statement can be used to complete printing of the final page of output from a program.
If a new page number is specified, this takes effect after print unit has been advanced to the new
page. A page.no of less than one causes the page number to be set to one.
A PAGE statement directed to the display causes the pagination prompt to be displayed unless it
has been suppressed. The screen will be cleared to advance to the new page.
Example
PAGE ON PRINT.UNIT
This statement causes the print unit identified by PRINT.UNIT to advance to the next page.
See also:
FOOTING, HEADING
2.11-0
QMBasic 1015
PAUSE
The PAUSE statement pauses execution until awoken by another process. This function is not
available on the PDA version of QM.
Format
PAUSE {timeout}
where
timeout specifies the maximum time to wait in seconds. A value less than one indicates that
an infinite timeout should be used.
The PAUSE statement suspends program execution until awoken by another process using the
WAKE statement. The optional timeout specifies the maximum time in seconds for which the
program can remain suspended.
If the PAUSE is terminated by detection of a WAKE event, the STATUS() function will return
zero. If the PAUSE is terminated by a timeout, the STATUS() function will return ER$TIMEOUT.
A WAKE request occurring before the PAUSE is executed is remembered and the program is not
suspended. Note that under rare conditions, precise timing of the PAUSE/WAKE pair can cause a
program to appear to wake spuriously. Programs should be written to allow for this possibility.
2.11-0
1016 OpenQM
PRECISION
The PRECISION statement sets the maximum number of decimal places to appear when
converting numeric values to strings.
Format
PRECISION expr
where
expr is an expression specifying the number of decimal places. This value must be
between zero and fourteen. Negative values are treated as zero; values greater than
fourteen are treated as fourteen.
Arithmetic operations performed by QM always work to the maximum precision of the computer
system. The precision value determines the number of decimal places when numeric values are
converted to strings, for example, when printing.
Values are converted with rounding on the last digit. Trailing zero digits are removed from the
decimal places and, if the resultant value is an integer, the decimal point is also removed.
The precision value is associated with each program and subroutine and is initially set to 4. A
program which sets a precision of 6 and calls a subroutine will use precision 6 up to the call, the
subroutine will use precision 4 and, on return to the calling program, the precision reverts to 6.
Example
X = 333.33333
Y = 666.66666
PRINT X, Y
PRECISION 4
PRINT X, Y
PRECISION 1
PRINT X, Y
PRECISION 0
PRINT X, Y
2.11-0
QMBasic 1017
Format
where
print.unit identifies the print unit to which output is to be directed. If omitted, print unit
zero is used.
print.list is a list of items to print in the format described for the DISPLAY statement.
The data is output to the requested print unit. Print unit -1 is always associated with the display and
cannot be changed. Print unit 0 can be switched between the display and the printer by use of the
PRINTER statement. Print units 1 to 255 direct their output to the hold file by default but can be
redirected using the SETPTR command.
By using PRINT statements instead of DISPLAY in programs it is possible to select whether the
output is directed to the display or to a printer. The LPTR option to the RUN command is
equivalent to a PRINTER ON at the start of the program.
Use of the @(x,y) cursor movement function in a PRINT statement that sends output to the display
will disable pagination. See DISPLAY for more details.
Example
N = DCOUNT(LINE, @FM)
FOR I = 1 TO N
PRINT ON PU LINE<I>
NEXT I
PAGE ON PU
This program fragment emits each field of LINE to the print unit identified by PU and then
advances to a new page.
2.11-0
1018 OpenQM
PRINTCSV
Format
where
print.unit identifies the print unit to which output is to be directed. If omitted, print unit
zero is used.
var1, var2, ... is a list of items to be assembled as a CSV format text string.
The assembled CSV format data is output to the requested print unit. Print unit -1 is always
associated with the display and cannot be changed. Print unit 0 can be switched between the display
and the printer by use of the PRINTER statement. Print units 1 to 255 direct their output to the
hold file by default but can be redirected using the SETPTR command.
The optional trailing colon suppresses the normal linefeed after the data has been output.
Example
This statement prints the contents of the PROD.NO and QTY variables as a CSV format text
string.
See also:
INPUTCSV, READCSV, WRITECSV
2.11-0
QMBasic 1019
PRINTER
The PRINTER ON and OFF statements determine whether output from PRINT statements to the
default print unit (unit 0) is directed to the display or to the printer.
Format
PRINTER ON
PRINTER OFF
The PRINTER ON statement causes subsequent output to print unit zero to be directed to the
printer. A later PRINTER OFF statement resumes output to the display.
The STATUS() function returns the previous state of the PRINTER setting. A value of zero
indicates that the printer was on. A value of one indicates that it was off.
By using PRINT statements instead of DISPLAY in programs it is possible to select whether the
output is directed to the display or to a printer. The LPTR option to the RUN command is
equivalent to a PRINTER ON at the start of the program followed by a PRINTER CLOSE on
return to the command prompt.
Example
PRINTER ON
PRINT "This is sent to the printer"
PRINTER OFF
PRINT "This is sent to the display"
2.11-0
1020 OpenQM
PRINTER CLOSE
Format
where
print.unit identifies the print unit to be closed. If omitted, all print units are closed.
The PRINTER CLOSE statement terminates activity on a print unit. If this print unit was directed
to a spool file, the data will be printed. Any heading and footing text is discarded. Subsequent data
sent to the same print unit starts a new output stream. If this is for the default printer, it will be
necessary to use PRINTER ON if the output is to be directed to a printer rather than the screen.
All print units are closed automatically on return to the command prompt.
The PRINTER command has a KEEP.OPEN option which, when used, causes requests from
programs to close printers only to terminate the page and discard any heading and footing text. This
printer remains open so that subsequent output to the same print unit will be merged to form a
single print job.
2.11-0
QMBasic 1021
PRINTER DISPLAY
The PRINTER DISPLAY statement directs output sent to a print unit to the display.
Format
where
The ON ERROR clause is executed in the event of a fatal internal error. The error code returned
by the STATUS() function will indicate the cause of the error. If this clause is omitted, the program
will abort in the event of a fatal error.
The THEN clause is executed if the operation is successful. The STATUS() function will return
zero.
The ELSE clause is executed in the event of a non-fatal error. If this clause is omitted, program
execution continues after an error.
Example
PRINTER DISPLAY ON 1
2.11-0
1022 OpenQM
PRINTER FILE
The PRINTER FILE statement directs printer output to a named record in a directory file.
Format
where
record.name evaluates to the name of the record within file.name to which output to
print.unit is to be directed. If the record already exists, it will be
overwritten.
Output to print units 1 to 255 is directed to a hold file by default but can be redirected. The
PRINTER FILE statement causes the named record to be created and output will be directed to
this file until the print unit is closed. Reopening the print unit without changing the destination will
overwrite the same record.
The ON ERROR clause is executed in the event of a fatal internal error while attempting to open
the file. The error code returned by the STATUS() function will indicate the cause of the error. If
this clause is omitted, the program will abort in the event of a fatal error.
The THEN clause is executed if the operation is successful. The STATUS() function will return
zero.
The ELSE clause is executed if the file cannot be opened. The error code returned by the
STATUS() function will indicate the cause of the error. If this clause is omitted, program execution
continues after an error.
Example
This statement directs output from print unit 1 to record SAVED in directory file MYFILE.
2.11-0
QMBasic 1023
PRINTER NAME
The PRINTER NAME statement associates a named printer device with a print unit.
Format
where
The ON ERROR clause is executed in the event of a fatal internal error. The error code returned
by the STATUS() function will indicate the cause of the error. If this clause is omitted, the program
will abort in the event of a fatal error.
The THEN clause is executed if the operation is successful. The STATUS() function will return
zero.
The ELSE clause is executed if the printer does not exist. If this clause is omitted, program
execution continues after an error.
Example
This statement directs output from print unit 1 to a printer named LPT1.
2.11-0
1024 OpenQM
PRINTER RESET
The PRINTER RESET statement resets the default print unit and display output.
Format
PRINTER RESET
Output to the default print unit (unit 0) is directed to the display (similar to use of PRINTER
OFF)
Pagination is restarted on the display if it was previously suppressed.
The page number is reset to 1.
Any heading and footing set up for the display device are cancelled.
The PRINTER RESET statement is particularly useful in programs which have disabled line
counting through use of cursor movement @() functions and subsequently want to restart
pagination of line by line output.
2.11-0
QMBasic 1025
PRINTER SETTING
The PRINTER SETTING statement sets a control parameter for a print unit.
This statement is obsolete. The SETPU statement should be used in its place.
Format
where
print.unit evaluates to the print unit on which the action is be to performed. If omitted,
the default print unit (unit 0) is used.
new.value is the value to be set. A new.value of -1 sets the parameter to its default value.
The parameters which may be set by this statement are identified by param numbers. Tokens for
these are defined in the KEYS.H include record in the SYSCOM file.
The value of lines per page is best set to at least one less than the physical page size to prevent the
automatic page throw of most printers after the final line of the page is printed.
Example
This statement sets the number of lines per page on print unit 1 to 60.
2.11-0
1026 OpenQM
PRINTER.SETTING()
The PRINTER.SETTING() function sets or retrieves a control parameter for a print unit.
This function is obsolete. The SETPU statement or GETPU() function should be used in its
place.
Format
where
param identifies the parameter to be changed using the keys shown below.
new.value is the value to be set. A new.value of -1 sets the parameter to its default value.
A new.value of -2 returns the current value without changing it.
The PRINTER.SETTING() function returns the new (or unchanged) value of the parameter.
The parameters which may be set or retrieved by this statement are identified by param numbers.
Tokens for these are defined in the KEYS.H include record in the SYSCOM file.
2.11-0
QMBasic 1027
The value of lines per page is best set to at least one less than the physical page size to prevent the
automatic page throw of most printers after the final line of the page is printed.
Example
This statement sets the page width on print unit 1 to the default value and stores this value in
WIDTH.
2.11-0
1028 OpenQM
PRINTERR
The PRINTERR statement displays an error message which is removed from the screen when the
next input is entered.
Format
PRINTERR expr
where
The expr text is displayed on the bottom line of the screen using the current foreground and
background colours. This message will be removed after the first keystroke of the next INPUT @
statement. Input taken from the DATA queue will also clear the message.
Example
LOOP
DISPLAY "Enter password " :
PROMPT ""
INPUT @(5,10) PASSWORD : HIDDEN
WHILE PASSWORD # "SECRET"
PRINTERR "Incorrect password"
REPEAT
This program fragment reads a password from the keyboard. If it is entered incorrectly, a message
is displayed and the input is repeated. Note use of the HIDDEN qualifier in the INPUT statement so
that data entered at the keyboard is displayed as asterisks.
2.11-0
QMBasic 1029
PRIVATE
The PRIVATE statement defines private variables in a local subroutine or in a class module.
Format
where
mat(rows, cols) is a dimensioned matrix name. The rows and cols values must be numeric
constants.
Immediately after the LOCAL statement defining a local function or subroutine. It identifies
variables that have scope only within the local routine and are discarded on exit. If the routine
calls itself recursively, each invocation has its own private variables. See the LOCAL
statement for more details.
Used in a CLASS module, it defines variables that are private to the object but persist between
successive executions of components of the class module. See the CLASS statement and Object
Oriented Programming for more details. Private variables are initially unassigned.
See also:
Object oriented programming, CLASS, DISINHERIT, INHERIT, OBJECT(), OBJINFO(),
PUBLIC.
2.11-0
1030 OpenQM
PROCREAD
The PROCREAD statement reads data from the PROC primary input buffer.
Format
where
If the current program was called directly or indirectly from a PROC, the PROCREAD statement
copies the content of the PROC primary input buffer to the named variable and executes the THEN
clause.
If the current program was not called from a PROC, the variable is set to a null string and the
ELSE clause is executed.
See also:
VOC PQ-type records
2.11-0
QMBasic 1031
PROCWRITE
The PROCWRITE statement writes data to the PROC primary input buffer.
Format
PROCWRITE expr
where
The data specified by expr is copied to the PROC primary input buffer. The input pointer is set to
the start of the data.
See also:
VOC PQ-type records
2.11-0
1032 OpenQM
PROGRAM
Format
PROGRAM name
where
The name need not be related to the name of the source record though it is recommended that they
are the same as this eases program maintenance. The name must comply with the QMBasic name
format rules.
Example
PROGRAM SUM
TOTAL = 0
LOOP
DISPLAY TOTAL
INPUT S
WHILE LEN(S)
IF NUM(S) THEN TOTAL += S
ELSE DISPLAY @SYS.BELL :
REPEAT
END
This program reads numbers from the keyboard and displays a running total until a blank line is
entered.
2.11-0
QMBasic 1033
PROMPT
The PROMPT statement sets the character to be used as the prompt in INPUT statements.
Format
PROMPT expr
where
The first character of expr is used as the prompt character. If expr is a null string, the prompt is
suppressed.
The default input prompt is the question mark. Changes to the prompt character remain in effect
until the program returns to the command prompt.
Use of EXECUTE to start a new command processing layer resets the prompt to a question mark
but it will be restored to its previous value on return from the executed command.
Example
This program fragment suppresses the prompt for the INPUT statement and then restores the
default prompt character. In normal usage, a program would use the PROMPT statement once at
the start of the program to set the prompt character to be used for the entire program.
2.11-0
1034 OpenQM
PTERM()
Format
PTERM(action, value)
where
value specified the new value. A negative value returns the current setting.
The PTERM() function can be used to set, clear or query the following terminal settings:
Action values marked as boolean enable the feature if value is true and disable it if value is false.
The new state is returned as the value of the function. A negative value returns the current state
without changing it.
See also:
PTERM
2.11-0
QMBasic 1035
PUBLIC
The PUBLIC statement defines public property variables, subroutines and functions in a class
module.
Format
where
mat(rows, cols) is a dimensioned matrix name. The rows and cols values must be numeric
constants. The dimension values may be followed by READONLY to
indicate that external references to the variable may not update it.
name(arg1, arg2) is the subroutine or function name and an optional list of arguments. See
the CLASS statement for the maximum number of arguments allowed in
this list. Specifying the final argument name as three periods (...)
effectively extends the argument list to the maximum permissible length
with unnamed scalar arguments that may be accessed using the ARG()
function. Use of this syntax automatically implies the VAR.ARGS option
which must not also be present.
Note that the equivalence of a function to a subroutine with a hidden first argument as found with
the SUBROUTINE and FUNCTION statements does not apply to public subroutines and
functions.
The first form of the PUBLIC statement defines persistent variables that may be visible from
outside the object in which they appear. Public variables are initially unassigned.
The second and third forms of the PUBLIC statement define a subroutine or function that can be
referenced from outside the object. The synonyms GET and PUT may be used for PUBLIC
FUNCTION and PUBLIC SUBROUTINE respectively.
Arguments to public subroutines and functions may reference a whole matrix by following the
matrix name by its dimensions. The actual values given are ignored; the compiler simply counts
them to determine whether the matrix has one or two dimensions. For example:
PUBLIC SUBROUTINE CALC(CLIENT, CLI.REC(1), TOTVAL)
2.11-0
1036 OpenQM
In this example, the dimension value has been shown as 1 to emphasise that the actual value is
irrelevant. The compiler uses this purely to determine that CLI.REC is a single dimensional matrix,
possibly representing a database record read using MATREAD. The alternative syntax used with
SUBROUTINE statements by prefixing the matrix name with MAT and using a DIMENSION
statement to set dimensionality is not available for public subroutines and functions.
The number of arguments in calls to the subroutine or function must be the same as in the
declaration unless the VAR.ARGS option is used in which case any arguments not passed by the
caller will be unassigned. The ARG.COUNT() function can be used to determine the actual
number of arguments passed, excluding the hidden return argument.
PUBLIC FUNCTION CREDIT.RATING(CLIENT, CLASS, CODE) VAR.ARGS
In this example, if the calling program supplies only one argument, the CLASS and CODE
variables will be unassigned. If the calling program provides two arguments, the CODE variable
will be unassigned.
When using VAR.ARGS, default values may be provided for any arguments by following the
argument name with an = sign and the required numeric or string value. For example,
PUBLIC FUNCTION CREDIT.RATING(CLIENT, CLASS = 1, CODE =
"Standard") VAR.ARGS
In this example, if the calling program supplies only one argument, the CLASS variable will default
to 1 and the CODE variable will default to "Standard". If the calling program provides two
arguments, the default value for CLASS is ignored and the CODE variable defaults to "Standard".
Examples
The above function takes a fixed length list of two arguments and uses the supplied values to open a
socket connection to a remote server. The SKT variable in this example would be a private variable
within the class module.
This example extends the previous one by making the PORT argument optional and, if it is not
supplied by the caller, defaulting it to 4000.
2.11-0
QMBasic 1037
END
NEXT I
WRITE REC TO FVAR, ID
END
This example uses the ... syntax to specify a variable length argument list of the maximum
permissible length. It reads a record identified by the ID argument and then inserts all items from
the remaining arguments that are not already in the record.
See also:
Object oriented programming, CLASS, DISINHERIT, INHERIT, OBJECT(), PRIVATE
2.11-0
1038 OpenQM
PWR()
The PWR() function returns the value of a number raised to a given power.
Format
PWR(expr, pwr.expr)
where
The PWR() function returns the value of expr raised to the power pwr.expr. It is equivalent to use
of the ** operator.
If either expr or pwr.expr is a numeric array (a dynamic array where all elements are numeric), the
PWR() function operates on each element in turn and returns another numeric array. The structure
of this array will be the same as that of the expr and pwr.expr arrays if they are identical. For
arrays of differing structure, the structure of the result depends on whether the REUSE() function
is used.
Example
N = PWR(T, 3)
This statement finds the value of T cubed. For small integer values of pwr.expr, use of the multiply
operator is faster.
2.11-0
QMBasic 1039
QUOTE()
The QUOTE() function returns a copy of its argument string enclosed in double quotes. The
DQUOTE() synonym is identical.
The QUOTES() and DQUOTES() functions are similar but operate on successive elements of a
dynamic array, returning a similarly structured dynamic array of results.
Format
QUOTE(expr)
where
Examples
A = QUOTE('ABC123')
This program fragment encloses each element of dynamic array A in double quotes, storing the
result in B as
"ABC"VM"DEF"
See also:
SQUOTE()
2.11-0
1040 OpenQM
RAISE()
The RAISE() function converts mark characters in a string to the next higher level mark.
Format
RAISE(string)
where
The RAISE() function replaces mark characters according to the following table:
Original Replacement
Item mark Item mark (unchanged)
Field mark Item mark
Value mark Field mark
Subvalue mark Value mark
Text mark Subvalue mark
Example
FORMLIST RAISE(LIST)
This statement takes a value mark delimited variable LIST, raises the marks and uses this to create
a select list.
See also:
LOWER()
2.11-0
QMBasic 1041
RANDOMIZE
Format
RANDOMIZE expr
where
expr evaluates to a number. If omitted or a null string, the time of day is used.
The RANDOMIZE statement initialises the seed value of the random number generator function,
RND(). Supplying the same seed value in successive uses of this statement guarantees that the same
pseudo-random number sequence is generated. Note that the sequence returned may vary between
QM releases or on different platforms even if the same seed value is set.
If the expr value is omitted or given as a null string, the time of day is used thus giving a reasonable
chance of a different pseudo-random sequence on successive executions of the program.
See also:
RND()
2.11-0
1042 OpenQM
RDIV()
The RDIV() function returns the rounded integer result of dividing two values
Format
RDIV(dividend, divisor)
where
The RDIV() function divides dividend by divisor and returns the result as an integer, rounded
according to the rule that values with a fractional part of 0.5 or greater are rounded away from
zero.
Examples
See also:
IDIV()
2.11-0
QMBasic 1043
READ
Format
where
var is the name of a variable to receive the dynamic array read from the file.
When reading from a directory file, newlines in the data read from the file are replaced by field
marks. This action may be suppressed by using the MARK.MAPPING statement after opening the
file.
The ELSE clause is executed if the READ fails because no record with the given id is present on
the file. If the PICK.READ mode of the $MODE directive is used var will be left unchanged,
otherwise it will be set to a null string. The STATUS() function will indicate the cause of the error.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
Example
This program fragment reads a record from the a file previously opened to file variable STOCK
into variable ITEM. If successful, the processing statements are executed. If the record is not found,
a message is displayed.
2.11-0
1044 OpenQM
READ.SOCKET()
Format
where
flags is a value determining the mode of operation of the socket for this read, formed by
adding the values of tokens defined in the SYSCOM KEYS.H record. The flags
available in this release are:
SKT$BLOCKING Sets the default mode of data transfer as blocking.
SKT$NON.BLOCKING Sets the default mode of data transfer as
non-blocking.
If neither blocking flag is given, the blocking mode set when the socket was opened
is used.
The READ.SOCKET() function returns data read from the specified socket. The STATUS()
function returns zero if the action is successful, or a non-zero error code if an error occurs. A
timeout will return an error code of ER$TIMEOUT as defined in the SYSCOM ERR.H record.
Example
SRVR.SKT = CREATE.SERVER.SOCKET("", 0)
IF STATUS() THEN STOP 'Cannot initialise server socket'
SKT = ACCEPT.SOCKET.CONNECTION(SRVR.SKT, 0)
IF STATUS() THEN STOP 'Error accepting connection'
DATA = READ.SOCKET(SKT, 100, SKT$BLOCKING, 0)
CLOSE.SOCKET SKT
CLOSE.SOCKET SRVR.SKT
This program fragment creates a server socket, waits for an incoming connection, reads a single
data packet of up to 100 bytes from this connection and then closes the sockets. The timeout value
of 0 in the READ.SOCKET() call specifies that no timeout is to be used.
See also:
Using Socket Connections, ACCEPT.SOCKET.CONNECTION, CLOSE.SOCKET,
CREATE.SERVER.SOCKET(), OPEN.SOCKET(), SELECT.SOCKET(),
SERVER.ADDR(), SET.SOCKET.MODE(), SOCKET.INFO(), WRITE.SOCKET()
2.11-0
QMBasic 1045
READBLK
The READBLK statement reads a given number of bytes from the current file position in a record
previously opened using OPENSEQ.
Format
where
var is the name of a variable to receive the data read from the file.
The READBLK statement reads up to bytes bytes from the file. If at least one byte is available, the
data is returned in var and the THEN clause is executed.
The ELSE clause is executed if the READBLK fails. The STATUS() function will indicate the
cause of the error. For example, attempting to read when at the end of the file will return ER$EOF.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
If file.var refers to a serial port opened using OPENSEQ, the READBLK statement reads up to
bytes bytes of data from the port but does not wait if there is less than the requested number of
bytes available.
Example
This program fragment reads 100 bytes from the a file previously opened to file variable SEQ.F
into variable VAR.
2.11-0
1046 OpenQM
See also:
CLOSESEQ, CREATE, NOBUF, OPENSEQ, READCSV, READSEQ, SEEK, WEOFSEQ,
WRITEBLK, WRITECSV, WRITESEQ, WRITESEQF
2.11-0
QMBasic 1047
READCSV
The READCSV statement reads a CSV format line of text from a directory file record previously
opened for sequential access and parses it into multiple variables.
Format
where
file.var is the file variable associated with the record by a previous OPENSEQ
statement.
var1, var2 ... are the variables to receive the data read from the file.
A line of text is read from the file. It is then parsed according to the CSV format rules as defined in
RFC 4180, placing the elements into the data items identified by var1, var2, etc. If successful, the
THEN clause is executed and the STATUS() function would return zero.
If there are fewer data items in the line of text than the number of variables supplied, the remaining
variables will be set to null strings. If the line of text has more data items than the number of
variables supplied, the excess data is ignored.
If there are no further fields to be read, the ELSE clause is executed and the STATUS() function
would return ER$RNF (record not found). The target variables will be unchanged.
Example
LOOP
READCSV FROM DELIVERY.F TO PROD.NO, QTY ELSE EXIT
GOSUB PROCESS.DELIVERY.DETAILS
REPEAT
This program fragment reads CSV format lines of text from the record open for sequential access
via the DELIVERY.F file variable, placing the elements of the line into PROD.NO and QTY. It
then calls the PROCESS.DELIVERY.DETAILS subroutine to process the new item. The loop
terminates when the ELSE clause is executed when all fields have been processed.
See also:
CLOSESEQ, CREATE, CSVDQ(), NOBUF, OPENSEQ, READBLK, READSEQ, SEEK,
2.11-0
1048 OpenQM
2.11-0
QMBasic 1049
READL
The READL statement reads a record from a previously opened file, setting a read lock.
Format
where
var is the name of a variable to receive the dynamic array read from the file.
The specified record is read into the named variable and a read lock is set. See Locks for full details
of QM's locking mechanism.
The LOCKED clause is executed if the file or record is exclusively locked by another process.
The STATUS() function will return the user id of a process holding a lock on this file or record. If
the LOCKED clause is omitted and the file or record is locked, the program will wait for the lock
to be released.
The ELSE clause is executed if the READL fails because no record with the given id is present on
the file. If the PICK.READ mode of the $MODE directive is used var will be left unchanged,
otherwise it will be set to a null string. The STATUS() function will indicate the cause of the error.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
Example
2.11-0
1050 OpenQM
This program fragment reads a record from the a file previously opened to file variable. STOCK
into variable ITEM, setting a read lock on the record. If successful, the processing statements are
executed. If the record is not found, a message is displayed and the lock is released.
2.11-0
QMBasic 1051
READLIST
Format
where
list.no is the select list number. If omitted, select list zero is used. A Pick style
select list variable may be used instead of a list number.
The THEN and ELSE clauses are both optional. If neither is given, the program can recognise
failure by var being a null string.
The specified select list is read into var. If the list had already been partially processed by
READNEXT statements, only the remaining unprocessed items are stored in var.
The THEN clause is executed if var contains one or more items. Items are separated by field
marks. If compatibility with other software is required, it is suggested that programs should be
written to accept either field marks or item marks (or a mix) as list separators.
The ELSE clause is executed if the select list was not active or if no items remained to be
processed. In this case var will be set to a null string.
Example
This program fragment retrieves the remaining items in select list 2 and, if there are any, writes
them to a record UNPROCESSED in file LISTS.
See also:
FORMLIST
2.11-0
1052 OpenQM
READNEXT
The READNEXT statement returns the next item from an active select list.
Format
where
val.pos is the variable to receive the value position with an exploded select list.
subval.pos is the variable to receive the subvalue position with an exploded select list.
list.no is the select list number. If omitted, the default select list is used. The
READNEXT statement can also use select list variables returned by the
SELECTV statement or the RTNLIST option of the EXECUTE
statement.
The next item in the specified select list is removed from the list and stored in var. Although the list
may be of any size, a single item extracted by READNEXT cannot exceed 32k bytes. Attempting
to extract an item larger than this limit will be handled as a fatal error as described below.
The ON ERROR clause is executed if a fatal error occurs. The STATUS() function will return an
value relating to the error. If no ON ERROR clause is present, fatal errors result in an abort.
The THEN clause is executed if the select list was active and not empty.
The ELSE clause is executed if the select list was not active or no items remained to be read. The
var variable will be set to a null string.
The STATUS() function will return zero unless the ON ERROR clause is executed.
QM supports two styles of select list; a standard list and an exploded list.
A standard select list contains only simple data, usually record ids. The optional val.pos and
subval.pos items are always returned as zero with this type of list.
2.11-0
QMBasic 1053
An exploded select list is created using the BY.EXP or BY.EXP.DSND keywords of the query
processor to break apart multivalues and subvalues in a field. Each entry contains the record id
together with the value and subvalue position corresponding to the data element associated with the
list entry
The optional val.pos and subval.pos components of the READNEXT statement can be used to
retrieve this positional data. There are three possible formats:
If both are present, the value and subvalue positions are returned in these variables. Where the
value was not subdivided into subvalues, the subvalue position is returned as zero.
If only val.pos is present, the value position is returned and any subvalue information is
discarded.
If neither is present, normally only the record id is returned, however, if the program is
compiled with the COMPOSITE.READNEXT option of the $MODE compiler directive in
force, the data returned in var is made up from the record id, the value position and the
subvalue position separated by value marks.
Example
SELECT STOCK.FILE
LOOP
READNEXT ID
PRINT ID
REPEAT
This program fragment produces a list of the record keys present in STOCK.FILE.
2.11-0
1054 OpenQM
READSEQ
The READSEQ statement reads the next field (line of text)from a directory file record previously
opened for sequential access.
Format
where
var is the variable to receive the data read from the file.
file.var is the file variable associated with the record by a previous OPENSEQ
statement.
The next field (line of text) is read into var. If successful, the THEN clause is executed and the
STATUS() function would return zero.
If there are no further fields to be read, the ELSE clause is executed and the STATUS() function
would return ER$RNF (record not found).
If a fatal error occurs, the ON ERROR clause is executed. The STATUS() function can be used
to establish the cause of the error. If no ON ERROR clause is present, a fatal error causes an
abort.
The FILEINFO() function can be used with key FL$LINE to determine the field number that will
be read by the next READSEQ.
Example
LOOP
READSEQ REC FROM STOCK.LIST ELSE EXIT
GOSUB PROCESS.STOCK.ITEM
REPEAT
This program fragment reads fields from the record open for sequential access via the
STOCK.LIST file variable and calls the PROCESS.STOCK.ITEM subroutine for each field. The
loop terminates when the ELSE clause is executed when all fields have been processed.
See also:
CLOSESEQ, CREATE, NOBUF, OPENSEQ, READBLK, READCSV, SEEK, WEOFSEQ,
WRITEBLK, WRITECSV, WRITESEQ, WRITESEQF
2.11-0
QMBasic 1055
READU
The READU statement reads a record from a previously opened file, setting an update lock.
Format
where
var is the name of a variable to receive the dynamic array read from the file.
The specified record is read into the named variable and an update lock is set. See Locks for full
details of QM's locking mechanism.
The LOCKED clause is executed if the file or record is locked by another process. The STATUS()
function will return the user id of a process holding a lock on this file or record. If the LOCKED
clause is omitted and the file or record is locked, the program will wait for the lock to be released.
The ELSE clause is executed if the READU fails because no record with the given id is present on
the file. If the PICK.READ mode of the $MODE directive is used var will be left unchanged,
otherwise it will be set to a null string. The STATUS() function will indicate the cause of the error.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
Example
2.11-0
1056 OpenQM
This program fragment reads a record from the a file previously opened to file variable. STOCK
into variable ITEM, setting an update lock on the record. If successful, the processing statements
are executed. If the record is not found, a message is displayed and the record is unlocked.
2.11-0
QMBasic 1057
READV
The READV statement reads a specific field from a record of a previously opened file.
Format
where
var is the name of a variable to receive the dynamic array read from the file.
The specified record is read and the field identified by field.expr is extracted into the named
variable. If the field does not exist, var is set to a null string.
Note that internally, the file system operates at the record level so READV reads the entire record,
extracts the field and discards the rest. If multiple fields are to be extracted, it is always better to
read the whole record and use field extraction operations instead of using multiple READV
statements.
A field.expr value of zero may be used to determine if the record exists. If it does, the THEN
clause is taken and var is set to the record id. If the record does not exist, the ELSE clause is taken
and var will be set to a null string. The record is not transferred into memory, resulting in a
significant performance advantage over use of READ when the record is very large.
The THEN clause is executed if the record is read successfully regardless of whether the specified
field is present.
The ELSE clause is executed if the READV fails because no record with the given id is present on
the file. If the PICK.READ mode of the $MODE directive is used var will be left unchanged,
otherwise it will be set to a null string. The STATUS() function will indicate the cause of the error.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
Example
2.11-0
1058 OpenQM
This program fragment reads field 3 of a record from the file previously opened to file variable
STOCK into variable ITEM. If successful, the processing statements are executed. If the record is
not found, a message is displayed.
See also:
WRITEV
2.11-0
QMBasic 1059
READVL
The READVL statement reads a specific field from a record of a previously opened file, setting a
read lock. The READVU statement is similar but sets an update lock.
Format
where
var is the name of a variable to receive the dynamic array read from the file.
The specified record is read and the field identified by field.expr is extracted into the named
variable. If the field does not exist, var is set to a null string.
READVL sets a read lock is set on the record. READVU sets an update lock on the record. See
Locks for full details of QM's locking mechanism.
A field.expr value of zero may be used to determine if the record exists. var will be set to a null
string.
The LOCKED clause is executed if the file or record is locked by another process (exclusively in
the case of READVL). The STATUS() function will return the user id of a process holding a lock
on this file or record. If the LOCKED clause is omitted and the file or record is locked, the
program will wait for the lock to be released.
The THEN clause is executed if the record is read successfully regardless of whether the specified
field is present.
The ELSE clause is executed if the operation fails because no record with the given id is present on
the file. If the PICK.READ mode of the $MODE directive is used var will be left unchanged,
otherwise it will be set to a null string. The STATUS() function will indicate the cause of the error.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
2.11-0
1060 OpenQM
Example
This program fragment reads field 3 of a record from the file previously opened to file variable
STOCK into variable ITEM, setting an update lock. If successful, the processing statements are
executed and the modified value is written back to the file. If the record is not found, a message is
displayed and the record is unlocked.
2.11-0
QMBasic 1061
RECORDLOCKED()
Format
RECORDLOCKED(file.var, record.id)
where
The RECORDLOCKED() function returns a value indicating the state of any locks on record
record.id of the file open as file.var. The tokens shown in the table below are defined in the
KEYS.H record of the SYSCOM file.
A record may be multiply locked in which case the RECORDLOCKED() function reports only
one of the current locks. File locks take precedence over read or update locks. If no file lock is set,
read or update locks held by the process in which the RECORDLOCKED() function is performed
take precedence over locks held by other processes.
Executing the STATUS() function after a RECORDLOCKED() function indicates that a lock is
active will return the user number of the user holding the lock.
Example
This program fragment checks if record ORDER.LIST is locked and, if so, reports the user number
of the process that holds the lock.
2.11-0
1062 OpenQM
RECORDLOCKL, RECORDLOCKU
The RECORDLOCKL statement sets a read lock on a record. The RECORDLOCKU statement
is similar but sets an update lock.
Format
where
The RECORDLOCKL statement sets a read lock on record record.id of the file open as file.var.
The RECORDLOCKU statement sets an update lock.
The LOCKED clause is executed if the file or record is locked by another process in a manner than
prevents further locking. The STATUS() function will return the user id of a process holding a lock
on this file or record. If the LOCKED clause is omitted and the file or record is locked, the
program will wait for the lock to be released.
A process may lock records within files for which it also holds the file lock. These statements may
also be used to convert an existing read lock to an update lock or vice versa.
Example
This program fragment attempts to lock record ORDER.LIST of the file open as STOCK. If it is
locked, a message is displayed and a second RECORDLOCKL statement is executed without a
LOCKED clause to wait for the lock.
2.11-0
QMBasic 1063
RELEASE
Format
where
The RELEASE statement operates in three ways according to whether file.var and record.id are
specified.
With no file.var or record.id, all file, read and update locks owned by the process on all files
are released.
With file.var but no record.id, all locks associated with file.var are released.
The ON ERROR clause is executed if a fatal error occurs. The STATUS() function can be used
to obtain an error code to determine the cause.
Examples
This statement releases any locks on record ORDER.LIST of the file open as STOCK.
RELEASE
This statement releases all file, read and update locks held by the user.
2.11-0
1064 OpenQM
REM()
The REM() function returns the remainder when one value is divided by another.
Format
REM(dividend, divisor)
where
The REM() function returns the remainder of dividing dividend by divisor. This is defined as
where the SIGN() function returns 1 for x > 0, -1 for x < 0 and 0 for x = 0. (SIGN() is not part of
QMBasic. It is used here only to explain the action of the MOD() function).
The REM() function differs from the MOD() function when one of its arguments is negative. The
following table shows the result of the REM() function.
If either dividend or divisor is a numeric array (a dynamic array where all elements are numeric),
the REM() function operates on each element in turn and returns another numeric array. The
structure of this array will be the same as that of the dividend and divisor arrays if they are
identical. For arrays of differing structure, the structure of the result depends on whether the
REUSE() function is used.
Example
N = REM(T, 30)
2.11-0
QMBasic 1065
See also:
MOD(), ROUNDDOWN(), ROUNDUP()
2.11-0
1066 OpenQM
REMARK
The REMARK statement, which may be abbreviated to REM, enters comment text into a
program.
Format
REMARK text
where
The REMARK statement inserts text as a comment in the program which is totally ignored by the
compiler. The semicolon delimiter cannot be used to include an executable statement on the same
line as a REMARK as the entire line after the REMARK keyword is ignored.
Comments are more usually inserted using the an asterisk or exclamation mark prefix.
Examples
2.11-0
QMBasic 1067
REMOVE
The REMOVE statement and REMOVE() function extract characters from a dynamic array up to
the next mark character.
Format
where
var is the variable to be set according to the delimiter that terminates the extracted
substring.
The statement
S = REMOVE(X, Y)
is equivalent to
The REMOVE operation associates a remove pointer with the dyn.array from which data is
extracted. Whenever a string is assigned to a variable the remove pointer is set to point one
character before the start of the string. Subsequent REMOVE operations advance the pointer by
one character and then extract characters from the position of the remove pointer up to the next
mark character or the end of the string. Because the remove pointer gives immediate access to the
position at which the REMOVE should commence, this operation can be much faster than field,
value or subvalue extraction.
The value returned in var indicates the delimiter that terminated the REMOVE. The delimiter
character is not stored as part of the extracted substring. Values of var are
0 End of string
1 Item mark
2 Field mark
3 Value mark
4 Subvalue mark
5 Text mark
The mark character itself can be reconstructed as CHAR(256 - var) for a non-zero value of var.
Once the end of the dyn.array has been reached, the remove pointer remains positioned one
character beyond the end of the string and further REMOVE operations would return a null string.
The remove pointer may be reset to the start of the string by assigning a new value to string. Where
2.11-0
1068 OpenQM
it is required to reset the remove pointer without changing the string, the SETREM statement can
be used. Alternatively, applications frequently use a statement such as
S = S
which will assign S to itself thus resetting the remove pointer.
Note that the REMOVE operation performs a type conversion on dyn.arrray if it is not already a
string. Thus the program
S = 99
REMOVE X FROM S SETTING DELIM
would convert S to be a string "99". Although this is unlikely to have any undesirable effects, it is a
side effect to be aware of.
Examples
LOOP
REMOVE BOOK.NO FROM BOOK.LIST SETTING DELIM
PRINT "Book number is " : BOOK.NO
WHILE DELIM
REPEAT
This program fragment extracts entries from the BOOK.LIST dynamic array and prints then. There
is an assumption that BOOK.LIST is not a null string (in which case a single null BOOK.NO
would be printed).
S = ""
LOOP
REMOVE FLD FROM REC SETTING DELIM
S := FLD
IF DELIM = 2 OR DELIM = 0 THEN
PRINT S
S = ""
END ELSE
S := CHAR(256 - DELIM)
END
WHILE DELIM
REPEAT
This program prints fields from REC. Note the use of the ELSE clause to append the delimiter that
terminated the substring if it was not a field mark or the end of the string.
This is equivalent to
N = DCOUNT(REC, @FM)
FOR I = 1 TO N
PRINT REC<I>
NEXT I
but may be much faster where REC is large and has a very large number of fields.
2.11-0
QMBasic 1069
See also:
GETREM(), REMOVEF(), SETREM
2.11-0
1070 OpenQM
REMOVE.BREAK.HANDLER
Format
REMOVE.BREAK.HANDLER
A break handler subroutine can be established using SET.BREAK.HANDLER and will be called
if the break key is enabled and the user presses it.
The handler applies to the program that establishes it and to all programs called from it unless they
establish their own break handler.
The break handler will be deactivated when the program that established it terminates. The program
can also use REMOVE.BREAK.HANDLER to deactivate the handler while the program
continues to run. A program cannot remove the break handler of another program further down the
call stack. On deactivation of a break handler, any handler belonging to a program further down the
call stack becomes active again.
See also:
Interrupting commands, SET.BREAK.HANDLER
2.11-0
QMBasic 1071
REMOVEF()
Format
where
delimiter is the delimiter character that separates elements of string. If omitted, a field
mark is used. If delimiter is more than one character, only the first character is
used. If delimiter is a null string, count characters are extracted.
The REMOVEF() function uses the same optimised method as the REMOVE() function to extract
items from string sequentially but uses a specified delimiter character instead of terminating on any
mark character.
Whenever a string is assigned to a variable the remove pointer is set to point one character before
the start of the string. Subsequent uses of REMOVEF() advance the point by one character and
then extract characters from the position of the remove pointer up to the next delimiter character or
the end of the string. Because the remove pointer gives immediate access to the position at which
the REMOVEF() should commence, this operation requires no searching and is therefore very fast.
Once the end of the string has been reached, the remove pointer remains positioned one character
beyond the end of the string and further REMOVEF() operations would return a null string.
The REMOVEF() function uses the STATUS() function to return information about its outcome:
0 Successful
1 Null string
2 End of string
The remove pointer may be reset to the start of the string by assigning a new value to string. Where
it is required to reset the remove pointer without changing the string, the SETREM statement can
be used. Alternatively, applications frequently use a statement such as
S = S
which will assign S to itself thus resetting the remove pointer.
Examples
LOOP
REF = REMOVEF(REF.LIST, ',')
UNTIL STATUS()
PRINT "Reference number is " : REF
REPEAT
2.11-0
1072 OpenQM
This program fragment prints successive elements from the comma delimited REF.LIST variable.
See also:
GETREM(), REMOVE, SETREM
2.11-0
QMBasic 1073
REPLACE()
The REPLACE() function replaces a field, value or subvalue of a dynamic array, returning the
result.
Format
where
field evaluates to the field position number. If zero, this argument defaults to one.
value evaluates to the value position number. If omitted or zero, the entire field is
replaced.
subvalue evaluates to the subvalue position number. If omitted or zero, the entire value
is replaced.
If field, value and subvalue are not all present, the comma before the string argument must be
replaced by a semicolon.
The statement
S = REPLACE(S, F, V, SV, NEW)
is equivalent to
S<F, V, SV> = NEW
If the specified field, value or subvalue is not present in the dyn.array, mark characters are added
and the new item is inserted.
A negative value of field, value or subvalue causes a new field, value or subvalue to be appended.
The lower ranking items are taken as being one. For example,
S = REPLACE(X, -1, 2, 3, Z)
appends a new field. The value and subvalue arguments are treated as though the statement were
S = REPLACE(X, -1, 1, 1, Z)
See the description of the S<f,v,sv> assignment operator for a discussion of how QM appends
items, in particular with regard to the COMPATIBLE.APPEND option of the $MODE compiler
directive.
Example
S = REPLACE(REC, 3, 1; ITEM)
This statement assigns S with the result of replacing field 3, value 1 of REC by the contents of
2.11-0
1074 OpenQM
See also:
DEL, DELETE(), EXTRACT(), FIND, FINDSTR, INS, INSERT(), LISTINDEX(),
LOCATE, LOCATE()
2.11-0
QMBasic 1075
RESTORE.SCREEN
The RESTORE.SCREEN statement restores a rectangular portion of the display screen image
previously saved using SAVE.SCREEN().
This statement can only be used with QMConsole and QMTerm sessions and with terminals that
support the save and restore screen region functions (e.g. AccuTerm 5.2b upwards with terminal
definitions that have the -at suffix).
Format
where
restore.state is a boolean value indicating whether the cursor position, pagination mode
and current display attributes are to be restored from the saved data.
The RESTORE.SCREEN statement restores the data previously saved in image using
SAVE.SCREEN(). The data cannot be restored to a different screen position from which it was
saved. If the restore.state expression evaluates to a non-zero value, the pagination mode will also
be restored.
Example
The above code fragment saves the screen image, executes the command in variable
COMMAND.STRING and then restores the screen image.
See also:
SAVE.SCREEN
2.11-0
1076 OpenQM
RETURN
The RETURN statement returns from an internal subroutine entered by GOSUB or an external
subroutine entered by CALL.
Format
RETURN {expr}
RETURN TO label{:}
RETURN FROM PROGRAM
where
The RETURN statement returns from the most recent GOSUB or CALL statement. Thus the
same RETURN statement could leave either an internal or catalogued subroutine.
The RETURN expr form of the RETURN statement is only valid in a FUNCTION and returns
expr as the result of the function. If the function returns to its caller using a simple RETURN
statement with no expr, a null string is returned.
The optional TO label clause causes return from a GOSUB to continue execution at the given label
rather than at the statement following the GOSUB. This clause is ignored when returning from a
CALL. Excessive use of RETURN TO can lead to programs that are extremely difficult to
maintain.
Sometimes a subroutine needs to return to the calling routine but it is not known how many internal
subroutines may be active (e.g. in error paths). The standard way to achieve this in all multivalue
database products is with a statement of the form
ERROR.LABEL: RETURN TO ERROR.LABEL
This slightly strange construct will cause all internal subroutines to return to the RETURN
statement and then return to the calling program. This is different from STOP which would also
terminate the current sentence.
QMBasic provides a rather more readable (and marginally faster) method by using
RETURN FROM PROGRAM
Examples
SUBROUTINE PRINT.REPORT(ID)
...statements...
RETURN
END
2.11-0
QMBasic 1077
This skeleton subroutine performs its task and then returns to its caller.
FUNCTION MATMAX(MAT A)
MAX = A(1)
N = INMAT(A)
FOR I = 1 TO N
IF A(I) > MAX THEN MAX = A(I)
NEXT I
RETURN MAX
END
This function scans a one dimensional matrix and passes back the value of the largest element.
See also:
CALL, GOSUB
2.11-0
1078 OpenQM
REUSE()
The REUSE() function determines how arithmetic operators applied to numeric arrays handle
unequal numbers of fields, values or subvalues.
Format
REUSE(num.array)
where
Arithmetic operators such as addition applied to numeric arrays (dynamic arrays where each
element is numeric) operate on each field, value or subvalue in turn. Where the layout of fields,
values and subvalues in the two numeric arrays is identical there is no difficulty, each element of
one array being added (etc) to its corresponding element from the second array.
If the arrays are of different structure, such as one having more fields than the other or more values
in one field than the corresponding field of the other array, the arithmetic operators normally use a
default value for the missing item. This value is zero except for the divisor of a division operation
which defaults to one.
The REUSE() function causes the previous field, value or subvalue to be reused in place of this
default value where array structures do not match. The REUSE() function applies only to values in
expressions; its effect cannot be assigned to a variable but it can be used to qualify an argument in
a subroutine or function call.
Examples
In this example, C is set to "11FM22FM3" and D to "11FM22FM23". The REUSE() function causes the
final field of B to be reused in the addition with field 3 of A.
This example is similar except that numeric array B has been replaced by a simple numeric
constant which can be considered to be a single element numeric array.
In this case, C is set to "11FM2FM3" and D to "11FM12FM13".
A =
"1":@FM:"2":@VM:"3":@VM:"4":@FM:"5":@VM:"6":@VM:"7":@FM:"8"
B = "10":@FM:"20":@FM:"30":@VM:"40"
2.11-0
QMBasic 1079
C = A + B
D = A + REUSE(B)
In this example individual fields and values of A and B are matched into pairs for the addition
operations.
C is set to "11FM22VM3VM4FM35VM36VM7FM8".
D is set to "11FM22VM23VM24FM35VM36VM37FM48".
See also:
ANDS(), EQS(), GES(), GTS(), IFS(), LES(), LTS(), NES(), NOTS(), ORS()
2.11-0
1080 OpenQM
RND()
Format
RND(expr)
where
The RND() function returns a random number. The range of values is determined by the value of
expr rounded towards zero as an integer. If expr is positive, the number is in the range zero to expr
minus one. If expr is negative, the number is in the range expr plus one to zero. If expr is zero,
RND() returns zero.
If expr is a numeric array (a dynamic array where all elements are numeric), the RND() function
operates on each element in turn and returns a numeric array with the same structure as expr.
The seed value of the random number generator may be set using RANDOMIZE. Note that the
sequence returned may vary between QM releases even if the same seed value is set.
Example
This statement produces a value in TWO.DICE equivalent to throwing a pair of dice. The two calls
to the RND() function will each return a value in the range 0 to 5. The values are then brought into
the appropriate range by adding two.
See also:
RANDOMIZE
2.11-0
QMBasic 1081
ROUNDDOWN(), ROUNDUP()
The ROUNDDOWN() function returns an integer value rounded towards zero in a given
increment. The ROUNDUP() function returns an integer value rounded away from zero in a given
increment.
Format
ROUNDDOWN(value, increment)
ROUNDUP(value, increment)
where
The ROUNDDOWN() function returns the integer value rounded towards zero in steps of
increment. It is equivalent to use of
IDIV(value, increment) * increment
The ROUNDUP() function returns the integer value rounded away from zero in steps of increment.
For a positive value it is equivalent to use of
IDIV(value + increment - 1, increment) * increment
or, for a negative value
IDIV(value - increment + 1, increment) * increment
Example
FOR I = -10 TO 10
DISPLAY I, ROUNDDOWN(I, 3), ROUNDUP(I,3)
NEXT I
2.11-0
1082 OpenQM
5 3 6
6 6 6
7 6 9
8 6 9
9 9 9
10 9 12
See also:
MOD(), REM()
2.11-0
QMBasic 1083
SAVE.SCREEN()
The SAVE.SCREEN() function saves a rectangular portion of the display screen image.
This statement can only be used with QMConsole and QMTerm sessions and with terminals that
support the save and restore screen region functions (e.g. AccuTerm 5.2b upwards with terminal
definitions that have the -at suffix).
Format
where
col is the screen column (from zero) of the leftmost column to be saved.
line is the screen line (from zero) of the top line to be saved.
The SAVE.SCREEN() function saves the data and display attributes of the screen image within
the specified screen area. The value assigned to the variable set by this function can only be used by
the RESTORE.SCREEN statement.
Example
The above code fragment saves the screen image, executes the command in variable
COMMAND.STRING and then restores the screen image.
See also:
RESTORE.SCREEN
2.11-0
1084 OpenQM
SAVELIST
The SAVELIST statement saves an active select list to the $SAVEDLISTS file.
Format
where
list.no is the select list number to be saved. If omitted, this defaults to zero.
The SAVELIST statement saves an active select in the $SAVEDLISTS file. The numbered list is
destroyed by this operation.
If the list had been partially processed before the SAVELIST statement is performed, only the
unprocessed portion of the list is saved.
At least one of the THEN and ELSE clauses must be present. If the list is successfully saved, the
THEN clause is executed. If the list cannot be saved for any reason, the ELSE clause is executed.
See also:
GETLIST
2.11-0
QMBasic 1085
SEEK
The SEEK statement sets the current read / write position in a directory file record previously
opened for sequential access.
Format
where
file.var is the file variable associated with the record by a previous OPENSEQ
statement.
offset is the byte position relative to the point given by relto. If offset and relto
are both omitted, the file position is set to the start of the file.
relto indicates the point from which offset is calculated. Defaults to 0 if omitted.
0 Start of file (offset must be zero or positive).
1 Current position (offset may be any value)
2 End of file (offset must be zero or negative)
At least one of the THEN and ELSE clauses must be present. The THEN clause is executed if the
operation is successful. The ELSE clause is executed if the SEEK operation fails.
Example
This statement positions to the end of the record ready to append new data.
See also:
CLOSESEQ, CREATE, NOBUF, OPENSEQ, READBLK, READCSV, READSEQ,
WEOFSEQ, WRITEBLK, WRITECSV, WRITESEQ, WRITESEQF
2.11-0
1086 OpenQM
The SELECT statement creates a select list containing all record keys from a file.
Format
where
var is the file variable associated with an open file or a field mark delimited
dynamic array of items to form the list.
list.no is the select list number of the list to be created. If omitted, select list zero
is used.
list.var is the select list variable to receive the list. Select list variables can be
processed by the READNEXT statement as an alternative to using
numbered select lists. If the TO clause is omitted, a default select list
variable is used.
The SELECT and SELECTN statements construct a list of record keys in the file open as var and
store this as an active select list list.no replacing any previously active list. If there are no records in
the file, an empty list is created.
|The SELECTV statement constructs the list in the same way but stores it in a select list variable
which can be processed by a subsequent use of READNEXT. If the TO clause is omitted, the
default select list (numbered list 0) is used.
For compatibility with other database products, the action of the SELECT statement can be
changed to produce a select list variable in the same was as SELECTV. This is achieved by setting
the SELECTV option of the $MODE compiler directive.
Also for compatibility with other products, use of the PICK.SELECT option of the $MODE
compiler directive causes SELECTV (and SELECT when $MODE SELECTV is in effect) to
behave such that, if the default select list (list 0) is active when the statement is executed, the default
list is transferred into list.var, ignoring var completely. For example
EXECUTE "SELECT STOCK WITH DESCR LIKE 'Pen...'"
SELECT FVAR TO STOCK.LIST
would transfer the list generated by the executed SELECT into variable STOCK.LIST, ignoring
FVAR. The SELECTE statement provides a neater way to do this.
The QMBasic SELECT, SELECTN and SELECTV statements use an optimised method for
processing hashed files such that each group is examined only when the record keys are extracted
from the select list. This reduces disk transfers and gives better application performance than
2.11-0
QMBasic 1087
constructing the entire list in one operation. This overlapping of processing with record selection
means that, if the application writes new records while the select list is being processed, these new
records may be seen later in the operation.
It is important that a program that does not completely process a select list should clear the
remainder of the list because, while the list is active, split and merge operations are suspended on
the data file. Thus, leaving a list active may cause the file performance to degrade if updates are
made. Note that the file will automatically reconfigure for optimum performance once the select
operation has terminated. When using numbered select lists, the partially processed list can be
cleared using CLEARSELECT. For select list variables generated with SELECTV, the program
should overwrite the list variable with, for example, a null string.
The @SELECTED variable is set to the number of records selected for a directory file or the
number of records in the first non-empty group for a dynamic file.
The optional ON ERROR clause is executed in the event of a fatal error. This covers such
situations as disk hardware errors and faults in the internal structure of the file. The STATUS()
function will return a value relating to the cause of the error. If no ON ERROR clause is present, a
fatal error will result in an abort.
Except where the ON ERROR clause is taken, the STATUS() function will return zero.
For compatibility with Pick style environments, QM also supports a variation on these statements
where the var is a dynamic array in which each field becomes an entry in the target select list.
Example
SELECT STAFF TO 7
This statement creates a list of the records on the file with file variable STAFF and saves it as
active select list 7.
2.11-0
1088 OpenQM
SELECT.SOCKET()
Format
SELECT.SOCKET.INFO(skt.array, timeout)
where
skt.array is a dimensioned array of socket variables. Any element that is not a reference to an
open socket is ignored.
timeout is the time to wait in milliseconds before returning to the program if no events
occur. A value of zero causes an immediate return. A negative value waits
indefinitely.
The SELECT.SOCKET() enables a developer to write a program that can serve multiple socket
connections, pausing execution until an event occurs on any socket.
Use the SKT$EVENTS key to the SET.SOCKET.MODE() function to set the events to be
monitored (read, write, exception) on each socket in the array. Then use SELECT.SOCKET() to
wait for an event to occur.
If an event is detected, the function returns a dynamic array with a field to correspond to each
element in skt.array. The content of each field is a combination of uppercase letters R for a read
event, W for a write event and E for an exception event. Only events that have been selected for
monitoring will appear. Fields for which no event has occurred or where the corresponding element
of sky.array is not a socket variable will be blank. Alternatively, the SOCKET.INFO() function
can be used with key value SKT$EVENTS against each element of skt.array to check for the
socket status.
If the function returns as a result of a timeout or an error, the returned value is a null string and the
STATUS() function can be used to determine the cause/ A timeout will return ER$TIMEOUT. All
other values are errors.
Example
The example below shows the general principles of using socket event notification, monitoring
multiple incoming connections on port 9000. A real program would need to include additional error
handling.
2.11-0
QMBasic 1089
$include keys.h
dim skt(10)
loop
x = select.socket(skt, 5000)
for i = 1 to 10
if x<i> then ;* Must be a read event
if i = 1 then ;* New connection
* Find an unused table entry
for j = 2 to 10
if not(socket.info(skt(j), SKT$INFO.OPEN)) then
skt(j) = accept.socket.connection(skt(1), 0)
if not(set.socket.mode(skt(j),
SKT$INFO.EVENTS, SKT$READ.EVENT)) then
stop 'Error from set.socket.mode()'
end
exit
end
next j
end else
str = read.socket(skt(i), 1000, 0, 0)
if status() then ;* Socket closed
skt(i) = 0
end else
...process input...
end
end
end
next i
repeat
See also:
Using Socket Connections, ACCEPT.SOCKET.CONNECTION, CLOSE.SOCKET,
CREATE.SERVER.SOCKET(), OPEN.SOCKET(), READ.SOCKET(), SERVER.ADDR(),
SET.SOCKET.MODE(), WRITE.SOCKET()
2.11-0
1090 OpenQM
SELECTE
Format
SELECTE TO list.var
where
list.var is the select list variable to receive the list. Select list variables can be processed by
the READNEXT statement as an alternative to using numbered select lists.
The SELECTE statement transfers the unprocessed portion of the default select list (list 0) to the
named variable.
2.11-0
QMBasic 1091
SELECTINDEX
The SELECTINDEX statement creates a select list from an alternate key index entry.
Format
where
list.no is the select list number of the list to be created. If omitted, select list zero
is used.
If the value is omitted, the SELECTINDEX statement constructs a select list containing all the
values of the index identified by index.name. If the value is included, the SELECTINDEX
statement constructs a select list containing keys of records for which the index indentifed by
index.name has the given value.
Thus, in a file of orders with an index on the customer number field, the first form would return a
list of customers referenced by the orders file and the second form would return a list of orders for a
specific customer.
The STATUS() function returns zero if the SELECTINDEX is successful, non-zero if it fails
because the index does not exist. Selecting records for a value that is not present in the index will
return an empty list.
The @SELECTED variable is set to the number of entries in the returned list.
The SELECTINDEX operation leaves the internal index pointer used by the SELECTLEFT and
SELECTRIGHT statements positioned at the item that has been located or, if not found, at the
position where such an item would go.
Use of this statement inside a transaction will not reflect any uncommitted updates to the file.
Examples
2.11-0
1092 OpenQM
REPEAT
This program builds a select list of all the customers referenced by the orders file as list 7. The
inner loop then constructs a list of the order numbers for each customer in turn.
See also:
SETLEFT, SETRIGHT, SELECTLEFT, SELECTRIGHT
2.11-0
QMBasic 1093
SELECTINFO()
Format
SELECTINFO(list.no, key)
SELECTINFO(var, key)
where
list.no evaluates to the number of the select list to be examined. If omitted, select list zero
is used.
Values for the key to the SELECTINFO() function are defined in the KEYS.H record in the
SYSCOM file. These are
1 SL$ACTIVE Returns true (1) if the select list is active, false (0) if it is not active.
3 SL$COUNT Returns the number of items remaining to be processed in the select
list. If the list is not active, the SELECTINFO() function will return
zero.
Use of mode 3 with a list constructed using the QMBasic SELECT statement on a dynamic file
requires completion of the selection process and thus may reduce application performance.
Example
SELECT STOCK.FILE
PRINT "Stock file has " : SELECTINFO(0, SL$COUNT) : " records"
CLEARSELECT
This program fragment counts and reports the number of records in the file open with file variable
STOCK.FILE..
2.11-0
1094 OpenQM
The SELECTLEFT and SELECTRIGHT statements create a select list from the entry in an
alternate key index to the left or right of the last entry processed.
Format
where
key is the variable to be set to the key value associated with the returned list.
list.no is the select list number of the list to be created. If omitted, select list zero
is used.
The SELECTLEFT and SELECTRIGHT statements construct a select list from the alternate key
index entry to the left or right of the one most recently returned using SELECTINDEX,
SELECTLEFT or SELECTRIGHT. The position of the scan can be set to the extreme left using
SETLEFT or the extreme right using SETRIGHT.
These operations allow a program to find a specific value and then walk through successive values
in the sorted data structure that makes up an alternate key index.
If SELECTINDEX is used to locate a value that does not exist in the index, SELECTLEFT will
return a list of records for the value immediately before the non-existent one and SELECTRIGHT
will return a list of records for the value immediately after the non-existent one.
The STATUS() function returns zero if the operation is successful, non-zero if it fails because the
index does not exist. The @SELECTED variable is set to the number of entries in the returned list,
or zero if there are no further index entries to be returned.
Use of these statements inside a transaction will not reflect any uncommitted updates to the file.
Examples
KEY = 'M'
SELECTINDEX 'POSTCODE', KEY FROM CLIENTS.FILE
LOOP
LOOP
READNEXT CLIENT.NO ELSE EXIT
CRT CLIENT.NO
REPEAT
SELECTRIGHT 'POSTCODE' FROM CLIENTS.FILE SETTING POSTCODE
WHILE @SELECTED
WHILE POSTCODE[1,LEN(KEY)] = KEY
2.11-0
QMBasic 1095
REPEAT
This program displays a list of all clients with postcodes beginning with M.
The SELECTINDEX looks for an index entry for a postcode of "M". This is unlikely to exist and
hence the select list will probably be empty. If it did find any records, the inner loop would display
these. Having processed this initial list, the SELECTRIGHT moves one step right (i.e. in
ascending order) through the index tree and builds a list of these records. The POSTCODE variable
is returned as the value of the indexed item located. Processing continues until the
SELECTRIGHT finds an item that does not begin with the characters in KEY.
The above program fragment finds the record in the file open as LOG.F with the TIME field equal
to TIMESTAMP. If there is no such record it finds the record with the nearest time before the
requested timestamp. If multiple records have the same timestamp value, select list 1 will contain all
of their ids. If TIME was the id of records in the log file, the select list could never contain multiple
values.
See also:
SELECTINDEX, SETLEFT, SETRIGHT
2.11-0
1096 OpenQM
SENTENCE()
The SENTENCE() function returns command line that started the current program.
Format
SENTENCE()
2.11-0
QMBasic 1097
SEQ()
The SEQ() function returns the ASCII character set position value of a character.
Format
SEQ(char)
where
The SEQ() function returns the character value of char. It is the inverse of the CHAR() function.
If char is a null string, SEQ() returns zero. If char is more than one character in length, SEQ()
returns the value of the first character.
Example
N = SEQ(KEYIN())
This statement reads a single character from the keyboard and then uses SEQ() to find its ASCII
character set value.
See also:
CHAR()
2.11-0
1098 OpenQM
SERVER.ADDR()
The SERVER.ADDR() function returns the IP address for a given server name.
Format
SERVER.ADDR(server.name)
where
server.name is the name of the server for which the IP address is required.
The SERVER.ADDR() function can be used to find the IP address of a network server from its
name. This function is not usually needed as the QMBasic socket functions work with either IP
addresses or server names.
If successful, the STATUS() function will return zero. All error conditions return a null string as
the IP address and subsequent use of the STATUS() function will return the error code.
Example
DISPLAY SERVER.ADDR("openqm.com")
See also:
Using Socket Connections, ACCEPT.SOCKET.CONNECTION, CLOSE.SOCKET,
CREATE.SERVER.SOCKET(), OPEN.SOCKET(), READ.SOCKET(),
SELECT.SOCKET(), SET.SOCKET.MODE(), SOCKET.INFO(), WRITE.SOCKET()
2.11-0
QMBasic 1099
SET.ARG
The SET.ARG statement updates a subroutine argument value based on its position in the
argument list. It is intended for use with subroutines declared with the VAR.ARGS option.
Format
SET.ARG n, value
where
Subroutines declared with the VAR.ARGS option may have a variable number of arguments.
Although each argument must have a name assigned to it in the SUBROUTINE statement, it is
often useful to be able to process a series of arguments by indexing this list.
The SET.ARG statement sets the value of argument n. The actual number of arguments passed
may be determined using the ARG.COUNT() function. Use of an argument position value less than
one or greater than the number of arguments causes the program to abort.
See also:
ARG(), ARG.COUNT, ARG.PRESENT()
2.11-0
1100 OpenQM
SET.BREAK.HANDLER
Format
SET.BREAK.HANDLER name
where
name evaluates to the name of the break handler. This must be a catalogued subroutine.
The break handler subroutine will be called if the break key is enabled and the user presses it. The
subroutine takes a single argument through which it returns an action code telling QM how to
handle the break. Possible return values are:
0 Display normal break key action prompt
1 Continue execution
2 Quit (equivalent to use of STOP)
3 Abort
4 Logout
Any other value will display the normal break key action prompt.
The handler applies to the program that establishes it and to all programs called from it unless they
establish their own break handler. The handler may perform any appropriate application processing
to determine the action code to be returned but must not execute a STOP or ABORT statement
internally.
The break handler will be deactivated when the program that established it terminates. The program
can also use REMOVE.BREAK.HANDLER to deactivate the handler while the program
continues to run. A program cannot remove the break handler of another program further down the
call stack. On deactivation of a break handler, any handler belonging to a program further down the
call stack becomes active again.
See also:
Interrupting commands, REMOVE.BREAK.HANDLER
2.11-0
QMBasic 1101
SET.EXIT.STATUS
The SET.EXIT.STATUS statement sets the final exit status returned by QM to the operating
system. This operation has no effect on the PDA version of QM.
Format
SET.EXIT.STATUS value
where
By default, QM returns an exit status of zero to the operating system on termination. The
SET.EXIT.STATUS statement allows an application to return an alternative exit status value to
indicate, for example, success or failure. Note that error conditions detected during startup of a QM
session return an exit status of 1.
2.11-0
1102 OpenQM
The SETLEFT and SETRIGHT statements set the scanning position of an alternate key index at
the extreme left or right of the data.
Format
where
The SETLEFT and SETRIGHT statements are used with SELECTLEFT and
SELECTRIGHT to set the scan position to the first or last entry in an alternate key index.
The STATUS() function returns zero if the operation is successful, non-zero if it fails because the
index does not exist.
Example
This program displays a list of all postcodes commencing with a letter in the first half of the
alphabet.
See also:
SELECTINDEX, SELECTLEFT, SELECTRIGHT
2.11-0
QMBasic 1103
SET.PORT.PARAMS()
The SET.PORT.PARAMS() function sets the communications parameters for a serial port. This
function is not available on the PDA version of QM.
Format
SET.PORT.PARAMS(fvar, params)
where
fvar is the file variable from the OPENSEQ statement that was used to open the port.
The SET.PORT.PARAMS() function returns true (1) if successful, false (0) if an error occurs.
To allow for the possibility of additional fields being added in future releases, programs should use
the GET.PORT.PARAMS() function to retrieve the current settings, modify this as required and
then use SET.PORT.PARAMS() to set the new parameters.
Example
PARAMS = GET.PORT.PARAMS(PORT)
PARAMS<2> = 9600
IF NOT(SET.PORT.PARAMS(PORT, PARAMS) THEN STOP 'Error setting
parameters'
2.11-0
1104 OpenQM
SET.SOCKET.MODE()
Format
where
The SET.SOCKET.MODE() function returns TRUE (1) if the action is successful, FALSE (0) if
it fails. The STATUS() function can be used to determine the cause of failure.
The SKT$INFO.EVENTS mode allows a program to specify events that are to be monitored for the
socket when using the SELECT.SOCKET() function. The value argument is an additive value
chosen from:
1 SKT$READ_EVENT Notify availability of a new connection on a server socket
Notify availability of data that can be read with
READ.SOCKET()
Notify closure of connection
2 SKT$WRITE_EVENT Notify when data can be sent with WRITE.SOCKET()
4 SKT$EXCEPTION_EVENT Notify exceptions
See also:
Using Socket Connections, ACCEPT.SOCKET.CONNECTION, CLOSE.SOCKET,
CREATE.SERVER.SOCKET(), OPEN.SOCKET(), READ.SOCKET(),
SELECT.SOCKET(), SERVER.ADDR(), SOCKET.INFO(), WRITE.SOCKET()
2.11-0
QMBasic 1105
SET.TIMEZONE
The SET.TIMEZONE statement sets the time zone for use by the epoch conversion code.
Format
SET.TIMEZONE zone
where
The SET.TIMEZONE statement is equivalent to executing the CONFIG command to set the
TIMEZONE private configuration parameter. There is no validation performed on the zone name.
A program can retrieve the current time zone using the CONFIG() function with "TIMEZONE" as
the argument value.
See also:
Date, Times and Epoch Values, EPOCH(), MVDATE(), MVDATE.TIME(), MVEPOCH(),
MVTIME(), SET.TIMEZONE
2.11-0
1106 OpenQM
SETNLS
The SETNLS statement sets the value of a national language support parameter.
Format
where
The SETNLS statement sets the value of the named national language support parameter. NLS
parameter name tokens are defined in the KEYS.H include record.
Example
2.11-0
QMBasic 1107
SETPU
Format
where
2.11-0
1108 OpenQM
be char(12) or char(13):char(12)
2000 PU$LINENO Current line number
The SETPU statement sets the print unit characteristic specified by key to the given value. It is
closely related to the SETPU() subroutine.
Mode 15 (PU$PAGENUMBER) can be used to set the current page number before any output to
the print unit if a report is to start at a page number other than one. Using this mode after output
has commenced may have indeterminate effects.
Example
The above statement sets the destination for print unit 3 to be the LASER printer.
See also:
GETPU()
2.11-0
QMBasic 1109
SETREM
Format
where
Assigning a character string variable automatically sets the remove pointer to zero, effectively
pointing one character before the start of the string. The SETREM statement allows an application
to set the remove pointer to an arbitrary offset into string. The STATUS() function will return zero
if the action is successful.
If the offset is negative or greater than the length of string, any existing remove pointer is not
altered and the STATUS() function will return error code ER$LENGTH.
SETREM is typically used with GETREM() to save and restore the remove pointer position.
Example
RMV.PTR = GETREM(S)
GOSUB PROCESS.DATA
SETREM RMV.PTR ON S
The above code fragment saves the remove pointer associated with string S and restores it after
execution of subroutine PROCESS.DATA which might change this remove pointer.
See also:
GETREM, REMOVE
2.11-0
1110 OpenQM
SHIFT()
Format
SHIFT(value, shift.len)
where
The SHIFT() function converts value to a thirty two bit integer, truncating any fractional part of a
non-integer value, and shifts the bit pattern of this value by shift.len positions.
A positive value of shift.len shifts right (towards the low order end). A negative value of shift.len
shifts left (towards the high order end).
Values of shift.len that are outside the range -32 to +32 have undefined results.
Example
FOR I = 30 TO 0 STEP - 3
DISPLAY BITAND(SHIFT(N, I), 7) :
NEXT I
This program fragment displays the value of N in octal. The MO conversion mode of the
OCONV() function would be more appropriate.
See also:
BITAND(), BITNOT(), BITOR(), BITRESET(), BITSET(), BITTEST(), BITXOR()
2.11-0
QMBasic 1111
SIN()
Format
SIN(expr)
where
The SIN() function returns the cosine of expr. Angles are measured in degrees.
If expr is a numeric array (a dynamic array where all elements are numeric), the SIN() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
This statement finds the length of the opposite side of a right angled triangle from the length of the
hypotenuse and the adjacent angle.
See also:
ACOS(), ASIN(), ATAN(), COS(), TAN()
2.11-0
1112 OpenQM
SLEEP
The SLEEP statement causes the program in which it is executed to pause for a given number of
seconds or until a specific time. The synonym RQM may be used in place of SLEEP.
Format
SLEEP {time}
where
time determines the time for which the program is to sleep. If omitted, time defaults to
one.
The SLEEP statement operates in one of two ways depending on the format of time.
If time is a number, it is rounded to an integer value and the program sleeps for that number of
seconds. If time is negative or zero, the program continues without sleeping. See NAP for a way to
pause for less than one second.
If time is not a number, an attempt is made to convert it to a time of day using any of the formats
accepted by the ICONV() function MT conversion. If successful, the program sleeps until this
time. If the time of day specified by time has already passed, it is assumed to be a reference to that
time on the following day. If time cannot be converted to a time of day, the program continues
without sleeping.
In all cases, if there is more than one process running, the SLEEP statement causes a process
switch to occur. It can therefore be used to relinquish the remainder of the timeslice of the current
process if waiting for some event to occur in another process, such as release of a lock.
The actual sleep time may vary from that specified due to process scheduling actions within the
operating system.
If the break key is used to interrupt a program which is sleeping, selection of the G option will
continue to sleep to the specified time. The Q option will abort the program immediately.
Examples
SLEEP "10:30PM"
This statement causes the program to sleep until half past ten at night.
SLEEP 10
See also:
NAP
2.11-0
QMBasic 1113
SOCKET.INFO()
Format
SOCKET.INFO(skt, key)
where
The SOCKET.INFO() function returns information about an open socket as shown in the
parameter descriptions above.
See also:
Using Socket Connections, ACCEPT.SOCKET.CONNECTION, CLOSE.SOCKET,
CREATE.SERVER.SOCKET(), OPEN.SOCKET(), READ.SOCKET(),
SELECT.SOCKET(), SERVER.ADDR(), SET.SOCKET.MODE(), WRITE.SOCKET()
2.11-0
1114 OpenQM
SOUNDEX()
The SOUNDEX() function returns a four character string determined by the phonetic content of a
string. The SOUNDEXS() function is similar to SOUNDEX() but operates on successive elements
of a dynamic array, returning a similarly structured dynamic array of results.
Format
SOUNDEX(string)
where
The SOUNDEX() function is useful for situations where it is desired to compare or locate items by
their spoken sound. For example, names in a telephone directory could be indexed by their
SOUNDEX() value to aid location of similar sounding names.
The value returned by SOUNDEX() is made up from the first letter of string in upper case
followed by three digits which are found by examination of further characters of string according to
the following table.
0 A E H I O U W Y
1 B F P V
2 C G J K Q S X Z
3 D T
4 L
5 M N
6 R
Letters in group 0 are ignored. Consecutive letters that result in the same value result in only a
single character. If the result is less than four characters long, zeros are added to fill the remaining
positions. Thus the word SOUNDEX encodes to S532.
Example
This program fragment prompts for and reads a name. It then establishes the soundex key for this
name and attempts to read a list of similar sounding names from the PHONONYMS file. If found,
this list replaces the NAME value.
2.11-0
QMBasic 1115
SPACE()
The SPACE() function returns a string consisting of a given number of spaces. The SPACES()
function is similar to SPACE() but operates on successive elements of a dynamic array, returning a
similarly structured dynamic array of results.
Format
SPACE(count)
where
The SPACE() function is a useful way to generate multiple spaces. It can aid readability of
programs by removing the need for space filled strings and it can be used to provide variable
numbers of spaces where required.
Example
This statement prints the contents of TEXT indented by the number of spaces specified by
INDENT.
See also:
STR()
2.11-0
1116 OpenQM
SPLICE()
The SPLICE() function concatenates corresponding elements of a dynamic array, inserting a string
between each pair of items.
Format
where
The SPLICE() function returns the result of concatenating corresponding dynamic array
components (fields, values and subvalues) from the supplied arrays, inserting string between each
pair.
The REUSE() function can be applied to either or both dynamic arrays. Without this function, any
absent trailing values are taken as null strings.
Example
S1 = "ABC":@fm@"DEF"
S2 = "123":@vm:"456":@fm:"789"
X = SPLICE(S1,'-', S2)
The above code fragment concatenates elements of the two strings yielding a result in X of
"ABC123VM456FMDEF789"
2.11-0
QMBasic 1117
SQRT()
Format
SQRT(expr)
where
If expr is a numeric array (a dynamic array where all elements are numeric), the SQRT() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
N = SQRT(A)
2.11-0
1118 OpenQM
SQUOTE()
The SQUOTE() function returns a copy of its argument string enclosed in single quotes. The
SQUOTES() function is similar but operates on successive elements of a dynamic array, returning
a similarly structured dynamic array of results.
Format
SQUOTE(expr)
where
Example
A = SQUOTE('ABC123')
This program fragment encloses each element of dynamic array A in single quotes, storing the result
in B as
'ABC'VM'DEF'
See also:
QUOTE()
2.11-0
QMBasic 1119
SSELECT
The SSELECT statement creates a select list containing all record keys from a file sorted into left
justified ascending order.
Format
where
list.no is the select list number of the list to be created. If omitted, select list zero
is used.
A list of record keys in the file open as file.var is created and stored as an active select list list.no
replacing any previously active list. If there are no records in the file, an empty list is created. Keys
will be stored in left justified ascending order. The @SELECTED variable is set to the number of
records selected.
The optional ON ERROR clause is executed in the event of a fatal error. This covers such
situations as disk hardware errors and faults in the internal structure of the file. The STATUS()
function will return a value relating to the cause of the error. If no ON ERROR clause is present, a
fatal error will result in an abort.
Except where the ON ERROR clause is taken, the STATUS() function will return zero.
For compatibility with Pick style environments, QM also supports a variation on SSELECT where
the file.var is replaced by a dynamic array in which each field becomes an entry in the target select
list.
Example
SSELECT STAFF TO 7
This statement creates a sorted list of the records on the file with file variable STAFF and saves it
as active select list 7.
2.11-0
1120 OpenQM
STATUS()
The STATUS() function returns information following execution of certain other statements. In
many cases, this information gives details of an error condition.
Format
STATUS()
The STATUS() function is used to fetch status information set by other statements as documented
in their descriptions. Where the value relates to an error condition, the tokens in the ERR.H record
of the SYSCOM file can be used. Use of the actual values of error status codes is discouraged.
The STATUS() function can be used any number of times to retrieve the current status value but
this value may be changed by other statements. In general, the STATUS() function should be used
as close as possible to the statement that set the value to be retrieved. In particular, use of CALL
and EXECUTE are very likely to result in execution of statements that destroy the previous value
of the STATUS() function.
There is a standard subroutine, !ERRTEXT(), that can be used to translate an error number to an
equivalent text message.
See the OS.ERROR() function for a way to access operating system level error numbers.
Example
This program fragment attempts to open a file and, if the OPEN fails, reports the error code.
2.11-0
QMBasic 1121
STATUS
The STATUS statement returns a dynamic array containing a variety of information about an open
file. Not all fields are returned on the PDA version of QM.
Format
where
At least one of the THEN and ELSE clauses must be present for compatibility with other
multivalue products. The implementation of STATUS in QM never executes the ELSE clause.
The STATUS statement returns a dynamic array where the fields contain the following
information:
See also:
FILEINFO()
2.11-0
1122 OpenQM
STOP
The STOP statement terminates the current program. STOPE and STOPM provide compatibility
with other multivalue database products.
Format
STOP {message}
where
where
message evaluates to the id of a record in the ERRMSG file which holds the message to be
displayed. If this id is numeric, it will be copied to @SYSTEM.RETURN.CODE.
See the ERRMSG statement for a description of the ERRMSG file message format.
The STOPE statement always uses Pick style message handling and the STOPM statement always
uses Information style message handling, regardless of the setting of the PICK.ERRMSG option.
Examples
This statement terminates the program if the value of the variable NO.OF.ENTRIES is zero. No
error message is printed. STOP statements without error text messages can result in difficult
diagnostic work to locate faults.
2.11-0
QMBasic 1123
This program fragment attempts to open a file named STOCK.FILE. If the open fails, the program
displays an error message and terminates the program.
See also:
ABORT, ERRMSG
2.11-0
1124 OpenQM
STR()
The STR() function returns a string made up of a given number of repeated occurrences of another
string. The STRS() function is similar to STR() but operates on successive elements of a dynamic
array, returning a similarly structured dynamic array of results.
Format
STR(string, count)
where
The STR() function returns count occurrences of string. If count is less than one, a null string is
returned.
Examples
S = STRS('X':@VM:'Y':@SM:'Z', 2)
This statement sets S to be
XXVMYYSMZZ
See also:
SPACE()
2.11-0
QMBasic 1125
SUBR()
The SUBR() function calls a subroutine as a function in an expression. It is normally only used in
dictionary I-type items.
Format
where
The SUBR() function calls catalogued subroutine name, passing arg1, arg2, etc to it as its
arguments. The subroutine must be written to have an additional first argument through which it
returns its result which is used as the value of the SUBR() function.
A statement such as
A = B + SUBR("EVALUATE", C, D)
is equivalent to
CALL EVALUATE(X, C, D)
A = B + X
The name argument may be any expression that evaluates to the name of the subroutine. The
catalogue look-up process is performed for each execution of the SUBR() function unlike a CALL
statement where the look-up is performed just once for each invocation of the calling program.
When used from a dictionary I-type expression evaluated by the query processor, the @ID and
@RECORD variables will contain the id and data of the record currently being processed. If the
subroutine called with SUBR() modifies these variables, perhaps to use the ITYPE() function
internally, the original values must be saved and reinstated if the dictionary item is to be usable
within the query processor.
When used in a QMBasic program, the SUBR() function does not support the MAT keyword to
pass a whole matrix as an argument. The CALL statement must be used to achieve this.
Example
The above subroutine takes a customer number as its second argument and uses this to access an
2.11-0
1126 OpenQM
alternate key index, returning a list of all orders that were placed by the given customer. This
example assumes that the ORDERS.F file variable is in a common block defined in the FILES.H
include record and that the file is already open.
In either case, assuming that the subroutine or function is catalogued as CUST.ORD, it could be
used from within a dictionary I-type item by use of a SUBR() function such as:
SUBR('CUST.ORD', CUST.NO)
where CUST.NO is the name of a field within the data records being processed.
2.11-0
QMBasic 1127
SUBROUTINE
The SUBROUTINE statement introduces a subroutine. The abbreviation SUB may be used.
Format
where
The SUBROUTINE statement must appear before any executable statements. A SUBROUTINE
with no arguments is equivalent to a PROGRAM. The brackets are optional if there are no
arguments. The SUBROUTINE statement may be split over multiple lines by breaking after a
comma.
The name used in a SUBROUTINE statement need not be related to the name of the source record
though it is recommended that they are the same as this eases program maintenance. The name must
comply with the QMBasic name format rules
The number of arguments in calls to the subroutine must be the same as in the SUBROUTINE
statement unless the subroutine is declared with the VAR.ARGS option. When VAR.ARGS is
used, any arguments not passed by the caller will be unassigned. The ARG.COUNT() function can
be used to determine the actual number of arguments passed. The ARG.PRESENT() function can
be used to test for the presence of an optional argument by name. If the values of argument
variables are changed by the subroutine, these changes are reflected in the variables used in the
CALL statement that entered the subroutine.
SUBROUTINE CREDIT.RATING(CLIENT, CLASS, CODE) VAR.ARGS
In this example, if the calling program supplies only one argument, the CLASS and CODE
variables will be unassigned. If the calling program provides two arguments, the CODE variable
will be unassigned.
When using VAR.ARGS, default values may be provided for any arguments by following the
argument name with an = sign and the required numeric or string value. For example,
SUBROUTINE CREDIT.RATING(CLIENT, CLASS = 1, CODE = "Standard")
VAR.ARGS
In this example, if the calling program supplies only one argument, the CLASS variable will default
2.11-0
1128 OpenQM
to 1 and the CODE variable will default to "Standard". It the calling program provides two
arguments, the default value for CLASS is ignored and the CODE variable defaults to "Standard".
Subroutine arguments are normally passed by reference such that changes made to the argument
variable inside a subroutine will be visible in the caller's variable referenced by that argument. The
CALL statement allows arguments to be passed by value by enclosing them in brackets. The
SUBROUTINE statement also supports this dereferencing syntax. For example
SUBROUTINE INVOICE(P, (Q))
If dereferencing is used with the default argument syntax described above, the default value is
placed inside the parenthesis. For example,
SUBROUTINE INVOICE(P, (Q = 7)) VAR.ARGS
An argument may refer to a whole matrix. In this case the argument variable name must be
preceded by the keyword MAT and there must be a DIM statement following the subroutine
declaration to indicate whether this is a one or two dimensional matrix. Alternatively, the
dimensions may be given after the variable name in the SUBROUTINE statement. In either case,
the actual dimension values are counted by the compiler to establish whether the matrix has one or
two dimensions but are otherwise ignored. Developers frequently use of a dimension value of one to
emphasise to readers of the program that the value is meaningless. A matrix passed as an argument
cannot be redimensioned in the subroutine.
For example
SUBROUTINE MATMAX(MAX, MAT A)
DIM A(1)
MAX = A(1)
N = INMAT(A)
FOR I = 2 TO N
IF A(I) > MAX THEN MAX = A(I)
NEXT I
END
This subroutine scans a one dimensional matrix and passes back the value of the largest element via
the MAX argument. The first two lines could alternatively be written as
2.11-0
QMBasic 1129
SUBSTITUTE()
Format
where
delimiter is the single character delimiter separating items in old.list and new.list. If
omitted, this defaults to a value mark.
The SUBSTITUTE() function processes each element of dynamic array dyn.array constructing an
equivalently structured new dynamic array result. Where an element of dyn.array contains a value
in the old.list, the result contains the corresponding item from new.list. Where there is no match
with an item in old.list, the source data is copied to the result dynamic array.
Although this function is defined to operate on dynamic array, it may be equally useful when
dyn.array is a simple single valued string.
Example
A contains DFMDVMFVMP
2.11-0
1130 OpenQM
SUBSTRINGS()
Format
where
The SUBSTRINGS() function is the multivalued equivalent of the substring extraction operator [
start, length] and processes each element of dyn.array in turn to produce a result dynamic array.
Example
A contains ABCDEFMFGHIJVMKLMNOVMPQRST
B = SUBSTRINGS(A, 2, 3)
2.11-0
QMBasic 1131
SUM()
The SUM() function eliminates the lowest level of a dynamic array by adding the elements to form
an item of the next highest level.
Format
SUM(expr)
where
The SUM() function identifies the lowest level elements present in expr and forms the sum of each
group of elements at this level, replacing the group with an item of the next highest level.
In a numeric array containing subvalues, the subvalues are summed to form values.
If there are no subvalues and the numeric array contains values, the values are summed to form
fields.
If there are no subvalues or values, the fields are summed to form a single field.
Example
TOTAL.PAID = SUM(PAYMENTS)
This statement sums a multivalued list of payments to form the total amount paid.
See also:
SUMMATION()
2.11-0
1132 OpenQM
SUMMATION()
The SUMMATION() function returns the total value of all elements of a numeric array.
Format
SUMMATION(expr)
where
The SUMMATION() function adds together all elements of expr, returning the total value. It is
equivalent to repeated use of the SUM() function until just one value remains.
Example
TOTAL.PAID = SUMMATION(PAYMENTS)
This statement sums a multivalued list of payments to form the total amount paid.
See also:
SUM()
2.11-0
QMBasic 1133
SWAPCASE()
The SWAPCASE() function inverts the case of all alphabetic characters in a string.
Format
SWAPCASE(string)
where
The SWAPCASE() function returns the value of string with all uppercase letters converted to
lower case and all lowercase letters converted to uppercase. If string is a variable rather than an
expression, the value of the variable is not affected.
Example
S = "ABCdef"
PRINT SWAPCASE(S)
See also:
DOWNCASE(), UPCASE()
2.11-0
1134 OpenQM
SYSTEM()
The SYSTEM() function returns information regarding the status of various aspects of the system.
On the PDA version of QM, key values that are inappropriate return a zero value.
Format
SYSTEM(key)
where
The SYSTEM() function is provided for compatibility with other data management products. Many
of the key values correspond to those found in other multivalue database products though some
values are implemented inconsistently across products. Values 1000 and above are usually specific
to QM.
The following key values are implemented. All other key values return a zero value.
Key Function
1 Returns 1 if a PRINTER ON statement is in effect
2 Current page width of the default print unit
3 Current page length of the default print unit
4 Lines remaining on current page of the default print unit
5 Current page number of the default print unit
6 Current line number of the default print unit
7 Terminal type (same as @TERM.TYPE)
9 Cumulative processor time used (mS) by this QM session
10 Input waiting in the DATA queue? (1 if so, 0 if not)
11 Select list 0 active? (1 if so, 0 if not)
12 Time in seconds since midnight (same as TIME())
18 User number (same as @USERNO)
19 Returns a unique value formed from the internal form date and time in the user's time
zone as two five digit numbers. If the function is used more than once system wide in
the same second, an alphabetic suffix is added to create a unique value. This function is
unreliable in applications where users span multiple time zones.
23 Break key enabled? (1 if so, 0 if not)
24 Input echo enabled? (1 if so, 0 if not)
25 Is this a phantom process?
26 Returns the current input prompt character
27 Returns the operating system uid for the user's process. (Not Windows or PDA)
2.11-0
QMBasic 1135
28 Returns the operating system effective uid for the user's process. (Not Windows or
PDA)
29 Returns the operating system gid for the user's process. (Not Windows or PDA)
30 Returns the operating system effective gid for the user's process. (Not Windows or
PDA)
31 Licence number
32 Returns the system (QMSYS) directory pathname
38 Returns temporary directory pathname
42 Returns telnet connection IP address, null for a console user
91 Returns 1 on Windows, 0 on other platforms
1000 Returns 1 if EXECUTE CAPTURING is in effect, 0 otherwise
1001 Returns 1 if case inversion is enabled, 0 otherwise
1002 Returns the program call history. This is a dynamic array in which each program is
represented by a field, the current program being in field 1. The first value in each field
contains the program name. Subsequent values are divided into two subvalues
containing the program address and line number (where available) for each internal
subroutine call (GOSUB) in the program. The first value in each field has an
additional third subvalue containing the compile time of the program as an epoch value.
1003 Returns a dynamic array containing a list of open files. Each field has two values; the
first holds the internal file number, the second holds the file's pathname.
1004 Returns the peak number of files that have been open at one time since QM was
started.
1005 Returns the combined date and time value as DATE() * 86400 + TIME() based on the
user's time zone.
1006 Returns 1 if running on a Windows NT style system (NT and later).
1007 Returns the current transaction number, zero if not in a transaction.
1008 Returns the current transaction level, zero if not in a transaction.
1009 Returns the system byte ordering, 1 for high byte first, 0 for low byte first.
1010 Returns the platform name; Windows, Linux, FreeBSD, AIX, Mac, PDA.
1011 Returns the pathname of the QM configuration file
1012 Returns the QM version number.
1013 Returns user limit, excluding users reserved for phantom processes.
1014 Returns user limit, including users reserved for phantom processes.
1015 Returns the name of the host computer system.
1016 Returns the remaining number of licensed non-phantom users.
1017 Returns the tcp/ip port number for a socket connection.
1018 Returns the device licensing connection limit.
1019 Returns the offset in seconds of the user's local time zone from UTC. This will be
negative for zones to the west of longitude zero.
1020 Returns the time of day in milliseconds since midnight UTC.
2.11-0
1136 OpenQM
1024 Returns the current working directory pathname when QM was entered.
1025 Returns a dynamic array where field 1 is a multivalued list of environment variable
names and field 2 is a corresponding list of their values.
1026 Returns xxx when QM is entered using "qm xxx".
1027 Returns the name of the serial port when logged in on a serial connection.
1028 Returns the system id of the active QM licence, zero if the licence is not system
specific.
1029 Returns the current internal subroutine depth.
1030 Returns login time as date * 86400 + time in the user's local time zone using Pick date
numbering.
1031 Returns operating system process id.
1032 Returns and clears the break pending flag, set if the break key is pressed with breaks
disabled.
1033 Returns true if a COMO file is active.
1034 Returns true if COMO output is active but suspended.
1035 Returns the time as seconds since 00:00:00 on January 1 1970, Universal Coordinated
Time (UTC) independent of the user's time zone. Same as the EPOCH() function.
1036 Returns the period in tenths of a second for which login was delayed waiting for a spare
user. See the LGNWAIT configuration parameter.
1037 Returns a dynamic array with one field for each open QM file. In each field, value 1
holds the internal file number, value 2 holds the file pathname and value 3 is a subvalue
mark delimited list of QM user numbers for which the file is open.
1038 Returns login time as an epoch value.
1040 Returns true if operating system filenames are case insensitive.
1041 Returns a field mark delimited list of active replication subscribers.
1042 Returns the system id of the server. This will differ from SYSTEM(1028) for a USB
installation or a licence that is not system specific.
QM allows users to add definitions for their own SYSTEM() function key values by writing a
QMBasic subroutine that performs whatever processing is required. This subroutine takes two
arguments. The first is used to return the result and the second is the key value passed in. This
subroutine must be catalogued as $SYSTEM.
2.11-0
QMBasic 1137
TAN()
Format
TAN(expr)
where
The TAN() function returns the tangent of expr. Angles are measured in degrees.
If expr is a numeric array (a dynamic array where all elements are numeric), the TAN() function
operates on each element in turn and returns a numeric array with the same structure as expr.
Example
This statement finds the length of the opposite side of a right angled triangle from the length of the
adjacent side and the angle between it and the hypotenuse.
See also:
ACOS(), ASIN(), ATAN(), COS(), SIN()
2.11-0
1138 OpenQM
TCLREAD
The TCLREAD statement retrieves the sentence that started the current program.
Format
TCLREAD var
where
2.11-0
QMBasic 1139
TERMINFO()
Format
TERMINFO()
TERMINFO(cap.name)
where
The TERMINFO() function enables programs to examine the terminfo database to establish
capabilities of the currently selected terminal type.
In the first form, TERMINFO() returns a dynamic array containing a wide range of capability
information about the terminal. The structure of this dynamic array is defined in the TERMINFO.H
include record in the SYSCOM file. Additional entries may be added in future releases but existing
entries will not be moved.
The second form of the TERMINFO() function returns the value of the named capability. The
cap.name argument should evaluate to a capability name as used in terminfo source files. This
name is case sensitive. Unrecognised capabilities and those for which the terminfo database has no
entry will be returned as null strings.
See also:
TERM, @()
2.11-0
1140 OpenQM
TESTLOCK()
Format
TESTLOCK(lock.num)
where
The TESTLOCK() function enables programs to test which user, if any, owns a specific task lock.
If the lock is currently owned by a QM user, the TESTLOCK() function returns their user number.
If the lock is available, zero is returned.
See also:
CLEAR.LOCKS, LIST.LOCKS, LOCK (Command), LOCK (QMBasic), UNLOCK
2.11-0
QMBasic 1141
TIME()
The TIME() function returns the current time as the number of seconds since midnight.
Format
TIME()
The TIME() function returns the number of seconds since midnight within the user's time zone as
an integer value. The OCONV() function can be used to format this in a number of ways for
display.
See the SYSTEM() function for a way to return the time of day to millisecond precision.
Example
This statement displays the time in the form hh:mm:ss using the 24 hour clock.
See also:
@TIME, DATE(), EPOCH()
2.11-0
1142 OpenQM
TIMEDATE()
The TIMEDATE() function returns the current time and date as a string.
Format
TIMEDATE()
The TIMEDATE() function returns the current time and date as a 20 character string in the form
where
Example
This statement displays the time and date at the top right of the display.
2.11-0
QMBasic 1143
TIMEOUT
Format
where
file.var is the file variable associated with a file opened using OPENSEQ.
interval is the timeout period in seconds. A negative value disables the timeout.
The TIMEOUT statement can be used when OPENSEQ is used to open a FIFO (named pipe). If
no input is received by READBLK or READSEQ in the given interval, the read terminates.
The TIMEOUT statement is ignored on Windows systems and for files that are not FIFOs.
2.11-0
1144 OpenQM
TOTAL()
The TOTAL() function accumulates totals for use with the CALC query processor keyword. It is
only available in dictionary I-type items.
Format
TOTAL(expr)
where
expr is an expression.
The TOTAL() function can be used in dictionary I-type expressions. While processing the detail
lines of a report, the TOTAL() function returns the value of the expression but also accumulates a
running total internally. When the query includes fields prefixed by the CALC keyword, the
expression is re-evaluated on the total lines of the report using the accumulated total in place of the
TOTAL() function.
2.11-0
QMBasic 1145
The TRANS() function returns a field or the entire record from a named data file. It is normally
only used in dictionary I-type items. The synonym XLATE() may be used.
The RTRANS() function is similar but has a slight difference described below for closer
compatibility with some other environments.
Format
where
file.name evaluates to the name of the file from which data is to be retrieved. The
optional DICT prefix specifies that the dictionary portion of the file is to be
used. Alternatively, the file.name expression may include the uppercase word
DICT before the actual file name and separated from it by a single space.
field identifies the field to be returned. A field value of zero returns the record id and
can be used to check the existence of a record. A field value of -1 indicates that
the entire record is to be returned. When used in a dictionary I-type expression
this can also be
A D or I-type field name as defined in the target file's dictionary. If the
field name does not follow the rules for construction of QMBasic variable
names, it must be quoted.
A field number
@RECORD or -1 to return the entire record.
An expression that evaluates to the field position. This must be enclosed in
brackets to avoid potential syntactic ambiguity.
action determines the action taken if the file cannot be opened, the record does not
exist, or the required field is null. This may evaluate to:
C Return the record id.
V Print a warning message and return a null value.
2.11-0
1146 OpenQM
The TRANS() function returns the specified data with any mark characters lowered by one level
(e.g. value marks become subvalue marks).
If record.id is multivalued, the TRANS() function extracts each requested record and returns a
multivalued result with the data from each record separated by a value mark.
The RTRANS() function is identical to TRANS() except that it does not lower the mark
characters. This makes it impossible to distinguish between the results of retrieving a multivalued
field from a single record and retrieving a single valued field from multiple records.
Examples
The above statement reads from the STOCK file a record (or list of records) whose id(s) can be
found in the PART.NO variable. The X error code causes the TRANS() function to return a null
value for any record that cannot be found.
Both of the above statements perform the same action. Either might be used, for example, to
retrieve a record named DISCOUNT from the dictionary of the ORDERS file.
2.11-0
QMBasic 1147
Format
TRANSACTION START
THEN {statements}
ELSE {statements}
TRANSACTION COMMIT
THEN {statements}
ELSE {statements}
TRANSACTION ABORT
A transaction is a group of updates that must either be performed in their entirety or not at all. The
TRANSACTION START statement starts a new transaction. All updates within the transaction
are cached and only applied to the database when the TRANSACTION COMMIT statement is
executed. Execution of the program then continues at the statement following the TRANSACTION
COMMIT.
The TRANSACTION ABORT statement terminates the transaction, discarding any cached
updates. Execution continues at the statement following the TRANSACTION ABORT.
The THEN and ELSE clauses are optional and are provided for compatibility with other products.
Within QM any errors occurring in a TRANSACTION START or TRANSACTION COMMIT
will result in run time errors.
Deletes and writes inside a transaction will fail unless the program holds an update lock on the
record or the file. All locks obtained inside the transaction are retained until the transaction
terminates and are then released. Locks already owned when the transaction begins will still be
present after the transaction terminates, even if the record is updated or deleted within the
transaction.
Closing a file inside a transaction appears to work in that the file variable is destroyed though the
actual close is deferred until the transaction terminates and any updates have been applied to the
file. Rolling back the transaction will not reinstate the file variable.
Updates to sequential records opened using OPENSEQ are not affected by transactions.
2.11-0
1148 OpenQM
PHANTOM
Example
TRANSACTION START
READU CUST1.REC FROM CUST.F, CUST1.ID ELSE
TRANSACTION ABORT
RETURN
END
CUST1.REC<C.BALANCE> -= TRANSFER.VALUE
WRITE CUST1.REC TO CUST.F, CUST1.ID
The above program fragment transfers money between two customer accounts. The updates are
only committed if the entire transaction is successful.
2.11-0
QMBasic 1149
TRIM()
Format
TRIM(string)
TRIM(string, character{, mode})
where
The first format of the TRIM() function removes all leading and trailing spaces from string and
replaces multiple embedded spaces by a single space.
The second form is more generalised and allows other characters to be removed.
Examples
X = " 1 2 3 "
Y = TRIM(X)
This program fragment removes excess spaces from string X setting Y to "1 2 3"
X = "ABRACADABRA"
Y = TRIM(X, 'A', 'A')
This program fragment removes all occurrence of the letter A from string X setting Y to
"BRCDBR"
2.11-0
1150 OpenQM
X = "ABRACADABRA"
Y = TRIM(X, 'A', 'B')
This program fragment removes leading and trailing occurrences of the letter A from string X
setting Y to "BARCADABR"
See also:
TRIMB(), TRIMF(), TRIMS()
2.11-0
QMBasic 1151
TRIMB()
The TRIMB() function removes excess spaces from the back of a string. The TRIMBS() function
is similar to TRIMB() but operates on each element of a dynamic array and returns an equivalently
structured dynamic array of trimmed strings.
Format
TRIMB(string)
where
Examples
A = " 1 2 3 "
B = TRIMB(A)
This program fragment removes excess spaces from string A setting B to " 1 2 3"
This program fragment is similar to the previous example but it shows the way in which
TRIMBS() operates on the two fields separately.
B becomes " 1 2 3FM 4 5 6"
See also:
TRIM(), TRIMF(), TRIMS()
2.11-0
1152 OpenQM
TRIMF()
The TRIMF() function removes excess spaces from the front of a string. The TRIMFS() function
is similar to TRIMF() but operates on each element of a dynamic array and returns an equivalently
structured dynamic array of trimmed strings.
Format
TRIMF(string)
where
Where string is delimited by mark characters, the TRIMF() function works on each delimited
substring as a separate item.
Examples
A = " 1 2 3 "
B = TRIMF(A)
This program fragment removes excess spaces from string A setting B to "1 2 3 "
This program fragment is similar to the previous example but it shows the way in which
TRIMFS() operates on the two fields separately.
B becomes "1 2 3 FM4 5 6 "
See also:
TRIM(), TRIMB(), TRIMS()
2.11-0
QMBasic 1153
TRIMS()
The TRIMS() function removes excess characters from strings in a dynamic array, operating on
each element in turn and and returning an equivalently structured dynamic array of trimmed strings.
Format
TRIMS(string)
TRIMS(string, character{, mode})
where
The first format of the TRIMS() function removes all leading and trailing spaces from each
dynamic array element of string and replaces multiple embedded spaces by a single space.
The second form is more generalised and allows other characters to be removed.
Example
See also:
TRIM(), TRIMB(), TRIMF()
2.11-0
1154 OpenQM
TTYGET()
The TTYGET() function returns a dynamic array containing the current terminal settings.
Format
TTYGET()
The TTYGET() function allows an application that alters terminal settings to read and save the
original terminal settings for restore on exit.
The dynamic array currently contains the fields listed below. Further fields may be added in future.
Field Content
1 Ctrl-C treated as the break key? (PTERM BREAK mode)
2 Case inversion on? (PTERM CASE mode)
3 Break character value (PTERM BREAK n)
4 Output newline sequence (PTERM NEWLINE)
5 Input return key code (PTERM RETURN)
See also:
PTERM, TTYSET
2.11-0
QMBasic 1155
TTYSET
Format
TTYSET var
where
The TTYSET statement allows an application that alters terminal settings to restore previously
saved settings on exit.
The format of the dynamic array var is described under the TTYGET() function. Because this
dynamic array may be extended in future releases, programs must ensure that any additional fields
returned by TTYGET() are restored on use of TTYSET().
See also:
PTERM, TTYGET()
2.11-0
1156 OpenQM
UNASSIGNED()
Format
UNASSIGNED(var)
where
All QMBasic variables except those in common blocks are initially unassigned. Any attempt to use
the contents of the variable in an expression would cause a run time error until such time as a value
has been stored in it. The UNASSIGNED() function allows a program to test whether a variable is
unassigned, returning true (1) if it is unassigned or (0) if it is assigned.
Example
This program fragment validates an account code. The use of the UNASSIGNED() function
prevents an abort if the variable has not been assigned.
See also:
ASSIGNED()
2.11-0
QMBasic 1157
UNLOCK
Format
where
lock.num evaluates to the lock number in the range 0 to 63. If omitted or specified as
a negative value, all task locks owned by the process will be released.
The UNLOCK statement releases the specified task lock if it has previously been acquired using
the LOCK statement. There is no means for a program to determine which task locks are held by
the user except by attempting to lock each in turn and checking the STATUS() value. Beware that
unlike read, update and file locks, task locks are only automatically released on leaving QM, not on
return to the command prompt.
When lock.num is omitted or evaluates to a negative number, all task locks owned by the process
are released. This action is always successful, even if no locks are owned.
The THEN clause is executed if the lock is held by this process. The value of the STATUS()
function will be zero.
The ELSE clause is executed if the lock is not owned by this process. The value of the STATUS()
function will be ER$LCK if the lock is owned by another process or ER$NLK if it is not owned by
any process.
Example
LOCK 7 THEN
...processing statements...
UNLOCK 7
END
ELSE ABORT "Cannot obtain task lock"
This program fragment obtains task lock 7, performs some critical processing and then releases the
lock.
See also:
CLEAR.LOCKS, LIST.LOCKS, LOCK (Command), LOCK (QMBasic), TESTLOCK()
2.11-0
1158 OpenQM
UNTIL
The UNTIL statement is used in conjunction with the FOR / NEXT or LOOP / REPEAT
constructs to determine whether execution of the loop should continue.
Format
UNTIL expr
where
Example
FOR I = 1 TO 20
UNTIL A(I) < 0
DISPLAY A(I)
NEXT I
This program fragment displays elements of matrix A. The loop terminates if an element is found
with a negative value.
See also:
EXIT, WHILE
2.11-0
QMBasic 1159
UPCASE()
The UPCASE() function returns a string with all letters converted to upper case.
Format
UPCASE(string)
where
The UPCASE() function returns the value of string with all letters converted to upper case. If
string is a variable rather than an expression, the value of the variable is not affected.
Example
See also:
DOWNCASE()
2.11-0
1160 OpenQM
VOCPATH()
The VOCPATH() function returns the pathname for a file referenced via the VOC.
Format
VOCPATH(filename {, dict.flag})
where
filename is the file name for which the pathname is to be returned. The extended file
name syntaxes are allowed.
dict.flag evaluates to true to return the dictionary pathname, false to return the data
pathname. If omitted, the data pathname is returned.
The VOCPATH() function processes the VOC file to return the pathname for the supplied
filename. If filename corresponds to a Q-pointer, the function resolves the remote reference.
The optional dict.flag argument allows a program to specify whether the returned pathname should
be that of the data or dictionary components of the file. The function also recognises use of a prefix
of DICT and a single space on the front of the filename, returning the dictionary pathname
regardless of the value of dict.flag.
If the function is successful, the return value is the file pathname and the STATUS() function will
return zero. If the filename cannot be resolved to a pathname, the return value will be a null string
and the STATUS() function will return an explanatory error number.
Examples
DISPLAY VOCPATH('SALES')
This statement would display the pathname of the data part of the SALES file.
Adding the dict.flag as true would display the pathname of the dictionary part of the SALES file.
Use of the DICT prefix would also display the pathname of the dictionary part of the SALES file.
DISPLAY VOCPATH('CUSTOMERS,NORTH')
Used with a multi-file reference, the pathname returned wil be that of the NORTH subfile of the
CUSTOMERS file.
2.11-0
QMBasic 1161
DISPLAY VOCPATH('HR:PAYROLL')
This example uses an extended file name syntax to resolve the pathname of the PAYROLL file in
the HR account.
2.11-0
1162 OpenQM
VOID
Format
VOID expr
where
expr is an expression.
The VOID statement evaluates the supplied expression and discards the result. It is intended for use
when calling functions for which the returned value is not used by the program. Use of VOID
removes the need for a dummy variable and possible compiler warning messages regarding a
variable that is set but never used.
Example
VOID KEYIN()
The above statement waits for the user to press a key but discards the input data.
2.11-0
QMBasic 1163
VSLICE()
The VSLICE() function returns a string formed by extracting a given value or subvalue position
from a dynamic array.
Format
VSLICE(string, vpos)
VSLICE(string, vpos, svpos)
where
The first form of the VSLICE() function processes string to build a new dynamic array containing
only the specified value position from each field. Subvalues are returned as part of each value in the
result string.
The second form processes string to build a new dynamic array containing only the specified sub
value position from each field. If vpos is less than one, the subvalue is extracted from all value
positions and value marks are included in the returned string to match the structure of the original
data. If vpos is one or greater, the subvalue is extracted only from the specified value position and
no value marks are included in the result.
If vpos and svpos are both less than one, the VSLICE() function returns the source string.
Examples
VSLICE(S, 0) 1FM2VM3SM4VM5FM6VM7SM8VM9
VSLICE(S, 1) 1FM2FM6
VSLICE(S, 2) FM3SM4FM7SM8
VSLICE(S, 3)
VSLICE(S, 0, 1) 1FM2VM3VM5FM6VM7VM9
VSLICE(S, 0, 2) FM4FM8
VSLICE(S, 0, 3)
VSLICE(S, 1, 1) 1FM2FM6
VSLICE(S, 1, 2)
VSLICE(S, 2, 1) 3 7
FM FM
VSLICE(S, 2, 2) 4 8
FM FM
VSLICE(S, 2, 3)
2.11-0
1164 OpenQM
VSLICE(S, 3, 1) 5 9
FM FM
VSLICE(S, 3, 2)
2.11-0
QMBasic 1165
WAIT.FILE.EVENT
The WAIT.FILE.EVENT() function waits for a file monitoring event (Windows only).
Format
WAIT.FILE.EVENT(event, timeout)
where
timeout is the maximum period in seconds to wait. A zero or negative value causes an
infinite wait.
The WAIT.FILE.EVENT() function allows a program to wait for a change within the Windows
file system. It can be used, for example, to wait until a new file is created within a directory without
needing to write a loop that periodically compares the directory content with a previously recorded
list of items.
The event(s) to be monitored are established using the FILE.EVENT() function. Where only a
single event is to be monitored, the value returned by this function can be stored in a simple scalar
variable. If multiple events are to be monitored, the returned values should be stored in a
dimensioned array. The WAIT.FILE.EVENT() function will ignore any elements of the array that
are not file monitoring event values. See FILE.EVENT() for a list of the events that can be
trapped.
The WAIT.FILE.EVENT() function uses an efficient event waiting mechanism within the
Windows operating system. When a monitored event occurs, the function returns the index of the
associated element of the event array or, if this was a scalar variable, 1. If the function returns
because the timeout has expired, it returns zero.
When using an array of events, an event can be removed from the list by overwriting the relevant
element of the event array with any other type of data. Because use of a file event monitoring
variable in any other way returns a non-negative number, setting the element to a negative value or
a null string provides a reliable way to recognise unused entries. If the array contains no file event
monitoring variables, the WAIT.FILE.EVENT() function simply sleeps for the given timeout
period.
Beware that when the SAFEDIR configuration parameter is set to 1, if this function is used to
monitor a directory into which items are written using QM, two file notification events will occur
for each write.
Examples
2.11-0
1166 OpenQM
END ELSE
...Periodic actions...
END
REPEAT
The above program fragment creates a file monitoring event to trap changes to the C:\IMPORT
directory as a result of creating, deleting or renaming a file. The WAIT.FILE.EVENT() function
waits for an event to occur and then executes some processing code before waiting for the next
event. In this example, the wait includes a ten second timeout to allow the program to perform some
other periodic tasks.
DIM EVT(3)
EVT(1) = FILE.EVENT("C:\IMPORT", FE$FILE.NAME + FE$SUBTREE)
EVT(2) = FILE.EVENT("C:\EXPORT", FE$FILE.NAME + FE$SUBTREE)
LOOP
IF WAIT.FILE.EVENT(EVT, 0) > 0 THEN
...Processing...
END
REPEAT
In this example, two directories and their sub-directories are monitored. Note that the EVT array
has been dimensioned as three elements but only two are used. The WAIT.FILE.EVENT()
function will ignore the unused element. Monitoring of either directory could be temporarily
disabled in the processing code by setting the EVT array element to -1. Similarly, the processing
code could add a new monitored event in EVT(3).
2.11-0
QMBasic 1167
WAKE
The WAKE statement awakens another process that has executed a PAUSE. This function is not
available on the PDA version of QM.
Format
WAKE user.no
where
The WAKE statement resumes execution of another process that has executed a PAUSE
statement.
If the WAKE is executed before the other process attempts to pause, the program is not suspended.
Multiple wake events occurring in this way will only awaken the target process once.
The WAKE statement attempts to use an inter-process signalling mechanism to resume execution
of the other process. Due to operating system limitations, this is usually only possible if both
processes are running with the same user id. If this is not the case, the target process may take up to
about a second to restart.
2.11-0
1168 OpenQM
WEOFSEQ
The WEOFSEQ statement truncates a record open for sequential access at the current position.
Format
where
file.var is the file variable associated with the record by a previous OPENSEQ
statement.
The WEOFSEQ statement truncates the record at the current position. Performed immediately
after the OPENSEQ, this will remove all data from the record. Performed after one or more
READSEQ operations have been performed, all subsequent data is cleared from the record.
The ON ERROR clause is executed if a fatal error occurs. The STATUS() function can be used
to determine the cause of the error. If no ON ERROR clause is present, a fatal error causes an
abort.
Example
This program fragment opens the record STOCKS for sequential access. If it already exists, the
THEN clause of the OPENSEQ is taken and the existing data is removed using WEOFSEQ.
See also:
CLOSESEQ, CREATE, NOBUF, OPENSEQ, READBLK, READCSV, READSEQ,
WRITEBLK, WRITECSV, WRITESEQ, WRITESEQF
2.11-0
QMBasic 1169
WHILE
The WHILE statement is used in conjunction with the FOR / NEXT or LOOP / REPEAT
constructs to determine whether execution of the loop should continue.
Format
WHILE expr
where
Example
LOOP
REMOVE ITEM FROM LIST SETTING DELIMITER
DISPLAY ITEM
WHILE DELIMITER
REPEAT
This program fragment displays items removed from dynamic array LIST. The loop is terminated
when the value of DELIMITER becomes zero.
See also:
EXIT, UNTIL
2.11-0
1170 OpenQM
WRITE
The WRITE statement writes a record to a previously opened file. The WRITEU statement is
identical but preserves any lock on the record.
Format
where
The contents of var are written to the file. Any existing record of the same id is replaced by this
action.
When writing to a directory file, field marks in the data to be written are replaced by newlines. This
action may be suppressed by using the MARK.MAPPING statement after opening the file.
The WRITE statement releases any read or update lock on this record. The WRITEU statement
preserves the lock. Within a transaction, the lock is retained until the transaction terminates and
then released regardless of which statement is used. Attempting to write a record in a transaction
will fail if the process does not hold an update lock on the record or the file.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
When writing a new record to a directory file on a Linux or Unix system, the operating system level
file that represents the QM record is created using the current umask value. For sessions that
connect directly to QM rather than from the operating system shell (direct telnet and QMClient), the
umask value is specified by the UMASK configuration parameter or, if this parameter is not
present, a default of 002. This behaviour can be modified by executing a UMASK command within
the session.
Example
This statement writes the content of ITEM to a record with the id in ITEM.ID on the file previously
opened to file variable STOCK.
2.11-0
QMBasic 1171
WRITE.SOCKET()
Format
where
flags is a value determining the mode of operation of the socket for this write, formed by
adding the values of tokens defined in the SYSCOM KEYS.H record. The flags
available in this release are:
SKT$BLOCKING Sets the default mode of data transfer as blocking.
SKT$NON.BLOCKING Sets the default mode of data transfer as
non-blocking.
If neither blocking flag is given, the blocking mode set when the socket was opened
is used.
The WRITE.SOCKET() function writes the given data and returns the number of bytes written. If
non-blocking mode is used or a timeout occurs, this byte count may be less than the length of the
data. The remaining data can be written with a subsequent call to WRITE.SOCKET() when
buffer space becomes available.
The STATUS() function returns zero if the action is successful, or a non-zero error code if an error
occurs. A timeout will return an error code of ER$TIMEOUT as defined in the SYSCOM ERR.H
record.
Example
This program fragment opens a connection to port 3000 of IP address 193.118.13.14, sends the
data in DATA and then closes the socket.
See also:
Using Socket Connections, ACCEPT.SOCKET.CONNECTION, CLOSE.SOCKET,
CREATE.SERVER.SOCKET(), OPEN.SOCKET(), READ.SOCKET(),
2.11-0
1172 OpenQM
2.11-0
QMBasic 1173
WRITEBLK
The WRITEBLK statement writes data at the current file position in a record previously opened
using OPENSEQ.
Format
where
The ELSE clause is executed if the WRITEBLK fails. The STATUS() function will indicate the
cause of the error.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
Example
This program fragment writes data to a file previously opened to file variable SEQ.F.
See also:
CLOSESEQ, CREATE, NOBUF, OPENSEQ, READBLK, READCSV, READSEQ,
WRITECSV, WEOFSEQ, WRITESEQ, WRITESEQF
2.11-0
1174 OpenQM
WRITECSV
The WRITECSV statement writes data at the current file position in a record previously opened
using OPENSEQ. The data to be written is assembled from one or more variables and written in
CSV format.
Format
where
var1, var2, ... are the items to be written to the file. If any of the variables contains field
marks, each field is treated as a separate item in the resultant CSV data.
The data in the named variables is assembled as a CSV format text string which is then written to
the file with a newline appended. The THEN clause is executed if the WRITECSV is successful.
The ELSE clause is executed if the WRITECSV fails. The STATUS() function will indicate the
cause of the error.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
CSV Format
CSV format is used by many applications. QM adheres to the CSV standard (RFC 4180).
Items are enclosed in double quotes if they contain commas or double quotes. Embedded double
quotes are replaced by a pair of double quotes.
Examples
This program fragment writes the contents of the PROD.NO and QTY variables as a CSV item to a
file previously opened to file variable SEQ.F.
2.11-0
QMBasic 1175
This program fragment writes the contents of fields 1 to 3 of S as CSV data to a file previously
opened to file variable SEQ.F.
If dynamic array S in the previous example had only three fields, this program fragment writes
exactly the same data, treating each field as a separate CSV item.
See also:
CLOSESEQ, CREATE, CSVDQ(), NOBUF, OPENSEQ, READBLK, READCSV,
READSEQ, WEOFSEQ, WRITESEQ, WRITEBLK, WRITESEQF
2.11-0
1176 OpenQM
WRITESEQ
The WRITESEQ statement writes a string array to a directory file record previously opened for
sequential access. WRITESEQF is identical except that it force writes the data to disk.
Format
where
file.var is the file variable associated with the record by a previous OPENSEQ
statement.
The keyword TO may be replaced by ON. At least one of the THEN and ELSE clauses must be
present.
The data in var is written to the record at the current file position, overwriting any data already
present. The THEN clause is executed if the write is successful.
If a fatal error occurs, the ON ERROR clause is executed. The STATUS() function can be used
to establish the cause of the error. If no ON ERROR clause is present, a fatal error causes an
abort.
The FILEINFO() function can be used with key FL$LINE to determine the field number that will
be written by the next WRITESEQ. This information is not valid if the SEEK, READBLK or
WRITEBLK statements have been used.
The WRITESEQF statement is identical to WRITESEQ except that execution of the next
QMBasic statement does not occur until the data has been written to disk. With WRITESEQ, the
data may still be in internal buffers.
Example
This statement writes the data in REC to the record open for sequential access via the
STOCK.LIST file variable.
See also:
CLOSESEQ, CREATE, NOBUF, OPENSEQ, READBLK, READCSV, READSEQ,
2.11-0
QMBasic 1177
2.11-0
1178 OpenQM
WRITEV
The WRITEV statement writes a specific field to a record of a previously opened file. The
WRITEVU statement is identical but preserves any lock on the record.
Format
where
The contents of var are written to field field.expr of record record.id of the file. If the record does
not already exist, it will be created by this operation.. The WRITEV statement releases any read or
update lock on this record. The WRITEVU statement preserves the lock. Within a transaction, the
lock is retained until the transaction terminates and then released regardless of which statement is
used. Attempting to write a record in a transaction will fail if the process does not hold an update
lock on the record or the file.
A field.expr value of zero is treated as a reference to field one. A negative field number causes the
var string to be appended as a new field at the end of the record.
The ON ERROR clause is executed for serious fault conditions such as errors in a file's internal
control structures. The STATUS() function will return an error number. If no ON ERROR clause
is present, an abort would occur.
Example
This program fragment writes the value of ITEM to field 3 of record ITEM.ID in a file previously
opened to file variable STOCK.
See also:
READV
2.11-0
QMBasic 1179
XTD()
Format
XTD(expr)
where
The XTD() function converts the supplied expr hexadecimal string to a number. If expr contains
any characters other than 0-9 or A-F (upper or lower case) or is a null string, the function returns
the original value of expr.
See also:
DTX()
2.11-0
1180 OpenQM
The table below shows the keys that produce each character value on Windows systems using
QMConsole, on all systems using QMTerm, or when using KEYCODE() to decode key sequences.
0 1 2 3 4 5 6 7 8 9
00x Ctrl-A Ctrl-B Ctrl-C Ctrl-D Ctrl-E Ctrl-F Ctrl-G Ctrl-H Ctrl-I
Bsp Tab
01x Ctrl-J Ctrl-K Ctrl-L Ctrl-M Ctrl-N Ctrl-O Ctrl-P Ctrl-Q Ctrl-R Ctrl-S
Ctrl-rtn Return
02x Ctrl-T Ctrl-U Ctrl-V Ctrl-W Ctrl-X Ctrl-Y Ctrl-Z Esc Ctrl-}
04x ( ) * + , - . / 0 1
05x 2 3 4 5 6 7 8 9 : ;
07x F G H I J K L M N O
08x P Q R S T U V W X Y
09x Z [ \ ] ^ _ ` a b c
10x d e f g h i j k l m
11x n o p q r s t u v w
12x x y z | } ~ Ctrl-Bs F1 F2
p
14x Ctrl-F1 Ctrl-F2 Ctrl-F3 Ctrl-F4 Ctrl-F5 Ctrl-F6 Ctrl-F7 Ctrl-F8 Ctrl-F9 Ctrl-F1
0
15x Ctrl-F1 Ctrl-F1 Alt-F1 Alt-F2 Alt-F3 Alt-F4 Alt-F5 Alt-F6 Alt-F7 Alt-F8
1 2
16x Alt-F9 Alt-F10 Alt-F11 Alt-F12 Sh-F1 Sh-F2 Sh-F3 Sh-F4 Sh-F5 Sh-F6
17x Sh-F7 Sh-F8 Sh-F9 Sh-F10 Sh-F11 Sh-F12 CSA-F1 CSA-F2 CSA-F3 CSA-F4
18x
19x
21x End Insert Delete Ctrl-Ta C-PgUp C-PgDn C-Home C-End User0 User1
b
2.11-0
QMBasic 1181
23x
24x
25x
Character value tokens are defined in the KEYIN.H record of the SYSCOM file. Codes User0 to
User9 are only returned by the KEYCODE() function.
2.11-0
1182 OpenQM
6.7 @-Variables
QMBasic provides a number of special variables and constants with names prefixed by the @
character. Some @-variables can be updated by QMBasic programs though most are read-only.
Many of the @-variables are also available for use in I-type definitions or within paragraphs. A
complete list of @-variables appears below.
Compile-time Constants
These constants are available in QMBasic programs and I-type definitions to improve readability.
@FALSE 0
@TRUE 1
Variables
@ABORT.CODE A value indicating the cause of execution of the last abort. This
variable is particularly useful within ON.ABORT paragraphs or
programs invoked from them. Values are:
0 No abort has occurred
1 A QMBasic ABORT statement or the ABORT command has
been used
2 The Abort option has been selected after the break key was
pressed
3 An internal error has been detected
The value of @ABORT.CODE is initially zero and is reset to zero
only by the EXECUTE statement
@ABORT.MESSAGE Contains the text of any message associated with the most recent
abort event.
@ACCOUNT Synonym for @WHO.
@ANS Contains the result of the last virtual attribute expression evaluated.
This variable can be updated, usually only in C-type dictionary
2.11-0
QMBasic 1183
items.
@COMMAND The last command entered at the command prompt or initiated using
the QMBasic EXECUTE statement. This variable is stacked across
an EXECUTE and reverts to its previous value on completion of the
executed command. If multiple commands are executed in a single
EXECUTE statement, the @COMMAND variable will be updated
at each command.
@COMMAND.STACK This variable holds the history of commands executed at the
command prompt as a field mark delimited dynamic array. The most
recent command is field 1.
@CONV Extended information for user defined conversion codes.
@CRTHIGH Contains the number of lines per page of the display.
@CRTWIDE Contains the width of the display.
@DATA Data from REFORMAT command.
@DATA.PENDING Contains the data on the DATA queue, if any. Each item, including
the last, is followed by an item mark character.
@DATE The internal format date value (days since 31 December 1967) at
which the last command started execution. Any changes made to this
variable will also be reflected in the values of the @DAY,
@MONTH, @YEAR and @YEAR4 variables described below.
@DAY The day of the month at which the last command started execution as
a two digit value. Changing @DATE will also change this value.
@DICTRECS The query processor sets this variable to an item mark delimited copy
of the dictionary records that were used to construct the display
clause elements of the query (including any item with the
BREAK.SUP prefix). For dictionary records that contain object code
(C/I types and A/S types with correlatives), the object code is
omitted. This variable can be of use in post-processing query
processor output.
@DS Contains the operating system specific directory delimiter character, \
on Windows, / on other platforms.
@FILE.NAME The name of the file referenced in the most recent query processor
command. This variable may be updated by a QMBasic program.
@FILENAME Synonym for @FILE.NAME
@FMT The query processor sets this variable to a field mark delimited list of
the width and justification codes for each item in the display clause
of the query (including any item with the BREAK.SUP prefix). This
variable can be of use in post-processing query processor output.
@GID User's group id number for all platforms except Windows. Same as
SYSTEM(29).
@HOSTNAME The name of the server computer system. Same as SYSTEM(1015).
@ID The record id of the record being processed by a query processor
command or an I-type function. This variable may be updated by a
QMBasic program.
@IP.ADDR The IP address associated with a network user. Same as
2.11-0
1184 OpenQM
SYSTEM(42).
@ITYPE.MODE This variable can be used to determine the mode of execution of an
I-type. It has three possible values:
0 Normal
1 Evaluation of the old index value when updating or deleting a
record from a file with an alternate key index.
2 Evaluation of the new index value when updating or adding a
record to a file with an alternate key index.
@LEVEL The current command processor depth (EXECUTE level). The initial
command processor is level one, each EXECUTE level increments
this by one, decrementing on return from that level.
@LOGNAME User's login name. On Windows, this is converted to uppercase.
@LPTRHIGH Contains the number of lines per page of print unit zero. Depending
on the current setting of the PRINTER flag, this may refer to the
display or to the printer.
@LPTRWIDE Contains the width of print unit zero. Depending on the current
setting of the PRINTER flag, this may refer to the display or to the
printer.
@MONTH The month in which the last command started execution as a two
digit value. Changing @DATE will also change this value.
@NB Break number level. Set to zero on detail lines and one upwards on
break lines. A value of 255 represents the grand total line.
@NI Item counter. Used in I-types, this holds the number of records
retrieved by the query processor command.
@OPTION Contains a copy of field 4 of the V-type VOC entry when a verb
starts execution. Use of this variable enables related commands to be
handled by a single program.
@PARASENTENCE The sentence that invoked the most recent paragraph or sentence. On
entering a command at the keyboard, this variable will be set to the
same value as @COMMAND. If the command is a paragraph or
sentence which invokes a further paragraph or sentence, the value
will be updated to be the command which started this new paragraph
or sentence.
@PATH The pathname of the current account.
@PIB The PROC primary input buffer.
@POB The PROC primary output buffer.
@QM.GROUP The QM user group to which the user running this session belongs, a
null string if none.
@QMSYS The pathname of the system account.
@RECORD The data of the record being processed by an I-type function. This
variable may be updated by a QMBasic program.
@SELECTED Contains the total record count for the most recent SELECT or
SSELECT operation. Note that a QMBasic SELECT operation
against a dynamic file processes the file one group at a time and this
variable will show the record count for the group being processed.
2.11-0
QMBasic 1185
2.11-0
1186 OpenQM
2.11-0
QMBasic 1187
QMBasic includes a set of standard subroutines that may be called from user programs. These all
have an exclamation mark prefix to the subroutine name.
2.11-0
1188 OpenQM
!ABSPATH()
The !ABSPATH() subroutine forms an absolute pathname from a directory and file path.
Format
where
The !ABSPATH() subroutine uses the supplied directory and file path to construct an absolute
pathname.
If file commences with @QMSYS, path is returned as the file value with the @QMSYS token
replaced by the QMSYS account pathname.
Otherwise, path is formed by concatenating dir and file, inserting a directory separator character if
required.
Examples
2.11-0
QMBasic 1189
!ATVAR()
Format
where
name is the name of the @-variable to be retrieved. The leading @ character may
optionally be omitted. Variable names are case insensitive.
The !ATVAR() subroutine returns the value of the named @-variable. Although intended for
accessing user defined variables, it can also return the standard variables.
The !ATVAR() function sets the value returned by the STATUS() function. This will be zero if the
specified variable is found, non-zero if it is not recognised.
Example
or
See the !SETVAR() subroutine for a way to set the value of an updateable @-variable.
2.11-0
1190 OpenQM
!ERRTEXT()
Format
where
The !ERRTEXT() subroutine can be used to retrieve a text description of a QM error number for
display to a user or entry into a log file.
Where relevant, the associated operating system error number will be inserted into the text. For this
to be correct, the !ERRTEXT() subroutine must be called before any actions are performed that
might lose this value (e.g. file operations).
If errno is not recognised, the subroutine returns errno as the text description.
Examples
2.11-0
QMBasic 1191
!GETPU()
Format
where
key identifies the parameter to retrieved. This is as for the GETPU() function.
status is the return status value. Zero if the action is successful, a non-zero error code if
the action fails.
The !GETPU() subroutine retrieves the print unit characteristic specified by key, storing it in value.
It is closely related to the GETPU() function.
Example
The above statement gets the mode of print unit 3, storing it in MODE.
2.11-0
1192 OpenQM
!LISTU()
The !LISTU() subroutine returns the raw data used by the LISTU command.
Format
CALL !LISTU(dyn.array)
where
The !LISTU() subroutine allows a developer to construct their own variant of LISTU, perhaps as
a screen within an application.
The data returned in dyn.array is a dynamic array where each field is multivalued with a value for
each active QM process. The fields are:
1 User number. This will be in ascending order.
2 Operating system level process id. This can be negative on some Windows platforms.
3 Process type (I = interactive, P = phantom, C = QMClient, N = QMNet).
4 IP address for a direct network connection to QM. Entry from the operating system
command prompt will not set this.
5 Parent user id for a phantom process. This is zero if the process is not a phantom or if the
parent process has logged out.
6 User name
7 Terminal device name (where relevant)
8 Login time as date * 86400 + time in the local time zone of the user executing the
subroutine.
9 Account name
Example
CALL !LISTU(USERS)
NUM.USERS = DCOUNT(USERS<1>, @VM)
FOR I = 1 TO NUM.USERS
IF USERS<3,I> = 'I' THEN
DISPLAY FMT(USERS<1,I>, '3R') : ' ' : USERS<6,I>
END
NEXT I
The above program fragment displays a list of the user numbers and user login names of all
interactive processes.
2.11-0
QMBasic 1193
!PARSER()
Format
where
string is the returned token string. For key values 1 and 3, this is the string passed into the
parser.
keyword is the returned token keyword number as defined in the VOC and in the SYSCOM
PARSER.H record. This is negative if the token is not a VOC keyword. This
argument is ignored for key values 1 and 3.
voc.rec is an optional argument, returned as the VOC record when string corresponds to a
VOC key.
The !PARSER() subroutine can be used to parse the elements of a command line.
Example
2.11-0
1194 OpenQM
2.11-0
QMBasic 1195
!PATHTKN()
The !PATHTKN() subroutine processes special tokens in a VOC or ACCOUNTS file pathname.
Format
where
outpath is the returned processed pathname. This may be the same variable as inpath.
Pathnames recorded in the VOC or the QMSYS ACCOUNTS file may include special tokens that
represent variable components. The !PATHTKN() subroutine processes a pathname, substituting
the expansions for these tokens.
The !PATHTKN() subroutine is also defined as a function in the SYSCOM KEYS.H include
record:
outpath = PARSE.PATHNAME.TOKENS(inpath)
Examples
The entry for the QMSYS account in the ACCOUNTS register is simply
@QMSYS
This ensures that the entire system can be moved without needing to update the QMSYS account
location.
When using QM installed on a USB flash drive on Windows, creating an account on the USB
device sets the ACCOUNTS register entry as
@DRIVE:pathname
The account is therefore accessible even if the flash drive takes on a different drive letter in later
use.
2.11-0
1196 OpenQM
!PCL()
The !PCL () subroutine constructs PCL control strings for various useful operations. It is intended
for use as a series of functions defined in the SYSCOM PCL.H include record.
Format
where
key identifies the operation to be performed. See the PCL.H include record for the
relationship between the key values and the functions described below.
arg1,... are arguments defining the exact action. The !PCL() subroutine takes a variable
length argument list.
The !PCL() subroutine should be called using the function interfaces defined below. The returned
string can be sent to a PCL compatible printer to perform the requested action.
All page positioning values are measured using the PCL coordinate grid where (0,0) is at the top
left of the page and the grid scale is 300 per inch. There is a useful grid template printing program,
PCL.GRID, in the BP file of the QMSYS account.
Note: The quality of PCL implementations varies widely and these functions may not give the
expected results on some printers. In particular, setting some font metrics may cause inconsistent
character placement. It is the application developer's responsibility to ensure that the printed results
are acceptable.
The following functions are defined in the SYSCOM PCL.H include record. Each returns the
relevant control string to perform its action.
PCL.COPIES(copies)
Sets the number of copies to be printed.
PCL.CURSOR(x, y)
Sets the current cursor position to the given coordinates. Subsequent text output will occur at
this point.
PCL.DUPLEX(mode)
Sets duplex mode. 0 = off, 1 = long edge binding, 2 = short edge binding.
PCL.FONT(font)
Sets the font details for text output. The font argument consists of comma separated list of case
insensitive items chosen from the following list. Features that are not specified retain their
2.11-0
QMBasic 1197
PCL.LEFT.MARGIN(col)
Sets the left margin at column col.
PCL.ORIENTATION(layout)
Specifies the page format. The layout argument is a string and may be PORTRAIT or
LANDSCAPE.
PCL.PAPER.SIZE(size)
Specifies the page size. The size argument is a string chosen from A3, A4, B5, C5, COM10,
DL, EXECUTIVE, LEDGER, LEGAL, LETTER and MONARCH.
PCL.RESET()
Resets the printer.
PCL.RESTORE.CURSOR()
Restores a previously saved cursor position.
PCL.SAVE.CURSOR()
Saves the current cursor position. Note that there is a limit to the number of nested cursor save
operations.
The source version of the !PCL() subroutine is in the BP file of the QMSYS account so that users
can add further options. A copy of any changes should be retained as this item will be replaced
when an upgrade is installed.
Example
$INCLUDE PCL.H
PRINTER ON
PRINT PCL.RESET() :
PRINT PCL.FONT('Courier, Pitch 10, Regular') :
2.11-0
1198 OpenQM
PRINT PCL.BOX(300,300,300,100,2,15) :
PRINT PCL.CURSOR(350, 380) : 'Hello' :
The above program prints the word Hello in a box with rounded corners.
2.11-0
QMBasic 1199
!PHLOG()
The !PHLOG() subroutine returns the name of the log record for a running phantom process.
Format
where
A phantom process creates a log record in the $COMO file containing any output that would have
gone to the screen if the command had been run in an interactive session. The name of this log
record is PHn_date_time where n is the QM user number of the phantom process and date_time is
the date/time at which the phantom started in the form ddmmyy_hhmmss.
The !PHLOG() subroutine allows a process to determine the name of the log record for a phantom
so long as the phantom is still active.
If the phantom is started using the NO.LOG option of the PHANTOM command, name is returned
as a null string.
Because the !PHLOG() subroutine returns the log name via its first argument, it can be declared as
a function as in the example below.
Example
Note how the SETTING clause of the EXECUTE statement is used to capture the
@SYSTEM.RETURN.CODE value from the PHANTOM command. Simply using
@SYSTEM.RETURN.CODE as the argument to PHLOG() would not work as this would be the
return status of the EXECUTE operation, not the executed command.
See also:
CHILD(), LIST.PHANTOMS, PHANTOM, STATUS
2.11-0
1200 OpenQM
!PICK()
The !PICK() subroutine displays a list of entries from which a user may select one.
Format
where
item is the returned item. This will be returned as a null string if no item is selected
top.line is the line number of the topmost display line to be used. The pick list display uses
from this line to the bottom of the screen.
item.list is a field mark delimited list of items to display. Long items will be truncated to fit
a single line.
title is a short text description of the items being processed. This is displayed alongside
the item count at the bottom of the screen. This may be a null string to omit the
title.
pos enables programs to return to a pick list at the position of a previously displayed
item. On initial entry, this should be zero or a null string. If a variable name is used
for pos, this variable will be updated to contain position information related to the
list. A subsequent call to !PICK() using this updated value will display the screen
as it was when the previous item was selected. Programs should not make any
assumption about the format of this variable as it may change between QM
releases.
The !PICK() subroutine displays a list of items as specified in list. The user can move through this
list using the following keys:
Example
2.11-0
QMBasic 1201
...processing...
END
END
The above example shows a list of records in the ACCOUNTS file and processes the selected
record.
See also:
!PICKLIST()
2.11-0
1202 OpenQM
!PICKLIST()
The !PICKLIST() subroutine displays a list of entries from which a user may select one.
Format
where
value is the returned item. This will be returned as a null string if no option is selected.
list is a field mark delimited list of items to process. The display can show multiple
items for each entry (e.g. a code and an expanded text) in which case each field is
divided into values corresponding to the columns to be shown. The number of
displayed columns is determined by the number of values in the first field.
return.col identifies which column (from 1) of the selected item is to be returned as value.
index.col is the column number (from 1) for shortcut entry. The list must be sorted into
ascending order of this column. A value of zero implies that no shortcut is to be
allowed.
The !PICKLIST() subroutine displays a box containing the items to from list. The user can use the
up and down cursor keys to move through this list. If the list is longer than can be displayed, the
subroutine will scroll the displayed items. The page up and down key can be used to move rapidly
through the entries. The return key selects the current item, returning it in the value argument.
If index.col is non-zero, the user may enter the initial characters of an entry in the chosen column to
position directly to the first entry starting with the entered prefix. The characters entered are
displayed in the lower border of the box.
When used on a QMTerm or Windows QMConsole session or on a terminal that supports screen
region save and restore, the area of the screen overwritten by the pick list box is automatically
saved and restored. Programs using other terminal systems will need to arrange their own system to
recover the screen.
Example
LIST = 'Blue':@FM:'Green':@FM:'Red'
CALL !PICKLIST(ITEM, LIST, 1, 1)
DISPLAY 'Selected item was ' : ITEM
See also:
!PICK()
2.11-0
QMBasic 1203
!QMCLIENT
The !QMCLIENT class module provides an object oriented interface to the QMClient API for use
within QMBasic programs.
The table below lists the QMClient API calls and their actions available with this object.
2.11-0
1204 OpenQM
!SCREEN()
The !SCREEN() subroutine performs screen based input using a screen definition created using
the SCRB command.
Format
where
step holds the step number at which screen execution is to commence. If this is a
variable, it will be updated on exit to contain the step at which execution ended.
The !SCREEN() subroutine executes the screen starting at step except for the special step values
described below.
step Action
0 Clear the screen and paint text and data from all steps except those items with X in
their mode value.
-1 Paint text and data from all steps except those items with X in their mode value
without clearing the screen.
Example
2.11-0
QMBasic 1205
The above code fragment reads a screen definition and executes the screen driver to process the data
record using this definition.
2.11-0
1206 OpenQM
!SETPU()
Format
where
key identifies the parameter to set. This is as for the SETPU statement.
status is the return status value. Zero if the action is successful, a non-zero error code if
the action fails.
The !SETPU() subroutine sets the print unit characteristic specified by key to the given value. It is
closely related to the SETPU statement.
Example
The above statement sets the destination for print unit 3 to be the LASER printer.
2.11-0
QMBasic 1207
!SETVAR()
The !SETVAR() subroutine sets the value of a user defined @-variable. It can also update some
standard @variables.
Format
where
name is the name of the @-variable to be set. The leading @ character may optionally be
omitted. The name may be up to 32 characters and is case insensitive.
value is the value to be set. This may not include the mark characters.
The !SETVAR() subroutine sets the value of the named user defined @-variable. It can also set
other standard @variables that are not read-only (e.g. @USER0) though these can be set using
simple assignment statements.
The !SETVAR() function sets a status value that can be retrieved using the STATUS() function.
This will be zero if the action is successful, or a non-zero error code if the name is invalid.
Example
See the !ATVAR() subroutine for a way to retrieve the value of a user defined @-variable.
2.11-0
1208 OpenQM
!SORT()
The !SORT() subroutine sorts the elements of a dynamic array according to a specified sorting
rule.
Format
where
in.list is the dynamic array containing the items to be sorted. Any mark character (or a
mix of different mark characters) may be used to separate the items.
out.list is the variable to receive the sorted dynamic array. The items will be separated by
field marks.
sort.rule defines the manner of sorting. This is a string containing characters from the
following:
A Sort in ascending order (default)
D Sort in descending order
L Sort as left aligned values (default)
R Sort as right aligned values
N Ignore null elements
U Return unique items. Multiple occurrences of an item are replaced by just
one item.
Invalid or conflicting sort.rule elements are ignored.
The !SORT() subroutine sorts elements of in.list into the order defined by sort.rule, returning the
sorted list in out.list. The value of in.list is not changed unless it refers to the same variable as
out.list.
Right aligned sorts should normally be used when sorting numeric data.
Example
CUSTOMER.LIST = ""
SELECT INVOICES
LOOP
READNEXT ID ELSE EXIT
READ INVOICE.REC FROM INVOICES, ID THEN
CUSTOMER.LIST<-1> = INVOICE.REC<CUSTOMER.NAME>
END
REPEAT
CALL !SORT(CUSTOMER.LIST, CUSTOMER.LIST, "AU")
The above program fragment reads all the records from the INVOICE file and builds a list of
customer names. This is then sorted, removing duplicates.
This approach will be faster than using LOCATE and INS to build a sorted list unless there are a
very large number of duplicates.
2.11-0
QMBasic 1209
!USERNAME()
The !USERNAME() subroutine returns the user login name for a given QM user number.
Format
or
where
The !USERNAME() subroutine returns name as the login name associated with a given user
number. If there is no user logged in with that userno, a null string is returned.
Example
The above program fragment displays the login name of the user holding the lock if the READU is
blocked by another user.
2.11-0
1210 OpenQM
!USERNO()
The !USERNO() subroutine returns a list of QM user numbers for a given user name.
Format
or
where
userno is a field mark delimited list of QM user numbers for the given user name.
The !USERNO() subroutine returns a field mark delimited list of the QM user numbers of
processes running with the given user name. The user name is case insensitive. If there is no user
logged in with that username, a null string is returned.
Example
INPUT USERNAME
CALL !USERNO(UNO, USERNAME)
IF UNO # "" THEN
CRT "User numbers are: " : CHANGE(UNO, @FM, ", ")
END ELSE
CRT "There are no users logged in with this user name"
END
The above program fragment displays a comma separated list of QM users logged in under a given
user name.
2.11-0
QMBasic 1211
!VOCREC()
The !VOCREC() subroutine reads a VOC record, following links to remote records.
Format
or
where
The !VOCREC() subroutine attempts to read record id from the VOC file. If not found, it tries
again using an uppercase version of id.
If the record read from the VOC is an R-type item, the subroutine follows the link, again translating
to uppercase if the record is not found exactly as specified in the R-type link.
If the original VOC record or the target of the R-type link is not found, the rec variable is set to a
null string, otherwise rec contains the retrieved data.
The STATUS() function returns zero if a record was found or an error code if not.
Example
The above program fragment reads the VOC record identified by STYLE.NAME, following any
remote link. If no record can be found, the program terminates with an error message.
2.11-0
1212 OpenQM
The QM interactive debugger enables the developer to step through an application program in a
convenient manner, stopping at desired points and examining data items.
Programs to be debugged must be compiled with the DEBUGGING option to the BASIC
command or by including the $DEBUG compiler directive in the program source. At run time, the
debugger will stop at selected places in the execution of these programs but will run normally
through programs not compiled in this mode. Catalogued programs and subroutines may be
debugged in exactly the same way as other programs.
The debugger is activated either by use of the DEBUG command in place of RUN or by a
DEBUG statement encountered during execution of a program. The latter method enables debug
mode to be entered part way through execution of the program. The debugger can also be entered
from the break key action prompt if any program currently being executed has been compiled in
debug mode.
During application development it is often worth compiling the entire application in debug mode.
Execution of the program with the RUN command will not invoke the debugger unless a DEBUG
statement is encountered. There is a small performance impact of running a debug mode program in
this way but it is usually not significant.
Phantom processes and those acting as the server side of a QMClient connection can be debugged
using the PDEBUG command.
The debugger will identify the program from which it was entered and locate the source program
record. If this is not available, a warning is displayed and execution of the program continues in
non-debug mode though other programs and subroutines called by it will still be subject to
debugging if their source records are available.
When used with QMConsole on a Windows system, via the QMTerm terminal emulator or the
bundled version of AccuTerm using a terminal type with the -at suffix, the debugger operates in full
screen mode. The display is divided into two areas. The upper portion of the screen shows the
source program with the line about to be executed highlighted. The lower portion of the screen is
used to echo commands and to display their responses. The top line of the screen displays the
program name and current line and element number. The display may be toggled between the
debugger and the application by use of the F4 key. Full screen mode also supports a command stack
similar to that found at the command prompt.
When used on other terminals, the debugger output is mixed with the application output.
The current position in a program is referenced by a line number and an element number. Most
QMBasic source lines hold only a single element (element 0) but lines with multiple statements
separated by semicolons or clauses of IF/THEN/ELSE constructs, etc, are considered to represent
separate execution elements. The debugger can step line by line or element by element through a
program.
The debugger cannot step through statements inserted into a program from an include record. In
such cases, it will step over the included statements as though they were part of the immediately
preceding statement.
Debugger commands fall into two groups; function keys and word based commands. In many cases
2.11-0
QMBasic 1213
both forms are available. Not all terminals support function keys.
If an application dynamically rebinds the codes sent by keys used by the debugger, setting the
DEBUG.REBIND.KEYS mode of the OPTION command will cause the debugger to reset these to
the bindings specified in the terminfo entry for the current terminal type on each entry to the debug
screen. Note that the debugger cannot revert to the user bindings on exit as it has no way to
determine what these were. This feature is available only with AccuTerm.
Where a short form is available, this is the upper case portion of the command as shown.
Commands may be entered in any mix of upper and lower case.
2.11-0
1214 OpenQM
STACK Display the call stack. The current program is shown first.
Step n Execute n lines.
Step .n Execute n elements.
StepOver Step over subroutine call (internal or external)
STOP Quit the program, generating a stop.
UnWatch Cancels an active watch action.
View Display user screen (normal program output)
Watch {var} Watches the named variable (see below). Shows watched variable if var
omitted.
XEQ command Execute command. Note that some commands may interfere with correct
operation of the debugger.
Entering a variable name preceded or followed by a slash (/) or a question mark (?) displays the
type and content of the given variable (var/, /var, var?, ?var). This name may be local variable or a
variable in a common block defined in the current program. If the common block has not been
linked at the time the command is entered, the variable will appear as unassigned. For programs
compiled with case insensitive names, the debugger is also case insensitive.
Private local variables in a subroutine declared using the LOCAL statement can be referenced
using a name formed by concatenating the subroutine name and variable name with a colon between
them. If a subroutine is executed recursively, it is only possible to view the current instance of the
variables.
The debugger will not recognise names defined using EQUATE or $DEFINE.
2.11-0
QMBasic 1215
The debugger recognises variable names STATUS(), INMAT(), COL1(), COL2() and
OS.ERROR() to display the corresponding system variable. All @-variables may also be displayed
except for @VOC (which is a file variable) and those representing constants such as @FM and
@TRUE.
Display of long strings is broken into short sections to fit the available display space. Entering Q at
the continuation prompt will terminate display.
When displaying strings with an active remove pointer, the position of this pointer is also shown.
If the variable is a matrix, the name may be followed by the index value(s) for the element to be
displayed. Entry of the name without an index will display the dimensions of the matrix. Subsequent
presses of the return key display successive elements of the matrix until either all elements have
been displayed or another command is entered.
CLI.REC/
Array: Dim (20)
<return>
CLI.REC(0) = Unassigned
<return>
CLI.REC(1) = String (8 bytes): "J Watson"
<return>
CLI.REC(2) = 13756
CLI.REC(8)/
Integer: 86
The variable name may be followed by a field, value or subvalue reference which will be used to
restrict the display if the data is a string. Note that this qualifier has no effect on other data types.
REC/
String (11 bytes,R=4): "487FM912VM338"
REC<1>/
String (3 bytes): "487"
REC<2,1>/
String (3 bytes): "912"
Entering a slash alone will repeat the most recent display command.
Analysis of very large character strings is sometime easier from outside the debugger. The DUMP
command can be used to dump the contents of a variable to an operating system level file that can
then be processed with other tools.
The /* command, available in full screen mode only, displays all variables in the program, one per
line. The page up, page down, cursor up and cursor down keys can be used to move through the
data. When the current line marker in the leftmost column is positioned on an array, pressing the
return key shows the elements of the array. When positioned on a character string, pressing the
return key shows the string data in hexadecimal and character form. In all cases, the Q key returns
to the previous screen.
2.11-0
1216 OpenQM
Watching Variables
The WATCH command causes the debugger to monitor the named variable. Whenever a value is
assigned to this variable (even if the value is the same as currently stored), the debugger will stop
program execution and display the new value. Only one variable can be watched at a time.
There is an extended form of WATCH that will only report the new value and stop if the value
meets a specific condition. This form of WATCH is
WATCH var op value
where
var is the variable to watch.
op is the operator used to test the condition. This may be any of the standard relational
operators (=, #, <, >, <=, >=, EQ, NE, LT, GT, LE, GE) or the LIKE or MATCHES
operator for pattern matching. The debugger supports UNLIKE in this context.
value is the value to be used for comparison. This may be a number or a string enclosed in
single quotes, double quotes or backslashes.
The UNWATCH command cancels the watch action. The watch action is automatically cancelled
when the watched variable ceases to exist. This might be return from the program in which the
variable exists, redimensioning a common block, etc.
2.11-0
QMBasic 1217
QM includes the option to generate a process dump file containing a detailed report of the state of
the process. There are three ways to generate a process dump:
A process dump will be created automatically if the DUMP.ON.ERROR mode of the OPTION
command is active and the process aborts either due to an error detected by QM or from use of
the ABORT statement in a QMBasic program.
Selection of the P option following use of the break key.
Use of the PDUMP command. This can be used to generate a dump of a different process such
as a phantom or a QMClient process.
By default, the process dump is directed to an operating system level file named qmdump.n in the
QMSYS account directory where n is the QM user number. The directory to receive the dump file
can be changed using the DUMPDIR configuration parameter. Because use of PDUMP potentially
allows a user to view data from another user's session, reducing system security, the PDUMP
configuration parameter can be used to restrict the command to dumping other processes running
under the same user name.
The file consists of a number of sections detailing the current state of the user process at the time of
the error.
1. Environment data
QM version number
Licence number and site name
User number
Process id
Parent user number (zero except in phantom processes)
User name
2. @-variables
@-variables that are likely to be useful in determining the cause of an error.
4. Locks
The report shows all task locks, file locks and record locks owned by the process.
5. Program stack
This contains an entry for each program, working backwards from the program in which the
error occurred.
For each program, the dump shows
Program number (used in some cross-references within the dump)
Program name, instruction address and line number. Line numbers cannot be shown if the
program was compiled with no cross reference tables or these were removed when the
program was catalogued.
Program status flags showing various special program states.
GOSUB return stack, if not empty.
Variables. Local variables are sorted alphabetically. Elements of a common block are
2.11-0
1218 OpenQM
shown in memory order and are only dumped on the first program that references the block.
Non-printing characters in strings are replaced by \nn where nn is the hexadecimal
character value. Backslash characters are shown as \\. Character string data is not line
wrapped to simplify exploration of the data using tools such as the SED editor.
2.11-0
QMBasic 1219
Error numbers are defined in the ERR.H record of the SYSCOM file.
2.11-0
1220 OpenQM
2.11-0
QMBasic 1221
2.11-0
1222 OpenQM
2.11-0
QMBasic 1223
2.11-0
1224 OpenQM
2.11-0
QMBasic 1225
On Windows systems, we recommend use of the Astrum InstallWizard from Thraex Software (as
used by QM itself) but the following process should map onto other self-installer packages.
Whatever installer package you use, it needs to install both QM and the application. The
complication is that this process needs to run QM to create the account that will hold the
application. The steps to achieve this are:
1. Unpack all the application files to wherever they need to go. The directory that will become
the application account can be created during this process but the only QM specific
subdirectory that should be created is the private catalogue (cat). You can place your own
application install program into the cat subdirectory for later use. If you need to pre-load
dictionary items or data file records, these should be unpacked into a temporary location.
2. The self-extracting file must also include the relevant version of QM as its own
self-extracting file. This should be unpacked into a temporary directory.
3. Once everything has been unpacked, the process now needs to install QM by executing the
QM self-extracting program. On Windows systems, use of the /silent command line option
will suppress most user interaction.
4. Now that QM is installed (or upgraded), you need to use it to create the application
account. The process should check whether the account already exists by looking for the
VOC file and, if not, execute QM with a single command line option of
"CREATE.ACCOUNT account.name account.path NO.QUERY".
The quotes are required in this command and the working directory should be the QMSYS
account. The CREATE.ACCOUNT command will not fail if the cat subdirectory already
exists.
5. Next, you need to execute your own application installer program that should have been
included in the contents of the unpacked private catalogue directory. This is done by
executing QM with a command line option that is the catalogued item name and with a
working directory of the newly created account.
2.11-0
1226 OpenQM
· Create any application specific VOC entries such as paragraphs and sentences.
2.11-0
QMBasic 1227
There are advanced web based packages available for QM but for many applications a simple CGI
program gives an easy way to achieve web connectivity with no additional software.
See "Using the C API" in the QMClient API section for details of libraries that must be included
when this application is compiled and linked. The executable program file should be placed in the
cgi-bin subdirectory of the relevant web account.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <\qmsys\syscom\qmclilib.h> [ Windows ]
#include </usr/qmsys/SYSCOM/qmclilib.h> [ Linux / FreeBSD /
AIX / Mac ]
/*
================================================================
====== */
int main()
{
char * RequestMethod;
char * p;
RequestMethod = getenv("REQUEST_METHOD");
if (RequestMethod == NULL)
{
printf("Program must be executed by a Web browser\n");
return 1;
}
2.11-0
1228 OpenQM
if (!strcmp(RequestMethod,"GET"))
{
if ((p = getenv("QUERY_STRING")) != NULL) strcpy(InputData,
p);
}
else if (!strcmp(RequestMethod,"POST"))
{
if ((p = getenv("CONTENT_LENGTH")) != NULL)
{
fread(InputData, atoi(p), 1, stdin);
}
}
ParseInputData();
printf("Content-type: text/html\n\n");
printf("<meta http-equiv=\"Pragma\" content=\"no-cache\">\n");
printf("%s\n", Response);
return 0;
}
Web requests received by this program will be passed to the catalogued QMBasic subroutine
identified by SERVER_PROGRAM. The declaration of this is
SUBROUTINE SERVER(INPUT.DATA, CLIENT.IP, CLIENT.USER,
RESPONSE)
When used with HTML forms with the method attribute set to "post" or "get", any data sent with
the form will be passed to the QM server program via the first argument (INPUT.DATA).
Typically, the form would include an item in this data that can be used to determine the screen being
processed.
The CLIENT.IP is the network address of the client user and can be used for simple security
checking.
If the user has been authenticated using the conventional web user authentication process, the user
name appears in CLIENT.USER. If authentication has not been performed, this will be a null
string.
The server subroutine must return valid HTML data to be returned to the web client via the
RESPONSE argument. For applications that return very large HTML strings it may be better for
2.11-0
QMBasic 1229
the QMBasic component to write the data to a temporary file and pass this name back to the C
program. This avoids the need for the Response variable in the above example to be sized to fit the
largest string that could ever be returned.
2.11-0
Part
7
QMClient API
1232 OpenQM
7 QMClient API
Historically, multivalue databases have used a character based user interface. QM includes a set of
Windows OLE compatible functions that enable development of applications in, for example,
Visual Basic. This section describes these functions and includes examples of how to use them to
develop a Windows style front end to your application.
The same functions are also available in the qmclilib library (qmclilib.dll on Windows,
libqmclient.a on other platforms) for use in C programs and as a QMBasic class module for use in
QMBasic programs. All of these API sets are discussed here.
In addition, the QMClient.pb record in the SYSCOM file contains an interface layer for use with
the PureBasic product from Fantaisie Software.
A QMClient session is an interactive use of the system and hence is counted in determining the
licensed user limit.
Overview
The API functions enable a Visual Basic or C application to access data stored in a QM database
or allow connection to remote QM systems from within QMBasic application programs. There are
API equivalents to the major file handling statements of QMBasic as well as a range of string
functions for dynamic array data manipulations, functions to execute commands and catalogued
subroutines on the server, etc. Where both ends of the connection support it, the network traffic is
encrypted.
The secret of writing efficient client server applications is to perform the bulk data processing on
the server and only handle user interface issues on the client. This minimises the data transferred
between the systems and hence optimises performance.
Licensing
The QMClient DLL and corresponding libraries may be freely distributed with application
software. The QM licence redistributions clauses apply to the server software, not the QMClient
client-side components. Although every attempt is made to ensure compatibility with older versions
of the client libraries, there may be times when changes require the distributed client components to
be updated.
The QMClient Windows API consists of two components; a Visual Basic module (QMClient.bas,
QMClient.vb or QMClient 2005.vb) containing the API function definitions, and a dynamic link
library (QMClient.dll) containing the actual interface functions. The C programmers' API is a
single library, qmclilib.dll on Windows or libqmclient.a on other platforms.
To use the API functions in a Visual Basic application, include the appropriate module from the
2.11-0
QMClient API 1233
QMSYS file dependant on the version of Visual Basic in use. The distinction is based on the
representation of numeric data:
16 bit 32 bit 64 bit
QMClient.bas Integer Long
QMClient.vb Integer Long
QMCLient2005.vb Short Integer Long
All function declaration prototypes shown in this section are based on the QMClient.bas definitions.
The QMClient.dll library must be installed on the client system. This library is placed in the
Windows directory (not necessarily c:\windows) when QM is installed. These components may be
freely copied and distributed as necessary.
From QM release 2.2-8, QMClient allows multiple connections from a single client process. This
allows development of applications that transfer data between accounts or servers.
Functions that return boolean values, return 0 for False, -1 for True in the Visual Basic API.
Use of the C programmers' API is different depending on the compiler in use. On Linux, FreeBSD,
AIX and Mac, programs need to include the libqmclient.a library when linking the application. The
Linux version of QM also includes a shared object version of QMClient API named qmclilib.so. On
Windows, the qmclilib.dll dynamic link library is used and two import libraries are provided to
include when linking the application; qmcllbbl.lib for Borland C users and qmcllbms.lib for
Microsoft C users. All of these components can be found in the bin subdirectory of the QMSYS
account. The function definitions can be found in the qmclilib.h include record in the SYSCOM file.
QMClient allows multiple connections from a single client process. This allows development of
applications that transfer data between accounts or servers.
Functions that return boolean values, return 0 for False, 1 for True in the C API library.
API calls that return strings dynamically allocate memory to hold the returned data. It is the calling
program's responsibility to release this memory using the QMFree() function when it is no longer
required. This function must be used in place of the standard free() C runtime library routine to
ensure compatibility with the memory allocator used by the QMClient library.
The QMClient class module is supplied as a globally catalogued item named !QMCLIENT. To
create a QMClient session, the object is instantiated with a statement of the form
session = object("!qmclient")
Functions that return boolean values, return 0 for False, 1 for True in the QMBasic class module
API.
2.11-0
1234 OpenQM
Session Management
File Handling
2.11-0
QMClient API 1235
String Manipulation
Command Execution
Subroutine Execution
Error Handling
Many functions have an Errno argument passed by reference as an Integer variable. This will be set
to one of the following values broadly corresponding to the various clauses applicable to the
equivalent QMBasic statements.
1 SV_ON_ERROR Action took the ON ERROR clause to recover from a situation that
would otherwise cause the server process to abort.
2 SV_ELSE Action took the ELSE clause. In most cases the QMStatus() function
can be used to determine the error number.
3 SV_ERROR An error occurred for which extended error text can be retrieved using
the QMError() function.
4 SV_LOCKED The action was blocked by a lock held by another user. The
QMStatus() function can be used to determine the blocking user.
5 SV_PROMPT A command executed on the server is waiting for input. The only valid
client functions when this status is returned are QMRespond(),
QMEndCommandand QMDisconnect.
The tokens shown above are defined in the QMClient.bas module and the qmclilib.h C include file.
2.11-0
1236 OpenQM
2.11-0
QMClient API 1237
Because a QMClient session operates in two parts, one on the client and one on the server, it is
important to understand how this affects use of select lists.
A select list may be constructed on the server by use of the QMSelect() or QMSelectPartial()
functions or by execution of a program (QMCall) or a command (QMExecute).
Using the QMSelect() function followed by repeated use of the QMReadNext() function builds the
select list on the server and then returns items one by one. This will use the same group by group
optimisation that is described with the QMBasic SELECT statement but, because the select list is
maintained on the server, retrieval of each entry requires passing of a message pair between the
client and the server which may be slow. However, because the select list actually exists at the
server side of the QMClient session, it is available for use by commands and programs executed on
the server within the session.
A QMClient application can read the entire select list in a single operation using the
QMReadNext() function and then extract entries using the QMExtract() function. This requires
the list to be fully constructed before it can be returned to the client and hence loses the performance
advantage gained from the group by group selection process.
Use of QMSelectPartial() provides a way to gain much of the performance advantage of the group
by group select but without needing to retrieve each record id separately. This function performs an
optimised select operation on the server and then returns a number of ids as a field mark delimited
string. The QMNextPartial() function then retrieves a further set of record ids until the list is
exhausted. Because QMSelectPartial() returns the first part of the list immediately, the full list is
not available on the server for use by commands or programs executed within the QMClient
session.
QMNextPartial() is effectively the same as a series of QMReadNext() operations that merge the
results into a single string before returning it to the server. It can therefore also be used to retrieve
data from a select list constructed by QMSelect(), a program or a command.
There is a further consideration for processes that use QMReadNext() or QMNextPartial() and
also update the file by adding new records. Because the optimised selection process is finding
records one by one as processing progresses, any records written during the processing may appear
later in the returned list. Using QMReadList() to construct and retrieve the entire list before
processing commences ensures that records added during processing will not be included in the list.
If a QMClient application uses QMSelectPartial() but the server pre-dates introduction of this
function, the entire list is returned similar to use of QMSelect() followed by QMReadList().
Similarly, use of QMNextPartia() with a server that does not support it is equivalent to use of
QMReadList().
2.11-0
1238 OpenQM
In most systems, a normal terminal user is taken directly into the application on logging in and the
application itself controls what the user can do. The ON.ABORT paragraph provides a mechanism
to ensure that, even if the application fails, the user cannot fall back to a command prompt.
With QMClient, the client session is effectively at a command prompt from which it can open, read
and write files, execute commands, or call subroutines. It becomes the responsibility of the client
software to control what the user can do. A knowledgeable user with a valid user name and
password could, however, develop a client session that connects in the same way as the application
and then goes on to do almost anything. Setting appropriate access rights on files may help but is
unlikely to be a perfect solution to this potential security threat.
The QMCLIENT configuration parameter can be used to control the level of access that a
QMClient session has. It starts with the value defined in the QM configuration parameters and can
be modified to a higher level using the CONFIG command but cannot be taken to a lower level in
this way. Because QMClient sessions execute the LOGIN paragraph on connection, the CONFIG
command is easily executed from this paragraph.
It may also be useful to validate the client network address (See @IP.ADDR) in the LOGIN
paragraph.
2.11-0
QMClient API 1239
7.3 QMCall
The QMCall function calls a catalogued subroutine on the server. It is analogous to the QMBasic
CALL statement.
Format
where
ArgCount is the number of arguments following (not present in the QMBasic class
module API).
The QMCall function calls the named catalogued subroutine on the server system. This subroutine
may take up to 20 arguments. QMClient does not provide a method to call subroutines with a
greater number of arguments.
In the Visual Basic and C APIs, there may be at most 20 variables named as arguments and these
must be declared as strings.
In the C API, the size of any argument variable that may be overwritten by the subroutine must be
large enough to receive the updated value. Failure to observe this rule will result in memory
corruption.
If the subroutine modifies the values of any of its arguments, this will be reflected in the variables
specified in ArgList. It is a good idea to ensure that arguments that are only used for values
returned from the subroutine are set to empty strings before the call to minimise data unnecessarily
sent across the network.
The called subroutine may make use of any of the standard QMBasic programming statements and
functions, however, it may not perform terminal input or output as there is no terminal associated
with a server process.
Examples
VB ErrMsg = ""
QMCall "SET.CREDIT.LIMIT", 3, Client, NewLimit, ErrMsg
If ErrMsg <> "" Then MsgBox ErrMsg, VBExclamation,
"Failed"
2.11-0
1240 OpenQM
C ErrMsg[0] = '\0';
QMCall("SET.CREDIT.LIMIT", 3, Client, NewLimit, ErrMsg);
If (ErrMsg[0] != '\0') printf("Failed - %s\n", ErrMsg);
QMBasic ErrMsg = ""
session->Call("SET.CREDIT.LIMIT", Client, NewLimit,
ErrMsg)
if ErrMsg # "") then display "Failed - " : ErrMsg
The above example calls a subroutine on the server that sets the credit limit for a specific client.
The subroutine takes three arguments, the third of which is used to return an error message if the
action fails. Note how the ErrMsg variable is set to a null string before calling the subroutine so
that any old content of this variable is not unnecessarily sent across the network to the server. To
optimise network traffic, the server only returns arguments values if they have been modified by the
called subroutine.
See also:
QMTrapCallAbort
2.11-0
QMClient API 1241
7.4 QMChange()
The QMChange() function replaces occurrences of one substring with another in a string. It is
analogous to the QMBasic CHANGE() function.
Format
C char * QMChange(char * Src, char * OldStr, char * NewStr, int Occurrences, int
Start)
where
Start is the occurrence number from one of the first occurrence of OldStr to be
replaced. If omitted or less than one, replacement commences at the first
occurrence of OldStr.
The QMChange() function returns a new string with the specified substrings replaced.
One use of QMChange() is to replace mark characters with carriage return / line feed pairs when
transferring data from a dynamic array to a multi-line text box.
Examples
The above example changes three uppercase letter "A" to lowercase "a" in the supplied string
starting at the second occurrence, returning the result. Note that the C version will set X too point to
a dynamically allocated memory areas that must be released later using QMFree().
2.11-0
1242 OpenQM
7.5 QMChecksum()
The QMChecksum() function returns a checksum value for supplied data. It is analogous to the
QMBasic CHECKSUM() function.
Format
where
The QMChecksum() function calculates a checksum value for the supplied data item. Note that the
algorithm used by QM may be different from that of other multivalue products and hence may yield
a different result for the same data.
Examples
VB X = QMChecksum("ABCDE")
C X = QMChecksum("ABCDE");
2.11-0
QMClient API 1243
7.6 QMClearselect
Format
Obj Session->ClearSelect(ListNo)
where
The QMClearSelect function clears the specified select list. No error occurs if the list was not
active.
Applications that use select list 0 (the default select list) and could leave unprocessed items in the
list should always clear it to avoid unwanted effects on later server processing.
Examples
VB QMSelect fClients, 1
Do
Id = QMReadNext(1, ErrNo)
If ErrNo <> 0 Then Exit Do
Rec = QMRead(fClients, Id, ErrNo)
If QMExtract(Rec, 1, 0, 0) = "" Then Exit Do
Loop
QMClearSelect 1
C QMSelect(fClients, 1);
do {
Id = QMReadNext(1);
if (Id == NULL) break;
Rec = QMRead(fClients, Id, ErrNo);
QMFree(Id);
Fld = QMExtract(Rec, 1, 0, 0);
if (Fld == NULL) break;
QMFree(Rec);
QMFree(Fld);
} while(1);
QMClearSelect(1);
QMBasic session->Select(fClients, 1)
loop
Id = session->ReadNext(1)
until Id = ""
Rec = session->Read(fClients, Id, ErrNo)
2.11-0
1244 OpenQM
The above program fragment builds select list 1 and uses it to process records from the file open as
fClients. It exits from the loop when it finds the first record where field 1 is empty. Because this
will leave a partially processed select list, QMClearSelect is used to clear the list.
Note that the C example leaves variables Rec and Fld pointing to dynamically allocated memory
areas on exit from the loop. These must be released using QMFree() when they are no longer
needed.
2.11-0
QMClient API 1245
7.7 QMClose
The QMClose function closes a file. It is analogous to the QMBasic CLOSE statement.
Format
Obj Session->Close(FileNo)
where
The server maintains a list of files open for processing by the client application. The QMClose
function causes the server to close the specified file. It is not normally necessary to close files as
there is no practical limit to the number of files that the server can hold open at once, however, for
best performance applications should close files if they are unlikely to be referenced for a
considerable time.
Examples
VB fClients = QMOpen("CLIENTS")
Rec = QMRead(fClients, ClientNo, ErrNo)
QMClose(fClients)
C fClients = QMOpen("CLIENTS");
Rec = QMRead(fClients, ClientNo, ErrNo);
QMClose(fClients);
QMBasic fClients = session->Open("CLIENTS")
Rec = session->Read(fClients, ClientNo, ErrNo)
session->Close(fClients)
The above program fragment opens the CLIENTS file, reads the record identified by ClientNo, and
then closes the file. A real program should test the ErrNo status from the read to determine if the
action was successful.
Note that the C example leaves variables Rec pointing to a dynamically allocated memory area that
must be released using QMFree() when no longer needed.
2.11-0
1246 OpenQM
7.8 QMConnect()
Format
C int QMConnect(char * Host, int Port, char * UserName, char * Password, char *
Account)
where
Port is the port number to which connection is to be made. Set this to -1 to use the
QM default port.
UserName is the user name under which the server process is to run.
The QMConnect() function attempts to establish a QMClient process on the system identified by
the Host argument. If successful, the function returns True. If unsuccessful, the function returns
False and the QMError() function can be used to retrieve a text error message identifying the
cause of the failure.
Host can reference the local machine. For an alternative method of starting a local QM session, see
the QMConnectLocal() function.
A single client may open multiple connections simultaneously. The internal session number
associated with the session opened by QMConnect() can be retrieved using QMGetSession(). All
subsequent QMClient function calls relate to the most recently opened session unless
QMSetSession() is used to select an alternative session.
QMClient sessions run the LOGIN paragraph (if present) but not the MASTER.LOGIN paragraph.
A QMClient session can be recognised within this paragraph by testing the value of @TTY which
will be "vbsrvr" for QMClient. Note that a prompt for input within the actions performed by the
LOGIN paragraph cannot be handled via QMClient.
Examples
2.11-0
QMClient API 1247
End If
C if (!QMConnect(Host, -1, UserName, Password, Account))
{
printf("Failed to connect - %s\n", QMError());
exit;
}
QMBasic session = object("!qmclient")
if not(session->Connect(Host, -1, UserName, Password,
Account)) then
stop "Failed to connect - " : QMError()
end
The above program fragment attempts to connect to the server identified by Host, using login
credentials in UserName, Password and Account. If unsuccessful, it displays an error message
including the text returned by QMError().
2.11-0
1248 OpenQM
7.9 QMConnected()
Format
VB QMConnected() as Boolean
C int QMConnected()
The QMConnected() function can be used by an application to determine whether a client session
is open.
Examples
The above program tests whether a QMClient connection is open and, if not, displays an error
message.
2.11-0
QMClient API 1249
7.10 QMConnectionType
The QMConnectionType function sets parameters that will be applied to the next QMClient
session opened by the process. This function does not apply to the QMClient class module in
QMBasic.
Format
where
The QMConnectionType function sets parameters that will be used when the next QMClient
session is opened by the process.
Additional bit values may be used in future releases or for internal undocumented purposes.
2.11-0
1250 OpenQM
7.11 QMConnectLocal()
Format
where
The QMConnectLocal() function attempts to establish a QMClient process on the local system.
The process runs as the user executing the function. If successful, the function returns True. If
unsuccessful, the function returns False and the QMError() function can be used to retrieve a text
error message identifying the cause of the failure.
A single client may open multiple connections simultaneously. The internal session number
associated with the session opened by QMConnectLocal() can be retrieved using QMGetSession()
. All subsequent QMClient function calls relate to the most recently opened session unless
QMSetSession() is used to select an alternative session.
QMClient sessions run the LOGIN paragraph (if present) but not the MASTER.LOGIN paragraph.
A QMClient session can be recognised within this paragraph by testing the value of @TTY which
will be "vbsrvr" for QMClient. Note that a prompt for input within the actions performed by the
LOGIN paragraph cannot be handled via QMClient.
NOTE: The underlying operating system call needed by QMConnectLocal() is not implemented on
Windows 98/ME. It will be necessary to use QMConnect for these systems.
Use of QMConnectLocal() needs to know the location of the QMSYS directory. If this is not in its
default location (C:\QMSYS on Windows, /usr/qmsys on other platforms), the QMSYS
environment variable must be set to specify the location.
Examples
The above program fragment attempts to connect to the local system using the account name in
2.11-0
QMClient API 1251
Account. If unsuccessful, it displays an error message including the text returned by QMError().
2.11-0
1252 OpenQM
7.12 QMDcount()
The QMDcount() function counts delimited items in a string. It is analogous to the QMBasic
DCOUNT() function.
Format
where
Delim is the delimiter character. If Delim is more than one character long, only the
first character is used.
The QMDcount() function is usually used to count fields, values or subvalues in a dynamic array
but can be used to count elements in any string that is separated by some single character delimiter.
Examples
VB X = QMDcount(Address, ",")
C X = QMDcount(Address, ",");
The above example returns the number of comma separated items in the Address variable.
2.11-0
QMClient API 1253
7.13 QMDecrypt()
The QMDecrypt() function decrypts data that has been encrypted for secure storage or
transmission. It is analogous to the QMBasic DECRYPT() function.
Format
where
The QMDecrypt() function applies the AES 128 bit encryption algorithm to the supplied data and
returns the decrypted text. The key string may be up to 64 characters in length and may contain any
character. It is automatically transformed into a form that is useable by the AES algorithm. For
optimum data security, the key should be about 16 characters.
The encrypted data is structured so that it can never contain characters from the C0 control group
(characters 0 to 31) or the mark characters. As a result of this operation, the encrypted data is
slightly longer than the decrypted data.
Examples
VB X = QMDecrypt(VAR, "MyKey")
C X = QMDecrypt(VAR, "MyKey");
The above example decrypts the data in variable VAR using an encryption key of "MyKey".
See also:
QMEncrypt()
2.11-0
1254 OpenQM
7.14 QMDel()
The QMDel() function deletes a field, value or subvalue from a dynamic array. It is analogous to
the QMBasic DELETE() function.
Format
VB QMDel(ByVal Src as String, ByVal Fno as Integer, ByVal Vno as Integer, ByVal
Svno as Integer) as String
where
Vno is the number of the value to be deleted. If less than 1, the entire field is
deleted.
Svno is the number of the subvalue to be deleted. If less than 1, the entire value is
deleted.
The QMDel() function returns a new dynamic array with the given field, value or subvalue deleted.
If the required item is not found, the original string is returned unchanged.
Examples
The above example returns a copy of the dynamic array Rec with field 1, value Pos removed.
Note that variables Rec and NewRec in the C example point to dynamically allocated memory areas
that must be released using QMFree() when they are no longer needed.
2.11-0
QMClient API 1255
7.15 QMDelete()
The QMDelete function deletes a record from a file. It is analogous to the QMBasic DELETE
statement.
Format
where
The QMDelete function deletes the named record from the file open as FileNo. No error occurs if
the record does not exist.
Applications should always obtain an update lock for a record before deleting it. The lock is
released by this function.
Examples
VB fClients = QMOpen("CLIENTS")
QMRecordlock(fClients, ClientNo, True, True)
QMDelete(fClients, ClientNo)
QMClose(fClients)
C fClients = QMOpen("CLIENTS");
QMRecordlock(fClients, ClientNo, TRUE, TRUE);
QMDelete(fClients, ClientNo);
QMClose(fClients);
QMBasic fClients = session->Open("CLIENTS")
session->Recordlock(fClients, ClientNo, @true, @true)
session->Delete(fClients, ClientNo)
session->Close(fClients)
The above program fragment opens the CLIENTS file, deletes the record identified by ClientNo,
and then closes the file. Note the use of a record update lock to comply with recommended
programming rules.
2.11-0
1256 OpenQM
7.16 QMDeleteu()
The QMDeleteu function deletes a record from a file, retaining the record lock. It is analogous to
the QMBasic DELETEU statement.
Format
where
The QMDeleteu function deletes the named record from the file open as FileNo. No error occurs if
the record does not exist.
Applications should always obtain an update lock for a record before deleting it. The lock is
retained on return from this function.
Examples
VB fClients = QMOpen("CLIENTS")
QMRecordlock(fClients, ClientNo, True, True)
QMDeleteu(fClients, ClientNo)
C fClients = QMOpen("CLIENTS");
QMRecordlock(fClients, ClientNo, TRUE, TRUE);
QMDeleteu(fClients, ClientNo);
QMBasic fClients = session->Open("CLIENTS")
session->Recordlock(fClients, ClientNo, @true, @true)
session->Deleteu(fClients, ClientNo)
The above program fragment opens the CLIENTS file, locks and deletes the record identified by
ClientNo, retaining the lock.
2.11-0
QMClient API 1257
7.17 QMDisconnect
Format
VB QMDisconnect
C void QMDisconnect(void)
Obj Session->Disconnect
Examples
VB QMDisconnect
C QMDisconnect();
2.11-0
1258 OpenQM
7.18 QMDisconnectAll
The QMDisconnectAll function terminates all QMClient sessions from a client process.
Format
VB QMDisconnectAll
C void QMDisconnectAll(void)
A single client may establish multiple QMClient connections. The QMDisconnectAll function
terminates all such connections.
The QMDisconnectAll function has no equivalent in the QMBasic class module API as each
session is a separate instantiation of the object.
Examples
VB QMDisconnectAll
C QMDisconnectAll();
The above statement closes all QMClient connections open by the program.
2.11-0
QMClient API 1259
7.19 QMEncrypt()
The QMEncrypt() function decrypts data for secure storage or transmission. It is analogous to the
QMBasic ENCRYPT() function.
Format
where
The QMEncrypt() function applies the AES 128 bit encryption algorithm to the supplied data and
returns the encrypted text. The key string may be up to 64 characters in length and may contain any
character. It is automatically transformed into a form that is useable by the AES algorithm. For
optimum data security, the key should be about 16 characters.
The encrypted data is structured so that it can never contain characters from the C0 control group
(characters 0 to 31) or the mark characters. As a result of this operation, the encrypted data is
slightly longer than the resultant decrypted data.
Examples
VB X = QMEncrypt("ABRACADABRA", "MyKey")
C X = QMEncrypt("ABRACADABRA", "MyKey");
The above example encrypts the string "ABRACADABRA" using an encryption key of "MyKey".
See also:
QMDecrypt()
2.11-0
1260 OpenQM
7.20 QMEndCommand
The QMEndCommand function aborts a command executed on the server that is requesting input.
Format
VB QMEndCommand
C void QMEndCommand(void)
Obj Session->EndCommand
This function may only be used when an immediately preceding QMExecute() or QMRespond()
function has returned a status of SV_PROMPT.
2.11-0
QMClient API 1261
7.21 QMError()
Format
VB QMError() as String
C char * QMError(void)
VB Str = Session->error
Some API functions set extended error text and return an error code of SV_ERROR when an error
condition occurs. The QMError() function can be used to retrieve this text.
Note that in the C API, this function returns a pointer to a statically allocated error message buffer.
The calling program must not attempt to free this memory.
2.11-0
1262 OpenQM
7.22 QMExecute()
Format
where
The QMExecute() function executes the specified command on the server. The output from this
command is returned as a text string.
If the command completes without requesting input, the Errno variable is set to SV_OK.
If the command requests input, any output up to that point is returned and the Errno variable is set
to SV_PROMPT. The client may respond to this using the QMRespond() function or abort the
command using the QMEndCommand() function.
The executed command may perform most functions of the QM database. Specific restrictions are:
Input may be requested from the client using the QMBasic INPUT and INPUT@ statements.
Use of the KEYIN() function is not allowed.
Testing for input using the QMBasic KEYREADY() function or the INPUT -1 syntax will not
show input waiting.
The length parameter of an INPUT statement will be ignored if present.
Execution of a further command from within the executed command may not behave correctly.
2.11-0
QMClient API 1263
7.23 QMExtract()
The QMExtract() function extracts a field, value or subvalue from a dynamic array. It is
analogous to the QMBasic field extraction operator or the EXTRACT() function.
Format
where
Vno is the number of the value to be extracted. If less than 1, the entire field is
extracted.
Svno is the number of the subvalue to be extracted. If less than 1, the entire value is
extracted.
The QMExtract() function returns the given field, value or subvalue from the source string. If the
required item is not found, a null string is returned.
Examples
The above program fragment reads the record identified by ClientNo from the file open as fClients
and then extracts field 4 from it. A real program should test the ErrNo status from the read to
determine if the action was successful.
Note that the C example leaves variables CliAddr pointing to a dynamically allocated memory area
that must be released using QMFree() when no longer needed.
2.11-0
1264 OpenQM
7.24 QMField()
The QMField() function extracts one or more components of a delimited string. It is analogous to
the QMBasic FIELD() function.
Format
where
Start is the number from one of the first component of Src to be returned.
Examples
The above example takes a variable Name holding a person's first and last names separated by a
space and returns just their first name.
Note that the C example leaves variables FirstName pointing to a dynamically allocated memory
area that must be released using QMFree() when no longer needed.
2.11-0
QMClient API 1265
7.25 QMFree()
The QMFree() function releases memory returned by other functions. It is only used with the C
API library.
Format
where
addr is the pointer to a dynamic memory area returned by another API function.
Many of the C API functions return dynamically allocated memory. The QMFree() function allows
a program to release this. The C runtime library free() function should not be used as it may not be
compatible with the memory allocator used within the API functions.
Example
The above program fragment reads a record with an update lock, modifies it and then writes it back
to the file. A real program should test the ErrNo status from the read operations to determine if they
were successful. The QMFree() is used to release the dynamic memory allocated to store Rec and
Rec2.
2.11-0
1266 OpenQM
7.26 QMGetSession()
The QMGetSession() function returns the internal session number associated with the currently
selected QMClient session.
Format
VB QMGetSession() as Integer
C int QMGetSession(void)
A single client may open multiple QMClient connections, each identified by a session number. The
QMConnect() and QMConnectLocal() functions select an available session number to use for the
newly created session which can be retrieved using QMGetSession(). All subsequent QMClient
function calls relate to this session until an alternative session is selected using QMSetSession().
The QMGetSession() function has no equivalent in the QMBasic class module API as each session
is managed as a separate instantiation of the object.
2.11-0
QMClient API 1267
7.27 QMIns()
The QMIns() function inserts a field, value or subvalue in a dynamic array. It is analogous to the
QMBasic INSERT() function.
Format
VB QMIns(ByVal Src as String, ByVal Fno as Integer, ByVal Vno as Integer, ByVal
Svno as Integer, ByVal NewData as String) as String
C char * QMIns(char * Src, int Fno, int Vno, int Svno, char * NewData)
where
Vno is the number of the value to be inserted. If less than 1, an entire field is
inserted.
Svno is the number of the subvalue to be inserted. If less than 1, an entire value is
inserted.
NewData is the new data to form the new dynamic array element.
The QMIns() function returns a new dynamic array with the specified field, value or subvalue
inserted.
Examples
The above program fragment reads a record with an update lock, uses QMIns() to modify it and
then writes it back to the file. A real program should test the ErrNo status from the read operations
2.11-0
1268 OpenQM
Note how the C example uses QMFree() to release the dynamic memory allocated to store Rec and
Rec2.
2.11-0
QMClient API 1269
7.28 QMLocate()
The QMLocate() function searches a dynamic array for a field, value or subvalue matching a given
string. It is analogous to the LOCATE statement.
Format
C int QMLocate(char * Item, char * DynArray, int Fno, int Vno, int Svno, int * Pos,
char * Order)
where
Fno is the number of the field at which the search is to begin. If less than 1, 1 is
assumed.
Vno is the number of the value at which the search is to begin. If less than 1, the
function searches for a field containing Item.
Svno is the number of the subvalue at which the search is to begin. If less than 1, the
function searches for a value containing Item.
Order identifies the sort method to the applied. This may be:
AL Ascending, left aligned
AR Ascending, right aligned
DL Descending, left aligned
DR Descending, right aligned
If omitted, no sort order is applied.
If Vno is less than 1, the function searches the dynamic array for a field matching Item, starting at
the field position given by Fno.
If Vno is given but Svno is less than 1, the function searches field Fno of the dynamic array for a
value matching Item, starting at the value position given by Vno.
If Vno and Svno are given, the function searches field Fno, value Vno of the dynamic array for a
subvalue matching Item, starting at the value position given by Svno.
The Order argument determines the sorting system to be applied during the search:
2.11-0
1270 OpenQM
If Order is a null string, no sort rules are applied. The function scans all applicable dynamic array
elements for a match against Item. The Pos variable will be returned as the position at which the
item was found. If the item is not found, Pos will be returned as the position at which a new element
could be appended.
If the first character of Order is A, an ascending sort is applied. If the first character of Order is D,
a descending sort is applied. In either case, the search terminates if an entry is found that would be
beyond the correct position for Item. In this case, if the item is not found, Pos will be returned as
the position at which to insert Item to maintain the correct sort order.
If the second character of Order is L, a left aligned comparison is performed. Each entry of the
dynamic array is compared with Item character by character from the left until a difference is
found.
If the second character of Order is R, a right aligned comparison is performed. If the two items
being compared are of different lengths, spaces are added to the front of the shorter item before
comparison.
The QMLocate() function returns True if the item is found, False if it is not found.
Examples
The above example searches field 4 of dynamic array Order for a value that contains the same data
as the PartNo variable. If found, the value position is returned in variable Pos and Found is set to
true. If not found, Pos will indicate the position at which the item could be inserted to maintain
correct sorted order as implied by the AL sort code and Found will be set to false. Note that the
QMLocate() function follows the default "Information style" syntax of QM where the field, value
and subvalue positions indicate the point at which the search is to start. Thus, the above example
specifies a value position of 1 to search the entire field.
2.11-0
QMClient API 1271
7.29 QMLogto()
Format
where
The QMLogto() function attempts to move to the named account. If successful, the function
returns True. If unsuccessful, the function returns False and the QMError() function can be used
to retrieve a text error message identifying the cause of the failure.
If the VOC of the current account contains an executable item named ON.LOGTO, usually a
paragraph, this will be executed before moving to the new account.
If the VOC of the new account contains an executable item named LOGIN, this will be executed on
arrival in the new account.
A QMClient session can be recognised within these paragraphs by testing the value of @TTY
which will be "vbsrvr" for QMClient.
Examples
The above program fragment attempts to move to the account identified Account. If unsuccessful, it
displays an error message including the text returned by QMError().
2.11-0
1272 OpenQM
7.30 QMMarkMapping
The QMMarkMapping function enables or disables mark mapping for a directory file.
Format
where
The QMMarkMapping function enables or disables mark character mapping on the file open as
FileNo. See the QMBasic MARK.MAPPING statement for more details.
2.11-0
QMClient API 1273
7.31 QMMatch()
The QMMatch() function matches a string against a pattern template. It is analogous to the
QMBasic MATCHES operator.
Format
where
The QMMatch() function tests whether Src matches the Pattern template consisting of one or more
concatenated items from the following list.
The values n and m are integers with any number of digits. m must be greater than or equal to n.
The 0A, nA, 0N, nN and "string" patterns may be preceded by a tilde (~) to invert the match
condition. For example, ~4N matches four non-numeric characters such as ABCD (not a string
which is not four numeric characters such as 12C4).
A null string matches patterns ..., 0A, 0X, 0N, their inverses (~0A, etc) and "".
The 0X and n-mX patterns match against as few characters as necessary before control passes to
the next pattern. For example, the string ABC123DEF matched against the pattern 0X2N0X
matches the pattern components as ABC, 12 and 3DEF.
The 0N, n-mN, 0A, and n-mA patterns match against as many characters as possible. For example,
the string ABC123DEF matched against the pattern 0X2-3N0X matches the pattern components as
ABC, 123 and DEF.
The pattern string may contain alternative templates separated by value marks. The QMMatch()
function tries each template in turn until one is a successful match against the string.
2.11-0
1274 OpenQM
Examples
VB OK = QMMatch(PartCode, "2-4A3N")
C OK = QMMatch(PartCode, "2-4A3N");
The above example tests whether the contents of PartCode is formed from between two and four
letters followed by three digits, returning OK as a true/false value.
2.11-0
QMClient API 1275
7.32 QMMatchfield()
The QMMatchfield() function matches a character string against a pattern template and extracts
the part corresponding to a specified pattern component. It is analogous to the QMBasic
MATCHFIELD() function.
Format
where
Component is the pattern template component number for which the corresponding part of
Src is to be returned.
The QMMatchfield() function matches Src against the Pattern template as described for the
QMMatch() function. If the string matches, the portion corresponding to the specified Component
is returned. If the string does not match the pattern, a null string is returned.
Examples
The above example returns the alphabetic prefix of a value stored in PartCode if it is formed from
between two and four letters followed three digits.
Note that Prefix variable in the C example points to dynamically a allocated memory area that must
be released using QMFree() when no longer needed.
2.11-0
1276 OpenQM
7.33 QMNextPartial()
The QMNextPartial function returns the next part of a select list built using QMSelectPartial().
Format
Obj Session->NextPartial(ListNo)
where
The QMNextPartial() function provides an optimised way to process select lists within a QMClient
session. It returns the next part of a list constructed using QMSelectPartial(). A null string is
returned when the list is exhausted.
QMNextPartial() can also be used to return items from a select list built on the server by a
program, by execution of a command, or by use of QMSelect(). It is essentially the same as a series
of QMReadNext() operations that merge the ids into a single string before returning it to the
server.
See Select lists in QMClient sessions for a description of the alternative ways to handle select list
with QMClient.
Examples
VB List = QMSelectPartial(fClients, 1)
While List <> ""
N = QMDcount(List, FM)
For I = 1 To N
Id = QMExtract(List, I, 0, 0)
...processing...
Next I
List = QMNextPartial(1)
Wend
C List = QMSelectPartial(fClients, 1);
While(List != NULL)
{
N = QMDcount(List, FM);
For(I = 1; I <= N; I++)
{
Id = QMExtract(List, I, 0, 0);
...processing...
QMFree(Id);
}
QMFree(List);
2.11-0
QMClient API 1277
List = QMNextPartial(1);
}
QMBasic list = session->SelectPartial(fClients, 1)
loop
while list # ""
for each id in list
...processing...
next id
list = session->NextPartial(1)
repeat
The above program fragment builds select list 1 and uses it to process records from the file open as
fClients.
Note that the C example uses QMFree() to release dynamically allocated memory areas returned
from QMClient API calls.
2.11-0
1278 OpenQM
7.34 QMOpen()
The QMOpen() function opens a file. It is analogous to the QMBasic OPEN statement.
Format
where
FileName is the name of the file to be opened. This must correspond to an F or Q-type
entry in the VOC of the QM account in which the server is running.
The QMOpen() function opens a QM database file. The returned integer value is the file number
which must be used in all subsequent operations against this file. If the file cannot be opened, the
function returns zero. The QMStatus() function can be used to retrieve the error cause.
To open a dictionary, the FileName argument should commence with "DICT" and a single space
separating this prefix from the file name, for example:
There is no practical limit to the number of files that can be open at one time.
Examples
VB fClients = QMOpen("CLIENTS")
Rec = QMRead(fClients, ClientNo, ErrNo)
QMClose(fClients)
C fClients = QMOpen("CLIENTS");
Rec = QMRead(fClients, ClientNo, ErrNo);
QMClose(fClients);
QMBasic fClients = session->Open("CLIENTS")
Rec = session->Read(fClients, ClientNo, ErrNo)
session->Close(fClients)
The above program fragment opens the CLIENTS file, reads the record identified by ClientNo, and
then closes the file. A real program should test the ErrNo status from the read to determine if the
action was successful.
Note that the C example leaves variables Rec pointing to a dynamically allocated memory area that
must be released using QMFree() when no longer needed.
2.11-0
QMClient API 1279
7.35 QMRead()
The QMRead() function reads a record without locking. It is analogous to the QMBasic READ
statement.
Format
where
The QMRead() function requests the server to return the record with key Id from the file opened
as FileNo.
If successful, the function returns the record as a dynamic array string and the Errno variable is set
to SV_OK.
If the record cannot be found, the function returns a null string and the Errno variable is set to
SV_ELSE. The QMStatus() function can be used to retrieve the error number.
Conditions that would normally cause a QMBasic program to abort or to take the ON ERROR
clause of a READ statement return a null string and the Errno variable is set to SV_ON_ERROR.
The QMStatus() function can be used to retrieve the error number.
In the C API library, the dynamic memory allocated for the returned string must subsequently be
freed by the calling program.
Examples
VB fClients = QMOpen("CLIENTS")
Rec = QMRead(fClients, ClientNo, ErrNo)
QMClose(fClients)
C fClients = QMOpen("CLIENTS");
Rec = QMRead(fClients, ClientNo, ErrNo);
QMClose(fClients);
QMBasic fClients = session->Open("CLIENTS")
Rec = session->Read(fClients, ClientNo, ErrNo)
session->Close(fClients)
2.11-0
1280 OpenQM
The above program fragment opens the CLIENTS file, reads the record identified by ClientNo, and
then closes the file. A real program should test the ErrNo status from the read to determine if the
action was successful.
Note that the C example leaves variables Rec pointing to a dynamically allocated memory area that
must be released using QMFree() when no longer needed.
2.11-0
QMClient API 1281
7.36 QMReadl()
The QMReadl() function reads a record with a shareable read lock. It is analogous to the
QMBasic READL statement.
Format
where
Wait is a boolean value indicating the action to be taken if the record is currently
locked by another user:
True wait for the record to become available
False return an error code of SV_LOCKED
The QMReadl() function requests the server to return the record with key Id from the file opened
as FileNo. A shareable read lock is applied to the record. Any number of users may hold a
shareable read lock on the same record at one time but, while any user has a shareable read lock, no
other user can establish an update lock or a file lock.
If the action is blocked by a lock held by another user, the function returns a null string and the
Errno variable is set to SV_LOCKED. The QMStatus() function can be used to retrieve the user
number of the process holding the lock.
If successful, the function returns the record as a dynamic array string and the Errno variable is set
to SV_OK. The record is locked by the server process.
If the record cannot be found, the function returns a null string and the Errno variable is set to
SV_ELSE. The QMStatus() function can be used to retrieve the error number. The record is locked
by the server process. If the lock is not required, it should be released using the QMRelease()
function.
Conditions that would normally cause a QMBasic program to abort or to take the ON ERROR
clause of a READ statement return a null string and the Errno variable is set to SV_ON_ERROR.
The QMStatus() function can be used to retrieve the error number.
In the C API library, the dynamic memory allocated for the returned string must subsequently be
freed by the calling program.
2.11-0
1282 OpenQM
Examples
VB fClients = QMOpen("CLIENTS")
Rec1 = QMReadl(fClients, ClientNo, True, ErrNo)
Rec2 = QMReadl(fClients, OtherClient, True, ErrNo)
C fClients = QMOpen("CLIENTS");
Rec1 = QMReadl(fClients, ClientNo, TRUE, ErrNo);
Rec2 = QMReadl(fClients, OtherClient, TRUE, ErrNo);
QMBasic fClients = session->Open("CLIENTS")
Rec1 = session->Readl(fClients, ClientNo, @true, ErrNo)
Rec2 = session->Readl(fClients, OtherClient, @true,
ErrNo)
The above program fragment opens the CLIENTS file and reads two client records. By using
QMReadl() instead of QMRead(), there is no possibility that the first record has been updated by
the time the second record is read. The program therefore sees a guaranteed consistent state of the
data. A real program should test the ErrNo status from the read operations to determine if they were
successful.
Note that the C example leaves variables Rec1 and Rec2 pointing to dynamically allocated memory
areas that must be released using QMFree() when no longer needed.
2.11-0
QMClient API 1283
7.37 QMReadList()
The QMReadList() function reads a select list into a dynamic array in the client application. It is
analogous to the QMBasic READLIST statement.
Format
where
ListNo is the number of the select list to be read in the range 0 to 10.
If the action is successful, the returned value contains a field mark delimited set of unprocessed
entries from the given list. The original list is destroyed by this action.
The Visual Basic and object APIs returns an empty string if there is no data to read. The C API
returns NULL in this situation.
See Select lists in QMClient sessions for a description of the alternative ways to handle select list
with QMClient.
Examples
VB QMSelect fClients, 1
List = QMReadList(1, ErrNo)
C QMSelect(fClients, 1);
List = QMReadList(1);
QMBasic session->Select(fClients, 1)
List = session->ReadList(1)
The above program fragment builds select list 1 as a list of all records in the file open as fClients
and then transfers this to a dynamic array named List.
Note that variable List in the C example points to a dynamically allocated memory area that must
be released using QMFree() when no longer required.
2.11-0
1284 OpenQM
7.38 QMReadNext()
The QMReadNext() function retrieves the next entry from a select list. It is analogous to the
QMBasic READNEXT statement.
Format
where
ListNo is the number of the select list to be processed in the range 0 to 10.
Errno receives an error value indicating the outcome of the request. The C API does
not have this argument and returns NULL if an error occurs.
The QMReadNext() function retrieves the next entry from the select list identified by the ListNo
argument.
If successful, the function returns the list entry and, in the Visual Basic API, Errno is set to
SV_OK.
If the list is empty, the Visual Basic API function returns a null string and Errno is set to
SV_ELSE. In the C API implementation, the function returns NULL.
See Select lists in QMClient sessions for a description of the alternative ways to handle select list
with QMClient.
See also the QMReadList() function for a discussion of the relationship between QMReadNext()
and QMReadList().
Note that in the C API library, the returned string is dynamically allocated. A loop containing a call
to this function must free the memory from each call separately.
Examples
VB QMSelect fClients, 1
Do
Id = QMReadNext(1, ErrNo)
If ErrNo <> 0 Then Exit Do
Rec = QMRead(fClients, Id, ErrNo)
If ErrNo = 0 Then Go Sub ProcessRecord
Loop
C QMSelect(fClients, 1);
while((Id = QMReadNext(1)) != NULL)
2.11-0
QMClient API 1285
{
if (Id == NULL) break;
Rec = QMRead(fClients, Id, ErrNo);
if (ErrNo == 0)
{
ProcessRecord();
QMFree(Rec);
}
QMFree(Id);
}
QMBasic session->Select(fClients, 1)
loop
Id = session->ReadNext(1)
until Id = ""
Rec = session->Read(fClients, Id, ErrNo)
If ErrNo = 0 then gosub ProcessRecord
repeat
The above program fragment builds select list 1 and uses it to process records from the file open as
fClients.
Note that the C example uses QMFree() to release dynamically allocated memory areas returned
from QMClient API calls.
2.11-0
1286 OpenQM
7.39 QMReadu()
The QMReadu() function reads a record with an exclusive update lock. It is analogous to the
QMBasic READU statement.
Format
where
Wait is a boolean value indicating the action to be taken if the record is currently
locked by another user:
True wait for the record to become available
False return an error code of SV_LOCKED
The QMReadu() function requests the server to return the record with key Id from the file opened
as FileNo. An exclusive update lock is applied to the record. Only one user may hold an exclusive
update lock on any one record at one time. An exclusive update lock also cannot be obtained if
another user holds a shareable read lock on the record or a file lock on the entire file.
If the action is blocked by a lock held by another user, the function returns a null string and the
Errno variable is set to SV_LOCKED. The QMStatus() function can be used to retrieve the user
number of the process holding the lock.
If successful, the function returns the record as a dynamic array string and the Errno variable is set
to SV_OK. The record is locked by the server process.
If the record cannot be found, the function returns a null string and the Errno variable is set to
SV_ELSE. The QMStatus() function can be used to retrieve the error number. The record is locked
by the server process to allow creation of the record. If the lock is not required, it should be released
using the QMRelease() function.
Conditions that would normally cause a QMBasic program to abort or to take the ON ERROR
clause of a READ statement return a null string and the Errno variable is set to SV_ON_ERROR.
The QMStatus() function can be used to retrieve the error number.
In the C API library, the dynamic memory allocated for the returned string must subsequently be
freed by the calling program.
2.11-0
QMClient API 1287
Examples
The above program fragment reads a record with an update lock, modifies it and then writes it back
to the file. A real program should test the ErrNo status from the read operations to determine if they
were successful.
Note how the C example uses QMFree() to release the dynamic memory allocated to store Rec and
Rec2.
2.11-0
1288 OpenQM
7.40 QMRecordlock
Format
where
Wait is a boolean value indicating the action to be taken if the record is currently locked
by another user:
True wait for the record to become available
False return an error code of SV_LOCKED
The QMRecordlock function can be used to obtain a lock on a record without reading the record.
Examples
The above program fragment writes a new record into the file opened as fClients. To comply with
recommended locking rules, a record should never be written unless the program holds an update
lock on it. Use of QMRecordlock() gets this lock before the write.
2.11-0
QMClient API 1289
7.41 QMRelease
The QMRelease function releases a record lock. It is analogous to the QMBasic RELEASE
statement.
Format
where
FileNo is the file number returned by a previous QMOpen() call. If zero, all locks are
released.
Id is the id of the record to be unlocked. If given as a null string, all locks in the
file identified by FileNo are released.
The QMRelease function can be used to release a lock without writing or deleting the record. One
common use of this function is to release the lock obtained by a call to QMReadl() or QMReadu()
where the record was not found and the function returned the SV_ELSE status.
Examples
The above program fragment attempts to read a record with an update lock. If the record is not
found, the lock is released prior to exit from the subroutine.
Note how the C example uses QMFree() to release the dynamic memory allocated to store Rec.
2.11-0
1290 OpenQM
7.42 QMReplace()
The QMReplace() function replaces the content of a field, value or subvalue in a dynamic array. It
is analogous to the QMBasic REPLACE() function.
Format
C char * QMReplace(char * Src, int Fno, int Vno, int Svno, char * NewData as
String)
where
Vno is the number of the value to be replaced. If zero, the entire field is inserted. If
negative, a new value is appended to the specified field.
Svno is the number of the subvalue to be replaced. If zero, the entire value is
inserted. If negative, a new subvalue is appended to the specified value.
NewData is the new data to form the new dynamic array element.
The QMReplace() function returns a new dynamic array with the specified field, value or subvalue
replaced.
Examples
2.11-0
QMClient API 1291
The above program fragment reads a record with an update lock, uses QMReplace() to modify it
and then writes it back to the file. A real program should test the ErrNo status from the read
operations to determine if they were successful.
Note how the C example uses QMFree() to release the dynamic memory allocated to store Rec and
Rec2.
2.11-0
1292 OpenQM
7.43 QMRespond()
The QMRespond() function responds to a request for input from a command executed on the
server.
Format
where
This function may only be used when an immediately preceding QMExecute() or QMRespond()
function has returned a status of SV_PROMPT.
The QMRespond() function returns the given Response to the input request from the server
command. Further output from this command is returned as a text string.
If the command completes without requesting input, the Errno variable is set to SV_OK.
If the command requests further input, any output up to that point is returned and the Errno
variable is set to SV_PROMPT. The client may respond to this using the QMRespond() function
or abort the command using the QMEndCommand() function.
2.11-0
QMClient API 1293
7.44 QMRevision()
The QMRevision() function returns the revision level of the client and server components.
Format
VB QMRevision() as String
C char * QMRevision(void)
VB Str = Session->revision
This function returns the revision level of the client and server sides of the session in the standard
format of QM release numbers (major.minor-build). If executed before a connection is opened, only
the client revision is returned. If a connection is open, the data returned is a dynamic array with two
values where the first value is the client revision and the second value is the server revision. If the
server pre-dates introduction of this function in release 2.9-0, the server revision will appear as
0.0-0.
As for most functions in the C API that return strings, the calling program should free this memory
using QMFree().
2.11-0
1294 OpenQM
7.45 QMSelect()
The QMSelect function generates a select list containing the ids of all records in a file. It is
analogous to use of the QMBasic SELECT statement.
Format
where
The QMSelect() function constructs a list of record ids which can subsequently be processed using
the QMReadNext() function. Select list 0, the default select list, is used automatically by many
QM components to control their action and should, therefore, be used with caution. An unwanted or
partially processed select list can be cleared using the QMClearSelect function.
See Select lists in QMClient sessions for a description of the alternative ways to handle select list
with QMClient.
The QMSelect() function does not provide any method to select only those records that meet
specific conditions or to sort the list. These features can be accessed by executing query processor
commands using the QMExecute() function.
Examples
VB QMSelect fClients, 1
Do
Id = QMReadNext(1, ErrNo)
If ErrNo <> 0 Then Exit Do
Rec = QMRead(fClients, Id, ErrNo)
If ErrNo = 0 Then Go Sub ProcessRecord
Loop
C QMSelect(fClients, 1);
while((Id = QMReadNext(1)) != NULL)
{
if (Id == NULL) break;
Rec = QMRead(fClients, Id, ErrNo);
if (ErrNo == 0)
{
ProcessRecord();
QMFree(Rec);
}
2.11-0
QMClient API 1295
QMFree(Id);
}
QMBasic session->Select(fClients, 1)
loop
Id = session->ReadNext(1)
until Id = ""
Rec = session->Read(fClients, Id, ErrNo)
If ErrNo = 0 then gosub ProcessRecord
repeat
The above program fragment builds select list 1 and uses it to process records from the file open as
fClients.
Note that the C example uses QMFree() to release dynamically allocated memory areas returned
from QMClient API calls.
2.11-0
1296 OpenQM
7.46 QMSelectIndex
The QMSelectIndex function generates a select list from an alternate key index.
Format
where
The QMSelectIndex function constructs a list of record ids from an entry in an alternate key index.
This list can subsequently be processed using the QMReadNext() function. Select list 0, the default
select list, is used automatically by many QM components to control their action and should,
therefore, be used with caution. An unwanted or partially processed select list can be cleared using
the QMClearSelect function.
See the QMReadList() function for a discussion on different ways to process the select list.
2.11-0
QMClient API 1297
The QMSelectLeft() and QMSelectRight() functions traverse an alternate key index, creating a
select list from the entry to the left or right of the last entry processed.
Format
where
Var is the variable to receive the index key value associated with the returned list.
The QMSelectLeft() and QMSelectRight() functions construct a select list from the alternate key
index entry to the left or right of the one most recently returned by QMSelectIndex(),
QMSelectLeft() or QMSelectRight(). The position of the scan can be set at the extreme left using
QMSetLeft() or at the extreme right using QMSetRight().
These operations allow a program to find a specific value and then walk through successive values
in the sorted data structure that makes up an alternate key index.
If QMSelectIndex() is used to locate a value that does not exist in the index, QMSelectLeft() will
return a list of records for the value immediately before the non-existant one and QMSelectRight()
will return a list of records for the value immediately after the non-existant one.
The QMStatus() function returns zero if the operation is successful, non-zero if it fails because the
index does not exist.
2.11-0
1298 OpenQM
7.48 QMSelectPartial()
The QMSelectPartial function generates a select list containing the ids of all records in a file using
an optimised method for improved performance. It is analogous to use of the QMBasic SELECT
statement.
Format
where
The QMSelectPartial function constructs a list of record ids in the file open as FileNo. The first
part of the select list is returned as a field mark delimited string. Further items can then be returned
by use of the QMNextPartial() function until this returns a null string to indicate that there are no
further record ids available.
See Select lists in QMClient sessions for a description of the alternative ways to handle select list
with QMClient.
Select list 0, the default select list, is used automatically by many QM components to control their
action and should, therefore, be used with caution. An unwanted or partially processed select list
can be cleared using the QMClearSelect function.
The QMSelectPartial() function does not provide any method to select only those records that meet
specific conditions or to sort the list. These features can be accessed by executing query processor
commands using the QMExecute() function.
Examples
VB List = QMSelectPartial(fClients, 1)
While List <> ""
N = QMDcount(List, FM)
For I = 1 To N
Id = QMExtract(List, I, 0, 0)
...processing...
Next I
List = QMNextPartial(1)
Wend
C List = QMSelectPartial(fClients, 1);
While(List != NULL)
2.11-0
QMClient API 1299
{
N = QMDcount(List, FM);
For(I = 1; I <= N; I++)
{
Id = QMExtract(List, I, 0, 0);
...processing...
QMFree(Id);
}
QMFree(List);
List = QMNextPartial(1);
}
QMBasic list = session->SelectPartial(fClients, 1)
loop
while list # ""
for each id in list
...processing...
next id
list = session->NextPartial(1)
repeat
The above program fragment builds select list 1 and uses it to process records from the file open as
fClients.
Note that the C example uses QMFree() to release dynamically allocated memory areas returned
from QMClient API calls.
2.11-0
1300 OpenQM
The QMSetLeft() and QMSetRight() functions set the scanning position of an alternate key index
at the extreme left or right of the data.
Format
where
Var is the variable to receive the index key value associated with the returned list.
The QMSetLeft and QMSetRight functions are used with QMSelectLeft() and QMSelectRight
to set the scan position to the first or last entry in an alternate key index.
The QMStatus() function returns zero if the operation is successful, non-zero if it fails because the
index does not exist.
2.11-0
QMClient API 1301
7.50 QMSetSession()
Format
A single client may open multiple QMClient connections, each identified by a session number. The
QMSetSession() function determines to which session subsequent QMClient function calls relate.
The QMSetSession() function has no equivalent in the QMBasic class module API as each session
is managed by a separate instantiation of the object.
2.11-0
1302 OpenQM
7.51 QMStatus()
The QMStatus() function returns the value of the QMBasic STATUS() function for the last server
function executed.
Format
VB QMStatus() as Long
C int QMStatus(void)
Many server actions set the QMBasic STATUS() value and return it to the client process. The
QMStatus() function retrieves this value. This function does not require passing of a client server
message pair as the value is held on the client system.
2.11-0
QMClient API 1303
7.52 QMTrapCallAbort
The QMTrapCallAbort function enables or disables client side trapping of aborts in QMCall.
Format
where
By default, an abort occurring in a subroutine called using QMCall will display a message box
(VB) or display a message. The QMTrapCallAbort function allows an application to trap the
abort and take its own recovery action.
When call abort trapping is enabled, use of QMStatus() immediately after return from QMCall
will return zero if the call ran successfully or non-zero if an abort occurred. The actual abort
message can be retrieved using QMError().
When call abort trapping is not enabled, the value returned by QMStatus() after QMCall is the
current STATUS() function value on the server.
When operating with multiple server connections from a single client, the state of call abort
trapping applies to all connections
See also:
QMCall
2.11-0
1304 OpenQM
7.53 QMWrite
The QMWrite function writes a record. This is analogous to the QMBasic WRITE statement.
Format
where
The QMWrite function writes the given data to the file opened as FileNo. If a record with this Id
already exists, it is replaced. If the record does not already exist, it is added.
An application should always obtain an update lock on the record before writing it. This function
releases the lock.
When writing a new record to a directory file on a Linux or Unix system, the operating system level
file that represents the QM record is created using the umask value specified by the UMASK
configuration parameter or, if this parameter is not present, a default of 002. This behaviour can be
modified by executing a UMASK command either from the LOGIN paragraph or by using the
QMExecute() function.
Examples
The above program fragment reads a record with an update lock, modifies it and then writes it back
to the file. A real program should test the ErrNo status from the read operations to determine if they
were successful.
2.11-0
QMClient API 1305
Note how the C example uses QMFree() to release the dynamic memory allocated to store Rec and
Rec2.
2.11-0
1306 OpenQM
7.54 QMWriteu
The QMWriteu function writes a record, retaining the lock. This is analogous to the QMBasic
WRITEU statement.
Format
where
The QMWriteu function writes the given data to the file opened as FileNo. If a record with this Id
already exists, it is replaced. If the record does not already exist, it is added.
An application should always obtain an update lock on the record before writing it. The lock is
retained on return from this function.
When writing a new record to a directory file on a Linux or Unix system, the operating system level
file that represents the QM record is created using the umask value specified by the UMASK
configuration parameter or, if this parameter is not present, a default of 002. This behaviour can be
modified by executing a UMASK command either from the LOGIN paragraph or by using the
QMExecute() function.
Examples
The above program fragment reads a record with an update lock, modifies it and then writes it back
to the file, retaining the lock so that the record may be written again later. A real program should
2.11-0
QMClient API 1307
test the ErrNo status from the read operations to determine if they were successful.
Note how the C example uses QMFree() to release the dynamic memory allocated to store Rec and
Rec2.
2.11-0
Part
8
System Administration
1310 OpenQM
8 System Administration
System Configuration
Configuration Parameters Parameter descriptions
UPDATE.LICENCE Apply a new licence
The Terminfo Database Terminal configuration
The qmtic Utility Terminfo compiler
Account Management
Accounts What is an account?
CREATE.ACCOUNT Create an account
DELETE.ACCOUNT Delete an account
The Login Process What happens when a user logs in
System Security
ADMIN.USER User administration
CREATE.USER Create a user
DELETE.USER Delete a user
LIST.USERS List user name details
PASSWORD Password management (Windows 98/ME)
SECURITY Enable, disable or report security settings
Process Management
LISTU Who is logged in?
PSTAT Monitoring processes
LOGOUT Killing a process
2.11-0
System Administration 1311
QM has a number of configuration parameters that determine major settings for the system. These
are stored in a file named qmconfig in the QMSYS account directory. Only system administrators
should have write access to this file. Modifications can be made with the EDIT.CONFIG
command or any text editor such as ED or SED from within QM, Notepad on Windows, or vi on
Linux. Note that copying this file between systems may have unwanted effects as it also contains
other system configuration data.
The file is divided into a number of sections, each with a section title enclosed in square brackets.
The [qm] section configuration parameters described below may be global or private. Global
parameters apply to all users of QM. Private parameters, although initially set to the state defined
in the configuration file, may be updated for an individual process using the CONFIG command.
Private configuration parameters are marked with an asterisk in the table below.
CLIPORT The port for incoming QMClient telnet connections. If not present or
blank the default port 4243 is used.
Setting this port to zero disables incoming QMClient connections.
Take care not to confuse this parameter with the QMCLIENT parameter
in the [qm] section of the qmconfig file.
CMDSTACK * Determines the default size of the command stack. The value must be in
the range 20 to 999 and defaults to 99 if this parameter is not present. If
modified with the CONFIG command, the change affects only the session
in which it is applied.
CODEPAGE * Windows only. Specifies the code page to be used for QMConsole
connections. If omitted, QM uses the default console code page. Note that
a restriction in Windows requires that the console session is set to use
Lucida Console font for this feature to work. This parameter is not
applicable to the PDA version of QM. See Windows Code Pages for more
information.
DEADLOCK If set to 1, QM aborts any program that attempts to wait for a lock that
would result in a deadlock situation. The default value (0) allows
deadlocks to occur. This parameter is not applicable to the PDA version
of QM.
DHCACHE * Determines the size of the dynamic file cache. See Dynamic Files for more
details
DUMPDIR * The pathname of the directory to receive process dump files. If this
parameter is null, the QMSYS directory is used. On some systems, users
may not have write access to this directory. DUMPDIR may be specified
as a full pathname or relative to the account directory.
ERRLOG Sets the maximum size in kilobytes of the error log maintained in the
2.11-0
1312 OpenQM
errlog file in the QMSYS account directory. When the file reaches this
size, the first half of the logged data is discarded. If set to zero, error
logging is disabled. The minimum non-zero value is 10. A lower value
will be treated as 10. This parameter is not applicable to the PDA version
of QM.
EXCLREM * If set to 1, remote files are omitted from ACCOUNT.SAVE unless this
exclusion is over-ridden by other mechanisms within the
ACCOUNT.SAVE command processing. This parameter is not
applicable to the PDA version of QM.
FILERULE * Sets rules for special filename syntax usage. This value is formed by
adding together the following options as required:
1 Allow account:file
2 Allow server:account:file
4 Allow PATH:pathname
The CONFIG command can be used to modify this value within an
individual process but only to remove options. Thus, the setting of this
parameter in the configuration file represents the most powerful set of
filename option rules that can be used.
FIXUSERS Reserves a range of user numbers for exclusive use of users specifying a
fixed user number when logging in using qm -n where n is the required
user number.
The format of this parameter is
FIXUSERS=u,n
where
u is the lowest user number in the reserved range.
n is the number of user numbers to be reserved.
The highest available QM user number is normally 1023. Therefore, the
value of u + n must not exceed 1024.
This feature is provided for compatibility with other environments in
applications that rely on a fixed user numbers to recognise users. It is
recommended that user login names should be used for this purpose in
new applications as this gives a more secure system. This parameter is not
applicable to the PDA version of QM.
2.11-0
System Administration 1313
GRPSIZE * Determines the default group size in units of 1kb used when creating a
dynamic file. This parameter must be in the range 1 - 8 and defaults to 1.
For best performance, it should be a multiple of the operating system disk
block size.
INTPREC * Determines the rounding applied when converting a floating point number
to an integer.
2.11-0
1314 OpenQM
JNLDIR Specifies the pathname of the directory used to store journalling log files.
This directory will be created automatically if it does not exist.
JNLSIZE Sets the approximate maximum size of a journalling log file in Mb. The
default value is 10. The valid range is 1 to 512.
LGNWAIT Sets the maximum period in tenth of a second units for which a process
will wait when attempting to login if the user limit has been reached. This
can be useful, for example, with a web server application where peak
loads could briefly hit the licensed user limit. The delay period can be
retrieved using the QMBasic SYSTEM(1036) function, allowing
applications to monitor the average delay and determine whether a licence
with an increased user count is required.
LPTRHIGH * Determines the default number of lines per page when a print unit is first
referenced. This must be in the range 1 to 32767 and may be overridden
using the SETPTR command or equivalent QMBasic print unit
modification functions. This parameter is not applicable to the PDA
version of QM.
LPTRWIDE * Determines the default number of characters per line when a print unit is
first referenced. This must be in the range 1 to 1000 and may be
overridden using the SETPTR command or equivalent QMBasic print
unit modification functions. This parameter is not applicable to the PDA
version of QM.
MAXCALL * Sets the maximum depth of nested subroutine calls including internal
components of QM such as the command processor. If this limit is
reached due to, for example, a program error resulting in a recursive call
loop, QM will abort the program gracefully rather than failing in
unpredictable ways when it runs out of memory. The value must be in the
range 10 to 1000000 and defaults to 1000. This parameter is not
applicable to the PDA version of QM.
MAXIDLEN Sets the maximum allowed length of a record id. This must be in the range
63 to 255 and defaults to 63. Increasing this value increases the size of the
internal lock tables. It is therefore recommended that the value used
should be consistent with the needs of the application.
QM tracks the length of the longest id ever written to a file. Attempting to
access a file where this exceeds the value of the MAXIDLEN parameter
will cause the operation to fail. The qmfix utility will correct the recorded
longest id value if records have been deleted from the file.
2.11-0
System Administration 1315
MUSTLOCK * Setting this parameter to 1 enforces use of locks when writing or deleting
records. If a program attempts to write or delete a record when it does not
own a record update (READU) lock on the record or a file lock on the file
being updated, the program will abort with error ER$NOLOCK. The ON
ERROR clause can be used to trap this error. Leaving the parameter at
its default value of 0 allows writes or deletes when no lock is in place.
This parameter is not applicable to the PDA version of QM.
NETFILES By default QM does not allow access to files on remote drives. This is
because the locking system cannot detect that two systems are accessing
the file simultaneously. Where it is certain that a file will never be opened
from two systems concurrently, setting this parameter to 1 will enable
access to remote files. Incorrect use of this feature can result in corrupt
data files.
Setting NETFILES to 2 enables incoming connections from other QM
servers accessing files via the QMNet interface.
These two mode settings are additive and can be used together. This
parameter is not applicable to the PDA version of QM.
NUMFILES The maximum number of QM data files that may be opened at one time.
This is a system wide limit. Use of the same file by multiple users counts
as one file. Attempting to open more than this number of files will cause
an application to fail. Setting the parameter significantly too high may
have a small performance impact. The LIST.FILES command can be
used to determine whether the value of this parameter is appropriate.
NUMLOCKS The maximum number of record locks that can be held at one time as a
system wide limit. If the limit is reached, processes attempting to get locks
will wait for space to become available in the lock table. Setting the
parameter significantly too high may have a small performance impact.
The DETAIL option of the LIST.READU command can be used to
determine whether the value of this parameter is appropriate.
OBJECTS * The maximum number of programs which may be loaded into memory
before discard is attempted. A program is a candidate to be discarded
when it is not part of the call stack and it is not referenced from any
subroutine variables from indirect calls. Setting this parameter to zero
implies no limit on the number of concurrently loaded programs.
OPTIONS An additive value affecting the QMSvc service (Windows NT and later),
its predecessor, QMSrvr (Windows 98/ME and USB installations) and
qmlnxd on other platforms formed from:
1 Log client disconnection. There is a very small system overhead
for this but it should be negligible. (QMSvc only)
2 No longer used.
4 Controls socket inheritance. Use only if directed by QM support.
(QMSvc only)
2.11-0
1316 OpenQM
PHANTOMS Defines a fixed range of user numbers that are reserved for phantom
processes started with the USER option to the PHANTOM command.
PHANTOMS= u,n
where u = lowest user number, n = number of user numbers to be
reserved.
PORT The port for incoming client telnet connections. If not present or blank,
the default port 4242 is used. If QM is the only telnet style service used
on the host system, it may be useful to set this to 23, the standard port
used by telnet software.
Setting this port to zero disables incoming telnet client connections. See
also the PORTMAP QM configuration parameter described above.
PORTMAP Allows users to create a fixed mapping between tcp/ip port numbers and
QM user numbers. The format of this parameter is
PORTMAP=p,u,n
where
p is the lowest port number to be mapped.
u is the lowest corresponding user number.
n is the number of ports to be mapped.
The highest QM user number that may be mapped in this way is 1023.
Therefore, the value of u + n must not exceed 1024.
Use of PORTMAP does not prevent users entering QM via the normal
shared port defined by the QMSRVR PORT configuration parameter.
Note that this parameter appears in the QM section of the configuration
file as it relates to both QM and QMSvc.
This feature is provided for compatibility with other environments in
applications that rely on a fixed port number to user number relationship
to recognise users. It is recommended that user login names should be
used for this purpose in new applications as this gives a more secure
system.
This feature is not supported on Windows 98/ME or on the PDA version
of QM.
2.11-0
System Administration 1317
PWDELAY The pause in seconds between successive attempts to enter the user name
and password on network connections. This parameter defaults to 5.
RECCACHE * Sets the size of the record cache (default zero, maximum 32). When a QM
process reads a record, a copy of this record is retained in the cache. A
subsequent read for the same record can find it from the cache rather than
requiring an operating system call. The cache mechanism is most likely to
benefit an application that makes heavy use of the TRANS() function to
read the same record many times during a long query, for example when
looking up a tax rate that is applied to every record processed.
REPLDIR Pathname of directory to be used for replication log files on the publisher
system. This directory will be created automatically when QM is started if
it does not already exist.
REPLPORT Port number on which QM will listen for incoming network connections
from a replication subscriber system. Use of the default port 4244 is
recommended as this is also the default port used by the subscriber.
REPLSIZE Sets the approximate maximum size of a replication log file in Mb. The
default value is 10. The valid range is 1 to 512.
REPLSRVR Server name of a replication subscriber system. This must match the
name used on the publisher when setting up replication.
RETRIES The maximum number of attempts allowed for entry of a valid username
and password on network connections. This parameter defaults to 3.
RINGWAIT * QM uses a ring buffer to hold type-ahead characters received from the
keyboard. If this becomes full, incoming data is thrown away and a bell
character is sent back to the terminal. Some applications may need to
send a large burst of data which would fill the ring buffer and hence be
truncated. Setting the RINGWAIT parameter to 1 causes QM to wait for
space to become available in the buffer rather than rejecting input.
Enabling this feature could result in the inability to use the break key if
the ring buffer is full. The AccuTerm terminal emulator requires this
parameter to be set to 1. (This parameter currently only applies to the
Windows version of QM).
2.11-0
1318 OpenQM
SH * (Not Windows) Determines the shell processor and its options to be used
when the SH command is used to start an interactive shell. If not set, this
parameter defaults to "/bin/bash -i" on Linux, AIX and Mac, and "/bin/sh
-i" on FreeBSD. This parameter is not applicable to the PDA version of
QM.
SH1 * (Not Windows) Determines the shell processor and its options to be used
when the SH command or the QMBasic OS.EXECUTE statement is
used to execute a single command. If not set, this parameter defaults to
"/bin/bash -c" on Linux, FrrBSD and Mac, and "/bin/sh -c" on FreeBSD.
This parameter is not applicable to the PDA version of QM.
SORTMEM * The size in kilobytes at which a sort switches from memory based to disk
based. This value is per user and defaults to 1024 (1Mb). Setting values
lower than this may lead to poorer performance unless you are severely
restricted by memory size. Setting values larger than this will require
more memory for large sorts.
SORTMRG * A disk based sort produces a series of intermediate files that must be
merged to produce the final result. The SORTMRG parameter specifies
the number of files merged in each pass. This must be in the range 2 to 10
and defaults to 4. The effect of changes to this parameter on sort times is
dependant on the relative performance of the disk and processor.
SORTWORK * The pathname of the directory to hold temporary sort workfiles. These are
automatically deleted on normal completion of a sort. If this parameter is
null or the specified directory does not exist, the directory defined by the
TEMPDIR parameter is used. This parameter is not applicable to the
PDA version of QM.
SPOOLER * Sets the name of the default spooler on non-Windows platforms. If this
parameter is not specified or is a null string, the lp spooler is used. The
2.11-0
System Administration 1319
name specific may be another standard spooler (e.g. lpr) or a user written
program or shell script to perform custom print management.
The qualifying data to this configuration parameter can include other
options to be passed to the selected spooler. This parameter is not
applicable to the PDA version of QM.
See the description of the $SPOOLER control record in the section on
printing.
SRVRLOG Sets the maximum size of the log file (QMSvc only). A value of zero
causes QMSvc to start a new log each time the service is started, saving
the previous log as QMSvcLog.old. A non-zero value sets the maximum
size of the QMSvc.log file in kb. When this size is reached, the first half
of the data in the file is removed.
STARTUP Sets a command to be executed when QM starts. This may not contain
double quotes. This parameter is not applicable to the PDA version of
QM.
See Startup for more details.
TEMPDIR * The pathname of the directory to hold temporary files. These are normally
automatically deleted when no longer required but it is recommended that
this parameter points to a directory that is cleared on restart of the system
so that any files left behind at a system failure will be deleted. If this
parameter is null or the specified directory does not exist, QM uses the
TEMP subdirectory of the QMSYS account on Windows or the operating
system temporary directory on other platforms. This parameter is not
applicable to the PDA version of QM.
TERMINFO * The pathname of the directory holding the terminfo database. This
defaults to a subdirectory named terminfo under the QMSYS directory.
This parameter is not applicable to the PDA version of QM.
TIMEOUT The maximum wait period in seconds allowed during entry of a valid
username and password on QMSvc connections. This parameter defaults
to 30.
TIMEZONE * The time zone to be used by the epoch conversion code. The value of this
parameter must match the format required for the operating system TZ
environment variable. The default value is taken from the TZ environment
variable on entering QM. If this variable is not defined, the time zone of
the process that started QM is used.
TXCHAR * Windows only. Determines whether QM uses the OEM character set
translation functions on terminal i/o. The default value is 1 (use
translation). A value of zero disables translation.
UMASK Linux and Unix only. Sets the default umask value for network
connections to QM that do not enter via the operating system shell (direct
telnet, QMClient, QMNet). The mask is specified as an octal value as in
the operating system umask command. If this parameter is not present, a
default of 002 is used.
USERPOOL Determines the maximum user number that will be allocated by QM,
2.11-0
1320 OpenQM
default value 1023, maximum 16383. The actual maximum user number
will be the greater of the value of this parameter and the number of
simultaneous processes permitted by the licence.
YEARBASE * The earliest year in the 100 year range of dates entered with two digit year
numbers. This parameter is optional and defaults to 1930.
2.11-0
System Administration 1321
Control sequences and other characteristics of terminal devices are defined in the terminfo database.
This is normally a subdirectory structure under the QMSYS account but can be moved elsewhere if
required by use of the TERMINFO configuration parameter. The structure of the terminfo database
closely mimics that found as a standard component on Linux and other operating systems though
QM has some private extensions to the internal library format.
The terminfo directory contains a set of subdirectories named using the first character of the
terminal types stored within them. Each of these directories then contains a file for each terminal
type. Thus, for example, the definition for a vt100 terminal on a Windows system with the default
QMSYS location would be found in c:\qmsys\terminfo\v\vt100.
The definition files are stored in an encoded form that closely reflects the way in which QM uses the
data internally. QM provides a utility, qmtic, to compile or decompile terminfo entries.
A master source for a variety of terminals is in the QMSYS account directory as terminfo.src and
the entire set of definitions is compiled when QM is installed. To simplify maintenance of a private
set of new or modified terminal definitions, the QM installation process will look for a file named
terminfo.mods in the QMSYS account directory and, if it exists, will compile it after the standard
source, allowing new entries to be added or standard entries to be modified.
Linux users wishing to transfer entries from the standard Linux terminfo database to the QM
terminfo database should use the Linux infocmp tool to decompile the Linux definition and then
recompile it using qmtic, removing any entries that are not supported on QM.
Source Format
Terminfo entries contain three types of item; booleans, numbers and strings.
A boolean item is present in the terminfo entry if the feature or capability that it represents is
supported by the terminal. QM currently does not make use of any of the boolean items.
A number entry holds the value of a numeric parameter. For example, the cols item defines the
normal number of columns per line.
A string item holds a control string. These may be codes to be sent to the terminal to perform a
specific task such as clearing the screen or moving the cursor, or may be a code sent by the terminal
when a specific key is pressed by the user. Strings representing commands sent to the terminal
device often include parameterised information such as screen positions or counts.
A terminfo source file consists of one or more terminal definitions separated by at least one blank
line. Lines commencing with a hash character (#) are comments and are totally ignored during
compilation. Each definition consists of a number of comma separated items. A definition can be
split over multiple lines by inserting a newline after a comma.
The first line of each entry contains a list of terminal types defined by that entry and a text
description. For example:
2.11-0
1322 OpenQM
The remaining lines of the entry define the characteristics of the device. Although the order is not
fixed, terminfo entries normally have the booleans first, followed by the numbers, followed by the
strings.
A boolean entry consists only of its name. A number consists of the name, a hash character, and the
value of the parameter. A string consists of the name, an equals character (=), and the value of the
parameter. For example, the first few lines of the vt100 definition are:
vt100|vt100-am|dec vt100 (w/advanced video),
am, xenl, msgr, xon,
cols#80, it#8, lines#24, vt#3,
bel=^G, cr=\r, csr=\E[%i%p1%d;%p2%dr, tbc=\E[3g,
clear=\E[H\E[J$<50>, el=\E[K$<3>, ed=\E[J$<50>,
cup=\E[%i%p1%d;%p2%dH$<5>, cud1=\n, home=\E[H,
The %x parameter notation performs run time manipulation of the character string, often inserting
parameter values. These operations use a stack for intermediate results and are described in terms
of their C programming language equivalents:
2.11-0
System Administration 1323
For those of the above operators which are binary and not commutative, the stack works in the
usual way, with
%gx %gy %m
resulting in x mod y, not the reverse.
For example, the QMBasic @(col,row) function translates to the cup (cursor position) terminfo
entry. For the vt100 definition shown above this is
cup=\E[%i%p1%d;%p2%dH$<5>
Taking this apart, element by element for a usage as @(10,5):
\E Escape character
[ [ character
%i Increment both arguments to allow for positions numbered from 1 rather than 0. The
argument values 10 and 5 thus become 11 and 6.
%p1 Push parameter 1 (11) onto the stack
%d Print top item from stack as an integer
; ; character
%p2 Push parameter 2 (6) onto the stack
%d Print top item from stack as an integer
H H character
$<5> Delay - Ignored by QM.
Colour Mapping
Different terminal emulators use variations on the numeric values used to represent colours (see the
QMBasic @(-37) and @(-38) functions). To enable users to employ a consistent set of colour
values in application programs whilst working with different terminal emulators, the terminfo
definition may include an optional element named colourmap (British spelling) that provides a
2.11-0
1324 OpenQM
translation between internal colour values and the actual colour number transmitted to the terminal.
The format of this entry is
colourmap=0|1|2|3|7|5|6|4|8|9|10|11|12|13|14|15
where the elements correspond to internal colour values zero upwards and the number in each
element is the colour value to be sent to the terminal. In this example, colours 4 and 7 have been
swapped.
Colours for which the value is not to be changed may be left blank and trailing unchanged values
may be omitted. Thus, the above example could be shortened to
colourmap=||||7|||4
The terminfo database includes 10 entries (u0 to u9) for user use. QM pre-defines the function of
two of these, the remaining eight are available for any purpose that the user wishes.
u0 - u7 @(-100) to Undefined. Users may adopt these for any purpose.
@(-107)
The u8 code is used internally by some parts of QM. The remaining codes will only be used as
defined in user written application software.
AccuTerm Extensions
The AccuTerm terminal emulator includes support for additional special functions that are not part
of the standard terminal definitions for industry standard terminal types. These extra functions
include
Client side command execution (synchronous and asynchronous)
Screen region save and restore (used by the QMBasic debugger)
Mouse click detection
QM ships with extended definitions for some devices using terminal type names with a -at suffix
(e.g. vt100-at). Users can easily add similar extensions to other terminal definitions.
2.11-0
System Administration 1325
The qmtic tool can be used to compile new terminal definitions or to decompile existing ones.
Although it is possible to store separate source definitions of each terminal type, QM includes a
single master source file, terminfo.src, in the QMSYS directory. To simplify maintenance of a
private set of new or modified terminal definitions, the QM installation process will look for a file
named terminfo.mods in the QMSYS account directory and, if it exists, will compile it after the
standard source.
where
where
Replacing the -d option with -dall will decompile all terminfo entries to produce a new master
source file.
The format of the qmtic command to display an index of terminal types is:
qmtic {options} -i
The PDA version of QM does not support qmtic as there is no concept of a command line from
which to run it. Instead, there is a QMBasic version of a simple terminfo compiler that is run when
QM is installed to compile the terminfo.src and, if present, the terminfo.mods files. This can also be
2.11-0
1326 OpenQM
run at any time by using the TIC command in the QMSYS account.
2.11-0
System Administration 1327
Within Windows QMConsole sessions, single-byte characters are displayed as defined by the
current codepage. The default page is set by Windows based on your regional settings but it can be
changed at any time from the QM command prompt, within a paragraph, or by EXECUTE within
a Basic program by updating the CODEPAGE private configuration parameter or by use of the
PTERM command.
Use of code pages allows language localisation. Single-byte characters in the range 127 – 255 are
mapped to accented letters (such as é and õ), special characters (such as ç and ß), and symbols
(such as the Euro and Trademark signs). There are not enough single-byte characters for all the
languages of the world, so different mappings have been set up for different regions. Microsoft calls
these mappings code pages.
Word processing software, such as Notepad, handle the choice of code page through the choice of
font. Fonts have been built for many languages, some provided with Windows, others available for
download from Internet sites. Choose the correct font, and the special characters will display as
needed.
This method cannot be used by software such as QM which runs as a Windows console process
either directly or via the Windows command prompt. Within processes run in this way, there is just
one font (Lucida console) available for use with multiple languages. The characters displayed are
determined by which code page has been made current. Any given installation of Windows has a
default code page, and several other code pages available. More Information can be found on
Internet sites that specialise in language issues.
Note that this controls character display within QM – how characters appear at the command
prompt, in LIST output, within ED and SED, etc. A file written by a QM program, when viewed in
a Windows application such as Notepad or Excel, will show the characters as seen by that
Windows application.
Code pages are identified by numbers, usually of 3 or 4 digits. The codepage used by QM can be
controlled by use of the CODEPAGE configuration parameter. Setting a value for this parameter in
the QM configuration file will determine the default page used. This can be changed within a
session by use of CONFIG or PTERM.
To find out whether your copy of Windows has a particular code page available, go into the
command prompt and enter “chcp codepage”. This will return an error message if codepage is not
available.
To view the page in use by a QM session, execute either of the following commands:
2.11-0
1328 OpenQM
PTERM DISPLAY
PTERM CODEPAGE
To change the code page in a QM session, execute either of the following commands:
CONFIG CODEPAGE page
PTERM CODEPAGE page
Use of some code pages may also require the TXCHAR configuration parameter to be set
appropriately. This parameter controls whether QM uses the OEM character translation modes of
Windows. It defaults to 1 (use translation) but can be turned off for the current process using the
CONFIG command or for all processes by setting parameter to zero in the configuration file.
If there is a need to display special characters that are not supported by any of the available code
pages, it is possible to modify the Lucida Console font to display them. This can be done by the
following steps:
· Obtain a font editor from a supplier who specializes in font support. The font editor needs to
have the ability to associate the graphic form of a character - called its "glyph" - with the
byte that is to represent that character - called its "mapping". We have successfully used a
shareware product called FontCreator.
· Find the existing Lucida Console font, which a file, probably named "lucon.ttf", located in
the Fonts folder. The font name is one of the data items within the font file, so is distinct from
the name of the file. Windows can see the file as Lucida Console, even though it may have
been given another file name.
· Copy the original file to another folder, to keep a backup in case something goes wrong with
any of the rest of these stops. Then copy it to another file name, such as "myfont.ttf".
· Look in the character mapping of "myfont.ttf" for characters that are not needed. The "per
thousands" sign, dagger, and double dagger are possible examples.
· Using the font editor, replace the glyphs of the characters that are not needed with the glyphs
of the characters that are needed.
· Test "myfont.ttf" by copying it into the Fonts folder. Then go into QM Console, do LIST,
ED, etc, to confirm that characters display correctly. Any Windows software that gives a
choice of fonts should display the same way when Lucida Console is specified. This would
include Notepad, word processing, and spreadsheet products.
Like any other software, the font needs to be carefully backed up, and shared with whatever users
may need it. Fonts are subject to copyright, so property rights must be respected. It may be
necessary to get legal advice.
2.11-0
System Administration 1329
User Registration
QM includes an internal security system that imposes restrictions such that a user can only access
QM if their user name is registered using the CREATE.USER or ADMIN.USER command.
Users who are system administrators within the underlying operating system are not restricted.
When installing a new QM system, the installer will ask whether the security system is to be
enabled. This choice may be amended later using the SECURITY command.
On systems running Windows 98/ME, the underlying operating system does not have adequate user
authentication. If security is enabled, users entering QM over a direct network connection will be
required to enter a valid username and password that is private to the QM environment and is
created using the CREATE.USER or ADMIN.USER commands. If security is not enabled,
network users can connect directly to QM with no authentication. Entry to QM from the operating
system command prompt or by use of the QMConsole menu item is unrestricted.
On later versions of Windows and on other platforms, users entering QM directly from a network
will always be required to enter a valid username and password known to the operating system.
Furthermore, if security is enabled, this username must also be in QM's own register of usernames.
If there is no entry in the user register for the user, the system looks for an entry for DEFAULT
(case sensitive) and, if found, uses this to define the user's rights. Entry to QM from the operating
system command prompt (or the QMConsole menu option on Windows) will be validated against
the username used to log into the operating system. If security is not enabled, any user with a valid
operating system username will be able to enter QM.
A user can be assigned to a QM user group. User groups are much like operating system groups
found in Linux but are a totally separate internal system. The group name of a QM process can be
found using the @QM.GROUP variable.
The details set for a user via ADMIN.USER also include options to enable or disabled specific
features of QM that may have a bearing on system security. These are:
Create/delete accounts Controls use of CREATE.ACCOUNT, DELETE.ACCOUNT
and entering QM in a directory that is not already set up as an
account.
Define private servers Controls use of SET.PRIVATE.SERVER.
A user register entry will be created automatically for a user entering QM on a system with security
disabled who does not already appear in the user register. This entry will have all features
controlled by security options enabled.
Account Restrictions
QM provides the ability for restrictions to be placed on which accounts a user may go into. The
ADMIN.USER command can be used for each defined user name to create a list of accounts that is
either those accounts that the user may access or those accounts that the user may not access. This
mechanism is only meaningful when user level security is active (see the SECURITY command).
Users with administrator rights are not subject to account restrictions.
2.11-0
1330 OpenQM
Application Security
A well designed application never allows an end user to reach a command prompt. This leaves
restriction of what a user may do within the control of the application itself. Where it is necessary to
provide differing levels of access to different users, QM provides several ways to identify attributes
of the current user:
@IP.ADDR User's IP address for network connections. This is also available in
QMBasic as SYSTEM(42).
@LOGNAME User's login name.
@TTY Terminal device name.
SYSTEM(1017) Port number for network connection.
SYSTEM(27 to 30) UID, effective UID, GID and effective GID (not Windows)
A user could potentially escape from the controlled environment provided by the application if the
application were to abort. This can be avoided by a combination of the following techniques:
Disable the break key. The break key is automatically disabled until completion of the LOGIN
paragraph unless it is enabled within that paragraph by use of the BREAK ON command.
There should never be a need for use of the break key in a working application. In the unlikely
event of needing to re-enable it for a specific user as a result of an application fault, the system
administrator can use an extended form of the BREAK command to do this.
Use OPTION NO.USER.ABORTS to suppress all options through which a user can cause an
abort to occur. This removes the A option from the "Press return to continue" prompt, the query
processor pagination prompt and the break key options.
Implement the ON.ABORT paragraph. Despite the above techniques, an application may still
abort as a result of a run time error or use of the ABORT statement within the application
itself. When an abort occurs, QM discards all programs, menus, paragraphs, etc that are
running in the process and returns to the lowest level command processor. Before this displays
the command prompt, it checks in the VOC file for an executable item named ON.ABORT and,
2.11-0
System Administration 1331
if this is found, executes it. A typical ON.ABORT paragraph terminates the user's session after,
perhaps, logging the incident.
Some users such as application developers may need to be able to reach a command prompt. In this
case, security subroutines can be attached to R or V-type VOC entries to provide control over what
can be done.
See also:
Permissions
2.11-0
1332 OpenQM
8.5 Permissions
QM uses the underlying operating system to manage processes, files, devices, etc. Therefore, all
issues of access permissions ultimately lie with the operating system. This section gives some
guidance on setting permissions within a QM system but individual application needs should be
taken into account.
The only users who should be working in the QMSYS account are system administrators. It is
reasonable that these people should have write access to QMSYS. No other user ever needs to
create an item in the QMSYS directory itself. Therefore the directory can be protected so that only
administrators can write to it.
System administrators need write access to all items in the QMSYS account. The following table
sets out the additional access rights needed for other users.
Developers Others
2.11-0
System Administration 1333
Developers Others
ERRMSG Pick style error message file Read (note 4) Read (note 4)
1. Write access to $MAP is only needed by users who execute the MAP command to create a
catalogue map with the default destination file name.
2. Any user who is to be allowed to create new accounts will need write access to this file.
Restricting write access on this file closes a potential security risk by preventing users
creating synonyms to existing accounts that might subvert application level security
mechanisms.
3. If error logging is enabled (see the ERRLOG configuration parameter), all users need full
2.11-0
1334 OpenQM
access to the optional errlog file. Any user that does not have write access will not log
errors.
4. This file contains standard Pick style messages. Although rare, some applications may
write to this file.
5. It is possible to restrict access to individual items in the gcat subdirectory. Users need read
access (not execute access) to run a compiled QMBasic program.
Application Accounts
In general, users should have free access to all files. Taking write access away on the VOC can be
used to prevent users modifying its content but beware that some applications modify the VOC as
part of their normal operation.
See also:
Application level security
2.11-0
System Administration 1335
QM does not provide any special backup and restore utilities but relies instead on use of standard
operating system level backup tools. This section sets out some points to consider in planning a
backup strategy. Hopefully, you have already thought of these...
· Determine what to backup. If your backup needs to be as quick as possible, remember that
it is usually unnecessary to back up system files that can easily be recreated.
· Do not forget that distributed applications sometimes have critical data stored on client
PCs. These need to be backed up at the same time as the server to preserve data integrity
across the entire backup.
· How often will you back up? You need to make a sensible trade-off between the time it
takes to backup and the difficulty of bringing the system up to date in the event of a restore.
· Consider when to backup in relation to your business routine. It is unsafe to backup a
database while it is being used except as described below. You will end up with data
integrity problems and, possibly, structural integrity problems in files that were being
modified while the backup progressed. The safest approach is to log all users off while the
backup is performed. It is not necessary to shutdown QM.
· Use a cycle of backup media rather than continuously overwriting the same media so that
you are secure from failures during the backup and also have multiple points in time to
which you can revert.
· Ensure that your backup media is kept away from the system that it represents. A fireproof
safe or an offsite store is best.
· Think carefully about how long you will keep your backups. There are often legal
requirements to be able to restore business data for several years. Remember that
technology moves on at a rapid pace. You need to ensure that you still have the appropriate
drives to read your old backups.
· Test your backups. Check that you really can restore your data if the need arises.
Backup Tools
Because individual records in hashed files cannot be accessed from outside of QM, operating
system level backup tools can only save and restore an entire file. The T.DUMP command can take
a select list specifying the records to be saved.
Live Backup
Sometimes there is no alternative to backing up a system while users are logged in. As mentioned
above, simply copying the database files while they are being updated will almost certainly lead to
inconsistent data, perhaps with structural problems that make restore impossible.
QM provides the ability to suspend database updates by use of qm -suspend from the operating
2.11-0
1336 OpenQM
system command prompt. When this mode is in effect, applications will pause at any attempt to
modify a file until updates are enabled using qm -resume.
It is also possible to prevent users logging in new sessions by use of the INHIBIT.LOGIN
command. This does not logout other users who are already active. While login is inhibited, no new
QM processes can start with the exception of phantoms started by the user that set the login inhibit.
Rather than pausing the database for the duration of a full backup, various mechanisms are
available to minimise the time for which updates are suspended. If using mirrored disks, it would be
possible to suspend updates, break the mirror, resume updates, backup the offline half of the
mirrored data and then reconnect the mirror to catch up with changes during the backup.
Some environments provide snapshot backup systems where updates can be suspended, the
snapshot initiated and updates resumed. The actual backup process performed by the snapshot will
handle the complexities of database updates that occur during the backup.
Regardless of the technique used, beware that suspending updates will ensure structural integrity of
the saved files but will not ensure business level data integrity as the suspension may occur part
way through a series of related updates. Use of transaction programming techniques will help as the
suspension will occur on committal of the transaction but it is still possible that a business level
transaction is formed from multiple database transactions.
Where backup is performed by copying QM data files to an alternative location, a VOC pointer can
be created for any file in the backup copy just as though it was part of the local data. This can then
be used to recover specific records simply by copying them with the COPY command.
2.11-0
System Administration 1337
QM provides several tools to aid System Administrators in monitoring the system and locating
problems.
LIST.FILES Shows the names of all files currently open in the system. This command can
also help in determining the optimum value for the NUMFILES configuration
parameter.
LIST.READU Lists all active record and file locks. Includes a report of who is waiting for
locks. The DETAIL option to this command can also help in determining the
optimum value for the NUMLOCKS configuration parameter.
PSTAT Displays process status information including the command or program being
executed.
HSM More useful for programmers than administrators, the HSM (hot spot monitor)
command shows the processing time spent in each module of an application.
Releasing Locks
Sometimes a QM process may fail to release a lock. In most cases, QM will tidy up automatically if
the program or process terminates but there may be times when it is necessary to release a lock
manually.
Be careful to consider the implications before releasing a lock. The lock was taken to protect
something from simultaneous update. Releasing a lock always carries the risk of data integrity
problems.
Record, file locks and process synchronisation (task) locks can be released with the UNLOCK
command. This command can only be executed from the QMSYS account and requires
administrator rights.
Terminating QM Sessions
A System Administrator can terminate a QM session using the LOGOUT command. Also, the qm
command has a three special options that may be of use to System Administrators.
QM will attempt to tidy up, releasing any resources owned by the terminated process. Note that
2.11-0
1338 OpenQM
terminating a process carries the risk of data integrity problems if the termination occurs in the
middle of an update that affects multiple files.
The Windows Task Manager or the kill command on other platforms with signal number 9 (kill -9)
should only be used as a last resort if LOGOUT fails to kill the process. QM cannot catch this
event and hence cannot free resources assigned to the terminated process. If this style of process
termination is used while a QM process is updating a file, loss of data could occur.
Lost Processes
QM periodically compares its internal user table with the processes that are running at the operating
system level. If any process registered within QM is no longer running, it must have terminated
abnormally. An automated cleanup mechanism will remove the user from the internal table,
releasing any locks that were held by that process. This automated scan occurs at an interval set
with the CLEANUP configuration parameter, defaulting to once every five minutes if this
parameter is not used. Setting the interval to a very low value can impact performance.
The RECOVER.USERS command can be used from within the QMSYS account to perform a
similar cleanup manually. The same effect can be achieved using
qm -cleanup
from the operating system command prompt.
2.11-0
System Administration 1339
QM includes support for text message output in multiple languages. The standard message library
installed with QM contains English messages texts. Additional language libraries may be available
from Ladybridge Systems or from QM dealers. Users can also perform their own translations of the
source text downloaded from the product web site.
The message text source file includes comment lines detailing the rules for successful translation. It
is highly recommended that users should use the two letter international country code as the
language identifier in the PREFIX line (e.g. FR for French).
2.11-0
1340 OpenQM
QM includes an error logging system that records brief details of errors that may require
investigation by system administrators or application developers. These include:
· Run time program errors (e.g. unassigned variables)
· User authentication errors (failed logins)
· Forced logout
· Internal file system errors
The error log is maintained in a text file named errlog in the QMSYS directory. Although it can be
written directly by programs using the sequential file processing statements, this should be avoided
as the buffering used by these statements may result in lost messages. Application developers
should use the QMBasic LOGMSG statement or the LOGMSG command if they wish to add their
own messages to the log file.
To avoid faulty programs generating very large log files and to remove the need for file
maintenance, the ERRLOG configuration parameter sets the maximum size in kilobytes to which
the error log file may grow. When this size is reached, the first half of the data in the file is
discarded. The minimum acceptable non-zero value of the ERRLOG configuration parameter is
10. A smaller value will be treated as 10. Setting the ERRLOG parameter to zero disables error
logging.
Each log message consists of two or more lines of text. The first gives the date and time in the time
zone of the user that started QM, the QM user number, process id, login name and account name of
the user generating the error. The second line gives the actual message, indented by three spaces to
make the file more readable. Further lines may be present, also indented by three columns. This
format is easy to process using user written tools if required.
2.11-0
System Administration 1341
The QM executable stored in the bin subdirectory of the QMSYS account has a number of
command line options. The command option letters shown below are all case insensitive. Note that
to comply with Linux conventions, some of the options have a double hyphen prefix.
-n Logs the user in as user n where the value of n must be in the range of user
numbers reserved with the FIXUSERS configuration parameter. If there is
already a user logged in with this user number, the login fails. If the value of n
is not within the reserved range, the parameter is ignored.
-Aname Enters account name unless there is a fixed account name defined for the user
name of the user entering QM. Note that there is no space before the account
name.
-DL Initiate device licensing negotiation for entry to QM from the operating system
command prompt.
-CLEANUP Scans QM's internal list of users to identify any processes that have terminated
abnormally and, if found, tidies up from the lost process.
-QUIET Suppresses display of release information, etc on entry to QM. Useful in some
scripted sessions.
-STDOUT (Windows only) QM normally uses the Windows console APIs to output data
to the screen. This option causes it to use the stdout file handle and is of use
when capturing the output or piping it into other processes. It should not be
used for normal terminal output as some display features may not work with
this option.
2.11-0
1342 OpenQM
-TERM xxx Sets the initial terminal type. This may be changed later from within the
application. If this option is not used, QM defaults to the value of the operating
system TERM environment variable or, if this is not defined, vt100.
It is also possible to execute a QM command directly from the operating system command prompt
by appending it to the start up of the QM session, after any other command options. For example:
qm RUN OVERNIGHT
Note that quotes may be needed if the QM command contains any characters with special meaning
to the operating system. Use of QM in this way can be detected by use of the SYSTEM(1026)
function that will return the command (e.g. RUN OVERNIGHT in the above example).
Environment Variables
QMDL If defined, entry to QM from the operating system command prompt behaves
as though the -DL option had been used.
QMSYS Normally the location of the QMSYS directory is derived from the pathname
of the QM executable as this is installed in the bin subdirectory of the QMSYS
account. Specifies alternative default location for QMSYS account directory.
Also used by QMConnectLocal() if a non-default location is used.
2.11-0
System Administration 1343
The QM file system is designed to be robust, however, there are situations when power failures,
hardware failures or abnormal termination of a process might lead to structural integrity problems
within a file.
The qmfix utility can be used to check the structural integrity of a file and, if an error is detected,
then apply an automated correction. Although qmfix should always result in the file being usable,
there are error situations where data will be lost because it simply was not in the file.
To use qmfix, firstly ensure that no users have the file(s) to be processed open. It is safest to run
qmfix when no users are using QM. The qmfix utility is run from the operating system command
prompt, not from within QM. The command line is
qmfix options pathname
where
options are case insensitive option codes from the following set:
-B Suppresses progress bar display. This can be of use when capturing
the output for later review as repainting of the progress bars may make
the captured data less easy to read.
-C Check file for errors (implied if B, F, Q and R options all absent)
-F Fix errors without querying
-L Log the screen output in qmfix.log
-Lpath Log the screen output in path
-N Suppresses pagination of displayed output
-Q Query before fixing errors
-R Recover space from unused primary and overflow blocks. Occasional
use of this function may improve performance of some large files.
pathname is the pathname of the file to be processed. This may be a list of may include
wildcard characters. qmfix will ignore names that do not correspond to QM files.
Thus, to check all files in a directory, simply type
qmfix *
Do not run qmfix with the -F option without running it to check for errors first.
Note that qmfix may report that a dynamic has an incorrect load value or record count if the file
was not closed properly at a system failure. These errors are unlikely to cause any serious problems
and will be corrected by qmfix if the -F option is used and automatically by select operations that
complete without any intervening file updates.
No automated error recovery tool can ever be 100% accurate in its decisions about the nature of
errors so there is a very small risk that qmfix could make the situation worse. Always backup a file
before fixing any errors in it.
Ladybridge Systems aim to provide software of the highest quality. We would be very interested to
receive copies of any files that are reported as faulty by qmfix so that we can investigate the cause
and improve the resilience of the QM product.
2.11-0
1344 OpenQM
The QM file system supports alternate key indices for retrieval of data based on the content of a
non-key field. Normally, these indices reside in the directory that represents the data file. This helps
to ensure that the entire file and its indices are handled as one object when performing backup and
restore operations
Sometimes it may be useful to place the indices elsewhere. This could be to improve load balancing
across multiple disk drives or to simplify exclusion of large indices from backups since they can
always be recreated from the data file. This separation of the indices from the data can be achieved
using the PATHNAME option of the CREATE.INDEX or MAKE.INDEX commands when the
first index is created.
The qmidx program is an operating system level command that allows users to report or modify the
location of the indices. It has four modes of operation:
qmidx -m data.path index.path Moves the indices for the named file to the new location
specified by index.path. If the index path is omitted, the
indices are returned to their default location in the
directory identified by data.path.
qmidx -p data.path index.path Sets the index path for the given data file. This operation
is required after use of an operating system level tool to
copy or move a data file to a new location. Failure to
perform this step when duplicating a file may result in
any changes to the copied file updating the indices of
the original file.
qmidx -q data.path Queries the location of the indices for the given data file.
This program must only be used when the file is not in use. Failure to adhere to this rule may
lead to data corruption or process failure.
2.11-0
System Administration 1345
QM hashed files and QMBasic object code are sensitive to the byte ordering of the system on which
they are used. If a file or program is moved from a system with one byte ordering to a system of the
opposite byte ordering, the qmconv utility can be used to update the file or program.
This tool is run from the operating system command prompt. The command line is
qmconv options pathname(s)
where
options are case insensitive option codes from the following set:
-B Convert to "big-endian" format.
-L Convert to "little-endian" format.
pathname is the pathname of the file to be processed. Multiple pathnames may be given and
wildcards may be used. qmconv will ignore names that do not correspond to QM
files.
If neither mode option is given, the file is converted to the byte ordering of the system on which the
command is run.
2.11-0
Part
9
System Limits
1348 OpenQM
9 System Limits
Maximum floating point value IEEE 64 bit representation. Upper limit 21024.
Maximum number of public names in a CLASS module 32767
Maximum size of a program for debugging 65535 lines
2.11-0
Part
10
Glossary of Terms
1350 OpenQM
10 Glossary of Terms
2.11-0
Glossary of Terms 1351
Conversion code A code describing how data must be transformed from its internal
representation within the database before displaying it to a user. For
example, dates are usually stored internally as the number of days since 31
December 1967.
Correlative A rather limited equivalent to I-type dictionary items supported by QM in
A and S-type items to simplify migration from other multivalue database
products.
Database A collection of data stored in a form that enables easy access to specific
items.
Debugger A development tool for debugging QMBasic programs.
Device licensing An option that allows multiple connections to QM from a single client to
share a licence.
Dictionary A secondary component attached to most database files that contains a
description of the format of records stored in the file and default settings
controlling how the query processor will display this data.
Directory files A simple file structure that makes use of the underlying operating system's
files to represent database records. Directory files do not offer high
performance but can be accessed from outside QM and are therefore
frequently used to exchange data with other software.
Distributed file A view of a set of separate dynamic files as though they were a single file.
Dynamic array A character string divided into fields, values and subvalues using the mark
characters. A database record is stored in this way but dynamic arrays can
be used by application developers for other lists of items.
Dynamic file A type of hashed file that automatically changes its modulus value to react
to changes in the volume of data stored.
Epoch value A representation of a moment in time in a time zone independent manner.
errlog An error log file in the QMSYS account. QM writes entries to this log
whenever an error is detected. Applications can also write to the log using
the QMBasic LOGMSG statement.
Field A column from the tabular representation of a database file.
File A database table. QM supports hashed files for high performance and
directory files for data exchange.
Format code A code describing the way in which a data item is to be displayed or
printed specifying, for example, the number of characters and justification.
Group A portion of a hashed file. The number of groups in a file varies
automatically according to the volume of data stored in it.
Group size The size of a group in multiples of 1024 bytes. QM allows group size
values in the range 1 to 8.
Hashed files High performance files in which the location of a record is calculated by
applying the hashing algorithm.
Hashing algorithm A mathematical calculation applied to the characters of a record key to
deduce the group in which that record will be stored.
Hot Spot Monitor A tool for identifying the number of times each module of an application is
executed and the processing time spent in them.
2.11-0
1352 OpenQM
2.11-0
Glossary of Terms 1353
Partitioning algorithm A dictionary I-type expression used to transform the record id to a part
number in a distributed file.
Phantom A QM process that runs in the background without a terminal. Phantom
processes are started with the PHANTOM command and store a copy of
all output that would normally have been displayed on the terminal in the
$COMO file.
Phrase A part of a sentence, excluding the verb. Phrase entries may appear in the
VOC or in dictionaries. Phrases are used as short forms in commands, to
set defaults for the query processor, and to link fields within an
association.
Pick style A reference to the command and programming language style found in the
Pick multivalue database product and others that adopt this style. (The
first multivalue database environment was created by Dick Pick).
Primary key A character string that uniquely identifies a record in a file. QM supports
keys from 1 to 255 characters in length but lengths over 63 characters
require the MAXIDLEN configuration parameter to be amended.
Proc The predecessor of paragraphs found in other multivalue database
products and supported in QM for ease of migration. Development of new
Procs is discouraged.
Process dump file A text file optionally generated at a run time application error. This file
contains a full report on the state of the application at the time of the error.
Publisher The system that is exporting file updates in a system configured for data
replication.
QMBasic The programming language used to develop QM applications.
QMClient An interface that allows access to QM from other languages such as
Visual Basic or C.
QMFix A tool for checking the internal structure of QM files after a system crash.
QMIdx A tool for updating internal pointers if an alternate key index file is
moved.
qmlnxd A daemon process that runs on non-Windows system to perform
background system monitoring tasks.
QMNet An integrated component of QM that allows access to data stored on
another QM server with full support for locking.
Record An item stored in a database file. The file system accesses data at the
record level. Interpretation and manipulation of the content of the record is
up to the application and related system tools. A record is usually formed
from multiple fields which may in turn be broken down into values and
subvalues.
Relational Database A style of database that represents data in the form of tables (relations).
Replication A mechanism whereby updates made to files on a publisher system are
replicated on one or more subscriber systems.
Secondary key A data item in a record, or a value calculated from data in the record, that
is to be used to construct an alternate key index so that records can be
selected based on this value.
Select list A list of items, usually primary keys, to be processed. QM provides
2.11-0
1354 OpenQM
memory resident numbered select lists that are private to the process using
them and disk based named lists that can be shared or retained for later
use.
Sentence A complete QM command or the start of one. A sentence may be typed at
the command prompt or it may be stored in the VOC for later execution
simply by typing the name of the VOC record.
String A sequence of characters stored as a data item.
Subvalue A subdivision of a value to represent multiple instances of the same type of
data within the value. For example, an order processing system might have
a pair of associated multivalued fields storing the product number and
quantity for each item ordered. If it was necessary to store the serial
number of each item shipped, this would be a subvalued field in the same
association.
Subscriber The system that is receiving exported file updates in a system configured
for data replication.
Table Another name for a database file.
Terminfo An internal database that stores details of the control codes appropriate to
all terminal types supported by QM.
Transaction A related set up updates to a database that must either all happen or none
must happen.
Trigger A user written QMBasic subroutine that is executed whenever selected
operations are performed against a file. Triggers get their name from their
use to trigger other related updates but they can also be used for data
validation.
Value A subdivision of a field to represent multiple instances of the same type of
data. For example, an order processing system might have multiple values
stored in the product number field of an order.
Verb The command word in a sentence. This is always the first word and
corresponds to a V-type VOC entry.
VOC A file found in all accounts that contains a list of all the words and
symbols that can be used in commands and details of how they should be
processed. By changing the VOC, it is possible to extend or modify the
QM command language.
Vocabulary See VOC.
2.11-0
Index 1355
$NO.CATALOGUE 723
@MONTH 1184
@NB 1184
@NI 1184 -=-
@OPTION 1184 = 600
@PARASENTENCE 1184 =< 618
@PATH 1184 => 607
@PIB 1184
@POB 1184
@QM.GROUP 1184 ->-
@QMSYS 1184
> 610
@RECORD 1184
>< 628
@SELECTED 1184
>= 607
@SENTENCE 1185
@SEQNO 1185
@SIB 1185
@SOB 1185
-A-
@STDFIL 697, 1185 ABORT 200, 754
@SYS.BELL 1185 ABORTE 754
@SYSTEM.RETURN.CODE 1185 ABORTM 754
@TERM.TYPE 1185 ABS() 756
@TIME 1185 ABSENT.IGNORE 559
@TRANSACTION.ID 1185 ABSENT.NULL 560
@TRANSACTION.LEVEL 1185 ABSS() 756
@TRIGGER.RETURN.CODE 1185 ACCEPT.SOCKET.CONNECTION() 757
@TTY 1185 ACCOUNT.RESTORE 201
@UID 1185 ACCOUNT.SAVE 203
@USER 1185 Accounts 27
@USER.NO 1186 A-correlative conversion (A) 132
@USER.RETURN.CODE 1186 A-Correlatives 116
@USER0 1185 ACOS() 758
@USER1 1185 ADD.DF 205
@USER2 1185 ADMIN 206
@USER3 1185 ADMIN.SERVER 208
@USER4 1185 ADMIN.USER 211
@USERNO 1186 AFTER 610
@-Variables 1182 ALIAS 213
@VOC 1186 ALL.MATCH 561
@WHO 1186 ALPHA() 759
@YEAR 1186 Alternate key indices 174
@YEAR4 1186 ANALYSE.FILE 214
ANALYZE.FILE 214
AND 562
-~- ANDS() 760
ARG () 761
~ 647
ARG.COUNT() 762
AS 563
-<- ASCII() 764
ASIN() 765
< 622 ASSIGNED() 766
<= 618 Assignment statements (QMBasic) 683
<> 628 ASSOC 564
2.11-0
Index 1357
2.11-0
1360 OpenQM
FORMAT 313
Format specifications 165
FORMLIST 890 -I-
F-pointers 50 ICONV() 910
FROM 606 ICONVS() 910
FSTAT 317 ID.ONLY 614
FSYNC configuration parameter 1313 ID.SUP 615
FUNCTION 891 IDIV() 911
ID-SUPP 615
-G- IF 328, 912
IFS() 913
GDI configuration parameter 1313 IN 616, 914
GE 607 INCLUDE 718
GENERATE 319 INDEX() 915
GES() 893 INDEXS() 915
GET 1035 INDICES() 916
GET(ARG.) 894 INHERIT 918
GET.LIST 321 INHIBIT.LOGIN 330
GET.MESSAGES() 896 Inline prompts 77
GET.PORT.PARAMS() 897 INMAT() 919
GET.STACK 322 INPUT 920
GETLIST 898 INPUT @ 922
GETNLS() 899 INPUTCLEAR 797
GETPU() 900 INPUTCSV 926
GETREM() 902 INPUTERR 1028
Glossary of terms 1350 INPUTFIELD 927
GO 323 INS 930
GO TO 905 INSERT() 930
GOSUB 903 Installation 15
GOTO 905 INT() 932
GRAND.TOTAL 608 Integer conversion (IS, IL) 146
GRANT.KEY 324 Interrupting commands 44
GREATER 610 INTPREC configuration parameter 1313
Group conversion (G) 145 Introduction 8
GROUP.SIZE 246, 258 I-type expressions 129
GRPSIZE configuration parameter 1313 ITYPE() 933
GT 610
GTS() 906
-J-
-H- JNLDIR configuration parameter 1314
JNLMODE configuration parameter 1314
HDR.SUP 611 JNLSIZE configuration parameter 1314
HDR-SUPP 611
HEADER 612
HEADING 612, 907 -K-
HELP 325 KEYCODE() 934
HSM 326 KEYEDIT 936
HUSH 327, 909 KEYEXIT 938
KEYIN() 939
KEYINC() 939
2.11-0
Index 1361
2.11-0
1362 OpenQM
2.11-0
Index 1363
2.11-0
1364 OpenQM
2.11-0
Index 1367
-W-
WAKE 1167
Web server 1227
WEOFSEQ 1168
WHEN 663
WHERE 532
WHILE 1169
WHO 531
WITH 665
WITHOUT 668
WRITE 1170
WRITE.SOCKET() 1171
WRITEBLK 1173
WRITECSV 1174
2.11-0