EPOC OPL Guide & Reference

EPOC logo Glossary
  • Read This First
  • Introducing OPL
  • Programming in OPL
  • Example Programs
  • Keyword Reference
  • Using OPXs
  • OplTran
  • Appendices
  • Glossary
  • Contents

EPOC OPL Guide & Reference

Welcome to the OPL Guide and Reference documentation for EPOC Release 5.

Aimed at OPL application developers, the documentation contains all the information required to produce high-quality EPOC OPL programs, using a PC running Windows 95 or Windows NT as the development environment. You may use your favourite PC source editor and translate text-based OPL programs using the Opltran PC translator tool; you can also write and translate OPL programs within the Windows-hosted EPOC Emulator. The applications you develop will run on an EPOC machine with no further translation.

To begin using this system documentation, please start at the Read This First section. To start programming in OPL from scratch, read the Introducing OPL section and then Programming in OPL.

For information about Symbian's developer support, please refer to the EPOC SDK Products and Support section of Read This First, which gives details of the EPOC World web site.

Release 036
Copyright (c) 1997-1999 Symbian Ltd. All rights reserved.


Read This First

  • About this SDK
  • What’s new in OPL for EPOC Release 5
  • EPOC SDK Products and support
  • Year 2000 Compliance
  • Licence agreement
  • Acknowledgements
  • Documentation conventions


About this SDK

Contents

  • Product description
    • EPOC Release 5
    • Limited source code
    • Development tools
    • OPL Guide and Reference documentation
    • Examples
  • System requirements
  • What’s new

Product description

Section Contents

  • EPOC Release 5
  • Limited source code
  • Development tools
  • OPL Guide and Reference documentation
  • Examples

The EPOC Release 5 OPL SDK provides a PC-hosted development environment for rapid application development in OPL. It comprises EPOC Release 5 system components, development tools including the EPOC Emulator, system documentation and examples.

OPL (Organiser Programming Language) is a Symbian proprietary language with a long heritage in Psion PLC’s Organizer range. It provides a BASIC-like syntax, and its easy accessibility and shallow learning curve have spawned a vigorous development community. The EPOC OPL SDK enhances ease of OPL programming by providing PC-hosted development tools and documentation.

OPL APIs provide access to the most commonly-used EPOC facilities. OPL extensions (OPXs) may be written in C++ to provide access to other C++ APIs, or to provide optimised function implementations. To write OPXs, you need the EPOC C++ SDK. To use an OPX written by someone else, you need a suitable build of that OPX (either for the emulator, or for a target machine).

EPOC Release 5

EPOC Release 5 was made available in June 1999, and comprises EPOC Release 5 plus the EPOC Message Suite (EPOC Email, EPOC Web and associated communications components).

All EPOC Release 5 components are included in this SDK. Specifically, the base, engine support, comms, graphics, and EIKON GUI components as well as the EPOC Web application and engine and the EPOC Spell application and dictionaries are included, together with the OPL runtime system.

Limited source code

Test source code for the some of the standard OPXs is provided, in order to provide examples of how to use OPXs.

Development tools

The following development tools are included:

  • EPOC Emulator, including all applications
  • command-line OPL compiler, allowing OPL modules to be edited using a Windows-based editor, and then compiled for use under the EPOC Emulator
  • tools for manipulating EPOC graphics and sound formats
  • the EPOC resource compiler
  • Aleppo, a help compiler
  • the EPOC Install suite and makesis, for preparing programs for installation on EPOC target machines

OPL Guide and Reference documentation

The OPL Guide and Reference comprises

  • Quick Start: a quick introduction to the SDK.
  • The Symbian OPL programming manual: a guide on how to use OPL, and reference documentation for OPL functions and extensions.
  • Tools: reference information on developer tools.
  • Producing Online Help: help compiler information.
  • Style Guide: a style guide for applications.

Documentation is available in two formats:

  • HTML format, which can be browsed on any browser supporting tables and frames
  • Microsoft HTMLHelp format, which requires a compatible help browser (for example, an installation of Microsoft Internet Explorer 4.0)

Examples

Example code is provided to illustrate documentation, and to provide a starting point for writing your own code. Types of example include

  • a hello world OPL application, to verify SDK installation and use of developer tools
  • sample applications demonstrating OPX usage

System requirements

To install and run the EPOC Release 5 OPL SDK, you will need

  • a PC running Windows NT 4.0, Windows 95 or Windows 98
  • 80MB of free space
  • speed and RAM requirements as for Microsoft Windows installation

To install and run software on an EPOC device, you will need

  • an EPOC device using EPOC Release 5 or earlier. Note that there may be compatibility issues when using earlier devices with this SDK
  • EPOC Connect 2.1 or above, or badged version such as PsiWin, and a link cable

To browse the OPL Guide and reference documentation, you will need

  • a web browser which supports tables and frames, for the HTML version
  • a browser for HTML Help files, such as Microsoft Internet Explorer 4.0 or above, for the HTML Help version

If you wish to develop OPXs, you will need the EPOC Release 5 C++ SDK (and its PC requirements).

What’s new

Relative to the EPOC Release 3 revision 2 OPL SDK CD-ROM, this SDK contains

  • new documentation and example code covering the ER5 OPL changes
  • new OPXs for extended OPL functionality
  • example source code demonstrating new OPX usage
  • fixes and editorial changes
EPOC SDK Home Glossary Previous Next Up


What’s new in OPL for EPOC Release 5

The EPOC operating system has changed significantly for Release 5, and many of these changes and improvements are directly available to OPL programmers. There are new language keywords and OPXs, and the behaviour of some keywords and procedures have changed slightly. The principal areas of OPL that have changed for ER5 are colour support and MIME recognition.

  • MIME recognition though the MIME keyword.

    • EPOC Release 5 supports MIME recognition for foreign documents. These are files which are not native to EPOC and have no UIDs, for example plain text files or JPEG images. In ER5, these files can be recognised by the system and handed to an appropriate application. The new MIME keyword associates an OPL application with a MIME data type. See OPL and MIME [image] for details.

  • Changes to the way GETEVENT32 and SETDOC are used.

    • EPOC Connect now restarts applications that were closed for backup. OPL apps should handle the Start and Close system event messages with GETEVENT32 to take advantage of this.

    The System screen under ER4 and ER5 contains a Recent files list on its toolbar. In order to take advantage of this, ER4 and ER5 OPL applications should use SETDOC to announce an opened document to the system. As in EPOC release 3, this also has the effect of displaying the document name in the system task list.

  • Enhanced colour support

    • Colour capabilities have been improved for ER5, and OPL supports these improvements. A new keyword, gCOLORINFO, can be used to get the maximum number of colours available on the system, DEFAULTWIN and gCREATE have changed, and new constants have been added to Const.oph to cover these changes. The background colour of a window can be set with gCOLORBACKGROUND, and Toolbar.opo now supports colour.

    These changes are fully documented in the Colour graphics and Toolbar interaction topics and the keyword reference section.

  • Updates to menu behaviour.

    • Menu panes now scroll if they are larger than the screen. No code changes are needed to make use of this: see the Menu interaction topic.

  • Bug fixes to Date.opx.

    • Fixes bugs where DtNewDateTime() etc. could incorrectly fail with an ‘out of range’ error. The OPX header and OPX interface remain the same.

    These fixes were released with Date.opx 1.01 in EPOC Release 4.

  • Support for the Contacts list with Contact.opx.

    • Management of the contacts list used by the new Contacts application is available though OPL. A new OPX, Contact.opx, has been added to allow control over the contacts list; this OPX exports functions for adding, creating and deleting a user’s contact information, as well as sorting and searching.

  • Improved DBMS functionality.

    • Changes to the Database Management System for ER5 require that restricted views of tables be explicitly refreshed to make changes made to a table’s contents visible. DbRefresh: in the new dbUtils.opx can be used for this.

  • Changes to opltran

    • Opltran can now convert between ASCII and EPOC OPL formats.

ER5 changes to the OPL documentation

This documentation has been extensively revised and reformatted for EPOC release 5. In particular, it no longer discusses the SIBO implementation of OPL used on Psion’s Series 3 range of handheld computers. The EPOC OPL Guide and Reference documentation discusses only EPOC implementations of OPL.

The EPOC OPL Guide and Reference documentation is now distributed with the EPOC Tools and Utilities guide, and the EPOC Emulator documentation. The EPOC Tools and Utilities documentation describes tools that are shared by more than one SDK; and the EPOC Emulator manual describes how to use and configure the EPOC Emulator, which is the principal development and debugging platform for EPOC applications.

Opltran, the PC command-line OPL translator is documented in the EPOC OPL system documentation as it is a tool specific to OPL.


EPOC SDK Products and support

Contents

  • Overview
  • Developer products
    • C++
    • Java
    • OPL
    • Connectivity
  • Technical Services and Support

Overview

EPOC supports an unparalleled range of software development options for wireless information devices. Development of applications for EPOC devices is supported in three languages: C++, Java, and Symbian’s Basic-like OPL language.

PC-based applications for data conversion, synchronisation and remote control of EPOC machines may be written in Windows C++ or Visual Basic.

Developers are supported through Symbian’s EPOC World website. All SDKs are available free to developers. For up to the minute information, visit http://www.epocworld.com/.

Developer products

Section Contents

  • C++
  • Java
  • OPL
  • Connectivity

Symbian’s SDK product range is designed for both corporate developers and independent software vendors. SDK products for OEMs are also available.

The principal platform for all EPOC development is the Microsoft Windows-hosted EPOC Emulator. The Emulator uses the Win32 API to emulate the underlying hardware services required by EPOC devices. It implements all user-side EPOC APIs exactly as on an EPOC machine to provide a full emulation of a generic EPOC device.

As well as forming an essential component of all EPOC SDKs, it is freely available in standalone form from Symbian, providing a showcase for potential EPOC developers and users.

C++ software is built and debugged on the EPOC Emulator using Microsoft Visual C++, and then rebuilt for target machines using a customised GNU C++ Compiler implementation.

Java and OPL are interpreted languages. Programs may be developed and debugged under the Emulator, and then transferred to an EPOC target machine without rebuilding.

C++

EPOC is written in C++. The C++ SDK provides access to all EPOC user-side APIs. EPOC is thoroughly object-oriented in its design, giving the compactness and re-use essential to produce efficient software for the device classes it targets.

The GNU C++ Compiler is required to compile for native platforms, and is supplied with the C++ SDK. Microsoft Visual C++ (not supplied) is required for PC-based development. EPOC Connect (not supplied) is used to transfer binaries to the EPOC target machine.

The full C++ SDK is available free to developers, refer to the EPOC World website for details.

Java

Java is an industry-standard language supporting application and applet development on a very wide variety of machines. The EPOC SDK for Java provides a Java Compatible VM and library for the EPOC platform, and supports implementation of Java applications and applets written using any standard Java development system. The EPOC Emulator is included, together with tools and utilities shared with other EPOC SDKs.

Native method development is also supported — note that this requires the EPOC C++ SDK.

The EPOC SDK for Java is available free to developers, refer to the EPOC World website for details.

OPL

OPL is a Basic-like rapid application development language, with historical roots in the Organiser II and Series 3 handheld computers from Psion PLC, available since the mid 1980s. OPL may be programmed directly on many EPOC devices. For convenience, the OPL SDK supports PC-based development using the EPOC Emulator and tools and utilities shared with other EPOC SDKs.

OPL provides access to EPOC’s most commonly-used APIs. Other APIs may be accessed using OPL extensions (known as OPXs) written in C++. OPXs may also be used to implement optimised library functions for OPL programs. OPX development requires an EPOC C++ SDK.

The OPL SDK is available free to developers, refer to the EPOC World website for details.

Connectivity

Exchange and synchronisation of data between other machines and EPOC machines is vital for practical use of wireless information devices. The EPOC Connectivity SDK supports conversion and synchronisation of EPOC data formats with a range of PC applications. Additionally, it supports remote control of EPOC devices from a PC. PC-based applications may be developed in either Windows C++, or Visual Basic. Together with the other EPOC SDKs, this provides an exceptionally flexible basis for rapid development of corporate connectivity applications.

The Connectivity SDK is available free to developers, refer to the EPOC World website for details.

Technical Services and Support

Symbian offers a range of technical and support services to developers.

Developer support is managed through Symbian’s EPOC World website. Free membership allows developers full access to SDKs. Open public areas provide general information about EPOC and EPOC World services including training and other open developer events.

Professional EPOC World membership provides access to an extensive range of quality support services including support forums moderated by experienced Symbian developers, knowledge bases, example code, Beta test programs and technical papers, and regular SDK updates on CD.

Premium support services are available to companies requiring higher levels of support including multiple prepaid incidents and confidential services with guaranteed response times.

To register for any of the above services or to find out more information please go to the EPOC World Web site at http://www.epocworld.com/.


Year 2000 Compliance

Contents

  • Statement Of Compliance
  • Disclaimer
  • Note

Statement Of Compliance

This SDK has been checked for Year 2000 (Y2K) compliance and no problems have been found. For all components that are owned by Symbian:

  • No value for date will cause any interruption in operation
  • Any date based functions will operate in a consistent manner for dates prior to, during or after year 2000.
  • In any interfaces and in any storage, the century in any date will be specified either explicitly or by unambiguous algorithms or inferencing rules.
  • The Year 2000 will be recognised as leap year.

All third party add-on products have also been certified as Y2K compliant with the following exceptions:

  • GCC: While Symbian have no reason to believe that the version of GCC that comes as part of the OPL SDK is not Y2K compliant, it has not been officially tested by our suppliers. However, Symbian do certify as Y2K compliant all components which have been built using it.
  • UNZIP: We have inspected the authors’ official Y2K compliance statement for this utility. The only known issue is that it displays only two digits of the year when listing files. This is irrelevant for the SDK, as the integrity of files extracted from zipped archives is unaffected.

Disclaimer

This Statement of Compliance refers to the product as supplied by Symbian and does not constitute a warranty.

Note

If this Symbian product is to be used with other computers, the user should ensure that these products (e.g., other software, firmware and hardware) are also Year 2000 Compliant to ensure data integrity.


Licence agreement

PLEASE READ THIS LICENCE AGREEMENT CAREFULLY:

This Licence Agreement ("AGREEMENT") is a legal agreement between you (either an individual or an organisation such as a company) and Symbian Ltd ("SYMBIAN").

This licence agreement covers the use of the Symbian EPOC OPL Software Development Kit ("SDK"). The SDK includes "online" or electronic documentation, sample applications, development tools, utilities, computer software, and any printed materials. By installing or otherwise using the SDK, you agree to be bound by the terms of this AGREEMENT. If you do not agree to the terms of this AGREEMENT, SYMBIAN will not license the SDK to you. In such event, you may not use or copy the SDK, and you must destroy any copies of the SDK in your possession.

This AGREEMENT constitutes the entire agreement and understanding between the parties with respect to its subject matter and replaces all previous written or oral agreements, including all express or implied terms, and all representations between, or undertakings by, the parties with regard to such subject matter. This AGREEMENT cannot be changed except by written agreement between the parties.

PRODUCT LICENCE

The SDK is protected by international copyright laws and treaty provisions, as well as other intellectual property laws and treaties. The SDK is licensed, not sold.

GRANT OF LICENCE

This AGREEMENT grants you the following rights:

a) The non-exclusive and limited right to use one copy of the SDK by you (if you are an individual) or by any employee (if you are an organisation) for the sole purpose of designing, developing and testing software products (“PRODUCTS”) that

i) operate on devices that make use of the SYMBIAN EPOC operating system ("EPOC") as their primary operating system; or

ii) are a software development tool for EPOC; or

iii) utilise, or convert to or from, EPOC file formats.

b) The right to make a single back-up copy of the SDK. You may use the back-up copy solely for back-up and archival purposes.

c) The non-exclusive and limited right to make a single copy of the electronic documentation contained in the SDK solely for the purpose of aiding you in the designing, developing and testing of PRODUCTS.

DESCRIPTION OF OTHER RIGHTS AND LIMITATIONS

a) Limitations on Reverse Engineering, Decompilation and Disassembly. You may not reverse engineer, decompile, or disassemble the SDK, except and only to the extent that such activity is expressly permitted by applicable law. Notwithstanding this limitation, Symbian will terminate this Agreement if you attempt or have attempted to reverse engineer, decompile, or disassemble the SDK in breach of this provision.

b) Rental. You may not rent or lease the SDK.

c) Redistribution. With the exception of the components of the SDK covered by sections d) and e) below you must not distribute copies of the SDK, or any component of the SDK.

d) Example Code. You may use and modify the source code contained in the \epoc32\wins\c\opl\ directory of the SDK ("EXAMPLE CODE"), but solely for the purpose of designing, developing and testing PRODUCTS and you may distribute source and object code versions of this modified EXAMPLE CODE ("MODIFIED CODE"), provided that you comply with section h) below.

e) Redistributable Components. You may distribute the object code components contained in the \epoc32\release\marm\rel\ and \epoc32\tools\epocinst\ directories of the SDK ("REDISTRIBUTABLE COMPONENTS") provided that you comply with section h) below.

f) Software Transfer. You may not transfer any of your rights under this AGREEMENT.

g) Termination. The AGREEMENT lasts until you terminate it by destroying all copies of the SDK (including any printed materials and media). If you fail to comply with the conditions of the AGREEMENT, then SYMBIAN will terminate the AGREEMENT and you will be required, by the terms and conditions of the AGREEMENT, to destroy all copies of the SDK (including any printed materials and media).

h) Redistribution. You may distribute the MODIFIED CODE and REDISTRIBUTABLE COMPONENTS only as part of a software product ("APPLICATION") that adds significant functionality to the original functionality provided by the EXAMPLE CODE or REDISTRIBUTABLE COMPONENTS provided that:

1. Where the recipient of the APPLICATION is an end user you do not permit your end users further distribution of the MODIFIED CODE or REDISTRIBUTABLE COMPONENTS,

2. Where the recipient of the APPLICATION is a distributor they may further distribute your APPLICATION including any MODIFIED CODE or REDISTRIBUTABLE COMPONENTS provided they comply with all the terms of this AGREEMENT and provided that such MODIFIED CODE or REDISTRIBUTABLE COMPONENTS are only distributed as part of your APPLICATION.

3. You do not use SYMBIAN's trademarks, name or logos on or in relation to your Application or otherwise to market your APPLICATION,

4. You agree to indemnify and hold SYMBIAN harmless from and against any and all damages, losses, costs, claims, expenditure and liability arising out of or related to the use or distribution of your APPLICATION,

5. You agree that SYMBIAN reserves all rights not expressly granted.

6. You agree to include a copyright notice in the Application of equal prominence as any other copyright notice as follows: "This product includes software licensed from Symbian Ltd (c) Symbian Ltd 1999"

UPDATES

UPDATES may be made available by SYMBIAN from time to time. By installing or otherwise using such UPDATES you agree to be bound by any ADDITIONAL TERMS that may accompany such UPDATES. If you do not agree with such ADDITIONAL TERMS you may not install, copy or otherwise use such UPDATES.

COPYRIGHTS AND PATENTS

All title and copyrights in and to the SDK (including but not limited to any images, drawings, text and applications incorporated into the SDK), the accompanying printed materials, and any copies of the SDK, are variously owned by SYMBIAN and SYMBIAN suppliers. You may not copy any printed materials accompanying the SDK. All rights not specifically granted under this AGREEMENT are reserved by SYMBIAN. All patent rights and rights in inventions, in and to EPOC and in and to the SDK that are owned by SYMBIAN are not licensed to you. SYMBIAN reserves its rights to license these rights to you on commercial terms. Commercial production and distribution of PRODUCTS may infringe these rights. You agree to inform any recipient of an Application of the limited scope of rights passed onto it. Symbian reserves its rights to separately license these rights to any recipient of an Application.

DISCLAIMER OF WARRANTY

SYMBIAN PROVIDES NO WARRANTY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHERE OTHERWISE STATED IN WRITING, SYMBIAN PROVIDES THE SDK "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, BUT NOT LIMITED TO, ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THIS SDK IS LICENSED TO YOU WITHOUT FEE AND ACCORDINGLY YOU ACCEPT THAT THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE SDK IS WITH YOU AND YOU AGREE NOT TO TAKE ANY INCONSISTENT POSITION. SHOULD THE SDK PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION OF THE SDK AND OF ANY PRODUCT OR APPLICATION.

IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW WILL SYMBIAN BE LIABLE TO YOU FOR DAMAGES, (WHETHER ARISING IN CONTRACT, TORT, NEGLIGENCE OR OTHERWISE) INCLUDING ANY LOST PROFITS, LOST MONIES, LOST TIME, LOSSES ATTRIBUTABLE IN WHOLE OR PART TO ANY DEFECTS IN THE DESIGN OR PERFORMANCE OF THE SDK OR ANY PRODUCT OR APPLICATION, OR SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE SDK (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY THIRD PARTIES OR A FAILURE OF THE SDK TO OPERATE WITH PROGRAMS NOT DISTRIBUTED BY SYMBIAN), EVEN IF SYMBIAN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES, OR FOR ANY CLAIM BY ANY OTHER PARTY. NOTHING IN THIS AGREEMENT LIMITS SYMBIAN'S LIABILITY FOR DEATH OR PERSONAL INJURY CAUSED BY ITS NEGLIGENCE.


Acknowledgements

Contents

  • Copyright notices
  • Spell checker and Application royalties
  • Other software
  • GNU General Public License
    • Version 2, June 1991
    • Preamble
    • GNU GENERAL PUBLIC LICENSE
    • Appendix: How to Apply These Terms to Your New Programs
  • Trademarks

Copyright notices

Part of the software in this product is © Copyright STNC Ltd. 1994-1998. All rights reserved

Part of the software in this product is © Copyright ANT Ltd. 1998. All rights reserved

International CorrectSpell English Spelling Correction System, Copyright © 1995 by Lernout & Hauspie Speech Products NV. All rights reserved. Reproduction or disassembly of embodied algorithms or database prohibited.

UK English Concise International Electronic Thesaurus, Copyright © 1995 by Lernout & Hauspie Speech Products NV. All rights reserved. Reproduction or disassembly of embodied programs and databases prohibited.

Incorporates MPPC compression from Hi/fn

Spell checker and Application royalties

EPOC includes a spell checker, thesaurus and dictionary accessible through the elex.lib and elex.dll APIs, licensed to Symbian Ltd by Lernout & Hauspie Speech Products NV (L&H).

If you make commercially available an EPOC application which uses these libraries, you are required to enter into a license agreement directly with L&H. This agreement will require that you pay to L&H a non-refundable, prepaid, minimum royalty payment of US$5,000 together with further royalties of US$0.20 per licensed copy.

The contact details for L&H are provided below. Do not contact Symbian with regard to this license; the license is a matter between yourself and L&H. Symbian has no responsibility nor obligation in enforcing and administering such license agreements.

    Lernout & Hauspie Speech Products NV
    Sint-Krispijnstraat 7
    8900 Ieper
    BELGIUM
    Phone: 32/57-22-8888
    Fax: 32/57-20-8489
    Michael Stephenson
    European Sales Manager - ICM Group
    Phone/fax 44/181-644-8685
    Email: mstephenson@lhs.com

Other software

  • The following software is distributed with the SDK under the terms of the GNU General Public License (reproduced below):
    • the GNU C++ compiler, used as a text-file preprocessor for various EPOC tools, and for building ARM binaries
    • ActiveWare’s port of PERL, used for various EPOC tools. PERL is distributed with the C++ SDKs under the terms of the GNU General Public License.
  • Aleppo is packaged on this CD using Info-ZIP's compression utility. The installation program uses UnZip to read zip files from the CD. InfoZIP's software (Zip, UnZip and related utilities) is free and can be obtained as source code or executables from Internet/WWW sites, including http://www.cdrom.com/pub/infozip/.

GNU General Public License

Section Contents

  • Version 2, June 1991
  • Preamble
  • GNU GENERAL PUBLIC LICENSE
    • NO WARRANTY
    • REPAIR OR CORRECTION.
  • Appendix: How to Apply These Terms to Your New Programs

Version 2, June 1991

Copyright (c) 1989, 1991 Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA

Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software—to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation’s software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author’s protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors’ reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone’s free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

GNU GENERAL PUBLIC LICENSE

TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  • 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The “Program”, below, refers to any such program or work, and a “work based on the Program” means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term “modification”.) Each licensee is addressed as “you”.

    • Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

  • 1. You may copy and distribute verbatim copies of the Program’s source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

    • You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

  • 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

    • a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.

    c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

    These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

    Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

    In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

  • 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

    • a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

    The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

    If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

  • 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
  • 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.
  • 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients’ exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.
  • 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

    • If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

    It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

    This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

  • 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
  • 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

    • Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and “any later version”, you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

  • 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

  • 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,

REPAIR OR CORRECTION.

  • 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS

Appendix: How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the “copyright” line and a pointer to where the full notice is found.

    <one line to give the program’s name and a brief idea of what it does.>
    Copyright © 19yy  <name of author>
    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License as
    published by the Free Software Foundation; either version 2 of
    the License, or (at your option) any later version.
    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.
    You should have received a copy of the GNU General Public
    License along with this program; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
    USA.

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this when it starts in an interactive mode:

    Gnomovision version 69, Copyright © 19yy name of author
    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w’.
    This is free software, and you are welcome to redistribute it
    under certain conditions; type `show c’ for details.

The hypothetical commands `show w’ and `show c’ should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w’ and `show c’; they could even be mouse-clicks or menu items—whatever suits your program.

You should also get your employer (if you work as a programmer) or your school, if any, to sign a “copyright disclaimer” for the program, if necessary. Here is a sample; alter the names:

    Yoyodyne, Inc., hereby disclaims all copyright interest in the
    program `Gnomovision’ (which makes passes at compilers) written
    by James Hacker.
    <signature of Ty Coon>, 1 April 1989
    Ty Coon, President of Vice

This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.

Trademarks

Symbian and the Symbian logo are trademarks of Symbian Ltd.

EPOC and the EPOC logo, EPOC World and the EPOC World logo are trademarks of Symbian Ltd.

International CorrectSpell is a registered trademark of Lernout & Hauspie Speech Products N.V.

The following are trademarks and registered trademarks of Microsoft Corporation: Microsoft, MS, Internet Explorer, Windows, Windows NT, Win32, Visual Basic, Visual C++, Developer Studio, Visual Studio.

Psion and the Psion logo are registered trademarks of Psion PLC. Series 5 is a trademark of Psion PLC.

ARM, Thumb, StrongARM and ARM Powered are registered trademarks of ARM Limited.

Motorola and M·CORE are registered trademarks of Motorola, Inc.

Java and all Java-based marks are trademarks or registered trademarks of Sun Microsystems, Inc. in the U.S. and other countries

Pentium is a registered trademark of Intel Corporation.

Arial is a trademark of the Monotype Corporation registered in U.S. Patent and Trademark Office and certain other jurisdictions.

Times New Roman is a trademark of the Monotype Corporation registered in U.S. Patent and Trademark Office and certain other jurisdictions.

These trademarks, and others, are acknowledged. Conventional abbreviations of these trademarks are used throughout the product documentation.


Documentation conventions

Contents

  • Overview
  • New features and compatibility
    • ER5 feature level
    • ER4 feature level
    • Compatibility
  • Glossaries
  • Styles
  • BNF grammars

Overview

This topic provides a quick introduction to the conventions used in this documentation.

New features and compatibility

Section Contents

  • ER5 feature level
  • ER4 feature level
  • Compatibility

New features and changed behaviours for existing features are marked with icons in the text to indicate the EPOC release in which the documented behaviour was introduced. This makes it simple to recognise new or changed features, even without checking which document you are reading (which may not be immediately clear, for example when jumping between documents).

ER5 feature level

The icon [er5] at the heading of a feature indicates that the feature is introduced in EPOC Release 5. Changed features are indicated in the text.

ER4 feature level

The icon [er4] at the heading of a feature indicates that the feature was introduced in EPOC Release 4. Changed features are indicated in the text.

Compatibility

Some developers may want to produce programs that work both on ER5 and on previous EPOC releases. To help this, a subheading Compatibility in the documentation for a keyword or function provides discussion of compatibility issues. If no such section exists, it should be assumed that the feature can be used with releases before EPOC Release 5.

Glossaries

The Glossary provides definitions of important terms used in this documentation. Note that terms first used in other documentation, such as the EPOC C++ System Documentation, are defined in the glossaries belonging to those documents.

Styles

Style | Type
File | Open | Application text and menus
variable$, funccall:(),COMMANDNAME | OPL Code.
note this | Emphasised text containing unusual or surprising information
example | Example project.
Const.oph | Filename
SQL | Hyperlink to definition in the glossary
Alt+A | Key names
WINS | Text only applies to the indicated platform
Warning | Warning of an important issue

BNF grammars

Backus-Naur Form (BNF) grammars are used as a tool for describing constructions in other languages, for example:

select-statement :
SELECT select-list FROM table-name [ restriction ] [ ordering ]
restriction :
WHERE search-condition
ordering :
ORDER BY sort-order

A BNF definition states that the named item given before the colon is written as described after the colon. For example, an ordering is written as ORDER BY followed by a sort-order (which may be defined elsewhere).

BNF expression | What it means
named-construction : expression | Declares that a named-construction is written as expression.
named-construction : expression1 expression2 | Declares that a named-construction is written as either expression1 or expression2.
word | The word word, written literally.
exp1 exp2 | exp1 followed by exp2.
[ exp ] | exp is optional.
[ exp1 | exp2 ] | Either exp1 or exp2 or nothing.
exp+ | expression, repeated one or more times.
exp* | expression, repeated zero, one or more times.
EPOC SDK Home Glossary Previous Up


Introducing OPL

  • About OPL
  • A first program
  • File management
  • Running modules


About OPL

OPL (Organizer Programming Language) is a Symbian proprietary language with a long heritage in Psion PLC’s Organizer range. It provides a BASIC-like syntax, and its easy accessibility and shallow learning curve have spawned a vigorous development community.

OPL APIs provide access to the most commonly-used EPOC facilities. OPL extensions (OPXs) may be written in C++ to provide access to other C++ APIs, or to provide optimised function implementations. To write OPXs, you need the EPOC C++ SDK. To use an OPX written by someone else, you need a suitable build of that OPX (either for the emulator, or for a target machine).


A first program

Contents

  • Overview
  • Creating a new module
    • Inside the Program editor
  • An example procedure to type in
    • Type in and edit the procedure
    • What the keywords do when the program runs
  • Translating and running
    • What happens when you translate a module?
    • Running after translating

Overview

This tutorial describes how to create a very small initial program using the standard EPOC Program editor. All the example does is print some text to the screen, but following the tutorial will introduce you to some of the basics of OPL.

Creating a new module

The words program and module are used almost interchangeably to describe each OPL file. You say “OPL module” like you might say “Word Processor document”.

Create a new module and give it a name: Click the ‘New File’ button (or select ‘Create New File’ from the ‘File’ menu).

Select ‘Program’ from the Program selector. Type test as the ‘Name’ to use for this OPL module and press Enter. You will move into the Program editor.

Module names can be up to 256 characters long (including their folder names), like other EPOC file names. The names may include any characters except \, / and :, and any trailing spaces or dots (.) will be stripped automatically.

It’s always best to choose a name that describes what the module does. Then, when you’ve written several modules, you can still recognise which is which.

Inside the Program editor

When you first move into the Program editor you will see that PROC : has already been entered on the first line, and ENDP on the third.

PROC and ENDP are the keywords that are used to mark the start and end of a procedure. Larger modules are broken up into procedures, each of which has one specific function to perform. A simple OPL module, like the one you are going to create, consists of only one procedure.

A procedure consists of a number of statements — instructions upon which the machine acts. You type these statements, in order, between PROC : and ENDP. When you come to run the program, the statements are executed one by one. When the last statement in the procedure has been completed and ENDP is reached, the procedure ends.

You can type and edit in the Program editor in much the same way as in the Word application, except that text you type does not word-wrap; you should press Enter at the end of each statement.

You can use upper or lower case letters when entering OPL keywords.

An example procedure to type in

Section Contents

  • Type in and edit the procedure
  • What the keywords do when the program runs

The next few pages work with this example procedure:

    PROC test:
          PRINT "This is my OPL program"
          PAUSE 80
          CLS
          PRINT "Press a key to finish"
          GET
    ENDP

This short procedure is an example of how some common OPL keywords (PRINT, PAUSE, CLS and GET) are used. The procedure first displays This is my OPL program on the screen. After a few seconds the screen is cleared and then Press a key to finish is displayed. Then, when you press a key, the program finishes.

Type in and edit the procedure

Before you type the statements that constitute the procedure, you must type a name for it, after the word PROC. The flashing cursor is automatically in the correct place for you to do this (before the colon). You can choose any name you like within the following restrictions:

Procedure names may have up to 32 characters. The alphabetic and numeric characters are allowed and also the underscore character, _. The first character of any procedure name must be either an underscore or an alphabetic character.

For simple procedures which are the only procedure in a module, you might use the same filename you gave the module.

  1. Type test . The top line should now read PROC test: .
  2. Press the down cursor key. The text position is already indented, as if the Tab key had been pressed.
  3. You can now type the statements in this procedure:
  4. Type PRINT "This is my OPL program". (Note the space after PRINT.) Press Enter at the end of the line.

    5. Each new line is automatically indented, so you don’t need to press the Tab key each time. These indents are not obligatory, though as you’ll see, they can make a procedure easier to read. However, other spacing, such as the space between PAUSE and 80, is essential for the procedure to work properly.

Type the other statements in the procedure. Press Enter at the end of each line. You are now ready to translate the module and then run it.

When you are entering the statements in a procedure you can, if you want, combine adjacent lines by separating them with a space and colon. For example, the two lines:

    PAUSE 80
    CLS

could be combined as this one line:

    PAUSE 80 :CLS

You can, of course, use the other applications at any time while you are editing an OPL module.

To return to editing your program, either:

  • tap on the Program icon on the Extras bar, or
  • select the module’s name on the System screen, or
  • use the Task List to return to the Program editor.

What the keywords do when the program runs

  • PRINT: takes text you enter between quote marks, and displays it on the screen. The text to be displayed, in the first statement, is This is my OPL program.
  • PAUSE: pauses the program, for a specified number of twentieths of a second. PAUSE 80 waits for 4 seconds. (PAUSE 20 would wait for 1 second, and so on.)
  • CLS: clears the screen.
  • GET: waits for you to press a key on the keyboard.

Translating and running

Section Contents

  • What happens when you translate a module?
  • Running after translating

The translation process makes a separate version of your program in a format which the machine can run. You’d usually try to translate a module as soon as you finish typing it in, to check for any typing mistakes you’ve made, and then to see if the program runs as you intended.

Select the Translate option from the Tools menu or tap the Tran button on the toolbar menu.

What happens when you translate a module?

First: the procedures in the module are checked for errors.

If the translator cannot understand a procedure, because of a typing error, a message is shown, such as ‘Syntax error’. The cursor is positioned at the point where the error was detected, so that you can correct it. For example, you might have typed PRONT "This is...", or PAUSE80 without the space.

  • When you think you’ve corrected the mistake, select Translate again. If there is still a mistake, you are again taken back to where it was detected.

Note: If you’ve already used up almost all of the memory, the translation may be unable to complete, and will report a No system memory message. You’ll need to free some memory before trying again.

  • When Translate can find no more errors, the translation will succeed, producing a separate version of your module in a format which the machine can run.

Note: There may still be errors in your program at this point because there are some errors which cannot be detected until you try to run the program.

Running after translating

When your module translates successfully, the Run program dialog is displayed, asking whether to run the translated module. You’d usually run it straight away in order to test it.

Running a module does require some free memory, so again a No system memory message is possible.

  • Press Y to run the module. The screen is cleared, and the module runs.

When the module has finished running, you return to the Program editor, with the cursor where it was before.

  • If an error occurs while the module is running, you will return to editing the module, and the cursor will be positioned at the point where the error occurred.


File management

Contents

  • New OPL modules
  • Copying modules
  • Deleting modules
  • ‘File is in use’

New OPL modules

You can create new OPL modules in the same way as new Word documents. This can be done from the Program editor using the menu command File | Create New File, or from the System screen by tapping the New file button or selecting the menu command File | Create New | File....

The module names are listed on the System screen with a Program icon next to them. The Program icon looks like a sheet of paper with OPL on it. Successfully translated modules will also be listed in the same folder as their corresponding Program file with the OPL icon next to them and a name ending in .opo; translated OPL applications will be automatically created in a folder under \System\Apps\ on the current disk. The icon for translated OPL modules is just the letters OPL with a shadow.

To re-edit an existing OPL program, you can open the Program application and use File | Open file from the menu. You can also select the file directly from the System screen. This will automatically open the file and launch the Program application. Files which launch their associated applications when selected are known as documents. The application UID (unique identifier) is stored in the document header which is read by the system. As far as the user is concerned, the UID specifies a document’s type. A non-document file does not have an application UID and is displayed on the system screen with a special icon (a question mark) showing that it is unrecognised. Non-document files are known as external files.

Opening Program from its icon in the Extras bar will re-open the Program file last in use.

Copying modules

Use the Copy file option in the System screen to copy modules or translated modules. You can also use the ‘Save as’ option in the Program editor itself, to make new copies of an OPL module.

Deleting modules

You can delete an OPL module (or a translated version) as you would any other file. Go to the System screen, move the highlight on to the file and use the ‘Delete file’ option.

‘File is in use’

If you see a ‘File’ is in use error message when deleting or copying an OPL module, the file is open — it is currently being edited in the Program editor. Close the file from the editor and then try again.

If it’s the translated file you’re trying to delete or copy, ‘File’ is in use means that the translated file is currently running. Stop the running program by going to the running program, then either wait for the program to complete or press Ctrl+Esc to stop it, and then you can try again.


Running modules

Contents

  • Running from the Program editor
  • Running modules from the System screen
  • Stopping a program while it’s running
  • Looking at a running program
  • Running more than one module
  • Menu options while editing

Running from the Program editor

You can run a module at any time from within the Program editor, by selecting Tools | Run program and selecting a module to run. This runs the translated version of your program; if you’ve made changes to the module and haven’t translated it again, you must translate the module again, or the changes have no effect.

Run program displays a dialog, letting you select the name of any translated module which you want to run.

Running modules from the System screen

The names of any successfully translated programs automatically appear in the System screen.

Translated modules appear in the System screen with the OPL icon to the left of them. They have the same name as the Program file from which they were translated with the extension .opo added to their name, and appear in the same folder as their corresponding Program file. Just select the translated program you want to run, and then tap it again to run the program.

When an OPL module has been successfully translated and run, you will usually run it from the System screen. While you’re still editing and testing, however, it’s quicker to run it from inside the Program editor. This also positions the cursor for you, if errors occur.

Stopping a program while it’s running

  • To stop a running program, press Ctrl+Esc. (If you’ve switched to another program whilst an OPL program is running, the OPL program it will still be running, and you must first return to it. This is done by either selecting it from the System screen or by using the Task list to switch to it. then Ctrl+Esc will stop it.)
  • To pause a running program, press Ctrl+Fn+S. It will be paused as soon as it next tries to display something on the screen. Press Ctrl+Fn+Q to let the program resume running.

Looking at a running program

If you translate and run a module from the Program editor, the Task list will still allow you to return to the Program editor, even if the translated program has not finished running. A ‘Running…’ message is shown — you can move the cursor around the program as normal, but you can’t edit it.

To return to the running version, either use the Task list or select it from the System screen. The program icon on the system screen will be in bold, to show that it is currently running.

Running more than one module

If a module is running, and you select a second one from the System screen, the first one is not replaced — both modules run together, and both will be displayed in bold on the System screen. You can swap between them using the Task list.

Menu options while editing

While you’re typing in the procedure, all the options on the Edit menu such as Copy and Paste - are available and can be used as in Word. Refer to the User Guide for more information.

The menu options available are in general similar to those found in other applications, such as Word. The Tools menu has options for translating and running the current program. It also has a Show last error option, to re-display an error which prevented successful translation, and a Preferences option to determine the fonts available and whether spaces, tabs and paragraph ends are shown in the Program editor. It also provides an Infrared option (see the User Guide for more details of using infrared). The Create standard files option creates files in RAM from ROM files: see Including header files for more details of this.

The Format menu provides a Font dialog for changing fonts and styles in the Program editor. The ‘Indentation’ option can be used to set the tab width and to turn auto-indentation on and off.

The File menu also include Import text and Export as text options for importing text and exporting as text.

The toolbar on the left-hand side of the screen provides easy access via buttons to four options and also a clock. The options are Tran (‘Translate’), Find, ‘Find next’ and Go to. These options are all self-explanatory, except perhaps for the last: Go to gives a list (scrolled if necessary) of all the procedure in the module. Selecting one of them jumps to the beginning of the specified procedure.

EPOC SDK Home Glossary Previous Up


Programming in OPL

This section contains information about the basic OPL programming methodology, File Handling, Graphics, and Error Handling.

In addition, it also has a section coving more advanced programming techniques.


OPL Basics

  • Values and expressions
  • Commands
  • Control structures
  • Calling procedures
  • Including header files


Values and expressions

Contents

  • Overview
  • Values
    • Types of value
  • Constants and variables — Storing values for later use
    • Variables
    • Constants
  • Expressions — Manipulating and combining values
    • Arithmetic operations
    • Values from functions
    • Problems with integers
    • Operations on strings

Overview

This section covers the basic OPL constructions that can be used within a procedure. It describes the basic ways in which programs can deal with data, store and retrieve it, manipulate it and combine it.

See also: Control structures, Commands.

Values

Section Contents

  • Types of value
    • Number values
    • Text values

Before using a value, you must decide what sort of information you need to represent, and to some extent what you need to do with the data. There are different types of value for different tasks and uses.

Each value in an OPL program has a type associated with it. If you try to use the wrong type of value in a place where a particular type of variable is expected, an error message will be displayed when you try to translate your program.

The numbers and strings in quote marks written in an OPL program are sometimes called literals. In practice, you will use literal values without thinking about them. For example:

0.32 | Floating-point number.
569 | Integer.
32768 | Long integer.
$2b | Integer, specified in hexadecimal.
"hello" | String.

You can only use these values in a statement — such as print "hello world" — so this section will use the print command when discussing values.

Types of value

OPL can represent values of various kinds. Each value has an associated type.

Before using a value, decide what information you need to represent. There are different types of variables for different sorts of values. If you try to give the wrong type of value to a variable, an error message will be displayed.

Number values

  • For small whole numbers — for example 6 — use the integer type.

    • Integers can only be used for numbers in the range -32768 to +32767.

  • For larger whole numbers — for example 10000000 — use the long integer type.

    • Long integers can handle whole numbers in the range -2147483648 to +2147483647. If you may have to handle numbers outside normal integer range, use the long integer representation.

  • For non-whole numbers — for example 2.5 — use the floating-point type.

    • Floating-point numbers can represent numbers from 2.2250738585072015E-308 to 1.7976931348623157E+308, and 0.

    If you know that at some stage in your program your variable will have to handle non-whole numbers, like 1.2, use a floating-point, not an integer variable. Otherwise you may get unpredictable results. (There’s more about this later in this topic.)

    For very large whole numbers outside long integer range you should also use floating-point variables.

When assigning numbers to a variable, you should ensure the variable is of the right type. You may get unpredictable results or translation errors if a variable is not of the right type for the value it is to store (see below).

Writing numbers

Besides writing simple decimal numbers as above, you can also write numbers in hexadecimal, or use exponential notation.

Integers specified in hexadecimal must be preceded by a $ and long hex integers by a &. For example, $f or &80000000. This is explained under the HEX$ entry in the Keyword Reference section.

Exponential notation may be useful for very large or very small numbers. Use E (capital or lower case) to mean “times ten to the power of” — for example, 3.14E7 is 3.14 x 107 (31400000), while 1E-9 is 1 x 10-9 (0.000000001).

More on number representation

It is possible to use the full available range of 64-bit floating-point values, i.e. all real numbers with absolute values in the range 2.2250738585072015E-308 to 1.7976931348623157E+308 and 0. Precision remains limited to about 15 significant figures in this range. It is also possible to use numbers which have absolute values in the range 5E-324 to 2.2250738585072015E-308 (called denormals), however the precision decreases in this range to only 1 significant figure at the lower end. It is possible to enforce the ranges used by earlier releases of OPL (see below) by using the SETFLAGS command. See the Keyword Reference section for details of this.

Constants for the maximum and minimum values of all variable types are given in Const.oph. See const.oph for more on this.

With SETFLAGS KTwoDigitExponent& in effect, floating-point variables can only represent numbers as big as 9.99999999999e99 and as small as 1e-99, and 0. Intermediate results in calculations (which are not displayed on the screen) may exceed this and can take any value in the full range of 64-bit floating point numbers as above.

Text values

For text — “Are you sure?”, “54th”, etc. — use a string variable.

To write a string, write the string in double quotes:

    print "some text"

A string can only be written on one line; it may contain no return characters. If you need to write a double quote character in a string, use "". OPL understands doubled "s in a string as single "s:

    print """This deck contains no twos"", Tom deduced."

Constants and variables — Storing values for later use

Section Contents

  • Variables
    • Declaring variables
    • Choosing names for variables
    • Variable types
    • Initial values
    • Assignment — Putting a value in a variable
    • Using variables — Getting a variable’s value
  • Constants
    • Declaring constants

OPL can store values and use them later by declaring that a name represents a particular value. This can be done in two ways, either by a variable or by a constant. Variables are used to store values which may change, and constants store fixed values.

Variables

Declaring variables

Most procedures begin by declaring (creating) variables:

    LOCAL x,y,z

LOCAL is the keyword telling OPL to create variables, with the names which follow - here x, y and z — separated by commas. These variables initially have the value 0.

The statement LOCAL x,y,z declares three variables called x, y and z. OPL will recognise these names whenever you use them in this procedure. If you used them in another procedure, they wouldn’t be recognised; the variables are ‘local’ to the procedure in which they are declared.

Any variables you wish to use must be declared at the start of a procedure.

Variables can also be declared GLOBAL at the start of a procedure if you want them to be recognised by other procedures. See GLOBAL under Keyword Reference for more on this.

Two variables cannot have the same name. For example, it is not possible to write:

    PROC badProcedure:
          LOCAL x,y,z
          GLOBAL v,w,x  REM duplicate "x" value
    ENDP

This will display a Duplicate name error when you try to translate it.

Choosing names for variables

To make it easier to write your programs, and understand them when you read through them at a later date, give your main variables names which describe the values they hold. For example, in a procedure which calculates fuel efficiency, you might use variables named speed and distance.

All variable names:

  • May be entered in any combination of upper and lower case. sPeeD and SpEEd would be considered the same name.
  • Must not use any of the names of keywords, as listed in the Keyword Reference section. If you use these you will see a Declaration error message when you translate your module.
  • May be up to 32 characters long
  • Must start with either an underscore (_) or an alphabetic character, but after that may use any combination of numbers, letters and the underscore character.

The $, & and % symbols (see Variable types, below) are included in the 32 characters allowed in variable names, so V2345678901234567890123456789012% is too long to be a valid variable name, but V234567890123456789012345678901% is acceptable.

When variables are declared, they automatically get a default value. See Initial values.

Variable types

The types a variable can have correspond to the types of value OPL can represent (see Types of value, above)

Scalar variables

Simple numbers and strings are called scalar values. You give the type of a variable by appending a type character onto the end of the variable name:

Type character | Variable type | Example declaration
(nothing) | Floating-point. | LOCAL aFloating
% | Integer. | LOCAL anInteger%
& | Long integer. | LOCAL aLong&
$ | String. | LOCAL aString$
Array variables

You may want a group of variables, for example to store lists of values. Instead of having to declare separate variables a, b, c, d and e, you can declare array variables a(1) to a(5) in one go like this:

LOCAL a%(5) | Array of integer variables.
LOCAL a(5) | Array of floating-point variables.
LOCAL a$(5,8) | Array of string variables (note the second number).
LOCAL a&(5) | Array of long integers.

The number in brackets is the number of elements in the array. So LOCAL a%(5) creates five integer variables: a%(1), a%(2), a%(3), a%(4) and a%(5).

With strings, the second number in the brackets specifies the maximum length of the strings. All the elements in the string array have the same capacity — for example, LOCAL ID$(5,10) allocates memory space for five strings, each up to 10 characters in length.

OPL does not support two-dimensional arrays.

For efficiency
  • Integer variables use less memory than long integer variables, and both use less than floating-point.
  • Integer variables are processed very much faster than floating-point.

However, the cardinal rule is still to use the right kind of variable for the values you want to store. If a number needs to represent non-integer quantities, use a floating-point variable to store it, and if it needs to represent large numbers, use a long integer or a floating-point number as appropriate.

Initial values

When a variable is declared, it automatically has some default value. For numeric values, the initial value is zero. For strings, the initial value is the empty string (written "").

Assignment — Putting a value in a variable

Values can be assigned to a variable using an assignment statement. This is the variable name, an equals sign, and the value you want to assign to the variable. Examples are:

    a%=42
    profit=378.373721
    greeting$="Good day!"
    bignum&=65535+2001-(42*3)

In assignment statements, the variable assigned to can be used in the expression to the right of the equals sign. Expressions are covered below.

z%=z%+1 | makes the value of z% one greater than its current value
x%=(x%/4)+y% | makes the value of x% a quarter of its current value, plus the value of y%

Using variables — Getting a variable’s value

A variable name can be used anywhere you’d normally use a variable of the appropriate type. For example:

    PROC test1:
          LOCAL i%
          i% = 42
          PRINT 42+7
          PRINT i%+7
          GET        REM Wait for a keypress
    ENDP

This example prints 49 twice, because i% was assigned the value 42.

Constants

Constants are essentially variables whose values can never change. They are used exactly like variables (see Using variables — Getting a variable’s value, above), but their declaration is different.

Using constants allows you to assign a name to a value so it may be used throughout the module. If you need to use a particular value several times in your program, it is easier to define it as a constant and use its name rather than spelling it out in full every time you need to use it. Also, if the value you need to use changes during your program’s development, it is far easier to change a single value at the top of a module than it is to change every occurrence of a value in the program.

Constants can be shared between modules, and there are several standard OPL values defined in Const.oph. See Including header files for more on how to use this.

By convention, all constants are named with a leading K to distinguish them from variables.

Declaring constants

Constants are declared with the CONST keyword. Because their value never changes, constants must be assigned a value where they are declared:

    CONST KMinimumTemp%=-237

Constants must be declared outside procedures. You will get a translation error if you try to declare a constant inside a procedure.

The names of constants must not clash with those of variables declared with LOCAL or GLOBAL. It’s usual to add a K prefix to the constant name. This helps avoid name clashes, and is also a useful reminder that you can’t change the name’s value when you use it.

Expressions — Manipulating and combining values

Section Contents

  • Arithmetic operations
  • Values from functions
  • Problems with integers
  • Operations on strings

Expressions are combinations of numbers, variables, and functions that the interpreter can use as a value. An example of an OPL statement using an expression is:

    print 42+(2*3)

The value of the expression 42+(2*3) is 48, so the statement prints 48 to the text display.

Expressions can be built from other expressions (sub-expressions) as well as values: notice that in the example above, (2*3) is a sub-expression. Expressions can be as complex as you like, although it’s a good idea to keep things reasonably simple so you can understand them later.

Expressions can be used anywhere OPL expects a value. Types of expression include operations on values, and function calls.

For example:

z=x+y/2 | gives z the value of x plus the value of y/2.
z=x*y+34.78 | gives z the value of x times y, plus 34.78.
z=x+COS(y) | gives z the value of x plus the cosine of y.

COS(y) in the example above is a function call — see Values from functions below.

Arithmetic operations

You can use these operators:

+ | Plus. | x%+13
- | Minus (or make negative). | -70-32.8
/ | Divide. | 9/3
* | Multiply. | 9*5
** | Raise to a power. | 2**8
% | Percentage. | 17.5%

Operators have the same precedence as in the Calc application. For example, 3+51.3/8 is treated as 3+(51.3/8), not (3+51.3)/8. For more information on operators and precedence, see Operators and logical expressions.

Values from functions

There are two kinds of keyword — commands and functions:

  • A command is just a straightforward instruction to OPL to do some particular thing. PRINT and PAUSE, for example, are commands.
  • A function is just like a command but it also returns a value which you can then use.

GET (as used above) is, in fact, a function; it waits for you to press a key on the keyboard, and then returns a value which identifies the key which was pressed. In previous example programs, the value returned by GET was ignored, as GET was being used to provide a pause while you read the screen. This is a common use of the GET function.

The number returned by GET will always be a small whole number, so you might store it away in an integer variable, like this:

    a%=GET

There is more about the GET function later in this topic.

    a%=COS(b)

COS is another OPL function. Unlike the GET function, COS requires a value or variable to work with. As you can see, you put this in brackets after the function name. Values you give to functions in this way are called arguments to the function. There is more information about arguments in Commands.

Problems with integers

When calculating an expression, OPL uses the simplest arithmetic possible for the numbers involved. If all of the numbers are integers, integer arithmetic is used; if one is outside integer range, but within long integer range, then long integer arithmetic is used; if any of the numbers are not whole numbers, or are outside long integer range, floating-point arithmetic is used.

This has the benefit of maximising speed, but you must beware of calculations going out of the range of the type of arithmetic used. For example, in X=200*300 both 200 and 300 are integers, so integer arithmetic is used for speed (even though X is a floating-point variable). However, the result, 60000, cannot be calculated because it is outside integer range (32767 to -32768), so an ‘Overflow’ error is produced.

You can get around this by using the INT function, which turns an integer into a long integer, without changing its value. If you rewrite the previous example as X=INT(200)*300, OPL has to use long integer arithmetic, and can therefore give the correct result (60000). (If you understand hexadecimal numbers, you can instead write one of the numbers as a hexadecimal long integer, e.g. 200 would become &C8.)

Integer arithmetic uses whole numbers only. For example, if y% is 7 and x% is 4, y%/x% gives 1. However, you can use the INTF function to convert an integer or long integer into a floating-point number, forcing floating-point arithmetic to be used for example, INTF(y%)/x% gives 1.75.

This rule applies to each part of an expression — e.g. 1.0+2/4 works out as 1.0+0 (=1.0), while 1+2.0/4 works out as 1+0.5 (=1.5).

If one of the integers in an all-integer calculation is a constant, you can instead write it as a floating-point number. 7/4 gives 1, but 7/4.0 gives 1.75.

Operations on strings

If a$ is "down" and b$ is "wind", then the statement c$=a$+b$ means c$ becomes "downwind".

Alternatively, you could give c$ the same value with the statement c$="down"+"wind".

When adding strings together, the result must not be longer than the maximum length you declared e.g. if you declared LOCAL a$(5) then a$="first"+"second" would cause a String is too long error to be displayed.

Most operators do not work on strings. To cut up strings, use string functions like MID$, LEFT$ and RIGHT$, explained in the Keyword Reference section. You need these functions to extract even a single character — you cannot, for example, refer to the fourth character in a$ as a$(4).


Commands

Contents

  • Overview
  • Displaying variables
    • Where the cursor goes after a PRINT
    • Displaying a list of things
    • Displaying the quote character
  • Reading values from the keyboard
    • Inputting a line
    • Single keypresses
    • Example using GET$
    • Modifier keys

Overview

This section describes what an OPL statement is and gives some useful techniques for reading values from the keyboard and printing them to the screen.

A statement is a line of a program that instructs the OPL interpreter to perform some action, for example printing a line of text to the screen or assigning to a variable.

Most statements other than assignment use keywords, There are two kinds of keyword — commands and function calls:

A command is just a straightforward instruction to OPL to do some particular thing. PRINT and PAUSE, for example, are commands.

A function is just like a command but it also returns a value which you can then use.

Assignment and calling functions are covered in the Values and expressions section.

Displaying variables

Section Contents

  • Where the cursor goes after a PRINT
  • Displaying a list of things
  • Displaying the quote character

PRINT is one of the most useful OPL commands. Use it to display any combination of text messages and the values of variables on the screen.

Where the cursor goes after a PRINT

In general, each PRINT statement ends by moving to a new line. For example:

    A%=127 :PRINT "A% is"
    PRINT a%

would display as

    A% is
    127

You can stop a PRINT statement from moving to a new line by ending it with a semicolon. For example:

    A%=127 :PRINT "A% is";
    PRINT a%

would display as

    A% is127

If you end a PRINT statement with a comma, it stays on the same line, but displays an extra space. For example:

    A%=127 :PRINT "A% is",
    PRINT a%

would display as

    A% is 127

Displaying a list of things

You can use commas or semicolons to separate things to be displayed on one line, instead of using one PRINT statement for each. They have the same effect as before:

    A%=127 :PRINT "A% is",a%

would display as

    A% is 127

while

    user$="Fred"
    PRINT "Hello",user$;"!"

would display as

    Hello Fred!

Displaying the quote character

Each string you use with PRINT must start and end with a quote character. Inside the string to display, you can represent the quote character itself by entering it twice. So PRINT "Press "" key" displays as Press " key, while PRINT """" displays a single quote character.

Reading values from the keyboard

Section Contents

  • Inputting a line
    • Comments
    • AT command
  • Single keypresses
  • Example using GET$
  • Modifier keys

Inputting a line

If you want a program to be reusable, it often needs to be able to accept different sets of information each time you use it. You can do this with the INPUT command, which takes numbers and text typed in at the keyboard and stores them in variables.

For example, this simple procedure converts from Pounds Sterling to Deutschmarks. It asks you to type in two numbers — the number of Pounds Sterling, and the current exchange rate. You can edit as you type the numbers — the Delete key, for example, deletes characters, and Esc clears everything you’ve typed. Press Enter when you’ve finished each number. The values are assigned to the variables pounds and rate, and the result of the conversion is then displayed:

    PROC exch:
          LOCAL pounds,rate
          AT 1,4
          PRINT "How many Pounds Sterling?",
          INPUT pounds :REM value from keyboard
          PRINT "Exchange rate (DM to £1)?",
          INPUT rate :REM value from keyboard
          PRINT "=",pounds*rate,"Deutschmarks"
          GET
    ENDP

Here PRINT is used to show messages (often called prompts) before the two INPUT commands, to say what information needs to be typed in. In both cases the PRINT command ends in a comma, which displays a single space, and keeps the cursor position on the same line. Without the commas, the numbers you type to the INPUT commands would appear on the line below.

The value entered to an INPUT command must be of the appropriate kind for the variable which INPUT is setting. If you enter the wrong type (for example, if you enter the string three for the floating-point variable rate), INPUT will show a ? prompt, and wait for you to enter another value.

When using INPUT with a numeric variable (integer, long integer or floating-point), you can enter any number within the range of that type of variable. Note that if you enter a non-whole number as the value for an integer variable, it will take only the whole number part (so e.g. if you enter 12.75 for an integer variable, it will be set to 12).

Comments

The REM command lets you add comments to a program to help explain how it works. Begin the comment with the word REM (short for ‘remark’). Everything after the REM command is ignored.

If you put a REM command on the end of a line, the colon you would normally put before it is optional. For example, you could use either of these:

    CLS :REM Clears the screen

or

    CLS REM Clears the screen

AT command

This positions the cursor or your message at the co-ordinates you specify. Use the command like this:

    AT column%,row%

where column% and row% give the character position to use.

AT 1,1 positions the cursor to the top left corner.

Single keypresses

In addition to using INPUT to ask for values, your program can ask for single keypresses. Use one of these functions:

  • GET waits for a keypress and returns the key pressed.
  • KEY returns a key if any was pressed, but doesn’t wait for one.

Every separate letter, number or symbol has a number which represents it, called a character code. The full list of character codes — the character set — for may be found in Character codes. GET and KEY return the character code of the key pressed for example, if A were pressed, these functions would return the value 65. KEY returns 0 if no key was pressed.

KEY$ and GET$ work in the same way as KEY and GET, except that they return the key pressed as a string, not as a character code:

  • GET$ waits for a keypress and returns the key pressed, as a string.
  • KEY$ returns a key if any was pressed, but doesn’t wait for one. KEY$ returns a null string if no key was pressed.

Unlike INPUT, these functions do not display the key pressed on the screen, and do not wait for you to press Enter.

Example using GET$

    PROC kchar:
          LOCAL k$(1)
          PRINT "Press a key, A-Z:"
          k$=GET$
          PRINT "You pressed",k$
          PAUSE 60
    ENDP

Single keypresses are often useful for making decisions. A program might, for example, offer a set of choices which you choose from by typing the word’s first letter, like this:

    Add (A) Erase (E) or Copy (C) ?

Or it might ask for confirmation of a decision, by displaying a YES or NO? message and waiting until Y or N is pressed.

See Control structures for details of how to identify which key is pressed.

Modifier keys

If you need to check for the Shift, Control, Fn keys and/or Caps Lock being used, see the description of the KMOD function, in the Keyword Reference section.


Control structures

Contents

  • Introduction
  • Loops
    • DO...UNTIL — Repeat instructions until a condition is true
    • WHILE...ENDWH — Repeat instructions while a condition is true
  • Conditionals
    • IF...ENDIF — Execute instructions if a condition is true
  • More on loops and conditionals
    • Example — Using IF
    • Example — Using DO...UNTIL and IF
    • Nesting structures — the ‘Too complex’ message
    • True and false values
    • Logical operators
  • Jumping to a different line
    • BREAK — Jumping out of a loop
    • CONTINUE — Jumping to the test condition
    • GOTO — Jumping to a label
    • VECTOR/ENDV — Vectoring to a label
  • Infinite loops — UNTIL 0 and WHILE 1

Introduction

The programs in the previous sections, A first program and Values and expressions, consist of a number of instructions which are executed one by one, from start to finish.

However, there are a number of other ways a program can proceed:

  • Repeating a set of instructions (loops)
  • Doing one set of instructions or another (IF statements)
  • Jumping from one line of your program to another

Loops

Section Contents

  • DO...UNTIL — Repeat instructions until a condition is true
  • WHILE...ENDWH — Repeat instructions while a condition is true
    • Example using WHILE...ENDWH

The DO...UNTIL and WHILE...ENDWH commands are structures — they don’t actually do anything to your data, but control the order in which other commands are executed:

  • DO...UNTIL repeats a set of instructions until a certain condition is true.
  • WHILE...ENDWH repeats a set of instructions so long as a certain condition is true.

There is a test condition at the end of the DO...UNTIL loop, and at the beginning of the WHILE...ENDWH loop.

DO...UNTIL — Repeat instructions until a condition is true

    PROC test:
          LOCAL a%
          a%=10
          DO
                PRINT "A=";a%
                a%=a%-1
          UNTIL a%=0
          PRINT "Finished"
          GET
    ENDP

DO tells OPL to execute all the following instructions until an UNTIL is reached. If the condition following UNTIL is not met, the same set of instructions is repeated until it is.

The first time through the loop, a%=10. 1 is subtracted from a%, so that a% is 9 when the UNTIL statement is reached. Since a% isn’t zero yet, the program returns to DO and the loop is repeated.

a% goes down to 8, and again it fails the UNTIL condition. The loop therefore repeats 10 times until a% does equal zero.

When a% equals zero, the program continues with the instructions after UNTIL.

The statements in a DO...UNTIL loop are always executed at least once.

WHILE...ENDWH — Repeat instructions while a condition is true

    PROC test2:
          LOCAL a%
          a%=10
          WHILE a%>0
                PRINT "A=";a%
                a%=a%-1
          ENDWH
          PRINT "Finished"
          GET
    ENDP

The instructions between the WHILE and ENDWH statements are executed only if the condition following the WHILE is true - in this case if a% is greater than 0.

Initially, a%=10 and so A=10 is displayed on the screen. a% is then reduced to 9. a% is still greater than zero, so A=9 is displayed. This continues until A=1 is displayed. a% is then reduced to zero, and so Finished is displayed.

Unlike DO...UNTIL, it’s possible for the instructions between WHILE and ENDWH not to be executed at all.

Example using WHILE...ENDWH

    PROC newkey:
          WHILE KEY :ENDWH
          PRINT "Press a new key."
          GET
    ENDP

This procedure ignores any keys which may already have been typed, then waits for a new keypress.

KEY returns the value of a key that was pressed, or 0 if no key has been pressed. WHILE KEY :ENDWH reads any keys previously pressed, one by one, until they have all been read and KEY returns zero.

Conditionals

IF...ENDIF — Execute instructions if a condition is true

In a program, you might have several possible cases (x% may be 1, or it may be 2, or 3...) and want to do something different for each one (if it’s 1, do this, but if it’s 2, do that...). You can do this with the IF...ENDIF structure:

    IF condition1
          do these statements
    ELSEIF condition2
          do these statements
    ELSEIF condition3
          do these statements
           :
           :
    ELSE
          do these statements
    ENDIF

These lines would do either

  • the statements following the IF line (if condition1 is met)

or

  • the statements following one of the ELSEIF lines (if one of condition2, condition3... is met)

or

  • the statements following the ELSE line (if none of condition1, condition2, condition3... have been met).

and then continue with the statements after the ENDIF.

You can cater for as many cases as you like with ELSEIF statements. You don’t have to have any ELSEIFs. There may be either one ELSE statement or none; you do not specify conditions for the ELSE statement.

Every IF in your program must be matched by an ENDIF — otherwise you’ll see an error message when you try to translate the module. The structure must start with an IF and end with an ENDIF.

More on loops and conditionals

Section Contents

  • Example — Using IF
  • Example — Using DO...UNTIL and IF
  • Nesting structures — the ‘Too complex’ message
  • True and false values
  • Logical operators

Example — Using IF

    PROC zcode:
          LOCAL g%
          PRINT "Are you going to press Z?"
          g%=GET
          IF g%=%Z OR g%=%z
                PRINT "Yes!"
          ELSE
                PRINT "No."
          ENDIF
          PAUSE 60
    ENDP
% operator

The program checks character codes with the % operator. %a returns the code of a, %Z the code of Z and so on. Using %A is entirely equivalent to using 65, the actual code for A, but it saves you having to look it up, and it makes your program easier to follow.

Be careful not to confuse character codes like these with integer variables.

OR operator

OR lets you check for either of two conditions. OR is an example of a logical operator. There is more about logical operators below and in Operators and logical expressions.

Example — Using DO...UNTIL and IF

    PROC testny:
          DO
            g$=UPPER$(GET$)
          UNTIL g$="N" OR g$="Y"  REM wait for a Y or N
          IF g$="N"               REM was it an N?
              ...                 REM ‘N’ pressed
          ELSE                    REM must have been a Y
              ...                 REM ‘Y’ pressed
          ENDIF
    ENDP

This procedure checks for a ‘Y’ or ‘N’ keypress. You’d put your own code in the IF statement, where ... has been used.

Arguments to functions

Some functions, as with commands like PRINT and PAUSE, require you to give a value or values. These values are called arguments. The UPPER$ function needs you to specify a string argument, and returns the same string but with all letters in upper case. For example, UPPER$("12.+aBcDeF") returns 12.+ABCDEF.

Functions as arguments to other functions

Since GET$ returns a string, you can use this as the argument for UPPER$. UPPER$(GET$) waits for you to press a key, because of the GET$; the UPPER$ takes the string returned and, if it’s a letter, returns it in upper case. This means that you can check for Y without having to check for y as well.

Nesting structures — the ‘Too complex’ message

You can have up to eight DO...UNTIL, WHILE...ENDWH and/or IF...ENDIF structures nested within each other. If you nest them any deeper, a ‘Too complex’ error message will be displayed.

True and false values

The test condition used with DO...UNTIL, WHILE...ENDWH and IF...ENDIF can be any expression, and may include any valid combination of operators and functions. Examples:

Condition | Meaning
x=21 | does the value of x equal 21? (Note — as this is a test condition, it does not assign x the value 21)
a%<>b% | is the value of a% not equal to the value of b%?
x%=(y%+z%) | is the value of x% equal to the value of y%+z%? (does not assign the value y%+z% to x%).

The expressions actually return a logical value — that is, a value meaning either ‘True’ or ‘False’. Any non-zero value is considered ‘True’ (to return a ‘True’ value, OPL uses -1), while zero means ‘False’. So if a% is 6 and b% is 7, the expression a%>b% will return a zero value, since a% is not greater than b%.

Constants for ‘True’ and ‘False’ are given in Const.oph.

These are the conditional operators:

< | less than
> | greater than
= | equal to
<= | less than or equal to
>= | greater than or equal to
<> | not equal to

Logical operators

The operators AND, OR and NOT allow you to combine or change test conditions. This table shows their effects. (c1 and c2 represent conditions.)

Example | Result | Integer returned
c1 AND c2 | True if both c1 and c2 are true | -1
 | False if either c1 or c2 are false | 0
c1 OR c2 | True if either c1 or c2 is true | -1
 | False if both c1 and c2 are false | 0
NOT c1 | True if c1 is false | -1
 | False if c1 is true | 0

However, AND, OR and NOT become bitwise operators — something very different from logical operators — when used exclusively with integer or long integer values. If you use IF A% AND B%, the AND acts as a bitwise operator, and you may not get the expected result. You would have to rewrite this as IF A%<>0 AND B%<>0. (Operators, including bitwise operators, are discussed further in Operators and logical expressions.)

Jumping to a different line

Section Contents

  • BREAK — Jumping out of a loop
  • CONTINUE — Jumping to the test condition
  • GOTO — Jumping to a label
  • VECTOR/ENDV — Vectoring to a label

BREAK — Jumping out of a loop

The BREAK command jumps out of a DO...UNTIL or WHILE...ENDWH structure. The line after the UNTIL or ENDWH statement is executed, and the lines following are then executed as normal. For example:

CONTINUE — Jumping to the test condition

The CONTINUE command jumps from the middle of a loop to its test condition. The test condition is either the UNTIL line of a DO...UNTIL loop or the WHILE line of a WHILE...ENDWH loop. For example:

GOTO — Jumping to a label

The GOTO command jumps to a specified label. The label can be anywhere in the same procedure (after any LOCAL or GLOBAL variable declarations). In this example, when the program reaches the GOTO statement, it jumps to the label exit::, and continues with the statement after it.

The two PRINT statements are missed out.

Labels themselves must end in a double colon. This is optional in the GOTO statement - both GOTO exit:: and GOTO exit are OK.

The jump to the label always happens — it is not conditional.

Don’t use GOTOs instead of DO...UNTIL or WHILE...ENDWH, as they make procedures difficult to understand.

VECTOR/ENDV — Vectoring to a label

VECTOR jumps to one of a list of labels, according to the value in an integer variable. The list is terminated by the ENDV statement. For example:

          VECTOR p%
                FUNCA,FUNCX
                FUNCR
          ENDV
          PRINT "p% was not 1/2/3" :GET :STOP
      FUNCA::
          PRINT "p% was 1" :GET :STOP
      FUNCX::
          PRINT "p% was 2" :GET :STOP
      FUNCR::
          PRINT "p% was 3" :GET :STOP

Here, if p% is 1, VECTOR jumps to the label FUNCA::. If it is 2, it jumps to FUNCX::, and if 3, FUNCR::. If p% is any other value, the program continues with the statement after the ENDV statement.

The list of labels may spread over several lines, as in this example, with a comma separating labels in any one line but no comma at the end of each line. Again, you can write each label in the list with a double colon, if you like.

VECTOR...ENDV can sometimes save you from having to write very long IF...ENDIF structures, with ELSEIF used many times.

Stopping a running program

This example introduces the STOP command. This stops a running program completely, just as if the end of the program had been reached. In a module with a single procedure, STOP has the same effect as using GOTO to jump to a label above the final ENDP.

Infinite loops — UNTIL 0 and WHILE 1

Zero and non-zero are logical values meaning ‘False’ and ‘True’ respectively. UNTIL 0 and WHILE 1 therefore mean ‘do forever’, since the condition 0 is never ‘True’ and the condition 1 is always ‘True’. Use loops with these conditions when you need to check the real condition somewhere in the middle of the loop. When the real condition is met, you can BREAK out of the loop.

For example:

    PROC test:
          WHILE 1
                ...  REM some other lines here
                IF KEY :BREAK :ENDIF
                ...  REM some other lines here
          ENDWH
    ENDP

This example uses the KEY command. KEY returns 0 if no key has been pressed. When a key is pressed, KEY returns a non-zero value which counts as ‘True’, and the BREAK is executed.


Calling procedures

Contents

  • Using more than one procedure
    • Modules containing more than one procedure
    • Calling procedures
    • Uses of calling procedures
  • Parameters
    • Multiple parameters
    • Returning values
  • GLOBAL variables
    • Passing back values
    • ‘Undefined externals’ error

Using more than one procedure

Section Contents

  • Modules containing more than one procedure
  • Calling procedures
  • Uses of calling procedures

If you wanted a single procedure to perform a complex task, the procedure would become long and complicated. It is more convenient to have a module containing a number of procedures, each of which you can write and edit separately.

Many OPL modules are in fact a set of procedures linked up — each procedure doing just one job (such as a certain calculation) and then passing its results on to other procedures, so they can do other operations:

OPL is designed to encourage programs written in this way, since:

  • You can store all the procedures which make up a program in the same module file

and

  • One procedure can call, that is execute, another.

Modules containing more than one procedure

You can have as many procedures as you like in a module. Each must begin with PROC and end with ENDP.

When you run a translated module it is always the first procedure, at the top of the module, which is actually run. When this finishes, the module stops; any other procedures in the file are only run if and when they are called.

Although you can use any name you want, it’s common to give the first procedure a name like start.

Procedures which run on their own should be written and translated as separate modules, otherwise you won’t be able to run them.

Calling procedures

To run another procedure, simply give the name of the procedure (with the colon). For example, this module contains two procedures:

    PROC one:
          PRINT "Start"
          PAUSE 40
          two:                REM calls procedure two:
          PRINT "Finished"
          PAUSE 40
    ENDP

    PROC two:
          PRINT "Doing..."
          PAUSE 40
    ENDP

Running this module would run procedure one:, with this effect: Start is displayed; after a PAUSE it calls two:, which displays Doing...; after another PAUSE two: returns to the one: procedure; one: displays Finished; and after a final PAUSE, one: finishes.

Remember the Go to button on the toolbar allows you to jump between procedures, for quick navigation around the module.

Uses of calling procedures

Calling procedures can be used to:

  • Structure your programs more clearly so they’re easier to adapt after you’ve written them
  • Use the same procedure in different programs — say, to perform a certain common calculation.

For example, when your program asks you “Do this or do that?”, make two procedure calls - either this: or that: procedure - depending on what you reply, for example:

    PROC input:
          LOCAL a$(1)
          PRINT "Add [A] or Subtract [S]?:",
          a$=UPPER$(GET$)
          IF a$="A"
                add:                     REM first procedure
          ELSEIF a$="S"
                subtract:                REM second procedure
          ENDIF
    ENDP

To make full use of procedure calls, you must be able to communicate values between one procedure and another. There are two ways of doing this: global variables and parameters.

Parameters

Section Contents

  • Multiple parameters
  • Returning values

Values can be passed from one procedure to another by using parameters. They look and act very much like arguments to functions.

In the example below, the procedure price: calls the procedure tax:. At the same time as it calls it, it passes a value (in this case, the value which INPUT gave to the variable x) to the parameter p named in the first line of tax:. The parameter p is rather like a new local variable inside tax:, and it has the value passed when tax: is called. (The tax: procedure is not changing the variable x.)

The tax: procedure displays the value of x plus 17.5% tax.

In the called procedure, follow the procedure name by the names to be used for the parameters, enclosed by brackets and separated by commas - for example proc2:(cost,profit).

The parameter type is specified as with variables - for example p for a floating-point parameter, p% for an integer, p& for a long integer, p$ for a string. You can’t have array parameters.

  • In the calling procedure, the values for the parameters are given in brackets, in the right order and separated by commas, after the colon of the called procedure — for example proc2:(60,30).

The values passed as parameters may be the values of variables, strings in quotes, or constants. So a call might be calc:(a$,x%,15.8) and the first line of the called procedure PROC calc:(name$,age%,salary).

In the called procedure, you cannot assign values to parameters — for example, if p is a parameter, you cannot use a statement like p=10.

You will see a ‘Type mismatch’ error displayed if you try to pass the wrong type of value to a parameter — for example, 45 to (a$).

Multiple parameters

In the following example, the second procedure tax2: has two parameters:

  • The value of the price variable x is passed to the parameter p1.
  • The value of the tax rate variable r is passed to the parameter p2.

tax2: displays the price plus tax at the rate specified.

This uses the % symbol as an operator - p1+p2 % means p1 plus p2 percent of p1. Note the space before the %; without it, p2% would be taken as representing an integer variable.

Operators and logical expressions has more about the % operator.

Returning values

In the following example, the RETURN command is used to return the value of x plus tax at r percent, to be displayed in price3:. This is very similar to the way functions return a value.

The tax3: procedure calculates, but doesn’t display the result. This means it can be called by other procedures which need to perform this calculation but do not necessarily need to display it.

Only one value may be returned by the RETURN command.

The name of a procedure which returns a value must end with the correct identifier - $ for string, % for integer, or & for long integer. To return a floating-point number, it should end with none of these symbols. For example, PROC abcd$: can return a string, while PROC counter%: can return an integer. In this example, ref$: returns a string:

    PROC refname:
          LOCAL a$(30),b$(2)
          PRINT "Enter reference and name:",
          INPUT a$
          b$=ref$:(a$)
          PRINT "Ref is:",b$
          GET
    ENDP

    PROC ref$:(name$)
          RETURN LEFT$(name$,2)
          REM LEFT$ takes first 2 letters of name$
    ENDP

If you don’t use the RETURN command, a string procedure returns the null string (""). Other (numeric) types of procedure return zero.

GLOBAL variables

Section Contents

  • Passing back values
  • ‘Undefined externals’ error

You can only return one value with the RETURN command. If you need to pass back more than one value, use global variables.

Instead of declaring LOCAL x%,name$(5)declare GLOBAL x%,name$(5). The difference is that:

  • Local variables are valid only in the procedure in which they are declared.
  • Global variables can also be used in any procedures (including those in loaded modules) called by the procedure in which they are declared.

So this module would run OK:

    PROC one:
          GLOBAL a%
          PRINT a%
          two:
          GET
    ENDP

    PROC two:
          a%=2                REM Sees a% declared in one:
          PRINT a%
    ENDP

When you run this, the value 0 is displayed first, and then the value 2.

You would see an ‘Undefined externals’ error displayed if you used LOCAL instead of GLOBAL to declare a%, since the procedure two: wouldn’t recognise the variable a%. In general, though, it is good practice to use the LOCAL command unless you really need to use GLOBAL.

A local declaration overrides a global declaration in that procedure. So if GLOBAL a% was declared in a procedure, which called another procedure in which LOCAL a% was declared, any modifications to the value of a% in this procedure would not effect the value of the global variable a%.

Passing back values

You can effectively pass as many values as you like back from one procedure to another by using global variables. Any modifications to the value of a variable in a called procedure are automatically registered in the calling procedure. For example:

    PROC start:
          GLOBAL varone,vartwo
          varone=2.5
          vartwo=2
          op:
          PRINT varone,vartwo
          GET
    ENDP

    PROC op:
          varone=varone*2
          vartwo=vartwo*4
    ENDP

This would display 5 8

‘Undefined externals’ error

If, perhaps because of a typing error, you use a name which is not one of your variables, no error occurs when you translate the module. This is because it could be the name of a global variable, declared in a different procedure, which might be available when the procedure in question was called. If no such global variable is available, an ‘Undefined externals’ error is shown when the translated module is run. This also displays the variable name which caused the error, together with the module and procedure names, in this format: ‘Error in MODULE\PROCEDURE, VARIABLE’.

DECLARE EXTERNAL can be used at the head of your program to detect this kind of error during translation: see DECLARE EXTERNAL in the Keyword Reference section.


Including header files

Contents

  • Procedure prototypes
  • Const.oph

OPL allows you to include header files which may include definitions of procedure prototypes and constants, but not procedures themselves. Constants and procedure prototypes may also be declared at the top of modules themselves, although it is tidier to put them into a header file. Indeed, including a file is logically identical to replacing the INCLUDE statement by the file’s contents.

A header file is included in a module using the INCLUDE command at the beginning of the module, outside any procedure. For example,

    INCLUDE "Header.oph"

The filename of the header may or may not include a path. If it does include a path, then OPL will only scan the specified folder for the file. However, the default path for INCLUDE is \System\Opl\, so when INCLUDE is called without specifying a path, OPL looks for the file firstly in the current folder and then in \System\Opl\ in all drives from Y: to A: and then in Z:.

Commonly the statement,

    DECLARE EXTERNAL

will follow the INCLUDE declaration. DECLARE EXTERNAL causes the translator to report ‘Undefined externals’ errors if any variables or procedures are used before they are declared, rather than leaving this until runtime.

Procedure prototypes

Procedure prototypes are declared with the command EXTERNAL. For example,

    EXTERNAL Proc1:

A prototype is a declaration of the name of the procedure along with the arguments it takes. This amounts to the same as PROC declaration with the PROC keyword, which declares the start of a procedure, omitted. The procedure may then be referred to before it is defined when the DECLARE EXTERNAL statement has been made. As well as reporting ‘Undefined externals’ error at translate-time, the other advantage of using the DECLARE EXTERNAL and EXTERNAL statements is that it allows parameter type-checking to be performed at translate-time rather than at runtime, and also provides the necessary information for the translator to coerce numeric argument types, thus avoiding ‘Type violation’ errors at runtime. Hence a ‘Type violation’ error does not result in the following example, even though a & does not precede the 2 passed to the procedure two:(),

    DECLARE EXTERNAL
    EXTERNAL two:(long&)

    PROC one:
          two:(2)
    ENDP

    PROC two:(long&)
          ...
    ENDP

The same coercion occurs as when calling the built-in keywords.

Const.oph

Const.oph is the standard header file in the ROM. It provides many of the standard constant declarations required for effective and maintainable OPL programming. For convenient reference, the contents Const.oph is reproduced in full in Listing of Const.oph. This and other files stored in the ROM (for example, the OPX header files) may be created in RAM by using the ‘Create standard files’ option in the ‘Tools’ menu in the Program editor.

See also Keyword Reference.

EPOC SDK Home Glossary Previous Up


Database File Handling

  • Database manipulation
  • SQL specification
  • OPL and disks


Database manipulation

Contents

  • Overview
    • Terminology — Files, tables, records and fields
  • Accessing an open database
    • The current record
    • The current view
    • Assigning values to fields
    • Field names
    • Opening a file for sharing
  • Creating databases and tables
  • Opening databases and tables
  • Writing records
  • Transactions
    • Record position
    • Sequential access
    • The number of records
  • Closing views and databases
  • Indexes and dBase.opx
  • Additional database functionality
  • Compacting databases
  • Finding a record
    • DbFind&: — Finding records using string wildcards
    • DbFindField&: — More controlled finding
  • Opening a database created by the Data application

Overview

Section Contents

  • Terminology — Files, tables, records and fields
    • ‘View’ vs. ‘table’

You can use OPL to create data files (databases) like those used by the Data application. You can store any kind of information in a data file, and retrieve it for display, editing or calculations.

EPOC devices use a relational database management system (DBMS) which supports a subset of SQL, a standardised language for querying relational databases. A full description of the SQL queries possible in OPL is given in SQL specification.

Terminology — Files, tables, records and fields

Data files (or databases) are made up of tables. These tables consist of records which contain data in each of their fields. Fields are named, and each record in a table has the same fields. For example, in a table of names and addresses, each record might have a name field, a telephone number field, and separate fields for each line of the address.

In OPL you can:

  • Create a new file or table with CREATE, or open an existing file with OPEN, and copy, delete and rename files with COPY, DELETE and RENAME.
  • Add a new record with INSERT, change an existing one with MODIFY, and remove a record with ERASE.

‘View’ vs. ‘table’

This document makes the distinction between views and tables.

  • A table is the physical representation of data inside a database file.
  • A view is a way of looking at a table. OPL doesn’t have to load an entire table into memory in order to examine or alter its data; instead it uses a view of the data in the file, and keeps the data in the file until it needs to be read.

Views and tables both represent data in records with fields. This document often says ‘view’ rather than ‘table’ to emphasise that the data being looked at is really stored in a file outside the program. The whole database file is not read into memory when the database manipulation commands are used and it doesn’t have to be.

Accessing an open database

Section Contents

  • The current record
  • The current view
  • Assigning values to fields
  • Field names
  • Opening a file for sharing

You can have up to 26 views open at any time. Each of these must have a logical name, from A to Z. Logical names allow you to refer to a view many times without having to keep using the same file name or a lengthy SQL expression.

A different logical name must be used for each currently open view; when a view is closed the logical name is freed for use by another view. More than one view can be opened on a single database file.

Field handles are used like variables, so they have a %, $ or & appended to specify their type. They refer to the fields of a database view, so when they are used the logical name standing for the view must also be given. The two are separated by a dot:

current-record-lookup :
logical-name . field-handle-name [ % | $ | & ]

e.g., A.name$. This gives the contents of a particular field in the current record.

    CREATE "mydatabase",A,name$,price,contact$,numordered&
      :
    PRINT "Product name:"; a.name$
    PRINT "Number ordered:"; a.numordered&

Field handle names can be up to 32 characters long, including any qualifier like $ or &.

See also Creating databases and tables for details of CREATE.

The current record

OPL uses the idea of the current record within a view. Each database view has one record which is current, and subsequent field assignment operates on this record.

The FIRST, LAST, BACK, and NEXT keywords do not alter data in the database, but do change which record is current in the current view; INSERT also sets the current record. Records can also be searched for in a view with DbFind&: or DbFindField&: (see Finding a record below), and these keywords also set which record is current.

The current view

When OPL creates or opens a view, that view is current. This means that PUT saves records to this view, and the record-position commands move around this view. You can still use other open views, for example A.field1=B.field2

USE makes current one of the other opened files. For example USE B selects the file with the logical name B. If you attempt to USE a file which has not yet been opened or created, an error is reported.

Assigning values to fields

Fields can be assigned values just like variables. The field name must be used with the logical file name like this: A.f%=1 or INPUT A.f$. Field assignment operates on the current record in the named view.

If you try to give the wrong type of value to a field (for example "Davis" to A.f%) an error message will be displayed.

You can access the fields of an open view from other procedures, just like GLOBAL variables.

Field names

You must know the type of each field, and you must give each a separate name - you cannot refer to the fields in any indexed way, e.g. as an array.

Opening a file for sharing

The OPENR command works in exactly the same way as OPEN, except that the file cannot be written to with UPDATE, only read. However, more than one running program can then look at the file at the same time.

Creating databases and tables

Views of tables in databases are created with the OPL command CREATE:

CREATE opl-create-string , logical-name , field-handle-list

Which creates a table in a database, and assigns a view of it to logical-name. The database file given in create-expression is opened, or created if needed. After a CREATE statement, logical-name can be used to refer to the new database view.

field-handle-list is a comma-separated list of OPL variables which is used to provide the field handles for OPL (see Accessing an open database, above).

opl-create-string is a SQL table creation query encapsulated in an OPL string. It gives the name of the file to open, and optionally the table to look at and the names of the fields to put in it. Table creation queries are documented fully in Table creation.

If the table and field names are not given, then the table is called Table1, and the fields are named after the field handles. See below for examples of these.

N.B.: New tables cannot be created in databases that are already open. CREATE can be used to create a new table in an existing database, but the database must not be open when CREATE is called. If the database file is already open, use CLOSE to close it. OPEN can be used to reopen existing views.

A new table in a database contains a single record whose fields are blank — zero for numbers and the empty string for strings.

Examples of using CREATE

create-expressions can be simple or more complex. The simplest example is:

    CREATE "datafile",A,f1%,f2%

This creates a view of the data in the default table in the file datafile. The default table is called Table1. The field names in the new table are named after the names of the field handle variables, which in this case are f1% and f2%.

A more complex example:

    CREATE "people FIELDS name, number TO phoneBook",A,n$,number$

This will create a table called phoneBook in the database called people, creating the database too if it does not exist. The table will have fields name and number, whose respective types are specified by the field handles n$ and number$, both strings in this example.

In both examples, the contents of the database can then be accessed through A.

Opening databases and tables

The OPEN command opens a view of an existing table in a database:

OPEN opl-select-string , logical-name , field-handle-list

opl-select-string is a SQL selection query encapsulated in an OPL string. Selection queries are documented fully in Select statements.

field-handle-list is a comma-separated list of database field handles. These are used with logical-name to access the view as described in Accessing an open database (above).

Examples of using OPEN

    OPEN "datafile",A,f1%,f2%

Opens the default table Table1 and provide access to as many fields as there are handles supplied.

It is also possible to open multiple views on a table simultaneously and to specify which fields are to be available in a view, e.g.

    OPEN "people SELECT name FROM phoneBook",A,n$

This view gives you access to just the name field from the phoneBook table.

The string from SELECT onwards in the OPEN statement forms an SQL query which is passed straight on to the underlying EPOC DBMS. The SQL command-set is specified in SQL specification.

A more advanced view, ordered by an index (described later), would be opened as follows,

    OPEN "people SELECT name,number FROM phoneBook ORDER BY name
         ASC, number DESC",A,n$,num%

This would open a view with name fields in ascending alphabetical order and if any names were the same then the number field would be used to order these records in descending numerical order.

Writing records

Changes can be made to a view, and can be written into a database file at a later date.

When using CREATE and OPEN, you should also use the MODIFY, INSERT, PUT and CANCEL keywords. There are older keywords in OPL retained for compatibility — APPEND and UPDATE — but these are deprecated in the current release.

  • MODIFY begins a modification phase on the current record. It makes a copy
  • INSERT adds a new record to the current view with numeric fields set to zero and string fields empty if values have not been assigned to them. It also marks the start of a modification phase on the new record.
  • PUT marks the end of a database’s INSERT or MODIFY phase and makes the changes permanent.
  • CANCEL marks the end of a database’s INSERT or MODIFY phase and discards the changes made during that phase.

MODIFY and INSERT must take place within a transaction (see below). You’d use MODIFY or INSERT like this:

    BEGINTRANS    REM Start a transaction on some related records
      INSERT
        A.species$ = "King penguin"
        A.height   = 42.102
        A.name$    = "Gerald"
      PUT
       :          REM Maybe some more additions
    COMMITTRANS   REM End the transaction
                  REM write all PUTs to the file

Transactions

Section Contents

  • Record position
  • Sequential access
  • The number of records

A set of related records should be committed only on successfully PUTting the last one. Otherwise all new records may be discarded using ROLLBACK. This ensures the atomicity of the whole transaction.

Transactions allow changes to a database to be committed in stages. It is necessary to use transactions in database operations to achieve reasonable speeds.

A transaction is carried out using the following commands:

  • BEGINTRANS begins a transaction on the current view. Once a transaction has been started on a view (or table) then all database keywords will function as usual, but the changes to that view will not be made until COMMITTRANS is used.
  • COMMITTRANS commits the transaction and writes all changes into the file.
  • ROLLBACK cancels the current transaction on the current view. Changes made to the database with respect to this particular view since BEGINTRANS was called will be discarded.
  • INTRANS finds out whether the current view is in a transaction.

Transactions can be thought of as single, unitary operations on the file in which the current view is stored.

Record position

In the EPOC DBMS model, as with most modern relational database models, absolute record position does not have much significance.

Bookmarks can be assigned to particular records to provide fast record access and should be used in preference to POS and POSITION when opening views using the OPEN...SELECT.. or CREATE ... FIELDS... statements. POS and POSITION can be used safely on tables opened or created using a filename-only OPEN or CREATE statement. However, POS and POSITION should not be used in conjunction with bookmarks as bookmarks can cause these keywords — kept mainly for compatibility with older versions of OPL — to become inaccurate.

Note that if bookmarks are used in conjunction with POS and POSTION accuracy can be restored by using FIRST or LAST on the current view.

The bookmark commands are as follows: BOOKMARK puts a bookmark at the current record of the current database view. The value returned can be passed to GOTOMARK to make the record current again and to KILLMARK to delete the bookmark.

Sequential access

It is often useful to iterate through a database from the first record to the last. This can be achieved with the FIRST or LAST keywords in conjunction with BACK and NEXT:

  • FIRST positions to the first record in the current view.
  • LAST positions to the last record in the current view.
  • BACK positions to the last record in the current view.
  • NEXT positions to the last record in the current view.

You’d normally iterate forwards through a view using EOF:

    OPEN "mysortedfile",A,a$,b%
    FIRST
    DO
          PRINT A.a$
          PRINT A.b%
          NEXT
    UNTIL EOF
    GET

The number of records

The COUNT function returns the number of records in the file. If you try to count the number of records between MODIFY/INSERT and PUT, an ‘Incompatible update mode’ error will be raised.

Closing views and databases

CLOSE closes the current view on a database. If there are no other views open on the database then the database itself will be closed.

You should always ‘close’ a view (with the CLOSE command) when you have finished using it. Data files are fully closed automatically when a program ends.

You can use up to 26 logical names at a time — if you are using 26 logical names and you want to use another one, you must close one of the open files or views first. CLOSE closes the file or view referred to by the current logical name.

Indexes and dBase.opx

Indexes can be constructed on a table using several fields as keys. These indexes are subsequently used to provide major speed improvements when opening a table or views on them. This further functionality is provided in dBase.opx, which is supplied on the Release 5 EPOC ROMs.

Additional database functionality

Additional utilities for managing databases are provided in dbUtils.opx, which is supplied with the EPOC Release 5 OPL SDK.

Compacting databases

COMPACT compacts a database, rewriting the file in place without any removed or deleted data. All views on the database and the hence the file itself should be closed before calling this command. Compaction may also be done automatically on closing a file by setting the automatic compaction flag using SETFLAGS. See Keyword Reference for full details of this.

Finding a record

Section Contents

  • DbFind&: — Finding records using string wildcards
  • DbFindField&: — More controlled finding

DbFind&: (in SysRam1.opx) makes current the next record which has a field matching your search string. Capitals and lower-case letters match. For example:

    r&=DbFind&:("Brown")

would select the first record containing a string field with the value "Brown", "brown" or "BROWN", etc. The number of that record in the database is returned, in this case to the variable r&. If the number returned is zero, no matching field was found. Any other number means that a match was found.

The search includes the current record. So after finding a matching record, you need to use NEXT before you can continue searching through the following records.

DbFind&:("Brown") would not find a field "Mr Brown". To find this, use wildcards, as explained below.

You can only search string fields, not number fields. For example, if you assigned the value 71 to the field a%, you could not find this with DbFind&:. But if you assigned the value "71" to a$, you could find this.

DbFind&: — Finding records using string wildcards

r&=DbFind&:("*Brown*") would make current the next record containing a string field in which Brown occurred - for example, the fields "MR BROWN", "Brown A.R." and "Browns Plumbing" would be matched. The wildcards you can use are:

? | matches any one character
* | matches any number of characters.

Once you’ve found a matching record, you might display it on the screen, erase it or edit it. For example, to display all the records containing "BROWN":

    FIRST
    WHILE DbFind&:("*BROWN*")
          PRINT a.name$,a.phone$
          NEXT
          GET
    ENDWH

Note: DbFind&: replaces the buggy language keyword FIND, which is deprecated. See Including header files for details on how to include the header file SysRam1.oph, which defines DbFind&:.

DbFindField&: — More controlled finding

DbFindField&:, like DbFind&:, finds a string, makes the record with this string the current record, and returns the number of this record. However you can also use it to do case-dependent searching, to search backwards through the file, to search from the first record (forwards) or from the last record (backwards), and to search in one or more fields.

    f& = DbFindField&:(string$,start&,num&,flags&)

searches for the string string$ in num& fields in each record, starting at the field with number start& (1 is the number of the first field). start& and num& may refer to string fields only and other types will be ignored. If you want to search in all fields, use 1 as the second argument and for the third argument use the number of fields you used in the OPEN/CREATE command.

The flags& argument specifies the type of search as explained in the SysRam1 OPX reference documentation. Constants for flags& are supplied in Const.oph.

flags& can be used to make the search case-dependent, where case-dependent means that the record will exactly match the search string in case as well as characters. Other wise the search will case-independent which means that upper case and lower case characters will match.

For example, if the following OPEN (or CREATE) statement had been used:

    OPEN "clients",B,nm$,tel$,ad1$,ad2$,ad3$

then the command

    r&=DbFindField&:("*Brown*",1,3,16)

will search the nm$, tel$ and ad1$ fields of each record for strings containing "Brown" searching case-dependently backwards from the current record.

If you find a matching record and then you want to search again from this record, you must first use NEXT or BACK (according to the direction in which you are searching) to move past the record you have just found, otherwise the search will find the same match in the current record again.

Note: DbFindField&: replaces the buggy language keyword FINDFIELD, which is deprecated. See Including header files for details on how to include the header file Sysram.oph, which defines DbFindField&:.

Opening a database created by the Data application

It is not possible to open an OPL database from the Data application. You can however open a file created by the Data application in an OPL program. The file is opened for reading only because if it were written to, OPL would have to discard all the formatting characters and prevent the Data application from reopening the file subsequently. An OPL program can create a new OPL database and copy the Data application records into it if necessary.

To open a Data application database that has one string field which you need to access, you could use:

    OPEN "file",a,a$

Types not supported by OPL will be ignored. Note that integer fields in the Data application correspond to long integer fields in OPL: the Data application does not support 16-bit integer fields. The types and order of the OPL field handles must match the fields in the Data file. For example, if the data file Data2 contains:

  1. long integer field
  2. date/time field (ignored by OPL)
  3. string field
  4. floating-point number field

You could access the fields supported by OPL using:

    OPEN "Data2",A, f1&,f2$,f3

It would be better, however, to use the SQL SELECT clause to name the required Data file fields explicitly. For this to be possible it is necessary to use table name and the same field names as are used by Data. All Data files have a single table called Table1. The fields (referred to internally as columns in Data) are named ColA1, ColA2, etc.

So, with the field types from the previous example, the Data file could be opened using:

    OPEN "Data2 SELECT ColA1,ColA3,ColA4 FROM Table1",a,f1&,f2$,f3


SQL specification

Contents

  • Overview
  • Specifying the database to operate on
  • Table creation
  • Select statements
    • Selecting columns
    • Table and column names
  • Search conditions
    • Predicates
    • Specifying a sort order

Overview

The Structured Query Language is a standardised language for querying relational databases. It is abbreviated SQL, pronounced Sequel.

EPOC’s database management system uses a subset of SQL and permits SQL queries of databases; in OPL, SQL queries are used as string parameters to the CREATE and OPEN OPL commands (see Database manipulation). This document gives a BNF specification for these query strings.

Specifying the database to operate on

SQL statements act on databases, so the database file is passed first:

opl-create-string :
" database-file-name [ create-statement ] "

opl-open-string :
" database-file-name [ select-statement ] "

Table creation is handled by OPL’s CREATE command, and view selection and searching are handled by OPEN. CREATE and OPEN are described in the Database manipulation and Keyword Reference sections, and the syntax of the SQL queries create-statement and select-statement are described below.

Table creation

create-statement :
file-name [ field-restriction ] [ table-spec ]

field-restriction :
FIELDS field-name [ , field-name ]*

table-spec :
TO table-name

Table creation queries are used to make new tables in a database.

Select statements

Section Contents

  • Selecting columns
  • Table and column names
select-statement :
SELECT select-list FROM table-name [ where-clause ] [ ordering ]

where-clause :
WHERE search-condition

ordering :
ORDER BY sort-order

Use a select-statement to specify what data should be present in the view, and how to present it.

Selecting columns

select-list :
column-name-comma-list
*

column-name-comma-list :
column-name [ , column-name-comma-list ]

Specify * to request that all columns for the table be returned in the view, in an undefined order; otherwise a comma separated list specifies which columns to return, and the order that the columns appear in the view.

Table and column names

A table-name should be a table which exists in the database. column-names should refer to columns which exist in the specified table. Table and column names cannot contain spaces.

Search conditions

Section Contents

  • Predicates
    • Comparison predicate
    • Literals
    • Like predicate
    • Null predicate
  • Specifying a sort order
search-condition :
boolean-term [ OR search-condition ]

boolean-term :
boolean-factor [ AND boolean-term ]

boolean-factor :
[ NOT ] boolean-primary

boolean-primary :
predicate
( search-condition )

This specifies a condition which a row must meet to be present in the generated view. A trivial search condition is just a single predicate, more complex search conditions are constructed by combining predicates using the keywords AND, OR and NOT, and using parentheses to override the standard precedence of these operators. Without brackets, the order of precedence is NOT, AND then OR. e.g.

    a=1 or not b=2 and c=3

is equivalent to

    (a=1 or ((not b=2) and c=3))

Predicates

predicate :
comparison-predicate
like-predicate
null-predicate

These are the building blocks of the search condition. Each predicate tests one condition of a column in the selected table.

Comparison predicate

comparison-predicate :
column-name comparison-operator literal

comparison-operator :
< | > | <= | >= | = | <>

Compare a column value with a supplied literal value. Numeric columns (including bit columns) are compared numerically, text columns are compared lexically and date columns are compared historically. Binary columns cannot be compared. The literal must be of the same type (numeric, string, date) as the column.

Literals

literal :
string-literal
 numeric-literal
date-literal

A string-literal is a character string enclosed in single quote characters ('). To include a single literal quote character (') in a string-literal, use two literal quote characters: ('').

A numeric-literal is any sequence of characters which can be interpreted as a valid decimal integral or floating point number.

A date-literal is a character string enclosed by the # character, which can be interpreted as a valid date.

Like predicate

like-predicate :
column-name [ NOT ] LIKE pattern-value

pattern-value :
string-literal

Test whether or not a text column matches a pattern string. The wildcard characters used in the pattern-value are not standard SQL, instead the EPOC wildcard characters are used: ? for matching any single character and * for matching zero or more characters.

Null predicate

null-predicate :
column-name IS [ NOT ] NULL

Test whether or not a column is Null. This predicate can be applied to all column types.

Specifying a sort order

sort-order :
sort-specification-comma-list

sort-specification :
column-name [ ASC | DESC ]

Without an ORDER BY clause in the select statement the order that rows are presented is undefined. The columns specified in the sort-order can be ordered in ascending (the default) or descending order, and should appear in the sort-order in decreasing order of precedence. e.g.

    surname, first_name

will order the rows by the column surname, and any rows with identical surnames will then be ordered by the column first_name.


OPL and disks

Memory disks in the D: drive may be used in the same way as the internal memory by specifying D: where you would usually specify C:.

There are two main reasons for using disks:

  • To provide more room for storing data.
  • To make backup copies of important information, in case you accidentally change or delete it (or even lose your machine).

The internal memory, memory disks use a FAT directory structure, the same as that used by disks on PCs. For more details, see Advanced Topics.

The ROM drive, Z:, can also be read from. However, Z: is read-only.

EPOC SDK Home Glossary Previous Up


Graphics and Interaction

  • Graphics
  • Friendlier interaction


Graphics

Contents

  • Introduction
  • Simple graphics
    • Drawing lines
    • Clearing the screen
    • Using colour
    • Overwriting pixels
    • Graphical text
  • Windows
    • Window IDs and the default window
    • Graphics keywords and windows
    • Creating new windows
    • Closing windows
    • When windows overlap
    • Hiding windows
    • The graphics cursor in windows
    • Information about your windows
    • Other window keywords
  • Advanced graphics
    • Bitmaps
    • Masks
    • Speed improvements
    • Displaying a running clock
    • User-defined fonts and cursors
    • The text and graphics windows

Introduction

OPL graphics allow you, for example, to:

  • Draw lines and boxes.
  • Fill areas with patterns.
  • Display text in a variety of styles, at any position on the screen.
  • Scroll areas of the screen.
  • Manipulate windows and bit patterns.
  • Read data back from the screen.
  • Draw circles and ellipses.
  • Set the pen width.

Graphics keywords begin with a G. In this manual a lower case g is used — for example, gCOLOR or gBOX — but you can type them using upper or lower case letters.

Some graphics keywords are mentioned only briefly in this topic. For more details about them, see Keyword Reference.

Simple graphics

Section Contents

  • Drawing lines
    • Drawing dots
    • Right and down, left and up
    • Going off the screen
  • Clearing the screen
  • Using colour
    • Colour modes
    • Colour commands
    • Colour literals and using single-integer colours
  • Overwriting pixels
    • Drawing rectangles
    • Overwriting with any drawing command
    • Other drawing keywords
  • Graphical text
    • Displaying text with gPRINT
    • Fonts
    • Text style
    • Overwriting with gPRINT
    • Other graphical text keywords

The dimensions of the screens, expressed as points across and down the screen, are given by the gHEIGHT and gWIDTH keywords. These points are sometimes referred to as pixels.

Each pixel is identified by two numbers, giving its position across and down from the top left corner of the screen. 0,0 denotes the pixel in the top left corner; 2,1 is the pixel 2 points across and one down, and so on.

Note that these co-ordinates are very different to the cursor positions set by the AT command.

OPL maintains a current position on the screen. Graphics commands which draw on the screen generally take effect at this position. Initially, the current position is the top left corner, 0,0.

Drawing lines

Here is a simple procedure to draw a horizontal line in the middle of the screen:

    PROC lines:
          gMOVE 180,80
          gLINEBY 120,0
          GET
    ENDP

gMOVE moves the current position by the specified amount. In this case, it moves the current position 180 pixels right and 80 down, from 0,0 to 180,80. It does not display anything on the screen.

gLINEBY (g-line-by) draws a line from the current position (just set to 180,80) to a point at the distance you specify — in this case 120 to the right and 0 down, i.e. 300,80.

The end points of lines are not drawn: for gLINEBY dx%,dy%, point gX+dx%,gY+dy% is not drawn. Note, however, that OPL specially plots the point when the start and end-point coincide.

gLINEBY also has the effect of moving the current position to the end of the line it draws.

With both gMOVE and gLINEBY, you specify positions relative to the current position. Most OPL graphics commands do likewise. gMOVE and gLINEBY, however, do have corresponding commands which use absolute pixel positions. gAT moves to the pixel position you specify; gLINETO draws a line from the current position to an absolute position. The horizontal line procedure could instead be written:

    PROC lines:
          gAT 180,80
          gLINETO 300,80
          GET
    ENDP

gAT and gLINETO may be useful in very short graphics programs, and gAT is always the obvious command for moving to a particular point on the screen, before you start drawing. But once you do start drawing, use gMOVE and gLINEBY. They make it much easier to develop and change programs, and allow you to make useful graphics procedures which can display things anywhere you set the current position. Almost all graphics drawing commands use relative positioning for these reasons.

Drawing dots

You can set the pixel at the current position with gLINEBY 0,0.

Right and down, left and up

gMOVE and gLINEBY find the position to use by adding the numbers you specify on to the current position. If the numbers are positive, it moves to the right and down the screen. If you use negative numbers, however, you can specify positions to the left of and/or above the current position. For example, this procedure draws the same horizontal line as before, then another one above it:

    PROC lines2:
          gMOVE 180,80
          gLINEBY 120,0
          gMOVE 0,-20
          gLINEBY -120,0
          GET
    ENDP

The first two program lines are the same as before. gLINEBY moves the current position to the end of the line it draws, so after the first gLINEBY the current position is 300,80. The second gMOVE moves the current position up by 20 pixels; the second gLINEBY draws a line to a point 120 pixels to the left. The end pixel is never set.

Going off the screen

No error is reported if you try to draw off the edge of the screen. It is quite possible to leave the current position off the screen — for example, gLINETO 650,80 will draw a line from the current position to some point on the right-hand screen edge, but the current position will finish as 650,80.

There’s no harm in the current position being off the screen. It allows you to write procedures to display a certain pattern at the current position, and not have to worry whether that position is too close to the screen edge for the whole pattern to fit on.

Clearing the screen

gCLS clears the screen.

Using colour

Different EPOC devices have different display hardware. The number of different colours a device can display can be found using gCOLORINFO (see below). The gCOLOR and gCOLORINFO commands can be used to set any colour without error, but colours may be displayed differently — for example, on a greyscale machine, all colours are displayed in grey. On a 16-colour machine, many colours will be displayed as a dithering of supported colours.

It is possible to create windows with a greater colour depth then the display hardware allows — colours are dithered as described above. This is a processor-intensive operation.

Colour modes

OPL supports various colour modes:

  • 2-grey mode; stored as 1 bpp. Monochrome.
  • 4-grey mode; stored as 2 bpp.
  • 16-grey mode; stored as 4 bpp.
  • 256-grey mode; stored as 8 bpp.
  • 16-colour mode; stored as 4 bpp (fixed palette; low-colour EGA).
  • 256-colour mode; stored as 8 bpp (fixed palette).
  • 65,536-colour mode; stored as 16 bpp (16-bit true colour).
  • 16,777,216-colour mode; stored as 24 bpp (24-bit true colour).

By default the screen is in one of these modes — gCOLORINFO can be used to discover which. To enable drawing in non-standard colour modes, you need to use DEFAULTWIN mode at the start of your program. (Note that this also clears the screen.)

In general, deeper colour modes use more power. Also, note that setting the colour depth of any window using DEFAULTWIN or gCREATE any deeper than that of the screen consumes processor time — dithering is an expensive operation.

It is difficult to be more precise since the power consumption is also dependent on what is being displayed.

Colour commands

  • gCOLOR — sets the foreground (pen) colour.
  • gCOLORBACKGROUND [image] — sets the background (paper) colour.
  • gCOLORINFO [image] — query EPOC for the maximum screen depth the device is capable of.

To set the colour used for graphics, use gCOLOR red%,green%,blue%. The red%, green% and blue% values specify a colour, which will be mapped to white, black or a dithered colour or grey. If the values of red%, green% and blue% are equal, then a pure grey results.

Note that if you use gCOLOR, colours with shades between the colours available will appear dithered, that is areas of the colour will have some pixels set to one colour and some to another so as to give the appearance of a colour between the two colours used. If gCOLOR is used in 2-colour mode, light greys will be mapped to white and dark greys to black.

In general, you should use as few colours as you can in your graphical displays, as some EPOC devices will consume less power.

DEFAULTWIN does not affect PRINT statements — it applies only to graphics and graphics text (see gPRINT later).

Constants for the modes of DEFAULTWIN and gCREATE (see below) are supplied in Const.oph.

Colour literals and using single-integer colours

OPL supports colours using the three-value RGB system which uses three numeric values to uniquely define a colour. For example, the colour 'dark red' consists of RGB values $80, $00, $00. However it is possible to combine these values into one long integer number: &800000. To improve ease-of-use of some colours, colour constants have been added to Const.oph:

          CONST KRgbBlack&=&000000
          CONST KRgbDarkGray&=&555555
          CONST KRgbDarkRed&=&800000
          CONST KRgbDarkGreen&=&008000
          CONST KRgbDarkYellow&=&808000
          CONST KRgbDarkBlue&=&000080
          CONST KRgbDarkMagenta&=&800080
          CONST KRgbDarkCyan&=&008080
          CONST KRgbRed&=&ff0000
          CONST KRgbGreen&=&00ff00
          CONST KRgbYellow&=&ffff00
          CONST KRgbBlue&=&0000ff
          CONST KRgbMagenta&=&ff00ff
          CONST KRgbCyan&=&00ffff
          CONST KRgbGray&=&aaaaaa
          CONST KRgbDitheredLightGray&=&cccccc
          CONST KRgb1in4DitheredGray&=&ededed
          CONST KRgbWhite&=&ffffff

These colour constants can be used to define and pass colours to procedures in a compact manner. Using a set of colour masks and colour position constants, the RGB values can be easily extracted. For example, using the following constants declared in Const.oph,

          REM RGB color masking:
          CONST KRgbRedPosition&=&10000
          CONST KRgbGreenPosition&=$100
          CONST KRgbBluePosition&=$1
          CONST KRgbColorMask&=$ff

the following type of procedure can be coded:

          PROC SetColor:(rgb&)
            LOCAL red%,green%,blue%
            red%=rgb&/KRgbRedPosition& AND KRgbColorMask&
            green%=rgb&/KRgbGreenPosition& AND KRgbColorMask&
            blue%=rgb& AND KRgbColorMask&
            gCOLOR red%,green%,blue%
          ENDP

which allows the three colour values to be stored and passed in a single long integer. For example: SetColor:(KRgbMagenta&).

Overwriting pixels

Drawing rectangles

The gBOX command draws a box outline. For example, gBOX 100,20 draws a box from the current position to a point 100 pixels to the right and 20 down. If the current position were 200,40, the four corners of this box would be at 200,40, 300,40, 300,60 and 200,60.

If you have used gCOLOR as described earlier, the box is drawn in the colour selected.

gBOX does not change the current position.

gFILL draws a filled box in the same way as gBOX draws a box outline, but it has a third argument to say which pixels to set. If set to 0, the pixels which make up the box would be set. If set to 1, pixels are cleared; if set to 2, they are inverted, that is, pixels already set on the screen become cleared, and vice versa. The values 1 and 2 are used when overwriting areas of the screen which already have pixels set.

This procedure displays a "robot" face, using gFILL to draw set and cleared boxes:

    PROC face:
          gFILL 120,120,0                 REM set the entire face
          gMOVE 10,20 :gFILL 30,20,1      REM left eye
          gMOVE 70,0 :gFILL 30,20,1       REM right eye
          gMOVE -30,30 :gFILL 20,30,1     REM nose
          gMOVE -20,40 :gFILL 60,20,1     REM mouth
          GET
    ENDP

Before calling such a procedure, you would set the current position to be where you wanted the top left corner of the head.

You could make the robot wink with the following procedure, which inverts part of one eye:

    PROC wink:
          gMOVE 10,20                     REM move to left eye
          gFILL 30,14,2                   REM invert most of the eye
          PAUSE 10
          gFILL 30,14,2                   REM invert it back again
          GET
    ENDP

Again, you would set the current position before calling this.

The gPATT command can be used to draw a shaded filled rectangle. To do this, use -1 as its first argument, then the same three arguments as for gFILL - width, height, and overwrite method. Overwrite methods 0, 1 and 2 apply only to the pixels which are ‘on’ in the shading pattern. Whatever was on the screen may still show through, as those pixels which are ‘clear’ in the shading pattern are left as they were.

To completely overwrite what was on the screen with the shaded pattern, gPATT has an extra overwrite method of 3. So, for example, gPATT -1,120,120,3 in the first procedure would have displayed a shaded robot head, whatever may have been on the screen.

Overwriting with any drawing command

By using the gGMODE command, any drawing command such as gLINEBY or gBOX can be made to clear or invert pixels, instead of setting them. gGMODE determines the effect of all subsequent drawing commands.

The values are the same as for gFILL: gGMODE 1 for clearing pixels, gGMODE 2 for inverting pixels, and gGMODE 0 for setting pixels again. (0 is the initial setting.)

For example, some white lines can give the robot a furrowed brow:

    PROC brow:
          gGMODE 1                REM gLINEBY will now clear pixels
          gMOVE 10,8 :gLINEBY 100,0
          gMOVE 0,4 :gLINEBY -100,0
          gGMODE 0
          GET
    ENDP

Constants for the modes are supplied in Const.oph.

Other drawing keywords

For more details of these keywords, see Keyword Reference.

  • gBUTTON: draw a 3-D button (a picture of a key, not of an application button) enclosing supplied text. The button can be raised, depressed or sunken. The button may also enclose a bitmap with a mask (see the ‘Bitmaps’ section below).
  • gBORDER, gXBORDER: draw 2-D/3-D borders.
  • gINVERT: invert a rectangular area, except for its four corner pixels.
  • gCOPY: copy a rectangular area from one position on the screen to another.
  • gSCROLL: move a rectangular area from one position on the screen to another, or scroll the contents of the screen in any direction.
  • gPOLY: draw a sequence of lines.
  • gCIRCLE, gELLIPSE: draw a circle or ellipse which can be filled or empty.
  • gSETPENWIDTH: draw with a different pen width.

Graphical text

Displaying text with gPRINT

The PRINT command displays text in one font, in a screen area controlled by the FONT or SCREEN commands. You can, however, display text in a variety of fonts and styles, at any pixel position, with gPRINT.

gPRINT also allows you to draw text in colour if you have used the gCOLOR or gCOLORBACKGROUND commands previously. You can control the font and style used by OPL’s other text-drawing keywords, such as PRINT and EDIT. See The text and graphics windows (below).

gPRINT is a graphical version of PRINT, and displays a list of expressions in a similar way. Some examples:

    gPRINT "Hello",name$
    gPRINT a$
    gPRINT "Sin(PI/3) is",sin(pi/3)

Unlike PRINT, gPRINT does not end by moving to a new line. A comma between expressions is still displayed as a space, but a semicolon has no effect. gPRINT used on its own does nothing.

The first character displayed has its left side and baseline at the current position. The baseline is like a line on lined note paper graphically, this is the horizontal line which includes the lowest pixels of upper case characters. Some characters, such as ‘g’, ‘j’, ‘p’, ‘q’ and ‘y’, set pixels below the baseline.

After using gPRINT, the current position is at the end of the text so that you can print something else immediately beyond it. As with other graphics keywords, no error is reported if you try to display text off the edge of the screen.

While CURSOR ON displays a flashing cursor for ordinary text displayed with PRINT, CURSOR 1 switches on a cursor for graphical text which is displayed at the current position. CURSOR OFF removes either cursor.

Fonts

The gFONT command sets the font to be used by subsequent gPRINT commands.

A large set of fonts which can be used with gFONT is provided in the ROM.

The special font number &9a is set aside to give a machine’s default graphics font; this is the font used initially for graphics text. The default font is Arial 15, whose UID is KFontArialNormal15&. So gFONT KFontArialNormal15& or gFONT &9a both set the standard font, which gPRINT normally uses.

Fonts are identified by a 32-bit UID. You can directly specify the fonts by UID by using the definitions listed in the header file Const.oph. The Squashed and Tiny fonts are used for the toolbar in bold style.

For example, normal Arial proportional font with height 8 pixels has UID given by,

    CONST KFontArialNormal8&=268435954

so you could use

    INCLUDE "Const.oph"
    ...
    gFONT KFontArialNormal8&

See gINFO32 and FONT in the Keyword Reference if you need to find out more information about fonts.

This program shows you examples of the fonts. (!!! is displayed to emphasise the monospaced fonts) It displays a variety of fonts, using their UIDs.

    INCLUDE "Const.oph"

    PROC fonts:
          showfontbyuid:(KFontCourierNormal8&,15,"Courier 8")
          showfontbyuid:(KFontTimesNormal8&,25,"Times 8")
          showfontbyuid:(KFontTimesNormal11&,38,"Times 11")
          showfontbyuid:(KFontTimesNormal13&,53,"Times 13")
          showfontbyuid:(KFontTimesNormal15&,71,"Times 15")
          showfontbyuid:(KFontArialNormal8&,81,"Arial 8")
          showfontbyuid:(KFontArialNormal11&,94,"Arial 11")
          showfontbyuid:(KFontArialNormal13&,109,"Arial 13")
          showfontbyuid:(KFontArialNormal15&,127,"Arial 15")
          showfontbyuid:(KFontTiny4&,135,"Tiny 4")
    ENDP

    PROC showfontbyuid:(font&,y%,str$)
          gFONT font&
          gAT 20,y% :gPRINT font%
          gAT 50,y% :gPRINT str$
          gAT 150,y% :gPRINT "!!!"
    ENDP

Text style

The gSTYLE command sets the text style to be used by subsequent gPRINT commands.

Choose from these styles:

gSTYLE 1 | bold
gSTYLE 2 | underlined
gSTYLE 4 | inverse
gSTYLE 8 | double height
gSTYLE 16 | mono
gSTYLE 32 | italic

Constants for these values are supplied in Const.oph.

The ‘mono’ style is not proportionally spaced - each character is displayed with the same width, in the same way that PRINT displays characters (by default). A proportional font can be displayed as a mono-spaced font by setting the ‘mono’ style. See the previous section for the list of mono-spaced and proportional fonts.

N.B.: It is inefficient to use the ‘mono’ style to display a font which is already mono-spaced.

You can combine these styles by adding the relevant numbers together. gSTYLE 12 sets the text style to inverse and double-height (4+8=12). Here’s an example of this style:

    PROC style:
          gAT 20,50 :gFONT 11
          gSTYLE 12 :gPRINT "Attention!"
          GET
    ENDP

Use gSTYLE 0 to reset to normal style.

The bold style provides a way to make any font appear bold. Most system fonts look reasonably bold already. Note that using the bold style sometimes causes a change of font; if you use gINFO you may see the font name change.

Note that fonts which are always bold are available. Using a bold style with these fonts results in a double bold font. It is not necessary to use these fonts to produce bold font: you can of course use just the normal fonts in a bold style.

Overwriting with gPRINT

gPRINT normally displays text as if writing it with a pen - the pixels that make up each letter are set, and that is all. If you’re using areas of the screen which already have some pixels set, or even have all the pixels set, use gTMODE to change the way gPRINT displays the text.

gTMODE controls the display of text in the same way as gGMODE controls the display of lines and boxes. The values you use with gTMODE are similar to those for gGMODE: gTMODE 1 for clearing pixels, gTMODE 2 for inverting pixels, and gTMODE 0 for setting pixels again. There is also gTMODE 3 which sets the pixels of each character while clearing the character’s background. This is very useful as it guarantees that the text is readable.

Constants for these values are supplied in Const.oph.

This procedure shows the various effects possible via gTMODE:

    PROC tmode:
          DEFAULTWIN 2
          gFONT 11 :gSTYLE 0
          gAT 160,0 :gFILL 160,80,0              REM Black box
          gAT 220,0 :gFILL 40,80,1               REM White box
          gAT 180,20 :gTMODE 0 :gPRINT "ABCDEFGHIJK"
          gAT 180,35 :gTMODE 1 :gPRINT "ABCDEFGHIJK"
          gAT 180,50 :gTMODE 2 :gPRINT "ABCDEFGHIJK"
          gAT 180,65 :gTMODE 3 :gPRINT "ABCDEFGHIJK"
          gCOLOR $50,$50,$50
          gAT 160,80 :gFILL 160,80,0            REM Grey box
          gAT 220,80 :gFILL 40,80,1             REM White box
          gAT 180,100 :gTMODE 0 :gPRINT "ABCDEFGHIJK"
          gAT 180,115 :gTMODE 1 :gPRINT "ABCDEFGHIJK"
          gAT 180,130 :gTMODE 2 :gPRINT "ABCDEFGHIJK"
          gAT 180,145 :gTMODE 3 :gPRINT "ABCDEFGHIJK"
          GET
    ENDP

Other graphical text keywords

  • gPRINTB: display text left aligned, right aligned or centred, in a cleared box. The gTMODE setting is ignored.
  • gXPRINT: display text underlined/highlighted.
  • gPRINTCLIP: display text clipped to whole characters.
  • gTWIDTH: find width required by text.

All of these keywords take the current font and style into account, and work on a single string. They display text in the colour specified by gCOLOR.

Windows

Section Contents

  • Window IDs and the default window
  • Graphics keywords and windows
  • Creating new windows
  • Closing windows
  • When windows overlap
  • Hiding windows
  • The graphics cursor in windows
  • Information about your windows
  • Other window keywords

So far, you’ve used the whole of the screen for displaying graphics. You can, however, use windows - rectangular areas of the screen.

Sprites (described in About OPXs) can display non-rectangular shapes. OPL allows a program to use up to sixty-four windows at any one time.

Window IDs and the default window

Each window has an ID number, allowing you to specify which window you want to work with at any time.

When a program first runs, it has one window called the default window. Its ID is 1, it is the full size of the screen, and initially all graphics commands operate on it. (This is why ‘0,0’ has so far referred to the top left of the screen: it is true for the default window.)

Other windows you create will have IDs from 2 to 64. When you make another window it becomes the current window, and all subsequent graphics commands operate on it.

In the discussion and examples above, we used only the default window. However, everything actually applies to the current window. For example, if you make a small window current and try to draw a very long line, the current position moves off past the window edge, and only that part of the line which fits in the window is displayed.

Graphics keywords and windows

For OPL graphics keywords, positions apply to the window you are using at any given time. The point 0,0 means the top left corner of the current window, not the top left corner of the screen.

Each window can be created in any of the 3 colour modes by specifying the last argument in the gCREATE command (see below and Keyword Reference). gCOLOR can be used to specify the current pen colour and gSETPENWIDTH to specify the pen width. The default is 4-colour mode, as for the default window.

For the default window, the special command DEFAULTWIN is required to change colour modes because that window is automatically created for you in 4-colour mode; DEFAULTWIN clears the default window and resets colour mode to that specified. All other windows must be created in the colour mode in which they are required: it may not be changed once they are created.

Once a window has been created with a certain colour mode, colours specified by gCOLOR work in the exactly the same way as in the default window.

gCOLOR, gCOLORBACKGROUND, gGMODE, gTMODE, gFONT and gSTYLE can all be used with created windows in exactly the same way as with the default window, as described earlier. They change the settings for the current window only; all the settings are remembered for each window.

Creating new windows

The gCREATE function sets up a new window on the screen. It returns an ID number for the window. Whenever you want to change to this window, use gUSE with this ID.

You can create a window with any valid colour mode by specifying the last optional parameter to gCREATE.

Here is an example using gCREATE and gUSE, contrasting the point 20,20 in the created window with 20,20 in the default window.

    PROC windows:
          LOCAL id%
          id%=gCREATE(60,40,320,30,1,2)    REM 16-grey mode
          gBORDER 0 :gAT 20,20 :gLINEBY 0,0
          gPRINT " 20,20 (new)"
          GET
          gUSE 1 :gAT 20,20 :gLINEBY 0,0
          gPRINT " 20,20 (default)"
          GET
          gUSE id%
          gCOLOR $88,$88,$88               REM mid grey
          gPRINT " Back"
          gCOLOR 0,0,0                     REM black
          gPRINT " (with 16 colours)"
          GET
    ENDP

The line id%=gCREATE(60,40,320,30,1,2) creates a window with its top left corner at 60,40 on the screen. The window is set to be 320 pixels wide and 30 pixels deep. (You can use any integer values for these arguments, even if it creates the window partially or even totally off the screen.) The fifth argument to gCREATE specifies whether the window should immediately be visible or not; 0 means invisible, 1 (as here) means visible. The sixth argument specifies the colour mode. Constants for different colour modes are supplied in Const.oph.

If the sixth argument is not supplied at all (e.g. id%=gCREATE(60,40,320,30,1)) the window will have the default colour mode.

gCREATE automatically makes the created window the current window, and sets the current position in it to 0,0. It returns an ID number for this window, which in this example is saved in the variable id%.

The gBORDER 0 command draws a border one pixel wide around the current window. Here this helps show the position and size of the window. (gBORDER can draw a variety of borders. You can display the 3-D style borders seen in menus and dialogs, with the gXBORDER keyword.)

The program then sets the pixel at 20,20 in this new window, using gLINEBY 0,0.

gUSE 1 goes back to using the default window. The program then shows 20,20 in this window.

Finally, gUSE id% goes back to the created window again, and a final message is displayed, in grey and black.

Note that each window has its own current position. The current position in the created window is remembered while the program goes back to the default window. All the other settings, such as the font, style and grey setting are also remembered.

Closing windows

When you’ve finished with a particular window, close it with gCLOSE followed by its ID - for example, gCLOSE 2. You can create and close as many windows as you like, as long as there are only 64 or fewer open at any one time.

If you close the current window, the default window (ID=1) becomes current.

An error is raised if you try to close the default window.

When windows overlap

Windows can overlap on the screen, or even hide each other entirely. Use the gORDER command to control the foreground/background positions of overlapping windows.

gORDER 3,1 sets the window whose ID is 3 to be in the foreground. This guarantees that it will be wholly visible. gORDER 3,2 makes it second in the list; unless the foreground window overlaps it, it too will be visible.

Any position greater than the number of windows you have is interpreted as the end of the list. gORDER 3,9 will therefore always force the window whose ID is 3 to the background, behind all others.

Note in particular that making a window the current window with gUSE does not bring it to the foreground. You can make a background window current and draw all kinds of things to it, but nothing will happen on the screen until you bring it to the foreground with gORDER.

When a window is first created with gCREATE it always becomes the foreground window as well as the current window.

Hiding windows

If you are going to use several drawing commands on a particular window, you may like to make it invisible while doing so. When you then make it visible again, having completed the drawing commands, the whole pattern appears on the screen in one go, instead of being built up piece by piece.

Use gVISIBLE ON and gVISIBLE OFF to perform this function on the current window. You can also make new windows invisible as you create them, by using 0 as the fifth argument to the gCREATE command, and you can hide windows behind other windows.

The graphics cursor in windows

To make the graphics cursor appear in a particular window, use the CURSOR command with the ID of the window. It will appear flashing at the current position in that window, provided it is not obscured by some other window.

The window you specify does not have to be the current window, and does not become current; you can have the cursor in one window while displaying graphical text in another. If you want to move to a different window and put the graphics cursor in it, you must use both gUSE and CURSOR.

Since the default window always has an ID of 1, CURSOR 1 will, as mentioned earlier, put the graphics cursor in it.

CURSOR OFF turns off the cursor, wherever it is.

Information about your windows

You don’t have to keep a complete copy of all the information pertaining to each window you use. These functions return information about the current window:

  • gIDENTITY returns its ID number.
  • gRANK returns its foreground/background position, from 1 to 8.
  • gWIDTH and gHEIGHT return its size.
  • gORIGINX and gORIGINY return its screen position.
  • gX and gY return the current position.
  • gINFO32 returns information about the font, style, colour settings, overwrite modes and cursor in use.

Other window keywords

  • gSETWIN changes the position, and optionally the size, of the current window.

N.B.: You can use this command on the default window, if you wish, but you must also use the SCREEN command to ensure that the text window — the area for PRINT commands to use — is wholly contained within the default window. See The text and graphics windows (below).

  • gSCROLL scrolls all or part of both black and grey planes of the current window.
  • gPATT fills an area in the current window with repetitions of another window, or with a shaded pattern.
  • gCOPY copies an area from another window into the current window, or from one position in the current window to another.

It is inadvisable to use gCOPY to copy from windows as it is very slow. It should only be used for copying from bitmaps to windows or other bitmaps.

  • gSAVEBIT saves part or all of a window as a bitmap file.
  • gPEEKLINE reads back a horizontal line of data in the specified mode (see Keyword Reference) from a specified window.

Advanced graphics

Section Contents

  • Bitmaps
  • Masks
  • Speed improvements
  • Displaying a running clock
  • User-defined fonts and cursors
  • The text and graphics windows

This section should provide a taste of some of the more exotic things you can do with OPL graphics.

Bitmaps

A bitmap is an area in memory which acts just like an off-screen window. You can create bitmaps with gCREATEBIT.

It is possible to create bitmaps in any valid colour mode by specifying the optional third argument when using gCREATEBIT. The default is 2-bpp mode (black and white). Note, however, that black and white bitmaps differ from black and white windows. In particular, if you draw in 16 colours to a black and white bitmap then greys appear as dithered black and white, whereas if you draw exactly the same to a 2-colour graphics window you just get dark greys mapped to black and light greys mapped to white. This enables grey printing on black and white printers.

A further benefit is that the file size will be smaller if the bitmap is saved, with just 1 bpp used for black and white bitmaps.

Bitmaps have the following uses:

  • You can manipulate an image in a bitmap before copying it with gPATT or gCOPY to a window on the screen. This is generally faster than manipulating an image in a hidden window.
  • You can load bitmap files into bitmaps in memory using gLOADBIT, then copy them to on-screen windows using gCOPY or gPATT.

OPL treats a bitmap as the equivalent of a window in most cases:

  • Both are identified by ID numbers. Only one window or bitmap is current at any one time, set by gUSE.
  • If you use bitmaps as well as windows, the total number must be 64 or fewer.
  • The top left corner of the current bitmap is still referred to as 0,0, even though it is not on the screen at all.

Together, windows and bitmaps are known as drawables — places you can draw to.

Most graphics keywords can be used with bitmaps in the same way as with windows, but remember that a bitmap corresponds to only one plane in a window. Once you have drawn to it, you might copy it to the appropriate plane of a window.

The keywords that can be used with bitmaps include: gLINEBY, gLINETO, gBOX, gFILL, gCIRCLE, gELLIPSE , gCOLOR, gSETPENWIDTH, gUSE, gBORDER, gCLOSE, gCLS, gCOPY, gGMODE, gFONT, gIDENTITY, gPATT, gPEEKLINE, gSAVEBIT, gSCROLL, gTMODE, gWIDTH, gHEIGHT, and gINFO32. These keywords are described earlier in this topic.

Masks

There are several keywords that require an understanding of masks. In some cases the mask is a bitmap file, e.g. gBUTTON (see earlier in this topic and also Keyword Reference) and for ICON (see Advanced Topics), and in some cases it is an integer containing a bit-mask, e.g. for POINTERFILTER.

In all these cases, however, the principle is the same. The pixels or bits which are set in the mask specify pixels or bits in some other argument which are to be used. Pixels and bits which are clear in the mask specify pixels and bits that are not to be used from the other argument.

For example, when using gBUTTON with identical bitmap and mask, cleared pixels on the bitmap are drawn in the background colour of the button (i.e. they are clear) while set pixels are drawn on the button as they appear on the bitmap. This is generally how buttons on toolbars appear.

Speed improvements

The screen is usually updated whenever you display anything on it. gUPDATE OFF switches off this feature. The screen will be updated as few times as possible, although you can force an update by using the gUPDATE command on its own. (An update is also forced by GET, KEY and by all graphics keywords which return a value, other than gX, gY, gWIDTH and gHEIGHT).

This can result in a considerable speed improvement in some cases. You might, for example, use gUPDATE OFF, then a sequence of graphics commands, followed by gUPDATE. You should certainly use gUPDATE OFF if you are about to write exclusively to bitmaps.

gUPDATE ON returns to normal screen updating.

Also, remember that scrolling and moving windows require every pixel in a window to be redrawn.

The gPOLY command draws a sequence of lines, as if by gLINEBY and gMOVE commands. If you have to draw a lot of lines (or dots, with gLINEBY 0,0), gPOLY can greatly reduce the time taken to do so.

Displaying a running clock

gCLOCK displays or removes a running clock showing the system time. The clock can be digital or conventional, and can use many different formats. See Keyword Reference for full details.

User-defined fonts and cursors

If you have a user-defined font you can load it into memory with gLOADFONT.

gLOADFONT returns a file ID, which can be used only with gUNLOADFONT. The maximum number of font files which may be loaded at any one time is 16. To use the fonts in a loaded font you need to use the UIDs specified in the font file itself.

You can use four extra arguments with the CURSOR command. Three of these specify the ascent, width and height of the cursor. The ascent is the number of pixels (-128 to 127) by which the top of the cursor should be above the baseline of the current font. The height and width arguments should both be between 0 and 255. For example, CURSOR 1,12,4,14 sets a cursor 4 pixels wide by 14 high in the default window (ID=1), with the cursor top at 12 pixels above the font baseline.

If you do not use these arguments, the cursor is 2 pixels wide, and has the same height and ascent as the current font.

By default the cursor has square corners, is black and is flashing. Supply the fifth argument as 2 for non-flashing or 4 for grey. You can add these together - e.g. use 6 for a grey, non-flashing cursor.

Note that the gINFO32 command returns information about the cursor and font.

The text and graphics windows

PRINT displays mono-spaced text in the text window. You can change the text window font (i.e. that used by PRINT) using the FONT keyword.

You can use any of those fonts listed in Const.oph. Initially Courier 11 is used.

It should be noted that when using the console keywords PRINT, AT, SCREEN, etc. the use of proportional fonts such as Arial and Times may produce some unexpected behaviour because it is assumed in all cases that mono-spaced font is being used. The reason for this is so that use of keywords such as AT, SCREEN in the console is independent of whether the font is proportional or monospaced. An example of this behaviour may be seen when using inverted text: the rectangle to invert is calculated assuming that the font is mono-spaced, and hence the area inverted is larger than the text printed when using a proportional font. Another example is that a new line will be used before it appears necessary when using a proportional font, since the number of characters which will fit on a line is also calculated assuming the font is mono-spaced.

The text window is in fact part of the default graphics window. If you have other graphics windows in front of the default window, they may therefore hide any text you display with PRINT.

Initially the text window is very slightly smaller than the default graphics window which is full-screen size. They are not the same because the text window height and width always fits a whole number of characters of the current text window font. If you use the FONT command to change the font of the text window, this first sets the default graphics window to the maximum size that will fit in the screen and then resizes the text window to be as large as possible inside it.

You can also use the STYLE keyword to set the style for all characters subsequently written to the text window. This allows the mixing of different styles in the text window.

Use the same values as listed for gSTYLE (above).

To find out exactly where the text window is positioned, use SCREENINFO info%(). This sets info%(1)/info%(2) to the number of pixels from the left/top of the default window to the left/top of the text window. (These are called the margins.) info%(7) and info%(8) are the text window’s character width and height respectively.

N.B.: The margins are fully determined by the font being used and therefore change from their initial value only when FONT is used. You cannot choose your own margins. gSETWIN and SCREEN do not change the margins, so you can use FONT to select a font (also clearing the screen), followed by SCREENINFO to find out the size of the margins with that font, and finally gSETWIN and SCREEN to change the sizes and positions of the default window and text window taking the margins into account (see example below). The margins will be the same after calling gSETWIN and SCREEN as they were after FONT.

It is not generally recommended to use both the text and graphics windows. Graphics commands provide much finer control over the screen display than is possible in the text window, so it is not easy to mix the two.

If you do need to use the text window, for example to use keywords like EDIT, it’s easy to use SCREEN to place it out of the way of your graphics windows. You can, however, use it on top of a graphics window - for example, you might want to use EDIT to simulate an edit box in the graphics window. Use gSETWIN to change the default window to about the size and position of the desired edit box. The text window moves with it - you must then make it the same size, or slightly smaller, with the SCREEN command. Use 1,1 as the last two arguments to SCREEN, to keep its top left corner fixed. gORDER 1,1 will then bring the default window to the front, and with it the text window. EDIT can then be used.

Here is an example program which uses this technique - moving an ‘edit box’, hiding it while you edit, then finally letting you move it around.

    PROC gsetw1:
          LOCAL a$(100),w%,h%,g$(1),factor%,info%(10)
          LOCAL margx%,margy%,chrw%,chrh%,defw%,defh%
          SCREENINFO info%()           REM get text window info
          margx%=info%(1) :margy%=info%(2)
          chrw%=info%(7) :chrh%=info%(8)
          defw%=23*chrw%+2*margx%   REM new default window width
          defh%=chrh%+2*margy%      REM ... and height
          w%=gWIDTH :h%=gHEIGHT
          gSETWIN w%/4+margx%,h%/4+margy%,defw%,defh%
          SCREEN 23,1,1,1              REM text window
          PRINT "Text win:"; :GET
          gCREATE(w%*0.1,h%*0.1,w%*0.8,h%*0.8,1)     REM new window
          gPATT -1,gWIDTH,gHEIGHT,0                  REM shade it
          gAT 2,h%*0.7 :gTMODE 3
          gPRINT "Graphics window 2"
          gORDER 1,0                REM back to default+text window
          EDIT a$                   REM you can see this edit
          gORDER 1,65               REM to background
          CLS
          a$=""
          PRINT "Hidden:";
          GIPRINT "Edit in hidden edit box"
          EDIT a$                   REM YOU CAN’T SEE THIS EDIT
          GIPRINT ""
          gORDER 1,0 :GET           REM now here it is
          gUSE 1                    REM graphics go to default window
          DO                        REM move default/text window
                                    REM around
              CLS
              PRINT "U,D,L,R,Quit";
              g$=UPPER$(GET$)
              IF KMOD=2            REM Shift key moves quickly
                  factor%=10
              ELSE
                  factor%=1
              ENDIF
              IF g$="U"
                  gSETWIN gORIGINX,gORIGINY-factor%
              ELSEIF g$="D"
                  gSETWIN gORIGINX,gORIGINY+factor%
              ELSEIF g$="L"
                  gSETWIN gORIGINX-factor%,gORIGINY
              ELSEIF g$="R"
                  gSETWIN gORIGINX+factor%,gORIGINY
              ENDIF
          UNTIL g$="Q" OR g$=CHR$(27)
    ENDP


Friendlier interaction

Contents

  • Introduction
  • Menus
  • Dialogs
    • Lines you can use in dialogs
    • Other dialog information
  • Toolbars
    • Toolbar.oph
    • Typical Toolbar.opo usage
  • Giving information

Introduction

Everyday OPL programs can use the same graphical interface seen throughout the system:

  • Menus offer lists of options for you to choose from. You can also select these options with shortcut keys like Ctrl+A, Ctrl+B etc.
  • Dialogs let a program ask for all kinds of information numbers, filenames, dates and times etc. in one go.
  • Screen messages such as ‘Busy’ are available.

Menu keywords begin with an M, and dialog keywords with a D. In this manual a lower case is used for these letters for example, mINIT and dEDIT but you can type them using upper or lower case letters.

Menus

Section Contents

  • Defining the menus
  • Menu flags
  • Displaying the menus
  • Problems with menus
  • A menu example

Menus provide a simple way for any reasonably complex OPL program to let you choose from its various options.

To display menus in OPL generally takes three basic steps:

  • Use the mINIT command. This prepares OPL for new menus.
  • Use the mCARD and mCASC commands to define each menu.
  • Use the MENU function to display the menus.

You use the displayed menus like any others on the system. Use the arrow keys or the pen to move around the menus. Tap an option, press Enter when it is selected, or press the option’s shortcut key to use it, or press Esc or Menu again to cancel the menus without making a choice. In either case, the menus are removed, the screen redrawn as it was, and MENU returns a value to indicate the selection made.

Defining the menus

The first argument to mCARD is the name of the menu. This will appear at the top of the menu; the names of all of the menus form a bar across the top of the screen.

Any number of options on the menu may be defined, each specified by two arguments. If there are more items than can be displayed on the screen at once, then the menu is displayed with a scroll bar. It is recommended that the number of menu items on a menu does not exceed the maximum number displayable at once on the screen of the target device; keeping the number of menu items small means that the user can select the menu item without having to scroll the menu.

The first argument in a menu item pair is the option name, and the second is the keycode for a shortcut key. This specifies a key which when pressed together with the Ctrl key should select the option. (Your program must still handle shortcut keys which are pressed without using the menu.) It is easiest to specify the shortcut key with % e.g. %a gives the value for a.

If an upper case character is used for the shortcut key keycode, the Shift key must be pressed as well to select the option; this will appear as ‘Shift+Ctrl+A’ in the menu. If you supply a keycode for a lower case character, the option is selected only without the Shift key pressed. Both upper and lower case keycodes for the same character can be used in the same menu (or set of menus). This feature may be used to increase the total number of shortcut keys available, and is also commonly used for related menu options e.g. %m might be used for zooming to a larger font and %M for zooming to a smaller font (as in the built-in applications).

For example,

    mCARD "Comms","Setup",%s,"Transfer",%t

defines a menu with the title Comms. When you move to this menu, you’ll see it has the two options Setup and Transfer, with shortcut keys Ctrl+S and Ctrl+T respectively (and no Shift key required). On the other hand,

    mCARD "Comms","Setup",%S,"Transfer",%T

would give these options the shortcut keys Shift+Ctrl+S and Shift+Ctrl+T.

The options on a large menu may be divided into logical groups (as seen in many of the menus for the built-in applications) by displaying a line under the final option in a group. To do this, you must pass the negative value corresponding to the shortcut key keycode for the final option in the group. For example, -%A specifies shortcut key Shift+Ctrl+A and displays a grey line under the associated option in the menu.

Each subsequent mCARD defines the next menu to the right. A large OPL application might use mCARD like this:

    mCARD "File","New",%n,"Open",%o,"Save",%s
    mCARD "Edit","Cut",%x,"Copy",%c,"Paste",-%v,"Eval",%e
    mCARD "Search","First",%f,"Next",%g,"Previous",%p

Menu flags

It is possible to have menu items without shortcuts, by specifying shortcut values between 1 and 32. The value specified is still returned if the item is selected.

Dimming, checkboxes and option buttons are controlled by adding the following values to the shortcut keycode (the constants are found in Const.oph.):

KMenuDimmed% | $1000 | item dimmed
KMenuCheckBox% | $0800 | item has checkbox
KMenuOptionStart% | $0900 | item starts option button list
KMenuOptionMiddle% | $0A00 | item in middle of option button list
KMenuOptionEnd% | $0B00 | item ends option button list
KMenuSymbolOn% | $2000 | symbol on (checkbox/option button)
KMenuSymbolIndeterminate% | $4000 | symbol indeterminate

Dimming a menu item makes it unavailable and on trying to select it, the info print ‘This item is not available’ is automatically displayed. Items with checkboxes have a tick symbol on or off on their left hand side to show whether or not they have been selected. The start, middle and end option buttons are for specifying a group of related items that can be selected exclusively (i.e. if one item is selected then the others are deselected). The number of middle option buttons is variable.

Adding in the KMenuSymbolOn% flag sets the tick on a checkbox or the button on an option button item on. The display of ticks and option buttons is automatically changed appropriately when you select one of these items, but your program needs to maintain the state of any checkbox or option button between displays of the menu.

A single menu card can have more than one set of option buttons and checkboxes, but option buttons in a set should be kept together. For speed, OPL does not check the consistency of these items’ specification.

Cascaded items on which less important menu items can be displayed may also be created. The cascade must be defined before use in a menu cascade card. The following is an example of a ‘Bitmap’ cascade under the File menu of a possible OPL drawing application.

    mCASC "Bitmap","Load",%L,"Merge",%M
    mCARD "File","New",%n,"Open",%o,"Save",%s,"Bitmap>",16,"Exit",%e

The trailing > character specifies that a previously defined cascade item is to be used in the menu at this point: it is not displayed in the menu item. A cascade has a filled arrow head displayed along side it in the menu. The cascade title in mCASC is also used only for identification purposes and is not displayed in the cascade itself. This title needs to be identical to the menu item text apart from the >. For efficiency, OPL doesn’t check that a defined cascade has been used in a menu and an unused cascade will simply be ignored.

Shortcut keys used in cascades may be added with the appropriate constant values to enable checkboxes, option buttons and dimming of cascade items.

As is typical for cascade titles, a shortcut value of 16 is used in the example above. This prevents the display or specification of any shortcut key. However, it is possible to define a shortcut key for a cascade title if required, for example to cycle through the options available in a cascade.

Displaying the menus

The MENU function displays the menus defined by mINIT and mCARD, and waits for you to select an option. It returns the shortcut key keycode of the option selected, in the case supplied by you, whether you used the pen or Enter or the shortcut key itself to select it. If you supplied a negative shortcut key keycode for an underlined option, it is converted to its positive equivalent.

If you cancel the menus by pressing Esc, MENU returns 0.

Displaying a popup menu

A popup menu which appears at a specified point on the screen, may also be defined and drawn using mPOPUP. Note that popup menus have only one pane and need not and should not be within the mINIT...MENU structure. mPOPUP returns the value of the shortcut code in the same way as MENU. For example,

    mPOPUP(0,0,KMPopupPosTopLeft%,"Continue",%c,"Exit",%e)

The first two arguments specify the position of one corner and the third argument specifies which corner this is. This third argument takes values as follows,

KMPopupPosTopLeft% | 0 | Top left.
KMPopupPosTopRight% | 1 | Top right.
KMPopupPosBottomLeft% | 2 | Bottom left.
KMPopupPosBottomRight% | 3 | Bottom right.

Thus, the example above specifies a popup menu with 0,0 as its top left-hand corner and with the items ‘Continue’ and ‘Exit’, with the shortcuts Ctrl+C and Ctrl+E respectively.

You can add the same values to the shortcut key keycode as those used with mCARD and mCASC to display dimmed items, checkboxes and option buttons. Note, however, that cascades in popup menus are not supported. For example,

    mPOPUP(0,0,KMPopupPosTopLeft%,"View1",%v OR $2900,"View2",%b OR $A00,"View3",%n OR $B00)

would display a popup menu with option buttons, with the symbol initially set on on the View1 item ($2000 is ORed into it as well as $900).

Problems with menus

You must ensure that you do not use the same shortcut key twice when defining the menus, as OPL does not check for this.

Each menu definition uses some memory, so ‘No system memory’ errors are possible.

Don’t forget to use mINIT before you begin defining the menus.

If the menu titles defined by mCARD are wider than 40 characters, MENU will raise a ‘Too wide’ error.

Shortcut values must be alphabetic character codes or numbers between the values of 1 and 32. Any other values will raise an ‘Invalid arguments’ error.

Note also that a menu is discarded when an item fails to be added successfully. In effect the previous mINIT statement is discarded together with any previous mCARD statements. This avoids the problem of trying to use a badly constructed menu item.

It is therefore incorrect to ignore mCARD errors by having an ONERR label around an mCARD call (see Error Handling for more details). If you do, the menu is discarded and a ‘Structure fault’ will then be raised on using mCARD or MENU without first using mINIT again.

A menu example

This procedure allows you to press the Menu key and see a menu. You might instead be typing a number or some text into the program, or moving around in some way with the arrow keys, and this procedure returns any such keypresses. You could use this procedure instead of a simple GET whenever you want to allow a menu to be shown, and its shortcut keys to work.

Each of the options in the menus have a corresponding procedure named proc plus the shortcut key letter so for example, the option with shortcut key Ctrl+N (Psion-N) is handled by the procedure procn.

This procedure uses the technique of calling procedures by strings, as described in Advanced Topics. For example:

    PROC kget%:
          LOCAL k%,h$(9),a$(5)
          h$="nosciefgd"              REM our shortcut keys
          WHILE 1
              k%=GET
              IF k%=$122        REM Menu key
                  mINIT
                  mCARD "File","New",%n,"Open",%o,"Save",%s
                  mCARD "Edit","Copy",%c,"Insert",-%i,"Eval",%e
                  mCARD "Search","First",%f,"Next",%g,"Previous",%d
                  k%=MENU
                  IF k% AND (LOC(h$,CHR$(k%))<>0)    REM MENU CHECK
                      a$="proc"+CHR$(k%)
                      @(a$):       REM procn:, proco:, ...
                  ENDIF            REM END OF MENU CHECK
              ELSEIF KMOD AND $4   REM shortcut key pressed directly?
                  k%=k%+$40        REM remove Ctrl modification
                  IF LOC(h$,CHR$(k%)) REM DIRECT SHORTCUT KEY CHECK
                      a$="proc"+CHR$(k%)
                      @(a$):       REM procn:, proco:, ...
                  ENDIF     REM END OF DIRECT SHORTCUT KEY CHECK
              ELSE                 REM some other key
                      RETURN k%
                ENDIF
          ENDWH
    ENDP

procn:, proco:, etc. would need to be specified to use this example in practice on any of the machines:

    PROC procn:
          ...
    ENDP

    PROC proco:
          ...
    ENDP
    ...

Note that this procedure allows you to press a shortcut key with or without the Shift key. So Ctrl+Shift+N would be treated the same as Ctrl+N.

Neither LOC nor the @ operator (for calling procedures by strings) differentiate between upper and lower case. If you have Shifted shortcut keys you will need to compare against two sets of shortcut key lists. For example, with shortcut keys %A, %C, %a and %d, you would have upper/lowercase shortcut key lists like hu$="AC" and hl$="ad", and the "MENU CHECK" section becomes:

    IF k%<=%Z                   REM if upper case shortcut key
        IF LOC(hu$,CHR$(k%))
        a$="procu"+CHR$(k%)
            @(a$):              REM procua:, procuc:, ...
        ENDIF
    ELSE                        REM else lower case shortcut key
        IF LOC(hl$,CHR$(k%))
            a$="procl"+CHR$(k%)
            @(a$)               REM procla:, procld:, ...
        ENDIF
    ENDIF

(This calls procedures procua:, procuc:, procla: and procld:). If a shortcut key was pressed directly you cannot tell from k% whether Shift was used; so make the same change to the "DIRECT SHORTCUT KEY CHECK" section, but use IF KMOD AND 2 instead of IF k%<=%Z.

Dialogs

Section Contents

  • Lines you can use in dialogs
    • Strings, secret strings and filenames
    • Choosing one of a list
    • Numbers, dates and times
    • Results from dDATE
    • Displaying text
    • Displaying exit keys
  • Other dialog information
    • Positioning dialogs
    • Other dialog features
    • Restrictions on dialogs

In OPL, dialogs are constructed in a similar way to menus:

  • Use the dINIT command to prepare OPL for a new dialog. If you give a string argument to dINIT it will be displayed as a title for the dialog. The title will be in a grey box at the top of the dialog.
  • Define each line of the dialog, from top to bottom. There are separate commands for each type of item you can use in a dialog for example, dEDIT for editing a string, dDATE for typing in a date, and so on.
  • Use the DIALOG function to display the dialog. In general it returns a number indicating the line you were on when you pressed Enter (counting any title line as line 1), or 0 if you pressed Esc.

Use the up and down arrows to move from line to line, and enter the relevant information, as in any other dialog. You can even press Tab to produce vertical lists of options when appropriate.

Each of the commands like dEDIT and dDATE specifies a variable to take the information you type in. If you press Enter to complete the dialog, the information is saved in those variables. The dialog is then removed, and the screen redrawn as it was.

You can press Esc to abandon the dialog without making any changes to the variables.

If you enter information which is not valid for the particular line of the dialog, you will be asked to enter different information.

Here is a simple example. It assumes a global variable name$ exists:

    PROC getname:
          dINIT "Who are you?"
          dEDIT name$,"Name:"
          DIALOG
    ENDP

This procedure displays a dialog with Who are you? as its top-line title, and an edit box for typing in your name. If you end by pressing Enter, the name you have typed will be saved in name$; if you press Esc, name$ is not changed.

When the dialog is first displayed, the existing contents of name$ are used as the string to edit.

Note that the dialog is automatically created with a width suitable for the item(s) you defined, and is centred in the screen.

Lines you can use in dialogs

This section describes the various commands that can define a line of a dialog. In all cases:

  • prompt$ is the string which will appear on the left side of the line.
  • var denotes an argument which must be a LOCAL or GLOBAL variable, because it takes the value you enter. Single elements of arrays may also be used, but not field variables or procedure parameters. (var is just to show you where you must use a suitable variable you don’t actually type var.)

    • Where appropriate, this variable provides the initial value shown in the dialog.

Although examples are given using each group of commands, you can mix commands of any type to make up your dialog.

More details of the commands may be found in Keyword Reference.

Strings, secret strings and filenames

    dEDIT var str$,prompt$,len%

defines a string edit box.

len% is an optional argument. If supplied, it gives the width of the edit box (allowing for the widest possible character in the font). The string will scroll inside the edit box, if necessary. If len% is not supplied, the edit box is made wide enough for the maximum width str$ could be. (You may wish to set a suitably small len% to stop some dialogs being drawn all the way across the screen)

    dXINPUT var str$,prompt$

defines a secret string edit box, such as for a password. A special symbol will be displayed for each character you type, to preserve the secrecy of the string.

    dFILE var str$,prompt$,f%,Uid1&,Uid2&,Uid3&

defines a filename editor or selector box. dFILE automatically has ‘Folder’ and ‘Disk’ selectors on the lines below it. f% controls whether you have a file editor or selector in your dialog, and the kind of input allowed. Files selected may also be restricted by UID. See dFILE in Keyword Reference for full details of how to do this.

Here is an example dialog using these commands:

    PROC info:
          LOCAL n$(30),pw$(16),f$(255)
          dINIT "Your personal info"
          dEDIT n$,"Name:",15
          dXINPUT pw$,"Password:"
          dFILE f$,"Log file,Folder,Disk",0
          RETURN DIALOG
    ENDP

This procedure returns ‘True’ if Enter was used, indicating that the GLOBAL variables n$, pw$ and f$ have been updated.

dEDITMULTI var pData&,p$,widthInChars%,numLines%,maxLen%
defines a multi-line edit box to go into a dialog. Normally the resulting text would be used in a subsequent dialog, saved to file or printed using the Printer OPX (see About OPXs). The use of this dialog command is more complicated than the others (see Keyword Reference for full details).

Choosing one of a list

    dCHOICE var choice%,prompt$,list$

defines a choice list. list$ should contain the possible choices, separated by commas for example, "Yes,No". The choice% variable specifies which choice should initially be shown 1 for the first choice, 2 for the second, and so on.

For example, here is a simple choice dialog:

    PROC dcheck:
          LOCAL c%
          c%=2                              REM default to "View2"
          dINIT "Change View"
          dCHOICE c%,"View:","View1,View2,View3"
          IF DIALOG                   REM returns 0 if cancelled
                ...                         REM change view
          ENDIF
    ENDP

Extended choice lists may also be defined by using more than one dCHOICE statement (see Keyword Reference for full details of how to do this).

    dCHECKBOX chk%,prompt$

creates a checkbox entry. This is similar to a choice list with two items, except that the list is replaced by a checkbox with the tick either on or off. The state of the checkbox is maintained across calls to the dialog. Initially you should set the live variable chk% to 0 to set the tick symbol off and to any other value to set it on. chk% is then automatically set to 0 if the box is unchecked or -1 if it is checked when the dialog is closed.

Numbers, dates and times

    dLONG var long&,prompt$,min&,max&

and

    dFLOAT var fp,prompt$,min,max

define edit boxes for long integers and floating-point numbers respectively. Use dFLOAT to allow fractions, and dLONG to disallow them. min(&) and max(&) give the minimum and maximum values which are to be allowed. There is no separate command for ordinary integers use dLONG with suitable min& and max& values.

    dDATE var long&,prompt$,min&,max&

and

    dTIME var long&,prompt$,type%,min&,max&

define edit boxes for dates and times. min& and max& give the minimum and maximum values which are to be allowed.

For dDATE, long&, min& and max& are specified in "days since 1/1/1900". The DAYS function is useful for converting to "days since 1/1/1900".

For dTIME, long&, min& and max& are in "seconds since 00:00". The DATETOSECS and SECSTODATE functions are useful for converting to and from "seconds since midnight" (they actually use "seconds since 00:00 on 1/1/1970").

dTIME also has a type% argument. This specifies the type of display required:

0 | absolute time without seconds
1 | absolute time with seconds
2 | duration without seconds
3 | duration with seconds
4 | absolute times in 24 hour clock
8 | time not displaying hours

Constants for these values are defined in Const.oph.

For example, 03:45 is an absolute time, while 3 hours 45 minutes is a duration.

This procedure creates a dialog, using these commands:

    PROC delivery:
          LOCAL d&,t&,num&,wt
          d&=DAYS(DAY,MONTH,YEAR)
          DO
                t&=secs&:
          UNTIL t&=secs&:
          num&=1 :wt=10
          dINIT "Delivery"
          dLONG num&,"Boxes",1,1000
          dFLOAT wt,"Weight (kg)",0,10000
          dDATE d&,"Date",d&,DAYS(31,12,1999)
          dTIME t&,"Time",0,0,DATETOSECS(1970,1,1,23,59,59)
          IF DIALOG                              REM returns 0 if cancelled
                ...                               REM rest of code
          ENDIF
    ENDP

    PROC secs&:
          RETURN HOUR*INT(3600)+MINUTE*60
    ENDP

The secs&: procedure uses the HOUR and MINUTE functions, which return the time as kept by the machine. It is called twice to guard against an incorrect result, in the (albeit rare) case where the time ticks past the hour between calling HOUR and calling MINUTE.

The INT function is used in secs&: to force OPL to use long integer arithmetic, avoiding the danger of an ‘Overflow’ error.

d& and t& are set up to give the current date and time when the dialog is first displayed. The value in d& is also used as the minimum value for dDATE, so that in this example you cannot set a date before the current date.

DATETOSECS is used to give the number of seconds representing the time 23:59. The first three arguments, 1970, 1 and 1, represent the first day from which DATETOSECS begins calculating.

Results from dDATE

dDATE returns a value as a number of days

To convert this to a date use DAYSTODATE which converts a number of days since 1/1/1990, to the corresponding date. See ref.toc for full details.

Displaying text

    dTEXT prompt$,body$,type%

defines prompt$ to be displayed on the left side of the line, and body$ on the right. There is no variable associated with dTEXT. If you use a null string ("") for prompt$, body$ is displayed across the whole width of the dialog.

type% is an optional argument. If specified, it controls the alignment of body$:

0 | left align body$
1 | right align body$
2 | centre body$

Note that alignment of body$ is only supported when prompt$ is null, with the body being left aligned otherwise.

In addition, you can add any or all of the following three values to type%, for these effects:

$200 | draw a line below this item.
$400 | make the prompt (not the body) selectable.
$800 | make this item a text separator

dTEXT is not just for displaying information. Since DIALOG returns a number indicating the line you were on when you pressed Enter (or 0 if you pressed Esc), you can use dTEXT to offer a choice of options, rather like a menu:

    PROC selact:
          dINIT "Select action"
          dTEXT "Add","",$402
          dTEXT "Copy","",$402
          dTEXT "Review","",$402
          dTEXT "Delete","",$402
          RETURN DIALOG
    ENDP

In each case type% is $402 ($400+2). The $400 makes each prompt selectable, allowing you to move the cursor on to it. Note that only the prompts are selectable. However, the items will be centre aligned in the dialog.

See the Keyword Reference for full details of dTEXT.

Displaying exit keys

Most dialogs are completed by pressing Enter to confirm the information typed, or Esc to cancel the dialog. These keys are not usually displayed as part of the dialog.

However, some dialogs offer you a simple choice, by showing pictures of the keys you can press. A simple "Are you sure?" dialog might, for example, show the two keys ‘Y’ and ‘N’, and indicate the one you press.

If you want to display a message and offer Enter, Esc and/or Space as the exit keys, you can display the entire dialog with the ALERT function.

If you want to use other keys, such as Y and N, or display the keys below other dialog items such as dEDIT, create the dialog as normal and use the dBUTTONS command to define the keys.

ALERT and dBUTTONS are explained in detail in Keyword Reference.

Other dialog information

Positioning dialogs

If a dialog overwrites important information on the screen, you can position it with the dPOSITION command. Use dPOSITION at any time between dINIT and DIALOG.

dPOSITION uses two integer values. The first specifies the horizontal position, and the second, the vertical. dPOSITION -1,-1 positions to the top left of the screen; dPOSITION 1,1 to the bottom right; dPOSITION 0,0 to the centre, the usual position for dialogs.

dPOSITION 1,0, for example, positions to the right-hand edge of the screen, and centres the dialog half way up the screen.

Other dialog features

dINIT can take a second optional parameter to specify additional dialog features. This may be any ORed combination of the following constants,:

value | effect
1 | buttons positioned on the right rather than at the bottom
2 | no title bar (any title in dINIT is ignored)
4 | use the full screen
8 | don’t allow the dialog box to be dragged
16 | pack the dialog densely (not buttons though)

Constants for these flags are supplied in Const.oph.

It should be noted that dialogs without titles cannot be dragged regardless of the "No drag" setting. Dense packing enables more lines to fit on the screen for larger dialogs.

For example, the following could be used for a large dialog:

    dINIT "Big Dialog",$15

so that the dialog covers the full screen, has buttons (as defined by dBUTTONS) on the right and has items densely packed.

Restrictions on dialogs

The following general restrictions apply to all dialogs:

  • Only one dialog may be in use at a time.
  • A dialog must be initialised (dINIT), defined (dEDIT etc.) and displayed (DIALOG) in the same procedure.
  • No error is raised if the dialog is too wide or too long to fit on the screen: it is up to the programmer to ensure the dialog is displayed in a suitable way.

Toolbars

Section Contents

  • Toolbar.oph
  • Typical Toolbar.opo usage
    • TBarLink:
    • TBarColor:
    • TBarInit:
    • TBarInitC:
    • TBarSetTitle:
    • TBarButt:
    • TBarOffer%:
    • TBarLatch:
    • TBarShow:
    • TBarHide:
    • Public Toolbar globals

All OPL programs should use the ROM module Z:\System\Opl\Toolbar.opo to create a toolbar window with a title, four buttons and a clock.

The public interface to Toolbar.opo is supplied in Z:\System\Opl\Toolbar.oph which is reproduced below. The procedures and their usage are then discussed in detail.

Toolbar.oph

    rem Toolbar.oph
    rem Header file for OPL's toolbar
    rem Copyright (c) 1997-1998 Symbian Ltd. All rights reserved.

    external TBarLink:(appLink$)
    external TBarInit:(title$,scrW%,scrH%)
    external TBarInitC:(title$,scrW%,scrH%,winMode%)
    external TBarInitNonStd:(name$,scrW%,scrH%,width%)
    external TBarSetTitle:(name$)
    external TBarButt:(shortCut$,pos%,text$,state%,bit&,mask&,flags%)
    external TBarOffer%:(winId&,ptrType&,ptrX&,ptrY&)
    external TBarLatch:(comp%)
    external TBarShow:
    external TBarHide:
    external TBarColor:(fgR%,fgG%,fgB%,bgR%,bgG%,bgB%)

    rem The following are global toolbar variables usable by Opl programs
    rem or libraries: usable after toolbar initialisation:
    rem   TbWidth%         the pixel width of the toolbar
    rem   TbVis%           -1 if visible and otherwise 0
    rem   TbMenuSym%       the current 'Show toolbar' menu
    rem                    symbol (to be ORed with shortcut
    rem                    letter)
    rem Flags for toolbar buttons

    const KTbFlgCmdOnPtrDown%=$01

    rem The order and values of the following are significant so don't change without due care

    const KTbFlgLatchStart%=$12            rem start of latchable set
    const KTbFlgLatchMiddle%=$22      rem middle of latchable set
    const KTbFlgLatchEnd%=$32                  rem end of latchable set
    const KTbFlgLatched%=$04                  rem set for current latched item in set

    rem End of Toolbar.oph

Typical Toolbar.opo usage

Typically a program would use Toolbar.opo in the following way:

  • LOADM "Z:\System\Opl\Toolbar.opo" to load the toolbar module. This module must remain loaded as long as you need to use the toolbar.
  • ‘Link’ the toolbar-specific globals into the top-level of your program, using TBarLink:
  • (Possibly) initialise the toolbar’s title colours using TBarColor:.
  • Initialise the toolbar, creating an invisible toolbar window with title and clock, using TBarInit:( [image] : TBarInitC: can be used instead to supply a colour mode for the toolbar).
  • Add normal or latchable toolbar buttons to the toolbar, using TBarButt:
  • Make the toolbar visible, using TBarShow:
  • Offer all pointer events to the toolbar so that it can call your commands, change the system clock type or display the task list, using TBarOffer%:
  • Latch a button down to represent the current view when the view changes, using TBarLatch:
  • Change the toolbar title to the current document name, using TBarSetTitle:
  • Show and hide the toolbar as appropriate, using TBarShow: and TBarHide:
  • Provide command-handling procedures to be called by Toolbar.opo when a toolbar button is pressed.

TBarLink:

Usage: TBarLink:(appLink$)

TBarLink: provides all toolbar globals required in your application. It has to be called before TBarInit: and from a higher level procedure in your application than the one in which the globals are used.

appLink$ is the name of the so-called continuation procedure in your main application. TBarLink: calls this procedure, which should then go on to run the rest of your program. This allows the globals declared in TBarLink: to exist until the application exits. appLink$ must represent a procedure with name and parameters like:

    PROC appContTBarLink:
          REM Continue after ‘linking’ toolbar globals
          myAppInit:            REM run rest of program
          ...
    ENDP

i.e. taking no parameters and with no return-type specification character, so that it can be called using @(appLink$):.

TBarColor:

Usage: TBarColor:(foreR%,foreG%,foreB%,backR%,backG%,backB%)

Within the toolbar, the colours for the title text, title background and the clock border background default to black ($00,$00,$00) for the foreground and white ($ff,$ff,$ff) for the background.

TBarColor: sets the RGB values for the foreground colour, and the RGB values for the background colour.

Note: in order to set the colours, the TBarColor: procedure should be called before initialising the toolbar with TBarInit: or TBarInitC: (below).

TBarInit:

Usage: TBarInit:(title$,scrW%,scrH%)

Called at start of application only, this procedure creates the toolbar window, which guarantees that there will be sufficient memory available to display the toolbar at any subsequent time. The toolbar is made invisible when not shown. This procedure also draws all toolbar components except the buttons.

Note that, for speed, TBarInit: turns graphics auto-updating off (using gUPDATE OFF). If automatic updating is required, use gUPDATE ON after TBarInit: returns.

Note also that TBarInit: sets compute mode off (see SETCOMPUTEMODE: in System.opx — EPOC system functions) allowing the program to run at foreground priority when in foreground. By default OPL programs have compute mode on (i.e. they run at background priority even when in foreground).

Note: The toolbar needs a minimum of 4 greys to display the buttons and clock correctly. You should ensure the mode is at least 2-bit (KColorDefWin4GrayMode%) if using TBarInit.

  • title$ is the title shown in the toolbar. You should change this to the name of your current file, using TBarSetTitle:.
  • scrW% is the full-screen width (gWIDTH at startup).
  • scrH% is the full-screen height (gHEIGHT at startup).

See also TBarInitC:, below.

TBarInitC:

Usage: TBarInitC:(title$,scrW%,scrH%,winMode%)

Initialises the toolbar in colour mode. TBarInitC: is based on TBarInit: but takes an additional parameter winMode% which defines the window mode used to create the toolbar. You should use at least 4 grey mode (KColorgCreate4GrayMode%) for the window mode as explained above.

See gCREATE for the possible values of winMode%.

TBarSetTitle:

Usage: TBarSetTitle:(name$)

Sets the title in the toolbar.

name$ is the name of your current file for file-based applications (i.e. applications with the APP...ENDA construct containing FLAGS 1), or the name of your application for non-file applications.

TBarButt:

Usage: TBarButt:(shortcut$,pos%,text$,state%,bit&,mask&,flags%)

Adds a button to the previously initialised toolbar.

shortcut$ is the command shortcut for your application, which is used by Toolbar.opo to perform the command when a toolbar button is selected. On selecting the toolbar button, Toolbar.opo calls your procedure to perform the required command or action. shortcut$ is case sensitive in the sense that Toolbar.opo calls your procedure named:

  • "cmd"+shortcut$+%: for unshifted, lower-case shortcuts,
  • "cmdS"+shortcut$+%: for shifted, upper-case shortcuts.

For example, if you have the following two commands that also have associated toolbar buttons:

    mCARD "View","DoXXX",%x,"DoYYY",%Y
    REM shortcuts Ctrl+X,Shift+Ctrl+Y

you would need to provide command-handling procedures:

  • PROC cmdX%:
    REM handle shortcut Ctrl+X (lower case shortcut$="x")
  • PROC cmdSY%:
    REM handle shortcut Shift+Ctrl+Y (upper case shortcut$="Y")

and you would create buttons using, e.g.

  • TBarButt:("x",1,"DoXXX",0,XIcon&,XMask&,0)
    REM Button for calling cmdX:
  • TBarButt:("Y",1,"DoYYY",0,YIcon&,YMask&,0)
    REM Button for calling cmdSY:

pos% is the button position, with pos%=1 for the top button.

text$ and state% take values as required for gBUTTON.

bit& and mask& are the button’s icon bitmap and mask, used in in the same way as for gBUTTON. Note that a button is a purely graphical entity and so doesn't own the bitmaps. Therefore the bitmap may not be unloaded while the button is still in use.

flags% lets you control how the button is used in two distinct and mutually exclusive ways, as follows:

Two latchable buttons are often used by the built-in applications to indicate the current view. For an example, see the latchable ‘Desk’ and ‘Sci’ buttons in the built-in Calc application.
A set of latchable toolbar buttons can be specified in TBarButt: by setting flags% to one of:

  • KTbFlgLatchStart% for the first button in the latchable set.
  • KTbFlgLatchMiddle% for any middle buttons (these are optional and not generally used).
  • KTbFlgLatchEnd% for the last button in the latchable set.

To latch a button down initially to represent the initial setting, OR KTbFlgLatched% with one of the above settings. E.g.

    TBarButt:(sh1$,pos%,txt1$,st%,bit1&,msk1&,
              KTbFlgLatchStart%)
    TBarButt:(sh2$,pos%,txt2$,st%,bit2&,msk2&,
              KTbFlgLatchEnd% OR TbFlgLatched%)

will latch down the second button in the set initially.

In the toolbar window, the button with KTbFlgLatchStart% set must be above the buttons (if any) with KTbFlgLatchMiddle% set, and these in turn must be above the button with KTbFlgLatchEnd%.

Only one button in a set is ever latched and pressing another button unlatches the one that was previously set. After pressing and releasing a previously unlatched button in a latchable set, Toolbar.opo will, as usual, call your command-handling procedure. When the command has succeeded in changing view, this procedure should set the new state of the button by calling TBarLatch:(comp%) where comp% is the button number to be latched. This will also unlatch any button that was previously latched. The example below shows how a ‘View1’ button press, with ‘v’ as shortcut, should be handled. The other latchable button in this set might be ‘View2’ with shortcut ‘w’:

    PROC cmdV%:
          IF SetView1%:=0         REM if no error
                TBarLatch:(KView1TbarButton%)
                REM your CONST KView1TBarButton%
                CurrentView%=1
          ENDIF
    ENDP

    PROC cmdW%:
          IF SetView2%:=0                     REM if no error
                TBarLatch:(KView2TbarButton%)
                REM your const KView2TBarButton%
                CurrentView%=2
          ENDIF
    ENDP

You should call the same command-procedures when the command is performed via a menu or via a keyboard shortcut. This will ensure that the button is latched as required.

A setting of flags% can also be used to specify that your procedure should be called when the toolbar button is tapped (rather than when the button is released, which is the default). The ‘Go to’ button in the Program editor works in this way, displaying the popup list of procedures when the button is touched. To implement this using TBarButt:, pass flags%=KTbFlgCmdOnPtrDown% and provide a procedure named:

    "cmdTbDown"+shortcut$+%:

which could provide a popup menu, as follows:

    PROC cmdTbDownC%:
        REM popup next to button, with point specifying
        REM top right corner of popup
        IF mPOPUP(ScrWid%-TbWidth%,97,KMPopupPosTopRight%,
                                   "Cancel",0,"Clear",%c)
            cmdC%:    REM Do the command itself
        ENDIF
    ENDP

In this case the shortcut is not case-sensitive. Note that when this flag is used, the menu command-procedure is not used directly because a popup is not required when the command is invoked via the menu or via a keyboard shortcut.

TBarOffer%:

Usage: TBarOffer%:(winId&,ptrType&,ptrX&,ptrY&)

Offers a pointer event to the toolbar, returning -1 if used and 0 if not used. If not used, the event is available for use by your application.

It is important to call this procedure whenever you receive a pointer event, even when the event is not in the toolbar window, thus enabling Toolbar.opo to release the current button, both visually and otherwise.

TBarOffer%: handles:

  • the tapping of the clock to change the type between analog and digital system-wide.
  • the tapping of the toolbar title to display the task list.
  • the selection toolbar buttons, calling your command procedures.
  • drawing of the button in the appropriate state.

As usual, the word ‘pointer’ indicates a pen.

winId& is the ID of the window that received the pointer event.

ptrType& is pointer event type as returned by GETEVENT32 (pen up, pen down or drag).

ptrX&,ptrY& is co-ordinate of pointer event.

TBarLatch:

Usage: TBarLatch:(button%)

Latches down a toolbar button, where button%=1 for the top button in the toolbar. TBarLatch: also unlatches any button in the latchable set that was previously latched. See TBarButt: for further details on latching buttons.

TBarShow:

Usage: TBarShow:

Makes the toolbar visible. The toolbar must exist before calling this procedure. Use TBarInit: to create an invisible toolbar with no buttons. Use TBarButt: to add buttons.

TBarHide:

Usage: TBarHide:

Makes the toolbar invisible.

Public Toolbar globals

The following toolbar globals, provided by TBarLink:, may be used inOPL applications:

  • TbWidth% is the pixel width of the toolbar. The rest of the screen width is available for the application.
  • TbVis% is -1 if visible and otherwise 0
  • TbMenuSym% is the current ‘Show toolbar’ menu symbol to be added to menu shortcut for View|Show toolbar, e.g.

    • mCard "View","Show toolbar",%t or TbMenuSym%

    TbMenuSym%=(KMenuCheckBox% OR KMenuSymbolOn%) if the Toolbar is visible and

    TbMenuSym%=KMenuCheckBox% if invisible. The menu item will therefore be a checkbox item, with the check present or not as appropriate.

Giving information

Section Contents

  • Information messages
  • ‘Busy’ messages

Information messages

GIPRINT displays an information message for 2 seconds, in the bottom right corner of the screen. For example, GIPRINT "Not Found" displays Not Found. If a string is too long for the screen, it will be clipped.

You can add an integer argument to control the corner in which the message appears:

value | corner
0 | top left
1 | bottom left
2 | top right
3 | bottom right

Constants for these corner values are supplied in Const.oph.

For example, GIPRINT "Who?",0 prints Who? in the top left corner.

Only one message can be shown at a time. You can make the message go away for example, if a key has been pressed with GIPRINT "".

‘Busy’ messages

Messages which say a program is temporarily busy, or cannot respond for some reason, are by convention shown in the bottom left corner. The BUSY command lets you display your own messages of this sort. Use BUSY OFF to remove it.

BUSY "Paused...", for example, displays Paused... in the bottom left corner. This remains shown until BUSY OFF is used.

You can control the corner used in the same way as for GIPRINT.

You can also add a third argument, to specify a delay time (in half seconds) before the message should be shown. Use this to prevent BUSY messages from continually appearing very briefly on the screen.

For example, BUSY "Wait:",1,4 will display Wait: in the bottom left corner after a delay of 2 seconds. As soon as your program becomes responsive to the keyboard, it should use BUSY OFF. If this occurs within two seconds of the original BUSY, no message is seen.

The maximum string length of a BUSY message is 80 characters and an ‘Invalid argument’ error is returned for any value in excess of this.

Only one message can be shown at a time.

EPOC SDK Home Glossary Previous Up


Error Handling

  • Syntax errors — Errors reported during translation
  • Runtime errors — Handling errors reported while running programs
  • OPL error values


Syntax errors — Errors reported during translation

Contents

  • Overview
  • Punctuation errors
  • Structure errors

Overview

Syntax errors are errors which are reported when translating a procedure. (Other errors can occur while you’re running a program.) The OPL translator will return you to the line where the first syntax error is detected.

All programming languages are very particular about the way commands and functions are used, especially in the way program statements are laid out. Below are a number of errors which are easy to make in OPL. The incorrect statements are in bold and the correct versions are on the right.

Punctuation errors

Omitting the colon between statements on a multi-statement line:

Incorrect | Correct
a$="text" PRINT a$ | a$="text" :PRINT a$

Omitting the space before the colon between statements:

Incorrect | Correct
a$=b$:PRINT a$ | a$=b$ :PRINT a$

Omitting the colon after a called procedure name:

Incorrect | Correct
PROC proc1: GLOBAL a,b,c . proc2 ENDP | PROC proc1: GLOBAL a,b,c . proc2: ENDP

Using only 1 colon after a label in GOTO/ONERR/VECTOR (instead of 0 or 2):

Incorrect | Correct
GOTO below: . below:: | GOTO below . below::

Structure errors

The DO...UNTIL, WHILE...ENDWH and IF...ENDIF structures can produce a ‘Structure fault’ error if used incorrectly:

  • Mixing up the three structures - e.g. by using DO...WHILE instead of DO...UNTIL.
  • Using BREAK or CONTINUE in the wrong place.
  • Using ELSE IF with a space, instead of ELSEIF.
  • VECTOR...ENDV can also produce a ‘Structure fault’ error if used incorrectly.

Attempting to nest any combination of these structures more than eight levels deep will produce a ‘Too complex’ error.


Runtime errors — Handling errors reported while running programs

Contents

  • Overview
  • Error handling functions and commands
  • Strategy
  • TRAP
    • Example
  • ERR, ERR$ and ERRX$
    • Example
    • TRAP INPUT/EDIT and the Esc key
  • ONERR...ONERR OFF
    • Example
    • When to use ONERR OFF
    • Multiple ONERRs
    • TRAP and ONERR
  • RAISE
    • Example
    • TRAP RAISE

Overview

OPL may display an error message and stop a running program if certain ‘error’ conditions occur. This may happen because:

  • There is a mistake, or bug, in your program, which could not be detected during translation - for example, a calculation has involved a division by zero.
  • A problem has occurred which prevents a command or function from working - for example, an APPEND command may fail because a disk is full.

Unless you include statements which can handle such errors when they occur, OPL will use its own error handling mechanism. The program will stop and an error message be displayed. The first line gives the names of the procedure in which the error occurred, and the module this procedure is in. The second line is the ‘error message’ — one of the messages listed the OPL error values. If appropriate, you will also see a list of variable names or procedure names causing the error.

If you were editing the module with the Program editor and you ran it from there, you would also be taken back to editing the OPL module, with the cursor at the line where the error occurred.

Error handling functions and commands

To prevent your program being stopped by OPL when an error occurs, include statements in your program which anticipate possible errors and take appropriate action. The following error handling facilities are available in OPL:

  • TRAP temporarily suppresses OPL’s error processing.
  • ERR, ERR$, and ERRX$ find out what kind of error has occurred.
  • ONERR establishes an error handler which can suppress OPL’s error processing over whole modules.
  • RAISE can be used to simulate error conditions.

These facilities put you in control and must be used carefully.

Strategy

You should design the error handling of a program in the same way as the program itself. OPL works best when programs are built up from procedures, and you should design your error handling on the same basis. Each procedure should normally contain its own local error handling:

The error handling statements can then be appropriate to the procedure. For example, a procedure which performs a calculation would have one type of error handling, but another procedure which offers a set of choices would have another.

TRAP

TRAP can be used with any of these commands: APPEND, BACK, CANCEL, CLOSE, COPY, CREATE, DELETE, ERASE, EDIT, FIRST, gCLOSE, gCOPY, gFONT, gPATT, gSAVEBIT, gUNLOADFONT, gUSE, INPUT, INSERT, LAST, LCLOSE, LOADM, LOPEN, MKDIR, MODIFY, NEXT, OPEN, OPENR, POSITION, PUT, RAISE (see below), RENAME, RMDIR, UNLOADM, UPDATE and USE.

The TRAP command immediately precedes any of these commands, separated from it by a space - for example:

    TRAP INPUT a%

If an error occurs in the execution of the command, the program does not stop, and the next line of the program executes as if there had been no error. Normally you would use ERR on the line after the TRAP to find out what the error was.

Example

When INPUT is used without TRAP and a text string is entered when a number is required, the display just scrolls up and a ? is shown, prompting for another entry. With TRAP in front of INPUT, you can handle bad entries yourself:

    PROC trapinp:
          LOCAL profit%
          DO
                PRINT
                PRINT "Enter profit",
                TRAP INPUT profit%
          UNTIL ERR=0
          PRINT "Valid number"
          GET
    ENDP

This example uses the ERR function, described next.

ERR, ERR$ and ERRX$

Section Contents

  • Example
  • TRAP INPUT/EDIT and the Esc key

When an error occurs in a program, check what number the error was, with the ERR function:

    e%=ERR

If ERR returns zero, there was no error. The value returned by ERR is the number of the last error which occurred it changes when a new error occurs. TRAP sets ERR to zero if no error occurred. Check the number it returns against the error messages listed in the OPL error values .

The ERR$ function gives you the message for error number e%:

    e$=ERR$(e%)

You can also use ERR and ERR$ together:

    e$=ERR$(ERR)

This returns the error message for the most recent error.

The ERRX$ function gives you the extended message for the current error:
e$=ERRX$.

For example, ‘Error in MODULE\PROCEDURE,EXTERN1,EXTERN2,...’. This is the message which would have been presented as an alert if the error had not been trapped. The use of this function gives the list of missing externals and procedure names when an error has been trapped.

Example

The lines below anticipate that error number -101 (‘File already open’) may occur. If it does, an appropriate message is displayed.

    TRAP OPEN "main",A,a$
    e%=ERR
    IF e%                        REM Checks for an error
          IF e%=-101
                PRINT "File is already open!"
          ELSE
                PRINT ERR$(e%)
          ENDIF
    ENDIF

The inner IF...ENDIF structure displays either the message in quotes if the error was number -101, or the standard error message for any other error.

TRAP INPUT/EDIT and the Esc key

If in response to a TRAP INPUT or TRAP EDIT statement, the Esc key is pressed while no text is on the input/edit line, the ‘Escape key pressed’ error (number -114) will be raised. (This error will only be raised if the INPUT or EDIT has been trapped. Otherwise, the Esc key still leaves you editing.)

You can use this feature to enable someone to press the Esc key to escape from editing or inputting a value. For example:

    PROC trapInp:
          LOCAL a%,b%,c%
          PRINT "Enter values."
          PRINT "Press Esc to exit"
          PRINT "a% =", :TRAP INPUT a% :PRINT
          IF ERR=-114 :GOTO end :ENDIF
          PRINT "b% =", :TRAP INPUT b% :PRINT
          IF ERR=-114 :GOTO end :ENDIF
          PRINT "a%*b% =",a%*b%
          PAUSE -40
          RETURN
    end::
          PRINT :PRINT "OK, finishing..."
          PAUSE -40
          RETURN
    ENDP

ONERR...ONERR OFF

Section Contents

  • Example
  • When to use ONERR OFF
  • Multiple ONERRs
  • TRAP and ONERR

ONERR sets up an error handler. This means that, whenever an error occurs in the procedure containing ONERR, the program will jump to a specified label instead of stopping in the normal way. This error handler is active until an ONERR OFF statement.

You specify the label after the word ONERR.

The label itself can then occur anywhere in the same procedure - even above the ONERR statement. After the label should come the statements handling whatever error may have caused the program to jump there. For example, you could just have the statement PRINT ERR$(ERR) to display the message for whatever error occurred.

All statements after the ONERR command, including those in procedures called by the procedure containing the ONERR, are protected by the ONERR, until the ONERR OFF instruction is given.

Example

If an error occurs in the lines between ONERR errHand and ONERR OFF, the program jumps to the label errHand:: where a message is displayed.

Always cancel ONERR with ONERR OFF immediately after the label.

When to use ONERR OFF

You could protect the whole of your program with a single ONERR. However, it’s often easier to manage a set of procedures which each have their own ONERR...ONERR OFF handlers, each covering their own procedure. Secondly, an endless loop may occur if all errors feed back to the same single label.

For example, the diagram below shows how an error handler is left active by mistake. Two completely different errors cause a jump to the same label, and cause an inappropriate explanatory message to be displayed. In this example an endless loop is created because next: is called repeatedly:

Multiple ONERRs

You can have more than one ONERR in a procedure, but only the most recent ONERR is active. Any errors cause a jump to the label for the most recent ONERR.

ONERR OFF disables all ONERRs in the current procedure. If there are ONERRs in other procedures above this procedure (calling procedures) these ONERRs are not disabled.

TRAP and ONERR

TRAP has priority over ONERR. In other words, an error from a command used with TRAP will not cause a jump to the error handler specified with ONERR.

RAISE

Section Contents

  • Example
  • TRAP RAISE

The RAISE command generates an error, in the same way that OPL raises errors whenever it meets certain conditions which it recognises as unacceptable (for example, when invalid arguments are passed to a function). Once an error has been raised, either by OPL itself or by the RAISE command, the error-handling mechanism currently in use takes effect - the program will stop and report a message, or if you’ve used ONERR the program will jump to the ONERR label.

There are two reasons for using RAISE:

  • You may want to mimic OPL’s error conditions in your own procedures. For example, if you create a new procedure which performs a calculation and returns a value, you may want to RAISE an ‘Overflow’ or ‘Divide by zero’ error if unsuitable numbers are passed as parameters.

    • In this case, you would RAISE one of the standard error numbers. You could handle this yourself with ONERR, or let OPL handle it in the normal way.

  • OPL raises only a limited range of errors for general use, and you may want to raise new kinds of error codes specific to your program or particular circumstances.

    • In this case, you would RAISE a new error number. With ONERR on, RAISE would go to the ONERR label, where you would have code to interpret your new error numbers. You could then display appropriate messages.

    You can use any positive number (from 0 to 127) as a new error code. Do not use any of the numbers in the list that follows.

You may also find RAISE useful for testing your error handling.

Example

    PROC main:
          REM calling procedure
          PRINT myfunc:(0.0)                        REM will raise error -2
    ENDP

    PROC myfunc:(x)
          LOCAL s
          REM returns 1/sqr(x)
          s=SQR(x)
          IF s=0
                RAISE -2
                REM ‘Invalid arguments’
                REM avoids ‘divide by zero’
          ENDIF
          RETURN (1/s)
    ENDP

This uses RAISE to raise the ‘Invalid arguments’ error not the ‘Divide by zero’ error, since the former is the more appropriate message.

TRAP RAISE

TRAP RAISE err% can be used to clear the TRAP flag and sets ERR’s value to err%. For example, using err%=0 will clear ERR.


OPL error values

Contents

  • File and device errors
  • Translator errors
  • OPL specific errors

These are the numbers of the errors which OPL can raise, and the message associated with them:

Number | Message
-1 | General failure
-2 | Invalid arguments
-3 | O/S error
-4 | Service not supported
-5 | Underflow (number too small)
-6 | Overflow (number too large)
-7 | Out of range
-8 | Divide by zero
-9 | In use (e.g. serial port being used by another program)
-10 | No system memory
-11 | Segment table full
-12 | Semaphore table full
-13 | Process table full/Too many processes
-14 | Resource already open
-15 | Resource not open
-16 | Invalid image/device file
-17 | No receiver
-18 | Device table full
-19 | File system not found (e.g. if you unplug cable to PC)
-20 | Failed to start
-21 | Font not loaded
-22 | Too wide (dialogs)
-23 | Too many items (dialogs)
-24 | Batteries too low for digital audio
-25 | Batteries too low to write to Flash

File and device errors

-32 | File already exists
-33 | File does not exist
-34 | Write failed
-35 | Read failed
-36 | End of file (when you try to read past end of file)
-37 | Disk full
-38 | Invalid name
-39 | Access denied (e.g. to a protected file on PC)
-40 | File or device in use
-41 | Device does not exist
-42 | Directory does not exist
-43 | Record too large
-44 | Read only file
-45 | Invalid I/O request
-46 | I/O operation pending
-47 | Invalid volume (corrupt disk)
-48 | I/O cancelled
-50 | Disconnected
-51 | Connected
-52 | Too many retries
-53 | Line failure
-54 | Inactivity timeout
-55 | Incorrect parity
-56 | Serial frame (usually because Baud setting is wrong)
-57 | Serial overrun (usually because Handshaking is wrong)
-58 | Cannot connect to remote modem
-59 | Remote modem busy
-60 | No answer from remote modem
-61 | Number is black listed (you may try a number only a certain number of times; wait a while and try again)
-62 | Not ready
-63 | Unknown media (corrupt SSD)
-64 | Root directory full (on any device, the root directory has a maximum amount of memory allocated to it)
-65 | Write protected
-66 | File is corrupt
-67 | User abandoned
-68 | Erase pack failure
-69 | Wrong file type

Translator errors

-70 | Missing "
-71 | String too long
-72 | Unexpected name
-73 | Name too long
-74 | Logical device must be A-Z
-75 | Bad field name
-76 | Bad number
-77 | Syntax error
-78 | Illegal character
-79 | Function argument error
-80 | Type mismatch
-81 | Missing label
-82 | Duplicate name
-83 | Declaration error
-84 | Bad array size
-85 | Structure fault
-86 | Missing endp
-87 | Syntax Error
-88 | Mismatched ( or )
-89 | Bad field list
-90 | Too complex
-91 | Missing ,
-92 | Variables too large
-93 | Bad assignment
-94 | Bad array index
-95 | Inconsistent procedure arguments

OPL specific errors

-96 | Illegal Opcode (corrupt module translate again)
-97 | Wrong number of arguments (to a function or parameters to a procedure)
-98 | Undefined externals (a variable has been encountered which hasn’t been declared)
-99 | Procedure not found
-100 | Field not found
-101 | File already open
-102 | File not open
-103 | Record too big (data file contains record too big for OPL)
-104 | Module already loaded (when trying to LOADM)
-105 | Maximum modules loaded (when trying to LOADM)
-106 | Module does not exist (when trying to LOADM)
-107 | Incompatible translator version (OPL file needs retranslation)
-108 | Module not loaded (when trying to UNLOADM)
-109 | Bad file type (data file header wrong or corrupt)
-110 | Type violation (passing wrong type to parameter)
-111 | Subscript or dimension error (out of range in array)
-112 | String too long
-113 | Device already open (when trying to LOPEN)
-114 | Escape key pressed
-115 | Incompatible runtime version
-116 | ODB file(s) not closed
-117 | Maximum drawables open (maximum 8 windows and/or bitmaps allowed)
-118 | Drawable not open
-119 | Invalid Window (window operation attempted on a bitmap)
-120 | Screen access denied (when run from Calculator)
-121 | OPX not found
-122 | Incompatible OPX version
-123 | OPX procedure not found
-124 | STOP used in callback from OPX
-125 | Incompatible update mode
-126 | In database transaction or started changing fields

Constants for all error values are supplied in Const.oph. See Including header files for details of how to use this file and const.oph for a listing of it.

EPOC SDK Home Glossary Previous Up


Advanced Topics

  • About the advanced topics
  • Programs using more than one module
  • Calling procedures by strings
  • More on file specification
  • How OPL stores values
  • Safe pointer arithmetic
  • OPL applications
  • OPL and MIME
  • Foreground and background
  • Scanning the keyboard directly
  • I/O functions and commands
  • Dynamic memory allocation


About the advanced topics

Many of the subjects covered in this section may provide benefits for all levels of programmers.

However, the subjects become progressively more technical. This manual cannot cover every OPL keyword in detail, as some give access to the innermost workings of the operating system. Some of these keywords are touched on in this section.


Programs using more than one module

Program a general word for the “finished product” — a set of procedures which can be run. A program may consist of one module containing one or more procedures:

It may also consist of a number of modules containing various procedures:

A procedure in one module can call procedures in another module, provided this module has been loaded with the LOADM command. LOADM needs the filename of the module to load.

For example, if an OPL module MAIN has these two procedures:

    PROC main:
          LOADM "library"
          pthis:                 REM run pthis: in this module
          pother:                REM run pother: in "library"
          PRINT "Finished"
          PAUSE 40
          UNLOADM "library"
    ENDP

    PROC pthis:
          PRINT "Running pthis:"
          PRINT "in this module"
          PAUSE 40
    ENDP

and a module called LIBRARY has this one:

    PROC pother:
          PRINT "Running pother:"
          PRINT "in module called LIBRARY"
          PAUSE 40
    ENDP

then running MAIN would display Running pthis: and in this module; then display Running pother: and in module called LIBRARY; and then display Finished.

You would usually only need to load other modules when developing large OPL programs.

You can use LOADM up to seven times, to load up to seven modules.

If you want to load any further modules, you must first unload one of those currently loaded, by using UNLOADM with the filename. To keep your program tidy, you should UNLOADM a module as soon as you have finished using it.

If there is an error in the running program, you will only be positioned in the Program editor at the place where the error occurred if you were editing the module concerned (and you ran the program from there).

In spite of its name, LOADM does not "load" the whole of another module into memory. Instead, it just loads a block of data stored in the module which lists the names of the procedures which it contains. If such a procedure is then called, the procedure will be searched for, copied from file into memory and the procedure will then be run.

The modules are searched through in the order that they were loaded, with the module loaded last searched through last. You may make considerable improvements in speed if you as few modules as possible loaded at a time (so avoiding a long search for each procedure) and if you load the modules with the most commonly called procedures first.


Calling procedures by strings

Procedures can be called using a string expression for the procedure name. Use an @ symbol, optionally followed by a character to show what type of value is returned for example, % for an integer. Follow this with the string expression in brackets. You can use upper or lower case characters.

Here are examples showing the four types of value which can be returned:

i% = @%(name$) : (parameters) for integer

l& = @&(name$) : (parameters) for long integer

s$ = @$(name$) : (parameters) for string

f = @(name$) : (parameters) for floating-point

So, for example, test$:(1.0,2) and @$("test"):(1.0,2) are equivalent.

Note that the string expression does not itself include a symbol for the type (%, & or $).

You may find this useful if, in a more complex program, you want to "work out" the name of a procedure to call at a particular point. Friendlier interaction includes an example program which uses this method.


More on file specification

Contents

  • Using file specifications in OPL
  • Current folder
  • Control of folders

The internal memory and memory disks use a DOS-compatible directory structure, the same as that used on disks on PCs. However, the two machines differ quite considerably in this area as described below.

To specify a file completely, EPOC uses a drive (or device), folder and filename:

  • The drive is the area on the machine where the file is kept. This can be C: (internal disk), D: (memory disk drive) E:,..., Y: or Z: (ROM).
  • Every drive has one root folder, usually written as a backslash (\). This can "contain" files and/or other folders, each of which can contain more files and/or more folders. When you have "folders in folders" like this, they’re often called subfolders. Their names show where they are. For example, the root folder (\) could contain a folder called \Jo, which might in turn contain a folder called \Jo\Backup, which might contain some files.
  • Filenames are composed of up to 256 characters (but see below), with an optional file extension comprised of a dot and one or more other characters. A filename may not begin with a back or forward slash (\ or /) or a colon (:). Any trailing zeros on the filename are stripped.

    • The filing system does not treat extensions as a special component of a filename except when parsing (i.e. for PARSE$). You can also use long filenames with embedded spaces and any number of dots like: OPL Reference manual or Very.long.filename.

To specify a file completely, you add the three parts together. The folder part must end with a backslash. So an OPL module named test, in a folder called \Jo in the internal memory can be specified as C:\Jo\test. If this file were in the \Jo\Backup folder, it would be completely specified as C:\Jo\Backup\Test. If it were in the root folder, you would specify it as C:\Test.

A full file specification may be up to 255 characters long for OPL.

In OPL, as in other applications, the files are kept on the drive and in the folder you specify.

Using file specifications in OPL

OPL commands which specify a filename, such as OPEN, CREATE, gLOADBIT and so on, can also use any or all of the other parts that make up a full file specification. (Normally, the only other part you might use is the drive name, if the file were on a memory disk.) So for example, OPEN "C:\ADDR.TXT" tries to open a file called ADDR.TXT in the root folder of the internal disk.

You can use the PARSE$ function if you need to build up complex filenames. See Keyword Reference for more details of PARSE$.

Current folder

The current folder for all commands is always C:\ unless it has been changed by the command SETPATH. Hence any use of a keyword which takes a filename as an argument will only look in the current folder and so if this is other than C:\, it should be specified either by SETPATH or by including it in the filename. For example, to check whether the file Program1 in the directory D:\MyPrograms\ exists, either

    SETPATH "d:\MyPrograms\"
    ...
    IF EXISTS ("Program1")
    ...

or

    IF EXISTS ("d:\MyPrograms\Program1")
    ...

Control of folders

Use the MKDIR command to make a new folder. For example, MKDIR "C:\Mine\Temp" creates a C:\Mine\Temp folder, also creating C:\Mine if it is not already there. An error is raised if the chosen folder exists already. Use TRAP MKDIR to avoid this.

SETPATH sets the current folder for file access - for example,

    SETPATH "C:\DOCUMENTS"

LOADM continues to use the folder of the running program, but all other file access will be to the newly specified folder.

Use RMDIR to remove a folder - for example, RMDIR "C:\MINE" removes the MINE folder on C:. A ‘Does not exist’ error is raised if the folder does not exist. Use TRAP RMDIR to avoid this. A ‘File is in use’ error will result if you try to remove a folder which contains open files.


How OPL stores values

Contents

  • Integers
  • Long integers
  • Strings
  • Floating-point values
  • Arrays

OPL stores its variables’ data in memory in a specific format; this topic details the sequences of memory bytes used for different data types.

Usually you would find out the byte address with the ADDR function. For example, if var% has the value 7, PEEKW(ADDR(var%)) returns 7.

See also the PEEK and POKE commands and ADDR. See also 32-bit addressing.

MARM, WINS

Under both the WINS and MARM platforms, the byte with the lower address is the least significant — MARM and WINS are both little-endian.

Future EPOC devices may use a different machine word format.

Integers

Integers are stored in two bytes. The first byte is the least significant byte, for example:

    1   0            = 1
    0   1            = 256

ADDR returns the address of the first (least significant) byte.

Long integers

Long integers are stored in four bytes, the least significant first and the most significant last, for example:

    0   0   1   0      = 65536

ADDR returns the address of the first (least significant) byte.

Strings

Strings are stored with one character per byte, with a leading byte containing the string length, e.g.:

    3   65  66  67      = "ABC"

Each letter is stored as its character code - for example, A as 65.

For example, if var$="ABC", PEEK$(ADDR(var$)) will return the string ABC. ADDR returns the address of the length byte.

Floating-point values

Floating-point numbers are stored in IEEE format across eight bytes. PEEKF automatically reads all eight bytes and returns the number as a floating-point. For example if var=1.3 then PEEKF(ADDR(var)) returns 1.3.

Arrays

You can use ADDR to find the address of the first element in an array, for example ADDR(x%()), you can also specify individual elements of the array, for example ADDR(x%(2)).

The length of the array is stored in the two bytes immediately before the first element, and can be examined with PEEKW:

    proc demopeek:
          local ar%(42)
          print peekw(addr(ar%()) - 2)
          get
    endp


Safe pointer arithmetic

Note that if you are using 32-bit addressing, as will be the case by default (see 32-bit addressing, you should use ordinary long integer arithmetic and should not use UADD and USUB.

However if you have used SETFLAGS to enforce the 64K memory limit, whenever you wish to add or subtract something from an integer which is an address of something (or a pointer to something) you should use UADD and USUB. If you do not, you will risk an ‘Integer overflow’ error.

An integer address can be any value from 0 to 65535. An integer variable can hold the full range of addresses, but treats those values from 32768 to 65535 as if they were -32768 to -1. If your addition or subtraction would convert an address in the 0-32767 range to one in the 32768-65535 range, or vice versa, this would cause an ‘Integer overflow’.

UADD and USUB treat integers as if they were unsigned, i.e. as if they really held a value from 0 to 65535.

For example, to add 1 to the address of a text string (in order to skip over its leading byte count and point to the first character in the string), use i%=UADD(ADDR(a$),1), not i%=ADDR(a$)+1.

USUB works in a similar way, subtracting the second integer value from the first integer, in unsigned fashion for example, USUB(ADDR(c%),3).

USUB(x%,y%) has the same effect as UADD(x%,-y%).


OPL applications

Contents

  • Defining an application
  • Running the application
  • How the EPOC device talks to an application
  • System screen compliance
  • Launching help files
  • Example applications
  • When an application cannot respond

You can make an OPL program appear as an icon in the system screen, and behave like the other icons there, by converting it into an OPL application.

There are two settings for applications which are set using the FLAGS command:

  • FLAGS 1 is used if your application can create files. It will then be included in the list of applications offered when the user creates a new file from the System screen (like Program, Word etc.).
  • FLAGS 2 prevents the application from appearing in the Extras bar in the System screen. It is very unusual to have this flag set.

Once created, OPL applications may be used in the same way as the built in applications: new document files may be created from the System screen using ‘New File’ if the flag 1 is set and/or from the Extras bar if the flag 2 is not set. Existing files may be opened by selecting them on the System screen as usual. You can stop a running app by using the Task list.

Defining an application

To make an application, your OPL file should begin with the APP keyword, followed by a name for the app in the machine’s default language and its UID. The name may be up to 250 characters. (Note that it does not have quote marks.) If the CAPTION command is used, however, this default name will be discarded (see below).

The UID specifies the UID of the application. For applications that are to be distributed, UIDs are reserved by contacting Symbian. These official UIDs are guaranteed to be unique to the application and have values of &10000000 and above. To obtain a reserved UID you should contact Symbian in one of the following ways:

  • e-mail to uid_ew@symbian.com
  • or use the EPOC World web site, http://developer.epocworld.com/
  • or write to UID Allocations, Symbian Ltd, 17 Harcourt St, London W1N 1DT, England

For applications developed for personal use there is no need to reserve official UIDs, and any UID between &01000000 and &0fffffff may be selected. However, if the UIDs of two different applications did clash, then either your application’s documents will have the wrong icon and selecting these will run the other application, or the other application’s documents will seem to belong to your application.

The APP line may be followed by any or all of the keywords CAPTION, ICON and FLAGS. Finally, use ENDA, and then the first procedure may begin as in a normal OPL file. Here is an example of how an app might start:

    APP Expenses,&20000000    REM !!! Should be a reserved UID !!!
          FLAGS 1
          ICON "icon.mbm"
          CAPTION "Expenses",1        REM English name
          CAPTION "Expenses",10       REM American name
    ENDA

Here is another example:

    APP Picture,&30000000     REM !!! Should be a reserved UID !!!
          FLAGS 2
          ICON "picicon.mbm"
    ENDA

FLAGS takes an integer argument of 1 or 2. The meanings of these are outlined above. If you don’t specify the flags, none are set.

ICON gives the name of a multi-bitmap file (MBM), also known as an EPOC Picture file, which contains the icons for an OPL application. These icons are used on the Extras bar and for the application’s documents on the System screen. The multi-bitmap file can contain up to three bitmaps of sizes 2424, 3232 and 4848 pixels respectively, but each must be paired with a mask. Each bitmap should be followed by its mask in the multi-bitmap file, so that bitmaps and masks occur alternately. The pixels which are set in the mask specify pixels in the bitmap which are to be used. Pixels which are clear in the mask specify pixels that are not to be used from the bitmap, allowing the background to be displayed in these pixels. Only pixels which are set in the mask are drawn in the final icon.

The different sizes of bitmaps are used for the different zoom levels in the System screen. The sizes are read from the MBM and the most suitable size is zoomed if the exact sizes required are not provided or if some are missing.

You can use ICON more than once within the APP...ENDA construct. The translator only insists that all icons are paired with a mask of the same size in the final ICON list. This allows you to use MBMs containing just one bitmap, as produced by the Sketch application. Icons may also be created on a PC (if the appropriate tools are available), or of course by another OPL program or application.

CAPTION specifies an application’s public name (or caption) for a particular language, which is the name which will appear below its icon on the Extras bar and in the list of ‘Programs’ in the ‘New File’ dialog (assuming the setting of FLAGS allows these) when that is the language used by the machine. This name is also used as the default document name for documents launched using the Extras bar. The maximum length of the caption is 255 characters. However, note that a caption no longer than around 8 letters will look best on the Extras bar. If any CAPTION statement is included in the APP…ENDA structure, then the default caption provided by the APP declaration will be discarded. Therefore as many statements of CAPTION as are necessary to cover all the languages required, including the language of the machine on which the application is originally developed, should be used. The constants for the language codes are supplied in Const.oph. See Including header files.

Applications can declare themselves capable of handling files of a particular MIME content type. See OPL and MIME [image] for more information on this.

On creation of an application, a folder specifically for the application is also created. For example, if the application has the name AppXxx the folder created will be \System\Apps\AppXxx\. The .app file itself (the translated OPL module) and the application information file (AIF) which contains three icon and mask pairs and the application caption and flags, are created in this folder. For example, the AIF for AppXxx.app would be \System\Apps\AppXxx\AppXxx.aif. The AIF file will be generated based on all the information contained in the APP…ENDA construct, but if any information is missing defaults will be used. These are:

  • for ICON: the default (question mark) icons
  • for CAPTION: the caption specified in the APP declaration
  • for FLAGS: the default value of 0.

The arguments to any of the keywords between APP and ENDA must be constants and not expressions.

Running the application

Once you’ve successfully translated the OPL file, the applications icon will automatically appear on the Extras bar and/or on the ‘Program’ list in the ‘New File’ dialog (as specified by the FLAGS setting). The new documents of the application may then be created and existing ones opened as with other EPOC applications.

The first thing a file-based application should do is to get the name of the file to use, and check whether it is meant to create it or open it. CMD$(2) returns the full name of the file to use; CMD$(3) returns ‘C’ for Create, ‘O’ for Open, ‘R’ for Run or ‘X’ for Exit.

All document-based apps should handle all of these cases; for example, if a Create fails because the file exists already, or an Open fails because it does not, OPL raises the error, and the application should take suitable action. Note however, that in general the System screen will not allow such events to occur and therefore they are unlikely to happen.

‘R’ means that your application has been run from the OPL Program editor or has been selected via the application’s icon on the Extras bar, and not by the selection or creation of one of its documents from the system screen. A default filename, including path, is passed in CMD$(2). When ‘R’ is passed, an application should always try to open the last-used document. This is the document that was in use when the application was last closed, not the document that was most recently opened. The name of this document should be stored in a .ini file with the same name and in the same folder as your application but always on drive C:. So for example, AppXxx.app would have .ini file C:\System\Apps\AppXxx\AppXxx.ini. If the .ini file does not exist or cannot be opened for any reason, or if the document listed there no longer exists, you should create the document named in CMD$(2). CMD$(2) is a default name provided by the System based on your application’s caption. If the .ini file is corrupt it should be deleted before going on to create CMD$(2). No error message should be displayed in this case.

Constants for the array indices of CMD$ and the return values of CMD$(3) are supplied in Const.oph (see Including header files).

How the EPOC device talks to an application

When the EPOC device wants an app to exit or to switch files, it sends it a System message, in the form of an event. For example, this would happen if the ‘Close file’ option in the Task list were used to stop a running app.

TESTEVENT and GETEVENT32 (synchronous) and GETEVENTA32 (asynchronous) check for certain events, including both keypresses and System messages. All types of application must use these keywords to check for both keypresses and System messages; keyboard commands such as GET, KEY and KEYA cause other events to be discarded.

GETEVENT32 waits for an event whereas TESTEVENT simply checks whether an event has occurred without getting it. If TESTEVENT returns non-zero, an event has occurred, and can be read with GETEVENT32. However, it is recommended that you use either GETEVENT32 or GETEVENTA32 without TESTEVENT as the machine will switch off only when waiting on an event. If the program just runs around a loop using TESTEVENT to decide when there is something to do, it will simply consume the battery power for no purpose. GETEVENT32 may be used if you only wish to pick up window server events, but otherwise you should use the asynchronous GETEVENTA32 together with any other asynchronous requests which you require. TESTEVENT should generally only be used when polling while doing something else in background.

GETEVENT32 and GETEVENTA32 both take one argument: the name of a long integer array, for example, GETEVENT32 ev&(). The array should contain at least 16 long integers.

For example, if the event is a keypress (ev&(1) AND &400) = 0 and,

  • ev&(1) = keycode (as for GET)
  • ev&(2) = time stamp (gives the time of the keypress)
  • ev&(3) = scan code (locates the key on the keyboard)
  • ev&(4) = modifier code (e.g. Shift, Control)
  • ev&(5) = repeat. Note that this is strictly the repeat value, i.e. if there is only one keypress, then the value of ev&(5) is 0.

For non-key events (ev&(1) AND &400) will be non-zero. On the EPOC platforms with a pen, these include pointer events. For an application, it may be suitable to filter out certain pointer events. This may be done using the POINTERFILTER command. POINTERFILTER takes two arguments: a filter and a mask. Each of the bits in these two arguments represents a certain pointer event, allowing a flag to be set to say whether that event should be filtered out. The bits which are set in the mask specify bits in the filter which are to be used. Bits which are clear in the mask specify bits that are not to be used from the filter. This makes it possible to filter out some pointer events, filter back in some others and leave the settings of some alone all in one call to POINTERFILTER. To set or clear flags you would set and clear them in the filter and set all the flags that require changing in the mask. To leave some bits in the filter alone just don’t set the bits in the mask. See the Keyword Reference for more details of POINTERFILTER and the values returned to ev&() by GETEVENT32 and GETEVENTA32.

If the event is a System message to change files or quit, ev&(1)=&404. You should then use GETCMD$ to find the action required.

GETCMD$ returns a string, whose first character is "C", "O" or "X".

You can only call GETCMD$ once for each event. You should do so as soon as possible after reading the event. Assign the value returned by GETCMD$ to a string variable so that you can extract its components.

If you have c$=GETCMD$, the first character, which you can extract with LEFT$(c$,1), has the following meaning:

  • "C" - close the current document, and create the specified new file.
  • "O" - close the current document, and open the specified existing file.
  • "X" - save the name of the current document (if any) to the .INI file, close the current document and quit the app.

Again with c$=GETCMD$, MID$(c$,2,255) is the easiest way to extract the filename.

Note that events are ignored while you are using keywords which pause the execution of the program GET, GET$, EDIT, INPUT, PAUSE, MENU and DIALOG. If you need to use these keywords, use LOCK ON / LOCK OFF (described later) around them to prevent the System screen from sending messages.

System screen compliance

A well-behaved application should obey the following important guidelines:

  • All applications should respond in the standard way to the initial command-line and to any System screen messages to switch files. See How the EPOC device talks to an application, above.
  • All applications should support a toolbar. Toolbar.opo is supplied in the ROM and provides the set of procedures required for this support. See Toolbars.
  • All applications should save non-document files (external files) to their so-called application directory.

    • You can find out the full file specification of external files by using PARSE$. For example, in:

          p$=PARSE$("NEW",LEFT$(CMD$(1),LEN(CMD$(1)-4),x%())

    CMD$(1) gives the device and the path of the OPL application and the name of the file.

    By default the system screen hides the System folder and its subfolders. Use the ‘Preferences’ option in the ‘Tools’ menu of the System screen and check the checkboxes for both ‘Show hidden files’ and ‘Show ‘System’ folder’ to show all applications and their files.

  • The FLAGS keyword in the APP...ENDA construct should have the value 1 if the application supports documents. Without this flag the application will not be listed when the user chooses to create a new file from the System screen (see sections above).
  • You should set ESCAPE OFF so that it is impossible for the user to stop the application running by hitting Ctrl+Esc.

Launching help files

It is possible to write your own Help for your own application, which should be created in the Data application. The file should be similar to the built-in help, using two labels only for each entry to give a title and the explanation itself. The file should be stored in the application’s folder with the filename extension .hlp. The procedure RunApp&: in System.opx (see About OPXs for more details) may then be used to launch Data and open the application help file. For example, if you want to run a help file called Myapp.hlp, the help file for your own application called Myapp, you should use:

    drv$=LEFT$(CMD$(1),2)
    RunApp&:("Data",drv$+"\System\Apps\Myapp\Myapp.hlp","",0)

You should make it possible for users of your application to launched your help file from the application’s menus. Following the EPOC Style Guide, the ‘Help’ item should appear on the ‘Tools’ menu at the bottom of the section above ‘Infrared’, so it will be followed by a separating line. The shortcut key should be Ctrl+Shift+H.

Only one copy of the help file should be shown at a time, and the help file should be closed when the application exits. This can be done by creating a global variable called Help_Thread& in the program’s main procedure, and by calling the Help: procedure below to display the help file:

    PROC Help:
          IF EXIST(MyHelpFile$)
                IF Help_Thread&<>0   REM Is Data running?
                      ONERR NoLongerOpen::
                      SetForegroundByThread&:(Help_Thread&,0)
                      REM Switch Data to fore
                ELSE
                      NoLongerOpen::
                      ONERR OFF
                      Help_Thread&=RunApp&:("Data",MyHelpFile$,"",0)
                      REM Start Data and record its thread ID.
                ENDIF
          ELSE
                GIPRINT "Help not found", KBusyTopRight%
          ENDIF
    ENDP

This Exit: procedure should then be called when your program shuts down (either when the user selects "Close" or Ctrl+E, or when it receives a message from the System to close, as for in example the case of a backup — these different events should be trapped in your main event loop):

    PROC Exit:
          ONERR HelpClosed::
          IF Help_Thread&<>0
                EndTask&:(Help_Thread&,0)
          ENDIF
          HelpClosed::
          ONERR OFF
          STOP
    ENDP

Example applications

Here is an application which just prints the keys you press. It is not a document-based application (like Calc, but unlike Word which is document-based) so it uses FLAGS 0. The keyboard procedure getk&: returns the key pressed, as with GET, but jumps to a procedure endit: if a System message to close down is received. (apps with flags set to 0 do not receive "change file" messages.)

    CONST KUidAppMyApp0&=&40000000
                                        REM !!! Should be a reserved UID!!!
    APP myapp0,KUidAppMyApp0&
          CAPTION "Get Key",1
          ICON "myapp0.mbm"
    ENDA

    PROC start:
          GLOBAL a&(10),k&
          FONT 11,16
          PRINT "Q to Quit"
          PRINT " or select ‘Close file’"
          PRINT " from the Task List"
          DO
                k&=getk&:
                PRINT CHR$(k&);
          UNTIL (k& AND &ffdf)=%Q            REM Quick way to do uppercase
    ENDP

    PROC getk&:
          DO
                GETEVENT32 a&()
                IF a&(1)=&404
                      IF LEFT$(GETCMD$,1)="X"
                            endit:
                      ENDIF
                ENDIF
          UNTIL a&(1)<256
          RETURN a&(1)
    ENDP

    PROC endit:
          STOP
    ENDP

Here is a similar document-based application It does the same as the previous example, but System messages to change files cause the procedure fset: to be called. The relevant files are opened or created. A proper application with a toolbar would call TBarSetTitle: to change its title. See Friendlier interaction.

    CONST KUidAppMyApp1&=&50000000
                                  REM !!! Should be a reserved UID!!!
    APP myapp1,KUidAppMyApp1&
          FLAGS 1
          CAPTION "Get Key Doc",1
          ICON "myapp1.mbm"
    ENDA

    PROC start:
          GLOBAL a&(10),k&,w$(255)
          FONT 11,16 :w$=CMD$(2)
          fset:(CMD$(3))
          PRINT "Q to Quit"
          PRINT "use the Task list"
          PRINT "to create/switch files"
          DO
                k&=getk&:
                PRINT CHR$(k&);
          UNTIL (k& AND &ffdf)=%Q
    ENDP

    PROC getk&:
          LOCAL t$(1)
          DO
                GETEVENT32 a&()
                IF a&(1)=$404
                      w$=GETCMD$
                      t$=LEFT$(w$,1)
                      w$=MID$(w$,2,255)
                      IF t$="X"
                            endit:
                      ELSEIF t$="C" OR t$="O"
                            TRAP CLOSE
                            IF ERR
                                  GIPRINT ERR$(ERR)
                                  CONTINUE
                            ENDIF
                            fset:(t$)
                      ENDIF
                ENDIF
          UNTIL a&(1)<256
          RETURN a&(1)
    ENDP

    PROC fset:(t$)
          LOCAL p&(6)
          IF t$="C"
                TRAP DELETE w$
                SETDOC w$
                TRAP CREATE w$,A,A$
          ELSEIF t$="O"
                SETDOC w$
                TRAP OPEN w$,A,A$
          ENDIF
          IF ERR
                CLS :PRINT ERR$(ERR)
                REM should revert to old file if possible
                GET :STOP
          ENDIF
    ENDP

    PROC endit:
          STOP
    ENDP

You should, as in both these examples, be precise in checking for the System message; if in future the GETCMD$ function were to use values other than "C", "O" or "X", these procedures would ignore them.

If you need to check the modifier keys for the returned keypress, use a&(4) instead of KMOD.

SETDOC called just before the creation of the file ensures that the created file is a document, i.e. that the file launches its associated application when selected. The strings passed to SETDOC and CREATE (or gSAVEBIT) should be exactly the same, otherwise a non-document file will be created. SETDOC should also be called when opening a document to allow the System screen to display the correct document name in its task list. OPL explicitly supports database and multi-bitmap files as documents.

To be strict, whenever creating a file, an application should first use PARSE$ to find the disk and directory requested. It should then use TRAP MKDIR to ensure that the directory exists.

When an application cannot respond

The LOCK command marks an app as locked or unlocked. When an app is locked with LOCK ON, the System will not send it events to change files or quit. If, for example, you attempt to close down the app from the Task list, a message will appear, indicating that the app cannot close down at that moment.

You should use LOCK ON if your app uses a keyword such as MENU, DIALOG and EDIT which pauses the execution of the program. You might also use it when the app is about to go busy for a considerable length of time, or at any other point where a clean exit is not possible. Do not forget to use LOCK OFF as soon as possible afterwards.

An application is initially unlocked.


OPL and MIME

Contents

  • MIME priorities
  • MIME content types
    • References

OPL applications can support files with a recognised MIME content type though the MIME OPL keyword. This is in addition to their recognising their own kinds of document through the use of UIDs.

EPOC Release 5 supports MIME recognition for foreign documents. These are files which are not native to EPOC, and have no UIDs, such as plain text files. Under ER5, they can be identified by the system and handled by an appropriate program.

The foreign file is mapped to a MIME type by a MIME recogniser located in \System\Recogs\. When the file is started from the System screen, an appropriate application is started to handle the file based on its recognised MIME content type.

The MIME keyword is used as in the following example:

    APP myEditor, KUidMyEditorApp&
          FLAGS KFlagsAppFileBased%
          CAPTION "myEditor", KLangEnglish%
          MIME KDataTypePriorityNormal%, "text/plain"
    ENDA

MIME priorities

Each OPL application which can handle files of a particular MIME type has an associated priority as described in the reference for the MIME keyword. EPOC uses the priority of an application to decide whether it should be used for opening a file in preference to other applications which can handle files of the same MIME type. The application with the highest priority is used to open the file.

MIME content types

Files which are recognised by an EPOC system recogniser are associated with a particular MIME type. The MIME type of a file is a string which describes the content of that file; you can examine the MIME type of files on an EPOC device by selecting the file from the System screen and selecting File | Properties... from the menu. If the File type has a forward slash in it, e.g. text/plain or image/png, then that file is being recognised by a MIME recogniser.

The recogniser makes the association between a file and its type by a combination of factors, one of which is the file’s extension. If the file extension is changed, then a different association might be made, and a different application may be used to handle the file.

References

It is beyond the scope of this document to describe MIME content types and mechanisms in detail, but the possibilities are described fully in the following RFCs:

  • RFC 2045: Multipurpose Internet Mail Extensions (MIME) Part One: Mechanisms for Specifying and Describing the Format of Internet Message Bodies.
  • RFC 2046: Multipurpose Internet Mail Extensions (MIME) Part Two: Media Types.
  • RFC 2047: Multipurpose Internet Mail Extensions (MIME) Part Three: Message Header Extensions for Non-ASCII Text.
  • RFC 2048: Multipurpose Internet Mail Extensions (MIME) Part Four: Registration Procedures.
  • RFC 2049: Multipurpose Internet Mail Extensions (MIME) Part Five: Conformance Criteria and Examples.

RFCs are a standard resource for programmers, and may be downloaded from and read at many Internet sites including:

  • http://www.rfc-editor.org/ [USA]
  • http://www.it.kth.se/docs/rfc/ [Sweden]
  • http://www.csl.sony.co.jp/rfc/ [Japan]
  • http://src.doc.ic.ac.uk/rfc/ [United Kingdom]


Foreground and background

  • SETFLAGS $10000 tells the machine to send a "machine switch on" event to the current program, whenever it switches on, even if this program is in the background. If required, use it just once at the start of your program.
  • The System OPX procedure SETFOREGROUND: brings the current program to the foreground.
  • The System OPX procedure SETBACKGROUND: sends it to the background again.

Note that each of these should be followed by gUPDATE to ensure they take effect immediately.

Note that when a program runs in the background it can stop the "automatic turn off" feature from working. However, as soon as the program waits for a keypress or an event, with GET/GET$ or GETEVENT32, auto-turn off can occur.

Auto-turn off can also occur if the program does a PAUSE (of 2 or more 20ths of a second), but only if the program has used SETACTIVE from System.opx to mark the program as inactive. See About OPXs for more on this.


Scanning the keyboard directly

It is sometimes useful to know which keys are being pressed at a given moment and also when a key is released. For example, in a game, a certain key might start some action and releasing the key might stop it.

GETEVENT32 ev&() and GETEVENTA32 ev&() return the scan code of any key pressed to the third element of the array ev&(). It is the programmers responsibility to track the key currently being pressed. The scan codes are given in hex in the following representation of the keyboard:


I/O functions and commands

Contents

  • Overview
    • Error handling
    • Handles
    • var variables
  • Opening a file with IOOPEN
    • Mode Category 1 - Open mode
    • Mode Category 2 - File format
    • Mode Category 3 - Access flags
  • Closing a file with IOCLOSE
  • Reading a file with IOREAD
    • Text files
    • Binary files
  • Writing to a file
  • Positioning within a file
  • Example — displaying a plain text file
  • Asynchronous requests and semaphores
    • Asynchronous requests
    • The I/O semaphore
    • Status words
    • Cancelling an asynchronous request
    • Waiting for a particular completion
    • A first example using asynchronous I/O
    • Polling rather than waiting
  • I/O device handling and the asynchronous request functions
  • Some useful IOW functions
  • Example of IOW screen functions

Overview

Section Contents

  • Error handling
  • Handles
  • var variables

The memory which an OPL program may use is unlimited up to the constraint placed by the machine itself. This means that addresses must be represented by 32-bit integers, the widest numeric type available in OPL.

OPL includes powerful facilities to handle input and output (‘I/O’). These functions and commands can be used to access all types of files in the filing system, as well as various other parts of the low-level software.

This section describes how to open, close, read and write to files, and how to set the position in a file. The data file handling commands and functions have been designed for use specifically with data files. The I/O functions and commands are designed for general file access. You don’t need to use them to handle data files.

These are powerful functions and commands and they must be used with care. Before using them you must read this section closely and have a good grounding in OPL in general.

Error handling

You should have a good understanding of error handling (see Error Handling) before using the I/O functions.

The functions in this section never raise an OPL error message. Instead they return a value - if this is less than zero an error has occurred. It is the responsibility of the programmer to check all return values, and handle errors appropriately. Any error number returned will be one of those in the list given in OPL error values. You can use ERR$ to display the error as usual.

Handles

Many of these functions use a handle, which must be a long integer variable. IOOPEN assigns this handle variable a value, which subsequent I/O functions use to access that particular file. Each file you IOOPEN needs a different handle variable.

var variables

In this section, var denotes an argument which should normally be a LOCAL or GLOBAL variable. (Single elements of arrays may also be used, but not field variables or procedure parameters.) Where you see var the address of the variable is passed, not the value in it. (This happens automatically; don’t use ADDR yourself.)

In many cases the function you are calling passes information back by setting these var variables.

var is just to show you where you must use a suitable variable; you don’t actually type var.

For example: ret%=IOOPEN(var handle&,name$,mode%) in the syntax description indicates that IOOPEN(h&,"abc",0) is correct (provided h& is a simple variable), but IOOPEN(100,"abc",0) is incorrect.

It is possible, though, that you already have the address of the variable to use. It might be that this address is held in a field variable, or is even a constant value, but the most common situation is when the address was passed as a parameter to the current procedure.

If you add a # prefix to a var argument, this tells OPL that the expression following is the address to be used, not a variable whose address is to be taken.

Here is an example program:

    PROC doopen:(phandle&, name$, mode%)
          LOCAL error%
          REM IOOPEN, handling errors
          error% = IOOPEN(#phandle&, name$, mode%)
          IF error% : RAISE error% : ENDIF
    ENDP

The current value held in phandle& is passed to IOOPEN. You might call doopen: like this:

    LOCAL filhand%,...
    ...
    doopen:(ADDR(filhand%),"log.txt",$23)
    ...

The doopen: procedure calls IOOPEN with the address of filhand%, and IOOPEN will write the handle into filhand%.

Opening a file with IOOPEN

Section Contents

  • Mode Category 1 - Open mode
  • Mode Category 2 - File format
  • Mode Category 3 - Access flags
    ret%=IOOPEN(var handle%,name$,mode%

or

    ret%=IOOPEN(var handle%,address&,mode%)

for unique file creation.

Creates or opens a file (or device) called name$ and sets handle% to the handle to be used by the other I/O functions.

mode% specifies how the file is to be opened. It is formed by ORing together values which fall into the three following categories:

Mode Category 1 - Open mode

One and only one of the following values must be chosen from this category.

$0000

Open an existing file (or device). The initial current position is set to the start of the file.

$0001

Create a file which must not already exist.

$0002

Replace a file (truncate it to zero length) or create it if it does not exist.

$0003

Open an existing file for appending. The initial current position is set to the end of the file. For text format files (see $0020 below) this is the only way to position to end of file.

$0004

Creates a file with a unique name. For this case, you must use the address of a string instead of name$. This string specifies only the path of the file to be created (any file name in the string is ignored). The string at address% is then set by IOOPEN to the unique file name generated (this will include the full path). The string must be large enough to take 130 characters (the maximum length file specification). For example:

    s$="C:\home\"
    IOOPEN(handle%,ADDR(s$),mode%)

This mode is typically used for temporary files which will later be deleted or renamed.

Mode Category 2 - File format

One and only one of the following values must be chosen from this category. When creating a file, this value specifies the format of the new file. When opening an existing file, make sure you use the format with which it was created.

$0000 | The file is treated as a byte stream of binary data with no restriction on the value of any byte and no structure imposed upon the data. Up to 16K can be read from or written to the file in a single operation.
$0020 | The file is treated as a sequence of variable length records. The records are assumed to contain text terminated by any combination of the CR and LF ($0D, $0A) characters. The maximum record length is 256 bytes and Control-Z ($1A) marks the end of the file.

These values are declared as constants in Const.oph. See Including header files.

Mode Category 3 - Access flags

Any combination of the following values may be chosen from this category.

$0100 | Update flag. Allows the file to be written to as well as read. If not set, the file is opened for reading only. You must use this flag when creating or replacing a file.
$0200 | Choose this value if you want the file to be open for random access (not sequential access), using the IOSEEK function.
$0400 | Specifies that the file is being opened for sharing for example, with other running programs. Use if you want to read, not write to the file. If the file is opened for writing ($0100 above), this flag is ignored, since sharing is then not feasible. If not specified, the file is locked and may only be used by this running program.

Closing a file with IOCLOSE

Files should be closed when no longer being accessed. This releases memory and other resources back to the system.

    ret%=IOCLOSE(handle%)

Closes a file (or device) with the handle handle% as set by IOOPEN.

Reading a file with IOREAD

Section Contents

  • Text files
  • Binary files
    ret%=IOREAD(handle%,address&,maxLen%)

Reads up to maxLen% bytes from a file with the handle handle% as set by IOOPEN. address& is the address of a buffer into which the data is read. This buffer must be large enough to hold a maximum of maxLen% bytes. The buffer could be an array or even a single integer as required. No more than 16K bytes can be read at a time.

The value returned to ret% is the actual number of bytes read or, if negative, is an error value.

Text files

If maxLen% exceeds the current record length, data only up to the end of the record is read into the buffer. No error is returned and the file position is set to the next record.

If a record is longer than maxLen%, the error value ‘Record too large’ (-43) is returned. In this case the data read is valid but is truncated to length maxLen%, and the file position is set to the next record.

A string array buffer$(255) could be used, but make sure that you pass the address ADDR(buffer$)+1 to IOREAD. This leaves the leading byte free. You can then POKEB the leading byte with the count (returned to ret%) so that the string conforms to normal string format. See the example program.

Binary files

If you request more bytes than are left in the file, the number of bytes actually read (even zero) will be less than the number requested. So if ret%<maxLen%, end of file has been reached. No error is returned by IOREAD in this case, but the next IOREAD would return the error value ‘End of file’ (-36).

To read up to 16K bytes (8192 integers), you could declare an integer array buffer%(8192).

Writing to a file

    ret%=IOWRITE(handle%,address&,length%)

Writes length% bytes stored in a buffer at address& to a file with the handle handle%.

When a file is opened as a binary file, the data written by IOWRITE overwrites data at the current position.

When a file is opened as a text file, IOWRITE writes a single record; the closing CR/LF is automatically added.

Positioning within a file

ret%=IOSEEK(handle%,mode%,var offset&)

Seeks to a position in a file that has been opened for random access (see IOOPEN above).

mode% specifies how the argument offset& is to be used. offset& may be positive to move forwards or negative to move backwards. The values you can use for mode% are:

1 | Set position in a binary file to the absolute value specified in offset&, with 0 for the first byte in the file.
2 | Set position in a binary file to offset& bytes from the end of the file
3 | Set position in a binary file to offset& bytes relative to the current position.
6 | Rewind a text file to the first record. offset& is not used, but you must still pass it as a argument, for compatibility with the other cases.

IOSEEK sets the variable offset& to the absolute position set.

Example — displaying a plain text file

This program opens a plain text file — such as one created with the Export as text option in the File menu of the Program editor — and types it to the screen. Press Esc to quit and any other key to pause the typing to the screen.

    PROC ioType:
          LOCAL ret%,fName$(128),txt$(255),address&
          LOCAL handle%,mode%,k%
          PRINT "Filename?", :INPUT fName$ : CLS
          mode%=$0400 OR $0020  REM open=$0000,text=$0020,share=$0400
          ret%=IOOPEN(handle%,fName$,mode%)
          IF ret%<0
                showErr:(ret%)
                RETURN
          ENDIF
          address&=ADDR(txt$)
          WHILE 1
                k%=KEY
                IF k%                        REM if keypress
                      IF k%=27                   REM Esc pressed
                            RETURN            REM otherwise wait for a key
                      ELSEIF GET=27
                            RETURN            REM Esc pressed
                      ENDIF
                ENDIF
                ret%=IOREAD(handle%,address&+1,255)
                IF ret%<0
                      IF ret%<>-36            REM NOT EOF
                            showErr:(ret%)
                      ENDIF
                      BREAK
                ELSE
                      POKEB address&,ret%      REM leading byte count
                      PRINT txt$
                ENDIF
          ENDWH
          ret%=IOCLOSE(handle%)
          IF ret%
                showErr:(ret%)
          ENDIF
          PAUSE -100 :KEY
    ENDP

    PROC showErr:(val%)
          PRINT "Error",val%,err$(val%)
          GET
    ENDP

Asynchronous requests and semaphores

Section Contents

  • Asynchronous requests
  • The I/O semaphore
  • Status words
  • Cancelling an asynchronous request
  • Waiting for a particular completion
  • A first example using asynchronous I/O
  • Polling rather than waiting
    • Polling example

This section provides the general background necessary for understanding how EPOC I/O devices can be accessed by an OPL application program.

Asynchronous requests

Many operating system services are implemented in two steps:

  1. make the service request (sometimes referred to as the queuing of a request)
  2. wait for the requested operation to complete

In most cases, as well as providing functions for each step, the system provides a function containing both the above steps. Such functions are called synchronous because they automatically synchronise the requesting process by waiting until the operation has completed. The internal function that makes the request without waiting for completion is called an asynchronous function.

Examples of asynchronous request functions are:

IOC (or IOA) | for requests on an open I/O channel
KEYA | for requests on the keyboard channel
GETEVENTA32 | for requests of events from the window server
PLAYSOUNDA: | (in System.opx) for requests to play sound files

The synchronous versions of the above functions are IOW , GET, GETEVENT32 and PLAYSOUND: respectively.

Applications use asynchronous requests in situations like the following:

  1. make request A
  2. make request B
  3. wait for either of the requested operations to complete

Processes wait for the completion of asynchronous requests by waiting on their I/O semaphore where each request is associated with a status word.

The I/O semaphore

When a process is created, the system automatically creates an I/O semaphore on its behalf (a more accurately descriptive name would have been the asynchronous request semaphore). After making one or more asynchronous requests using IOC or IOA, a process calls IOWAIT to wait on the I/O semaphore for one of the requests to complete. A typical application spends most of its time waiting on its I/O semaphore. For example, an interactive application process that is waiting for user input is waiting on the I/O semaphore.

Semaphores are provided to synchronise cooperating processes (where, in this context, a process includes a hardware interrupt). In OPL semaphores are used for synchronising the completion of asynchronous requests.

The semaphores in EPOC are counting semaphores, having a signed value that is incremented by calling IOSIGNAL and decremented by calling IOWAIT. A semaphore with a negative value implies that a process must wait for the completion of an event.

The process or the hardware interrupt handler that implements the requested operation sends a signal to the process (using a generalised version of IOSIGNAL directed to the required process) to indicate that the operation has completed. If one or more wait handlers have been installed (wait handlers are described below), they may process the signal and re-signal using IOSIGNAL. In some cases, it is convenient for the requester to use IOSIGNAL to signal itself and subsequently to process that signal in a central call to IOWAIT.

Status words

Although the arguments to asynchronous request functions vary, they all take a so-called status word argument, which subsequently contains the status of the requested operation. The status word is a 16-bit integer except when calling an asynchronous OPX procedure that specifically requires a 32-bit integer status word, such as PLAYSOUNDA: in System.opx.

All asynchronous requests exhibit the following behaviour:

  • While the request is pending, a 16-bit status word contains the negative -46.

    • A 32-bit status word however contains &80000001. Const.oph provides constant definitions for these values.

  • When the operation has completed, a value other than -46 is written to the status word. This value is zero or positive to indicate success, or a negative error number to indicate failure. For 16-bit status words, an OPL error value is used. See Error Handling for a list of these.

    • For 32-bit status words an EPOC error value is used. The EPOC error values are listed in EPOC Error Values.

  • The requesting process’s I/O semaphore is signalled (after the status word has been written).

Making a request while a previous request on the same status word is still pending will normally result in a system panic where the program is killed immediately, without being able to trap the error.

When there are multiple requests, each request is associated with a different status word. After returning from IOWAIT, the caller typically polls each status word until one is found that contains other than -46. That completion is then processed (which might include renewing the asynchronous request) and IOWAIT is called again to process the next completion.

Cancelling an asynchronous request

Most asynchronous request functions made using IOC (or IOA) can be cancelled. To cancel such requests use the IOCANCEL function.

For asynchronous requests made using a mechanism other than IOC (or IOA), a specific cancelling function must be used instead:

  • Use KEYC to cancel a KEYA request.
  • Use GETEVENTC to cancel a GETEVENTA32 request.
  • Use STOPSOUND&:to cancel a PLAYSOUNDA: request.

The following general principles apply to all functions that cancel an asynchronous request:

  • the cancel precipitates the completion of the operation (it does not stop the operation from completing).
  • the cancel may or not be effective (that is, the operation may complete naturally before the cancel is processed).
  • after a cancel, you must still process the completion of the asynchronous request (typically by immediately calling IOWAITSTAT or IOWAITSTAT32, described below, to "use up" the signal). An exception to this rule is that GETEVENTC and KEYC themselves wait for the cancellation signal, so IOWAITSTAT must not be used.

A 16-bit status word is set to -48 when a request has been effective.

A 32-bit status word is set to -3 (EPOC’s error code for ‘Cancel error’) when a request using a 32-bit status word is cancelled.

Waiting for a particular completion

When waiting for the completion of a particular asynchronous request, the wait on the I/O semaphore must be sure that it is not fooled into a premature return by the completion of any other pending asynchronous request. This is done by calling IOWAITSTAT which behaves in a similar way to IOWAIT except that it only returns when the associated status word is other than -46.

For a 32-bit status word request, IOWAITSTAT32 is used instead, again behaving in a similar way to IOWAIT except that it only returns when the associated 32-bit status word is other than &80000001.

In general, IOWAITSTAT (IOWAITSTAT32) is a safer option than IOWAIT to "use up" the signal resulting from the cancelled operation. If the cancel is not immediately effective and another completion causes IOWAIT to return, the program could continue and make another request before the cancelled operation completes (which would result in a process panic).

A first example using asynchronous I/O

In the following example, the opened asynchronous timer timChan% is used to construct a synchronous function which attempts to write the passed string to the opened serial channel serChan%. If it takes more that 5 seconds to complete the write, the procedure raises the ‘inactivity’ error -54. For simplicity it is assumed that there are no other outstanding events which could complete and that both requests started successfully. Thus it is certain that on return from the call to IOWAIT, one of the two asynchronous requests has completed.

    PROC strToSer:(inStr$)
          LOCAL str$(255)      REM local copy of inStr$ needed for ADDR
          LOCAL len%,timStat%,serStat%,timeout%,ret%,pStr&

          str$=inStr$
          pStr&=ADDR(str$)+1
                      REM pointer to string skipping leading count byte
          len%=LEN(str$)
          IOC(serChan%,2,serStat%,#pStr&,len%)
          REM request asynchronous serial write
          timeout%=50                        REM 5 second timeout
          IOC(timChan%,1,timStat%,timeout%)
                                              REM Relative timer - function 1
          IOWAIT
          IF serStat%=-46                  REM must have timed out
          IOCANCEL(serChan%)                  REM cancel serial request
          IOWAITSTAT serStat%            REM use up the signal
          RAISE -54                              REM inactivity timeout
          ENDIF
          IOCANCEL(timChan%)                  REM cancel timer request
          IOWAITSTAT timStat%            REM use up the signal
    ENDP

Polling rather than waiting

In a multi-tasking operating system it is extremely anti-social to wait for an operation to complete by polling the status word in a tight loop rather than call IOWAIT (because the polling will "hog" the processor to no benefit). However, when there is useful work to be done between each poll, it can be appropriate to poll - for example, to check periodically for user input while performing an extended calculation.

When a poll detects a completed status word, it is still obligatory to "use up" the signal by calling IOWAIT (otherwise you will get a "stray signal" later).

Polling example

The status word will be set only when either IOWAIT or IOYIELD is called. For a 32-bit status word, call IOWAITSTAT32 instead.

For example:

    ...
    IOC(handle%,func%,stat%,#pBuf&,len%)
    DO
          calc:
          REM perform part of some calculation until request complete
          IOYIELD                                REM allow status word to be set
    UNTIL stat%<>-46
    ...

I/O device handling and the asynchronous request functions

The following I/O functions provide access to devices. A full description is not within the scope of this manual, since these functions require extensive knowledge of the EPOC operating system and related programming techniques. The syntax and argument descriptions are provided here for completeness.

The previous section explains in detail the semantics of asynchronous I/O. In the descriptions of the asynchronous I/O functions below, a careful reading of that section is assumed.

ret%=IOW(handle%,func%,var arg1,var arg2)
The device driver opened with handle% (as returned by IOOPEN) performs the synchronous I/O function func% with the two further arguments. The size and structure of these two arguments is specified by the particular device driver’s documentation.

IOC(handle%,func%,var stat%,var a1,var a2)
IOC(handle%,func%,var stat%,var a1)
IOC(handle%,func%,var stat%)
Make an I/O request with guaranteed completion. The device driver opened with handle% (as returned by IOOPEN) performs the asynchronous I/O function func% with up to two further arguments. The size and structure of these arguments is specified by the particular device driver’s documentation.

As explained in detail in the previous section, asynchronous means that the IOC returns immediately, and the OPL program can carry on with other statements. status% will always be set to -46, which means that the function is still pending.

When, at some later time, the function completes, status% is automatically changed. (For this reason, status% should usually be global since if the program is still running, status% must be available when the request completes, or the program will probably crash). If status%>=0, the function completed without error. If status%<0, the function completed with error. The return values and error codes are specific to the device driver.

If an OPL program is ready to exit, it does not have to wait for any signals from pending IOC calls.

ret%=IOA(handle%,func%,var status%,var arg1,var arg2)
The device driver opened with handle% (as returned by IOOPEN) performs the asynchronous I/O function func% with two further arguments. The size and structure of these two arguments is specified by the particular device driver’s documentation.

This has the same form as IOC, but the return value cannot be ignored. IOC is effectively the same as:

    ret%=IOA(h%,f%,stat%,...)
    IF ret%<0
          stat%=ret%
          IOSIGNAL
    ENDIF

IOC allows you to assume that the request started successfully - any error is always given in the status word stat%. If there was an error, stat% contains the error code and the IOSIGNAL causes the next IOWAIT to return immediately as if the error occurred after completion. There is seldom a requirement to know whether an error occurred on starting a function, and IOC should therefore nearly always be used in preference to IOA.

IOWAIT
Wait for an asynchronous request (such as one requested by IOC, KEYA or GETEVENTA32) to complete. IOWAIT returns when any asynchronous I/O function completes. Check status% to find out which request has completed. Use IOWAITSTAT with the relevant status word to wait for a particular request to complete.

IOSIGNAL
Replace a signal of an I/O function’s completion.

As shown in ‘A simple example using asynchronous I/O’ in the previous section, it is sometimes useful to construct a synchronous operation from two asynchronous operations by waiting for either to complete before returning. In that case it waited for either the serial write request or a timeout. As noted there, the example assumed that there were no other outstanding asynchronous requests. If there had been one or more asynchronous requests made before calling that procedure, such as a request to play a sound file, and if that request had completed before both the serial write and the timer request, the procedure would incorrectly assume that the timer had completed:

    IOWAIT
    IF serStat%=-46                  REM must have timed out
          IOCANCEL(serChan%)            REM cancel serial request
          IOWAITSTAT serStat%      REM use up the signal
          RAISE -54                        REM inactivity timeout
    ENDIF
    IOCANCEL(timChan%)                  REM cancel timer request
    IOWAITSTAT timStat%            REM use up the signal

To deal with this situation correctly, the procedure should instead check that one of the particular two requests it knows about has completed and re-signal to ‘put back’ the signal consumed for the sound file completion:

    PROC strToSer:(inStr$)
          LOCAL str$(255)      REM local copy of inStr$ needed for ADDR
          LOCAL len%,timStat%,serStat%,timeout%,ret%,pStr&
          LOCAL signals%            REM count of external signals
          LOCAL err%

          str$=inStr$
          pStr&=ADDR(str$)+1
                            REM ptr to string skipping leading count byte
          len%=LEN(str$)
          IOC(serChan%,2,serStat%,#pStr&,len%)
          REM request asynchronous serial write
          timeout%=50                  REM 5 second timeout
          IOC(timChan%,1,timStat%,timeout%)
                                        REM relative timer - function 1
          WHILE 1                        REM forever loop
                IOWAIT                        REM wait for any completion
                IF timStat%<>-46            REM timed out
                      IOCANCEL(serChan%)            REM cancel serial request
                      IOWAITSTAT serStat%      REM use up the signal
                      err%=-54            REM inactivity timeout (raised
                                        REM below after re-signalling)
                      BREAK                  REM stop waiting and re-signal
                ELSEIF serStat%<>-46            REM serial write complete
                      IOCANCEL(timChan%)            REM cancel timer request
                      IOWAITSTAT timStat%      REM use up the signal
                      BREAK                  REM stop waiting and re-signal
                ELSE                                    REM other unknown request
                      signals%=signal%+1            REM count other signals
                                                    REM loop again for next
                ENDIF
          ENDWH
          WHILE signals%>0
                REM now re-signal any consumed external signals
                IOSIGNAL
                signals%=signals%-1
          ENDWH
          IF err%
                RAISE err%
          ENDIF
    ENDP

IOSIGNAL is called only after exiting the IOWAIT loop, otherwise the signal would cause the IOWAIT to return immediately.

IOWAITSTAT var status%
Wait for a particular asynchronous function, called with IOC, to complete.

IOWAITSTAT32 var stat&
Similar to IOWAITSTAT but takes a 32-bit status word. IOWAITSTAT32 should be called only when you need to wait for completion of a request made using a 32-bit status word when calling an asynchronous OPX procedure. status& will be &80000001 while the function is still pending, and on completion will be set to the appropriate EPOC error code, listed in Error Handling. See also About OPXs and Keyword Reference.

IOYIELD
Ensures that any asynchronous function is given a chance to run. Some devices are unable to perform an asynchronous request if an OPL program becomes computationally intensive, using no I/O (screen, keyboard etc.) at all. In such cases, the OPL program should use IOYIELD before checking its status% variable. This is always the case under EPOC. IOYIELD is the equivalent of IOSIGNAL followed by IOWAIT - the IOWAIT returns immediately with the signal from IOSIGNAL, but the IOWAIT causes any asynchronous handlers to run.

IOCANCEL(handle%)
Cancels any outstanding asynchronous I/O request made using IOC (or IOA) on the specified channel, causing them to complete with the completion status word containing -48 (‘I/O cancelled’). The return value is always zero and may be ignored.

The IOCANCEL function is harmless if no request is outstanding (e.g. if the function completed just before cancellation requested).

GETEVENTA32(var status%,var event&())
This is an asynchronous window server read function. You must declare a long integer array with at least 16 elements. If a window server event occurs, the information is returned in event&() as described under GETEVENT32 in the alphabetic listing.

GETEVENTC(var status%)
Cancels a GETEVENTA32. Note that IOWAITSTAT should not be called after GETEVENTC - OPL consumes the GETEVENTC signal.

err%=KEYA(var status%,key%())
This is an asynchronous keyboard read function. You must declare an integer array with two elements here, key%(1) and key%(2) to receive the keypress information. If a key is pressed, the information is returned in this way:

key%(1) is assigned the character code of the key.

The least significant byte of key%(2) takes the key modifier, in the same way as KMOD 2 for Shift down, 4 for Control down and so on. KMOD cannot be used with KEYA.

The most significant byte of key%(2) takes the count of keys pressed (0 or 1).

KEYA needs an IOWAIT in the same way as IOC.

Some useful IOW functions

IOW has this specification:

    ret%=IOW(handle%,func%,var arg1,var arg2)

Here are some uses:

    LOCAL a%(6)
    IOW(-2,8,a%(),a%())             REM 2nd a% is ignored

senses the current text window (as set by the most recent SCREEN command) and the text cursor position ignoring any values already in the array a%(). This gives the same information as SCREENINFO, which should be used in preference (see Keyword Reference).

The first four elements are set to represent the offset of the current text window from the default text window. a%(1) is set to the x-offset of the top left corner of the current text window from the default text window’s top left corner and a%(2) to the y-offset of the top left corner of current text window. Similarly a%(3) and a%(4) give the offset of bottom right corner of text window from the bottom right corner of the default text window. For example, if the most recent SCREEN command was SCREEN 10,11,4,5 the first four elements of the array a%() would be set to (3,4,13,15). The x and y positions of the cursor relative to the current text window are written to a%(5) and a%(6) respectively. All positions and offsets take 0,0, not 1,1, as the point at the top left.

    LOCAL i%,a%(6)
    i%=2
    a%(1)=x1% :a%(2)=y1%
    a%(3)=x2% :a%(4)=y2%
    IOW(-2,7,i%,a%())

clears a rectangle at x1%,y1% (top left), x2%,y2% (bottom right). If y2% is one greater than y1%, this will clear part or all of a line.

Example of IOW screen functions

The final two procedures in this module call the two IOW screen functions described beforehand. The rest of the module lets you select the function and values to use. It uses the technique used in Menus of handling menus and short-cut keys by calling procedures with string expressions.

    PROC iotest:
          GLOBAL x1%,x2%,y1%,y2%
          LOCAL i%,h$(2),a$(5)
          x1%=2 :y1%=2
          x2%=25 :y2%=5                         REM our test screensize
          SCREEN x2%-x1%,y2%-y1%,x1%,y1%
          AT 1,1
          PRINT "Text window IO test"
          PRINT "Control-Q quits"
          h$="cr"                               REM our shortcut keys
          DO
                i%=GET
                IF i%=$122                  REM MENU key
                      mINIT
                      mCARD "Set","Rect",%r
                      mCARD "Sense","Cursor",%c
                      i%=MENU
                      IF i% AND INTF(LOC(h$,CHR$(i%)))
                            a$="proc"+chr$(i%)
                            @(a$):
                      ENDIF
                ELSEIF i% AND $200                  REM shortcut key
                      i%=(i%-$200)
                      i%=LOC(h$,CHR$(i%))      REM One of ours?
                      IF i%
                            a$="proc"+MID$(h$,i%,1)
                            @(a$):
                      ENDIF            REM ignore other weird keypresses
                ELSE                        REM some other key, so return it
                      PRINT CHR$(i%);
                ENDIF
          UNTIL 0
    ENDP

    PROC procc:
          LOCAL a&
          a&=iocurs&:
          PRINT "x";1+(a& AND &ffff);
          PRINT "y";1+(a&/&10000)
    ENDP

    PROC procr:
          LOCAL xx1%,yy1%,xx2%,yy2%
          LOCAL xx1&,yy1&,xx2&,yy2&
          dINIT "Clear rectangle"
          dLONG xx1&,"Top left x",1,x2%-x1%
          dLONG yy1&,"Top left y",1,y2%-y1%
          dLONG xx2&,"Bottom left x",2,x2%-x1%
          dLONG yy2&,"Bottom left y",2,y2%-y1%
          IF DIALOG
                xx1%=xx1&-1 :xx2%=xx2&-1
                yy1%=yy1&-1 :yy2%=yy2&-1
                iorect:(xx1%,yy1%,xx2%,yy2%)
          ENDIF
    ENDP

    PROC iocurs&:
          LOCAL a%(4),a&
          REM don’t change the order of these!
          a%(1)=x1% :a%(2)=y1%
          a%(3)=x2% :a%(4)=y2%
          IOW(-2,8,a%(),a%())       REM 2nd a% is ignored
          RETURN a&
    ENDP

    PROC iorect:(xx1%,yy1%,xx2%,yy2%)
          LOCAL i%,a%(6)
          i%=2 :REM "clear rect" option
          a%(1)=xx1% :a%(2)=yy1%
          a%(3)=xx2% :a%(4)=yy2%
          IOW(-2,7,i%,a%())
    ENDP


Dynamic memory allocation

Contents

  • Overview
  • Maximum data size in a procedure
  • 32-bit addressing
  • Overview of memory usage
  • The heap allocator
  • The heap structure
  • Growing and shrinking the heap
  • Lost cells
  • Internal fragmentation
  • The OPL runtime interpreter and the heap
  • Warning — peeking/poking the cell
  • Reasons for using the heap allocator
  • Using the heap allocator
  • Example using the allocator

Overview

For each running OPL program (or process) the operating system automatically allocates memory. There are no built-in memory limits and a module or application can use as much of the available memory as it requires.

Maximum data size in a procedure

Although there is no built-in limit to the total amount of data in an OPL program, it is still not possible to declare variables in a procedure that use in total more than 65516 bytes. This allows the largest integer array in a procedure to have 32757 elements. This number decreases for any other variables, externals or for procedures called from the given procedure, as they all consume some of the procedure’s data space.

32-bit addressing

As described above, memory addresses outside the 64K address space need to be stored in long integers. Thus all keywords which support addresses take and return long integers. Note also that where # is used to specify the address of a variable that is listed in the syntax using var, the address is a long integer, so you would use #address&. See the ‘I/O functions and commands’ section above.

Overview of memory usage

The actual memory used by an OPL program depends on the requirements of the process and is automatically grown or shrunk as necessary.

An OPL process contains several separate memory areas, but the only one of significant interest to the OPL programmer is the OPL heap, used to contain the OPL variables and dynamically allocated memory cells. The heaps of different processes are entirely separate - you need only concern yourself with the heap used in your own process.

The heap allocator

The heap allocator keywords are used to allocate, resize and free variable length memory cells from the OPL heap. Cells typically range in size from tens of bytes to a few kilobytes. Allocated cells are referenced directly by their address; they do not move to compact free space left by freed cells.

Heap allocator keywords are:

  • ALLOC allocates a cell of specified size, returning its address.
  • FREEALLOC frees a previously allocated cell, which is returned to the heap.
  • REALLOC changes the size of a cell, returning its new address.
  • ADJUSTALLOC opens or closes a gap in the middle of a cell (useful for insertion or deletion of cell content), changing the size of the cell as appropriate.
  • LENALLOC returns the size of a cell.

The heap structure

Initially, the heap consists of a single free cell. After a number of calls to allocate and free cells, the heap typically consists of ranges of adjacent allocated cells separated by single free cells (which are linked). If a cell being freed is next to another free cell the two cells are automatically joined to make a single cell to prevent the free cell linked list from growing unnecessarily.

Writing beyond the end of a cell will corrupt the heap’s integrity. Such errors are difficult to debug because there is no immediate effect - the corruption is a "time bomb". It will eventually be detected, resulting in the process exiting prematurely by a subsequent allocator call such as FREEALLOC.

Growing and shrinking the heap

The heap is not fixed in size. The operating system can grow the heap to satisfy allocation requests or shrink it to release memory back to the system.

Allocation of cells is based on "walking" the free space list to find the first free cell that is big enough to satisfy the request. If no free cell is big enough, the operating system will attempt to grow the data segment to add more free space at the end of the heap.

If there is no memory in the system to accommodate growth, the allocate request fails. There are few circumstances when an allocate request can be assumed to succeed and calls to ALLOC, REALLOC and ADJUSTALLOC should have error recovery code to handle a failure to allocate.

Lost cells

There are cases in which programs allocate a sequence of cells which must either exist as a whole or not at all. If during the allocate sequence one of the later allocations fails, the previously allocated cells must be freed. If this is not done, the heap will contain unreferenced cells that consume memory to no purpose.

When designing multi-cell sequences of this kind, you should be mindful of the recovery code that must be written to free partially built multi-cell structures. The fewer the cells in such a structure, the simpler the recovery code is.

Internal fragmentation

The free space in the heap is normally fragmented to some extent; the largest cell that can be allocated is substantially smaller than the total free space. Excessive fragmentation, where the free space is distributed over a large number of cells - and where, by implication, many of the free cells are small - should be avoided because it results in inefficient use of memory and reduces the speed with which cells are allocated and freed.

Practical design hints for limiting internal fragmentation are:

  • Avoid using the heap for small, highly transient data structures for which ordinary variables are adequate. High frequency cycling through allocate and free pairs, "churns" the heap and leads to a long free space list.
  • When you have a large number of variable length data structures - particularly when they are frequently resized, "granularise" them (i.e. round the allocation up to a multiple of some reasonable value) so that you decrease the chance of leaving small, unusable free space cells.

Although a small number of gaps are not too serious and should eventually disappear in most cases anyway, the new heap allocating keywords provide ample opportunity to fragment the heap. Provided that you create and free cells in a careful and structured way, where any task needing the allocator frees them tidily on completion, there should not be a problem.

The OPL runtime interpreter and the heap

The OPL runtime interpreter uses two separate heaps: one for process management and one for user variables and allocated cells. LOADM, CREATE, OPEN, etc. use the process management heap. This ensures that the use of these keywords will not cause fragmentation. It is therefore not necessary for you to understand the interpreter’s use of the heap.

Warning — peeking/poking the cell

Using the allocator is by no means simple in OPL since the data in an allocated cell usually has to be read or written in OPL using the PEEK and POKE set of keywords which are intrinsically subject to programming error. OPL does not provide good support for handling pointers (variables containing addresses), which are basic to heap usage, nor for complicated data structures, so that it is all too easy to make simple programming errors that have disastrous effects.

For these reasons, you are recommended to use the heap accessing keywords only when strictly necessary (which should not be very often) and to take extreme care when you do use them. On the other hand, for programmers with previous experience of dynamic memory allocation, the heap allocation keywords will often prove most useful.

Reasons for using the heap allocator

A few common instances where the allocator might be used are:

  • when the amount of data to be stored is variable or cannot be determined at the time of writing the program. Without using the allocator, you would have to declare a large array to hold the data always even when it turns out that only a few bytes are needed in a particular case. Using the allocator allows you to grow the cell containing your data as and when required.
  • the amount of data may be specified in a file or by the user of the program. Once again, you would need to declare a possibly unnecessarily large array to cope with all allowed cases.
  • a system of library procedures might use a common cell, usually called a control block, to store common data. You could have one procedure creating the cell and initialising data in it, other procedures in the system could be passed the address of the cell, using and possibly updating the data in it, and finally a further procedure could free the cell.
  • This concept will be familiar to you if you have used handles for the I/O keywords, where the handle references a cell used internally by the I/O system.
  • If you did not use the allocator in this case, you would probably need to declare a global array in the procedure calling the library procedures, with the disadvantages that the name and size of the array would need to be fixed for all time even when a better alternative mechanism has been devised for the library code with different data requirements.
  • ADJUSTALLOC allows you to insert or remove data at the start or in the middle of data that has previously been set up. With an array, you would need to copy each element to the next or previous element to make or close a gap.

Using the heap allocator

ALLOC and associated heap keywords

ALLOC, REALLOC and ADJUSTALLOC allocate cells that have lengths that are the smallest multiple of four greater than the size requested. All of these raise errors if the cell address argument is not in the range known by the heap. The same address checking is done for peeking and poking.

ALLOC, REALLOC and ADJUSTALLOC return a long integer value, so that a request can be made to allocate a cell of any length within memory constraints.

Allocating a cell

Use pcell&=ALLOC(size&) to allocate a cell on the heap of a specified size returning the pointer to the cell or zero if there is not enough memory. The new cell is uninitialised — you cannot assume that it is zeroed.

Freeing an allocated cell

Use FREEALLOC pcell& to free a previously allocated cell at pcell& as returned, for example, by ALLOC. Does nothing if pcell& is zero.

Changing a cell’s size

Use pcelln&=REALLOC(pcell&,size&) to change the size of a previously allocated cell at address pcell& to size&, returning the new cell address or zero if there is not enough memory. If out of memory, the old cell at pcell& is left as it was.

If successful, pcelln& will not be the same as pcell& on return only if the size increases and there is no free cell following the cell being grown which is large enough to accommodate the extra amount.

Inserting or deleting data in cell

Use pcelln&=ADJUSTALLOC(pcell&,offset&,amount&) to open or close a gap at offset& within the allocated cell pcell& returning the new cell address or zero if there is not enough memory. offset& is 0 for the first byte in the cell. Opens a gap if amount& is positive and closes it if negative. The data in the cell is automatically copied to the new position.

If successful, pcelln& will not be the same as pcell& on return only if amount& is positive and there is no free cell following the cell being adjusted which is large enough to accommodate the extra amount.

Finding out the cell length

Use len&=LENALLOC(pcell&) to get the length of the previously allocated cell at pcell&.

Example using the allocator

This example illustrates the careful error checking which is essential when using the allocator. RAISE is used to jump to the error recovery code.

If you cannot understand this example it would be wise to avoid using the allocator altogether.

    LOCAL pcell&                         REM pointer to cell
    LOCAL pcelln&                      REM new pointer to cell
    LOCAL p&                         REM general pointer
    LOCAL n%                         REM general integer
    ONERR e1
    pcell&=ALLOC(2+2*8)             REM holds an integer and 2
                                        REM 8-byte floats initially
    IF pcell&=0
          RAISE -10                   REM out of memory; go to e1::
    ENDIF
    POKEW pcell&,2                      REM store integer 2 at start of cell
                                        REM i.e. no. of floats
    POKEF UADD(pcell&,2),2.72               REM store float 2.72
    POKEF UADD(pcell&,10),3.14              REM store float 3.14 ...
    pcelln&=REALLOC(pcell&,2+3*8)       REM space for 3rd float
    IF pcelln&=0
          RAISE -10                           REM out of memory
    ENDIF
    pcell&=pcelln&                          REM use new cell address
    n%=PEEKW(pcell&)                         REM no. of floats in cell
    POKEF UADD(pcell&,2+n%*8),1.0       REM 1.0 after 3.14
    POKEW pcell&,n%+1                   REM one more float in cell ...
    pcelln&=ADJUSTALLOC(pcell&,2,8)       REM open gap before 2.72
    IF pcelln&=0
          RAISE -10                         REM out of memory
    ENDIF
    pcell&=pcelln&                        REM use new cell address
    POKEF UADD(pcell&,2),1.0             REM store 1.0 before 2.72
    POKEW pcell&,4                        REM 4 floats in cell now ...
    p&=UADD(pcell&,LENALLOC(pcell&))       REM byte after cell end
    p&=USUB(p&,8)                         REM address of final float
    POKEF p&,90000.1                        REM overwrite with 90000.1
    RAISE 0                                  REM clear ERR value
    e1::
    FREEALLOC pcell&                        REM free any cell created
    IF err<>0
          ...                                   REM display error message etc.
    ENDIF
    RETURN ERR
EPOC SDK Home Glossary Previous Up


Example Programs

  • About the example programs
  • Timer — Countdown timer
  • Dice — Rolls dice
  • Birthday — Calculates birthdays
  • Files — Data files
  • Reorder — Re-orders a database file
  • Watch — Simple stopwatch
  • Label — Inserts a new label into a database
  • Bounce — Displays a bouncing ball
  • Circles — Draws circles
  • Animate — Animated bitmaps


About the example programs

Contents

  • Overview
  • When you’re typing in
  • Errors

Overview

This section contains example programs written in OPL. The programs are not intended to demonstrate all the features of OPL, but they should give you a few hints. To find out more about a particular command or function, see Keyword Reference. There are some other example programs — see Advanced Topics.

When you’re typing in

  • You can type procedures in all uppercase, all lowercase or any mixture of the two. Be careful with character codes, though — %A is different to %a.
  • When there is more than one command or function on a line, separate each one with a space and colon - for example:
    CLS :PRINT "hello" :GET

    However, the colon is optional before a REM statement for example:

    CLS REM Clears the screen

    and

    CLS :REM Clears the screen

    are both OK.

  • Put a space between a command and the arguments which follow it - for example PRINT a$. But don’t put a space between a function and the arguments in brackets - for example CHR$(16).
  • It doesn’t matter how many spaces or tabs you have at the beginning of a line.

Errors

The following programs do not include full error handling code. This means that they are shorter and easier to understand, but may fail if, for example, you enter the wrong type of input to a variable.

If you want to develop other programs from these example programs, it is recommended that you add some error handling code to them. See Error Handling for further details.


Timer — Countdown timer

    REM Include System.oxh, which declares System.opx and
    REM supplies the MOD&: (modulo) function:
    INCLUDE "System.oxh"
    PROC timer:
          LOCAL min&,sec&,secs&,i%
          sec&=1
          dINIT "Countdown timer"
          dLONG min&,"Minutes",0,59
          dLONG sec&,"Seconds",0,59
          dBUTTONS "Cancel",-27,"Start",%s
          IF DIALOG=%s
                FONT 12,16
                secs&=sec&+60*min&
                WHILE secs&
                      PAUSE -20                     REM a key gets us out
                      IF KEY
                            RETURN
                      ENDIF
                      secs&=secs&-1
                      AT 20,6 :PRINT NUM$(secs&/60,-2);"m"
                      AT 24,6 :PRINT NUM$(mod&:(secs&,int(60)),-2);"s"
                ENDWH
                DO
                      BEEP 5,300
                      PAUSE 10
                      IF KEY :BREAK :ENDIF
                      i%=i%+1
                UNTIL i%=10
          ENDIF
    ENDP


Dice — Rolls dice

When the program is run, a message is displayed saying that the dice is rolling. You then press a key to stop it. A random number from one to six is displayed and you choose whether to roll again or not.

    PROC dice:
          LOCAL dice%
          DO
                CLS :PRINT "DICE ROLLING:"
                AT 1,3 :PRINT "Press a key to stop"
                DO
                      dice%=(RND*6+1)
                      AT 1,2 :PRINT dice%
                UNTIL KEY
                BEEP 5,300
                dINIT "Roll again?"
                dBUTTONS "No",%N,"Yes",%Y
          UNTIL DIALOG<>%y
    ENDP

Random numbers

In this example, the RND function returns a random floating-point number, between 0 and 0.9999999... It is then multiplied by 6, and 1 is added, to give a number from 1 to 6.9999999... This is rounded down to a whole number (from 1 to 6) by assigning to the integer dice%.


Birthday — Calculates birthdays

This procedure finds out on which day of the week people were born.

    PROC Birthday:
          LOCAL day&,month&,year&,DayInWk%
          DO
                dINIT
                dTEXT "","Enter your date of birth",2
                dTEXT "","Use numbers, eg 23 12 1963",$202
                dLONG day&,"Day",1,31
                dLONG month&,"Month",1,12
                dLONG year&,"Year",1900,2155
                IF DIALOG=0
                      BREAK
                ENDIF
                DayInWk%=DOW(day&,month&,year&)
                CLS :PRINT DAYNAME$(DayInWk%),day&,month&,year&
                dINIT "Again?"
                dBUTTONS "No",%N,"Yes",%Y
          UNTIL DIALOG<>%y
    ENDP

The DOW function works out what day of the week, from 1 to 7, a date is. The DAYNAME$ function then converts this to MON, TUE and so on. MON is 1 and SUN is 7.


Files — Data files

The following module works on a data file called DATA, containing names, addresses, post codes and telephone numbers. It assumes this file has already been created with a statement like this:

    CREATE "DATA",A,nm$,ad1$,ad2$,ad3$,ad4$,tel$

To use a database created with the Data application, see Database manipulation.

The first procedure is the controlling, calling procedure, offering you choices. The next two let you add or edit records.

    PROC files:
          GLOBAL nm$(255),ad1$(255),ad2$(255)
          GLOBAL ad3$(255),ad4$(255),tel$(255),title$(30)
          LOCAL g%
          OPEN "DATA",A,nm$,ad1$,ad2$,ad3$,ad4$,tel$
          DO
                CLS
                dINIT "Select action"
                dTEXT "Add new record","",$402
                dTEXT "Find and edit a record","",$402
                g%=DIALOG
                IF g%=2
                      add:
                ELSEIF g%=3
                      edit:
                ENDIF
          UNTIL g%=0
          CLOSE
    ENDP

    PROC add:
          nm$="" :ad1$="" :ad2$=""
          ad3$="" :ad4$="" :tel$=""
          title$="Enter a new record"
          IF showd%:
                APPEND
          ENDIF
    ENDP

    PROC edit:
          LOCAL search$(30),p%
          dINIT "Find and edit a record"
          dEDIT search$,"Search string",15
          IF DIALOG
                FIRST
                IF FIND("*"+search$+"*")=0
                      ALERT("No matching records")
                      RETURN
                ENDIF
                DO
                      nm$=A.nm$ :ad1$=A.ad1$ :ad2$=A.ad2$
                      ad3$=A.ad3$ :ad4$=A.ad4$ :tel$=A.tel$
                      title$="Edit matching record"
                      IF showd%:
                            UPDATE :BREAK
                      ELSE
                            NEXT
                      ENDIF
                      FIND("*"+search$+"*")
                      IF EOF
                            ALERT("No more matching records")
                            BREAK
                      ENDIF
                UNTIL 0
          ENDIF
    ENDP

    PROC showd%:
          LOCAL ret%
          dINIT title$
          dEDIT nm$,"Name",25
          dEDIT ad1$,"Street",25
          dEDIT ad2$,"Town",25
          dEDIT ad3$,"County",25
          dEDIT ad4$,"Postcode",25
          dEDIT tel$,"Phone",25
          ret%=DIALOG
          IF ret%
                A.nm$=nm$ :A.ad1$=ad1$ :A.ad2$=ad2$
                A.ad3$=ad3$ :A.ad4$=ad4$ :A.tel$=tel$
          ENDIF
          RETURN ret%
    ENDP


Reorder — Re-orders a database file

When you use the Data application and enter or change an entry, it goes to the end of the database file. However, if in your address book, each entry begins with a person’s second name - for example, Tate, Hazel - you can use this program to re-order all of the entries. This doesn’t change the way you find an entry, but after running it you can step through it like a paper address book, or print it out neatly ordered.

This procedure can be used as required for any data file in internal memory or on memory disk. The dialog it shows is set to show data files used by Data.

You can adapt this procedure to sort other types of data files in other ways.

Note that there more advanced features than this available in the Database OPX. See About OPXs for more details of this. You could also use restriction of files by UID in the dFILE keyword to restrict to databases only.

    PROC reorder:
          LOCAL last%,e$(255),e%,lpos%,n$(255),c%
          n$="\dat\*.dbf"
          dINIT "Re-order Data file"
          dFILE n$,"Filename",0
          IF DIALOG                              REM returns 0 if cancelled
                OPEN n$,a,a$
                LAST :last%=POS
                IF COUNT>0
                      WHILE last%<>0
                            POSITION last% :e%=POS
                            e$=UPPER$(a.a$)
                            DO
                                  IF UPPER$(a.a$)<e$
                                        e$=UPPER$(a.a$) :e%=POS
                                  ENDIF
                                  lpos%=POS :BACK
                            UNTIL pos=1 and lpos%=1
                            POSITION e%
                            PRINT e$
                            UPDATE :last%=last%-1
                      ENDWH
                ENDIF
                CLOSE
          ENDIF
          GET
    ENDP

If you try to reorder a file which is already open (i.e. shown in bold on the System screen) you will see a ‘File’ is in use’ error. You should close the file and then try again.


Watch — Simple stopwatch

Here is a simple stopwatch with lap times. Note that the machine switches off automatically after a time if no keys are pressed; you may want to disable this feature via the Control Panel on the System screen before running this program.

Each timing is only accurate to within one second, as the procedure is based on the SECOND function.

    PROC watch:
          LOCAL k%,s%,se%,mi%
          FONT 11,16
          AT 20,1 :PRINT "Stopwatch"
          AT 15,11 :PRINT "Press a key to start"
          GET
          DO
                CLS :mi%=0 :se%=0 :s%=SECOND
                AT 15,11 :PRINT "  S=Stop, L=Lap  "
    loop::
                k%=KEY AND $ffdf                   REM ensures upper case
                IF k%=%S
                      GOTO pause::
                ENDIF
                IF k%=%L
                      AT 20,6 :PRINT "Lap: ";mi%;":";
                      IF se%<10 :PRINT "0"; :ENDIF
                      PRINT se%;" ";
                ENDIF
                IF SECOND<>s%
                      s%=SECOND :se%=se%+1
                      IF se%=60 :se%=0 :mi%=mi%+1 :ENDIF
                      AT 17,8
                      PRINT "Mins",mi%,"Secs",
                      IF se%<10 :PRINT "0"; :ENDIF
                      PRINT se%;" ";
                ENDIF
                GOTO loop::
    pause::
                mINIT
                mCARD "Watch","Restart",%r,"Zero",%z,"Exit",%x
                k%=MENU
                IF k%=%r
                      GOTO loop::
                ENDIF
          UNTIL k%<>%z
    ENDP


Label — Inserts a new label into a database

If you insert a new label in a database, the entries will no longer match up with the labels. Rather than using the ‘Update’ option on every entry, to insert a suitable blank line in each one, you can use this program to do this for the entire data file.

The Data application allows you to use as many lines (fields) as you want in an entry (record); OPL can only access 32 fields. This program only lets you insert a new field in the first 16 fields, although you can adapt the program simply to check up to 31 fields.

If, in Data, you enter a line longer than 255 characters, it is stored as two fields, with a character of code 20 at the start of the second field. This program correctly handles any such fields.

The program checks that the 17th field is blank, as it will be overwritten by what was the 16th field. If a long entry has a 17th field, and it contains text, the program skips this entry. The rest of longer entries - even if there are more than 32 fields will be unchanged.

If you insert a new field at a position below the last label, Data will not show it, even when using ‘Update’.

The maximum record length in OPL is 1022 characters. The OPEN command will display a ‘Record too large’ error if the file contains a record longer than this.

    PROC label:
          LOCAL a%,b%,c%,d%,s$(128),s&,i$(17,255)
          s$="\dat\*.dbf"
          dINIT "Insert new field"
          dFILE s$,"Data file",0
          dLONG s&,"Break at line (1-16)",1,16
          IF DIALOG
                OPEN s$,A,a$,b$,c$,d$,e$,f$,g$,h$,i$,j$,k$,l$,m$,n$,o$,p$,q$
                c%=COUNT :a%=1
                WHILE a%<=c%
                      AT 1,1 :PRINT "Entry",a%,"of",c%,
                      IF A.q$=""      REM Entry (hopefully) not too long
                            i$(1)=A.a$ :i$(2)=A.b$ :i$(3)=A.c$
                            i$(4)=A.d$ :i$(5)=A.e$ :i$(6)=A.f$
                            i$(7)=A.g$ :i$(8)=A.h$ :i$(9)=A.i$
                            i$(10)=A.j$ :i$(11)=A.k$ :i$(12)=A.l$
                            i$(13)=A.m$ :i$(14)=A.n$ :i$(15)=A.o$
                            i$(16)=A.p$
                            d%=0 :b%=0
                            WHILE d%<s&+b%        REM find field to break at
                                  d%=d%+1
                                  IF LEFT$(i$(d%),1)=CHR$(20)
                                        REM line>255...
                                        b%=b%+1  REM ...so it’s 2 fields
                                  ENDIF
                            ENDWH
                            b%=17
                            WHILE b%>d%      REM copy the fields down
                                  i$(b%)=i$(b%-1) :b%=b%-1
                            ENDWH
                            i$(d%)=""            REM and make an empty field
                            A.a$=i$(1) :A.b$=i$(2) :A.c$=i$(3)
                            A.d$=i$(4) :A.e$=i$(5) :A.f$=i$(6)
                            A.g$=i$(7) :A.h$=i$(8) :A.i$=i$(9)
                            A.j$=i$(10) :A.k$=i$(11) :A.l$=i$(12)
                            A.m$=i$(13) :A.n$=i$(14) :A.o$=i$(15)
                            A.p$=i$(16) :A.q$=i$(17)
                      ELSE
                            PRINT "has too many fields"
                            PRINT "Press a key..." :GET
                      ENDIF
                UPDATE :FIRST
                a%=a%+1
                ENDWH :CLOSE
          ENDIF
    ENDP


Bounce — Displays a bouncing ball

    PROC bounce:
          LOCAL posX%,posY%,changeX%,changeY%,k%
          LOCAL scrx%,scry%,info%(10)
          SCREENINFO info%()
          scrx%=info%(3) :scry%=info%(4)
          posX%=1 :posY%=1
          changeX%=1 :changeY%=1
          DO
                posX%=posX%+changeX%
                posY%=posY%+changeY%
                IF posX%=1 OR posX%=scrx%
                      changeX%=-changeX%
                      REM at edge ball changes direction
                      BEEP 2,600                        REM low beep
                ENDIF
                IF posY%=1 or posY%=scry%            REM same for y
                      changeY%=-changeY%
                      BEEP 2,200                        REM high beep
                ENDIF
                AT posX%,posY% :PRINT "0";
                PAUSE 2                              REM Try changing this
                AT posX%,posY% :PRINT " ";
                                              REM removes old ‘0’ character
                k%=KEY
          UNTIL k%
    ENDP


Circles — Draws circles

Here is an example program for drawing circles or ellipses, filled or unfilled:

    PROC draw:
          LOCAL d%
          DO
                dINIT "Draw a circle or an ellipse?"
                dBUTTONS "Circle",%c OR $200,"Ellipse",%e OR $200,"Cancel",-27
                d%=DIALOG
                IF d%=%c
                      circle:
                ELSEIF d%=%e
                      ellipse:
                ENDIF
          UNTIL d%=0
    ENDP

    PROC circle:
          LOCAL x&,y&,r&,f%
          dINIT "Drawing parameters"
          x&=320 :dLONG x&,"Centre x position",0,639
          y&=120 :dLONG y&,"Centre y position",0,249
          r&=20 :dLONG r&,"Radius",1,320
          f%=0 :dCHECKBOX f%,"Filled"
          dBUTTONS "Draw",%d,"Cancel",-27
          IF DIALOG
                gAT x&,y&
                gCIRCLE r&,f%
                GET
                gCLS
          ENDIF
    ENDP

    PROC ellipse:
          LOCAL x&,y&,hr&,vr&,f%
          dINIT "Drawing parameters"
          x&=320 :dLONG x&,"Centre x position",0,639
          y&=120 :dLONG y&,"Centre y position",0,249
          hr&=20 :dLONG hr&,"Horizontal Radius",1,320
          vr&=20 :dLONG vr&,"Vertical Radius",1,320
          f%=0 :dCHECKBOX f%,"Filled"
          dBUTTONS "Draw",%d,"Cancel",-27
          IF DIALOG
                gAT x&,y&
                gELLIPSE hr&,vr&,f%
                GET
                gCLS
          ENDIF
    ENDP


Animate — Animated bitmaps

This program requires five bitmap files — one.pic to five.pic. Each of these would differ slightly. They might, for example, be five ‘snapshots’ of a running human figure, each with the legs at a different point in their cycle.

The program copies each bitmap into a window of its own, then makes each window visible in turn, each time slightly further across the screen.

To make bitmap files, first draw the pattern you want with any of the graphics drawing commands. (Use gLINEBY 0,0 to draw single dots.) When the pattern is complete, use gSAVEBIT to make the bitmap file. For advanced animation, you could use a sprite as described in About OPXs.

    PROC animate:
          LOCAL id%(5),i%,j%,s$(5,10),w%,h%,edge%
          REM example width and height
          w%=16 :h%=28
          edge%=gWIDTH                    REM screen edge
          s$(1)="one.pic" :s$(2)="two.pic" :s$(3)="three.pic"
          s$(4)="four.pic" :s$(5)="five.pic" :j%=1
          WHILE j%<6
                i%=gLOADBIT(s$(j%))
                id%(j%)=gCREATE(0,0,w%,h%,0)
                gCOPY i%,0,0,w%,h%,3
                gCLOSE i% :j%=j%+1
          ENDWH
          i%=0 :gORDER 1,9
          DO
                j%=(i%-5*(i%/5))+1                  REM (i% MOD 5)+1
                gVISIBLE OFF                        REM previous window
                gUSE id%(j%)                        REM new window
                gSETWIN i%,20                        REM position it
                gORDER id%(j%),1                  REM make foreground
                gVISIBLE ON                        REM make visible
                i%=i%+1 :PAUSE 2
          UNTIL KEY OR (i%>(edge%-w%))
    ENDP
EPOC SDK Home Glossary Previous Up


Keyword Reference

  • About OPL Keywords
  • ABS — ATAN
  • BACK — BYREF
  • CANCEL — CURSOR
  • DATETOSECS — dXINPUT
  • EDIT — EXTERNAL
  • FIND — FREEALLOC
  • gAT — gY
  • HEX$ — HOUR
  • IABS — IOYIELD
  • KEY — KMOD
  • LAST — LPRINT
  • MAX — mPOPUP
  • NEXT — NUM$
  • OFF — OPENR
  • PARSE$ — PUT
  • RAD — RND
  • SCI$ — SUM
  • TAN — TRAP RAISE
  • UADD — USUB
  • VAL — VECTOR
  • WEEK — WHILE...ENDWH
  • YEAR


About OPL Keywords

Contents

  • Typing keywords
  • How commands are specified
  • How functions are specified

Typing keywords

  • Commands, functions and arguments may be typed in any combination of UPPER and lower case.
  • To put more than one statement on a line, separate them by a space followed by a colon. For example:

    •       CLS : PRINT "hello" : GET

    Any commands may be strung together like this, and as many of them as you like, provided the total line length does not exceed 255 characters. The colon is optional before a REM statement.

  • Where one space is allowed, any number of spaces is allowed, e.g.

    •       CLS : PRINT "Press Esc"

  • Functions may be used as arguments to other functions or commands e.g. PRINT LEFT$(A$,3) and a = COS(ABS(x)) are OK.

How commands are specified

Commands are specified as,

    COMMAND argument(s)

where argument(s) follow the command after a space and are separated from each other by commas. The arguments may include:

  • Floating-point expressions (e.g. SIN(30)+2), variables (e.g. price or z), literal values (e.g. 78.9), or declared constants (e.g. KFixed).
  • Integer expressions (e.g. 3*567), variables (e.g. price%, or price& if in range), literal values (e.g. -5676), or declared constants (e.g. KFixed%).
  • Long integer expressions (e.g. 3*56799), variables (e.g. profit&), literal values (e.g. -5676869), or declared constants (e.g. KFixed&).
  • String expressions (e.g. b$+MID$(a$)), variables (e.g. price$), literal values (e.g. "word"), or declared constants (e.g. KFixed$).
  • Logical file names (e.g. A, B, Q).
  • Field names (e.g. B.taxcode%, P.item&).

For example, AT X%,Y% might be used like this: AT 15,2

How functions are specified

Functions are specified as,

    variable=FUNCTION(argument(s))

where variable may be f% or f& for a function returning an integer or long integer result, f for a function returning a floating-point result, or f$ for a function returning a string result. The argument(s):

  • follow the command immediately
  • are enclosed in brackets: ( )
  • are separated from each other in the brackets by a comma: ,
  • may include variables, literal values, expressions or declared constants of the appropriate kind - integer, long integer, floating-point or string, as described above.

E.g. f$=LEFT$(g$,x%) might be used like this: PRINT LEFT$(fname$,2)

If you use the wrong type of number as an argument it will, where possible, be converted. For example, you can use an integer for a floating-point argument, or a long integer for an integer argument. If the conversion is not possible — for example, if you use a floating-point number for an integer argument and its value is outside the range of integers an error will be produced and the program stopped. Some functions, such as GET, have no arguments.


ABS — ATAN

Contents

  • ABS — Absolute value of a floating point number
  • ACOS — Arccosine
  • ADDR — Address of variable
  • ADJUSTALLOC — Adjust memory allocation
  • ALERT — Alert dialog
  • ALLOC — Allocates a cell on the heap
  • APP — Defines an application
  • APPEND — Adds a record to a data file
  • ASC — Gets a character code from a string
  • ASIN — Arcsine
  • AT — Positions the text cursor
  • ATAN — Arctangent

ABS — Absolute value of a floating point number

Usage: a=ABS(x)

Returns the absolute value of a floating-point number that is, without any +/- sign for example ABS(-10.099) is 10.099

If x is an integer, you won’t get an error, but the result will be converted to floating-point for example ABS(-6) is 6.0. Use IABS to return the absolute value as a long integer.

ACOS — Arccosine

Usage: a=ACOS(x)

Returns the arc cosine, or inverse cosine (COS-1) of x.

x must be in the range -1 to +1. The number returned will be an angle in radians. To convert the angle to degrees, use the DEG function.

ADDR — Address of variable

Usage: a&=ADDR(variable)

Returns the address at which variable is stored in memory.

The values of different types of variables are stored in bytes starting at ADDR(variable). See PEEK for details. The return type of this function should be a long integer, however if the 64K memory limit is set via SETFLAGS, a& is guaranteed to fit into an integer.

See UADD, USUB.

ADJUSTALLOC — Adjust memory allocation

Usage: pcelln&=ADJUSTALLOC(pcell&,off&,am&)

Opens or closes a gap at off& within the allocated cell pcell&, returning the new cell address or zero if out of memory. off& is 0 for the first byte in the cell. Opens a gap if the amount am& is positive, and closes it if negative. An error will be raised if the cell address argument is not in the range known by the heap.

See also SETFLAGS if you require a 64K limit to be enforced on 32-bit target devices. If the flag is set to restrict the limit, pcelln& is guaranteed to fit into an integer.

See ALLOC. See also Dynamic memory allocation.

ARM

Cells are allocated lengths that are the smallest multiple of four greater than the size requested because the ARM processor requires a four-byte word alignment for its memory allocation. The ARM processor is used in the Psion Series 5 and other EPOC devices.

ALERT — Alert dialog

Usage: any of

    r%=ALERT(m1$,m2$,b1$,b2$,b3$)
    r%=ALERT(m1$,m2$,b1$,b2$)
    r%=ALERT(m1$,m2$,b1$)
    r%=ALERT(m1$,m2$)
    r%=ALERT(m1$)

Presents an alert — a simple dialog — with the messages and keys specified, and waits for a response. m1$ is the message to be displayed on the first line, and m2$ on the second line. If m2$ is not supplied or if it is a null string, the second message line is left blank.

Up to three keys may be used. b1$, b2$ and b3$ are the strings (usually words) to use over the keys. b1$ appears over an Esc key, b2$ over Enter, and b3$ over Space. This means you can have Esc, or Esc and Enter, or Esc, Enter and Space keys. If no key strings are supplied, the word CONTINUE is used above an Esc key.

The return value, r%, is one of the following:

KAlertEsc% | 1 | The Esc key.
KAlertEnter% | 2 | The Enter key.
KAlertSpace% | 3 | The Space bar.

These constants are supplied in Const.oph.

ALLOC — Allocates a cell on the heap

Usage: pcell& = ALLOC(size&)

Allocates a cell on the heap of the specified size, returning the pointer to the cell or zero if there is not enough memory.

See also SETFLAGS if you require a 64K limit to be enforced on 32-bit target devices. If the flag is set to restrict the limit, pcelln& is guaranteed to fit into an integer.

See ADJUSTALLOC, REALLOC, and FREEALLOC. See also Dynamic memory allocation.

ARM

Cells are allocated lengths that are the smallest multiple of four greater than the size requested because the ARM processor requires a four-byte word alignment for its memory allocation. The ARM processor is used in the Psion Series 5 and other EPOC devices.

APP — Defines an application

Usage:

    APP caption,uid&
    ...
    ENDA

Begins definition of an OPL application. caption is the application’s name (or caption) in the machine’s default language. Note that although caption is a string, it is not enclosed in quotes.

uid& is the application’s UID. For distributed applications, official reserved UIDs must be used. These can be obtained by contacting Symbian Ltd (see OPL applications for details of how to do this).

All information included in the APP … ENDA structure will be used to generate a .AIF file which specifies the applications caption in various languages, its icons for use on the System screen and its setting of FLAGS.

See CAPTION, ICON, FLAGS.

See also OPL applications for more details of OPL applications.

APPEND — Adds a record to a data file

Usage: APPEND

Warning: This function is deprecated and included only for compatibility with older versions of the OPL language. INSERT, PUT, and CANCEL should be used in preference to APPEND and UPDATE, although APPEND and UPDATE are still supported. However, note that APPEND can generate a lot of extra (intermediate) erased records. COMPACT should be used to remove them, or alternatively use SETFLAGS to set auto-compaction on.

Adds a new record to the end of the current data file. The record which was current is unaffected. The new record, the last in the file, becomes the current record.

The record added is made from the current values of the field variables A.field1$, A.field2$, and so on, of the current data file. If a field has not been assigned a value, zero will be assigned to it if it is a numeric field, or a null string if it is a string field.

Example:

    PROC add:
          OPEN "address",A,f1$,f2$,f3$
          PRINT "ADD NEW RECORD"
          PRINT "Enter name:",
          INPUT A.f1$
          PRINT "Enter street:",
          INPUT A.f2$
          PRINT "Enter town:",
          INPUT A.f3$
          APPEND
          CLOSE
    ENDP

To overwrite the current record with new field values, use UPDATE.

See Database File Handling for more details. See also INSERT, MODIFY, PUT, CANCEL, SETFLAGS.

ASC — Gets a character code from a string

Usage: a%=ASC(a$)

Returns the character code of the first character of a$. Alternatively, use A%=%char to find the code for char - e.g. %X for ‘X’. If a$ is a null string ("") ASC returns the value 0.

Example: A%=ASC("hello") returns 104, the code for h.

See also: Character codes.

ASIN — Arcsine

Usage: a=ASIN(x)

Returns the arc sine, or inverse sine (SIN-1) of x.

x must be in the range -1 to +1. The number returned will be an angle in radians. To convert the angle to degrees, use the DEG function.

AT — Positions the text cursor

Usage: AT x%,y%

Positions the cursor at x% characters across the text window and y% rows down. AT 1,1 always moves to the top left corner of the window. Initially, the window is the full size of the screen, but you can change its size and position with the SCREEN command.

A common use of AT is to display strings at particular positions in the text window. For example:

    AT 5,2 :PRINT "message".
  • PRINT statements without an AT display at the left edge of the window on the line below the last PRINT statement (unless you use , or ;) and strings displayed at the top of the window eventually scroll off as more strings are displayed at the bottom of the window.
  • Displayed strings always overwrite anything that is on the screen - they do not cause things below them on the screen to scroll down.

Example:

    PROC records:
          LOCAL k%
          OPEN "clients",A,name$,tel$
          DO
                CLS
                AT 1,7
                PRINT "Press a key to"
                PRINT "step to next record"
                PRINT "or Q to quit"
                AT 2,3 :PRINT A.name$
                AT 2,4 :PRINT A.tel$
                NEXT
                IF EOF
                      AT 1,6 :PRINT "EndOfFile"
                      FIRST
                ENDIF
                k%=GET
          UNTIL k%=%Q OR k%=%q
          CLOSE
    ENDP

ATAN — Arctangent

Usage: a=ATAN(x)

Returns the arc tangent, or inverse tangent (TAN-1) of x.

The number returned will be an angle in radians. To convert the angle to degrees, use the DEG function.


BACK — BYREF

Contents

  • BACK — Moves back one record in the data file
  • BEEP — Sounds the buzzer
  • BEGINTRANS — Begins a transaction on a database
  • BOOKMARK — Places a bookmark on the current record
  • BREAK — Breaks out of a control loop
  • BUSY — Busy message
  • BYREF — Passes a variable by reference

BACK — Moves back one record in the data file

Usage: BACK

Makes the previous record in the current data file the current record.

If the current record is the first record in the file, then the current record does not change.

BEEP — Sounds the buzzer

Usage: BEEP time%,pitch%

Sounds the buzzer. The beep lasts for time%/32 seconds so for a beep a second long make time%=32, etc. The maximum is 3840 (2 minutes).

The pitch (frequency) of the beep is 512/(pitch%+1) KHz.

BEEP 5,300 gives a comfortably pitched beep.

If you make time% negative, BEEP first checks whether the sound system is in use (perhaps by another OPL program), and returns if it is. Otherwise, BEEP waits until the sound system is free.

Example a scale from middle C:

    PROC scale:
          LOCAL freq,n%                  REM n% relative to middle A
          n%=3                         REM start at middle C
          WHILE n%<16
                freq=440*2**(n%/12.0)       REM middle A = freq 440Hz
                BEEP 8,512000/freq-1.0
                n%=n%+1
                IF n%=4 OR n%=6 OR n%=9 OR n%=11 OR n%=13
                      n%=n%+1
                ENDIF
          ENDWH
    ENDP

Alternatively, sound the buzzer with this statement: PRINT CHR$(7). This produces a click sound.

If your batteries are low, BEEP may not produce the desired effect: on the Psion Series 5, the buzzer will be used instead to produce the ‘beep’. The buzzer produces a higher pitched sound.

BEGINTRANS — Begins a transaction on a database

Usage: BEGINTRANS

Begins a transaction on the current database. The purpose of this is to allow changes to a database to be committed in stages. Once a transaction has been started on a view (or table) then all database keywords will function as usual, but the changes to that view will not be made until COMMITTRANS is used.

See also COMMITTRANS, ROLLBACK, INTRANS.

BOOKMARK — Places a bookmark on the current record

Usage: b%=BOOKMARK

Puts a bookmark at the current record of the current database view. The value returned can be used in GOTOMARK to make the record current again. Use KILLMARK to delete the bookmark.

BREAK — Breaks out of a control loop

Usage: BREAK

Makes a program performing a DO...UNTIL or WHILE...ENDWH loop exit the loop and immediately execute the line following the UNTIL or ENDWH statement.

Example:

BUSY — Busy message

Usage: any of

    BUSY str$,c%,delay%
    BUSY str$,c%
    BUSY str$
    BUSY OFF

BUSY str$ displays str$ in the bottom left of the screen, until BUSY OFF is called. Use this to indicate ‘Busy’ messages, usually when an OPL program is going to be unresponsive to keypresses for a while.

If c% is given, it controls the corner in which the message appears:

KBusyTopLeft% | 0 | top left
KBusyBottomLeft% | 1 | bottom left (default)
KBusyTopRight% | 2 | top right
KBusyBottomLeft% | 3 | bottom right

These corner value constants are supplied in Const.oph.

delay% specifies a delay time (in half seconds) before the message should be shown. Use this to prevent ‘Busy’ messages from continually appearing very briefly on the screen.

Only one message can be shown at a time. The maximum string length of a BUSY message is 80 characters, given by Const.oph’s KBusyMaxtext%. An ‘Invalid argument’ error is returned for any value of str$ longer than this.

KBusyMaxtext%

80

Maximum length of a BUSY message.

BYREF — Passes a variable by reference

Usage: BYREF variable

Passes variable by reference to an OPX procedure when used in a procedure argument list. This means that the value of the variable may be changed by the procedure.

See the OPX header files for more details.


CANCEL — CURSOR

Contents

  • CANCEL — Cancels a database transaction
  • CAPTION — Sets an application’s caption
  • CHR$ — Converts a charcode to a string
  • CLEARFLAGS — Clears system flags
  • CLOSE — Closes the current database view
  • CLS — Clears the text window
  • CMD$ — Command line arguments
  • COMMITTRANS — Commits the current database transaction
  • COMPACT — Compacts a database file
  • CONTINUE — Jump to loop test condition
  • CONST — Declares a constant
  • COPY — Copies files
  • COS — Cosine
  • COUNT — Counts records in the current data file
  • CREATE — Creates a table in a database
  • CURSOR — Sets the text cursor

CANCEL — Cancels a database transaction

Usage: CANCEL

Marks the end of a database’s INSERT or MODIFY phase and discards the changes made during that phase.

CAPTION — Sets an application’s caption

Usage: CAPTION caption$,languageCode%

Specifies an application’s public name (or caption) for a particular language, which will appear below its icon on the Extras bar and in the list of ‘Programs’ in the ‘New File’ dialog (assuming the setting of FLAGS allows these) when the language is that used by the machine. CAPTION may only be used inside an APP...ENDA construct.

The language code specifies for which language variant the caption should be used, so that the caption need not be changed when used on a different language machine. If used, for whatever language, CAPTION causes the default caption given in the APP declaration to be discarded. Therefore CAPTION statements must be supplied for every language in which the application is liable to be used, including the language of the machine on which the application is originally developed.

The values of the language code should be one of the following:

KLangEnglish% | 1 | KLangPortuguese% | 13
KLangFrench% | 2 | KLangTurkish% | 14
KLangGerman% | 3 | KLangIcelandic% | 15
KLangSpanish% | 4 | KLangRussian% | 16
KLangItalian% | 5 | KLangHungarian% | 17
KLangSwedish% | 6 | KLangDutch% | 18
KLangDanish% | 7 | KLangBelgianFlemish% | 19
KLangNorwegian% | 8 | KLangAustralian% | 20
KLangFinnish% | 9 | KLangBelgianFrench% | 21
KLangAmerican% | 10 | KLangAustrian% | 22
KLangSwissFrench% | 11 | KLangNewZealand% | 23
KLangSwissGerman% | 12 | KLangInternationalFrench% | 24

These constants are supplied in Const.oph.

The maximum length of caption$ is 255 characters. However, you should bear in mind that a caption longer than around 8 characters will not fit neatly below the application’s icon on the Extras bar.

See APP. See also OPL applications.

CHR$ — Converts a charcode to a string

Usage: a$=CHR$(x%)

Returns the character with character code x%.

You can use it to display characters not easily available from the keyboard. For example, the instruction PRINT CHR$(133) displays an ellipsis (...).

The full character set for EPOC is in Character codes.

CLEARFLAGS — Clears system flags

Usage: CLEARFLAGS flags&

Clears the flags given in flags& if they have previously been set by SETFLAGS, returning to the default.

See SETFLAGS.

CLOSE — Closes the current database view

Usage: CLOSE

Closes the current view on a database. If there are no other views open on the database then the database itself will be closed. See SETFLAGS for details of how to set auto-compaction on closing files.

If you’ve used ERASE to remove some records, CLOSE recovers the memory used by the deleted records, provided it is held either in the internal memory, or on a memory disk.

CLS — Clears the text window

Usage: CLS

Clears the contents of the text window.

The cursor then goes to the beginning of the top line. If you have used CURSOR OFF the cursor is still positioned there, but is not displayed.

CMD$ — Command line arguments

Usage: c$=CMD$(a%)

Returns the command-line arguments passed when starting a program. Null strings may be returned. a% is one of the constant values KCmdAppName%, KCmdUsedFile%, or KCmdLetter% defined in Const.oph. CMD$(KCmdUsedFile%) and CMD$(KCmdLetter%) are only defined for OPL applications.

The value returned by CMD$ and its meaning depends on the value of a%:

KCmdAppName% | 1 | Returns the full path name used to start the running program.
KCmdUsedFile% | 2 | Returns the full path name of the file to be used by an OPL application. For example, if CMD$(3)=R (see below), a default filename, including path, is passed in CMD$(2).
KCmdLetter% | 3 | Returns one of the values below, and indicates the kind of command which was used to start the application.

If an application passes KCmdLetter% to CMD$, the return value is one of:

KCmdLetterCreate$ | "C" | Application was started as a result of a Create new file command in the shell.
KCmdLetterOpen$ | "O" | Application was started by opening a file belonging to it in the system screen.
KCmdLetterRun$ | "R" | Application was run directly from the Extras bar, by opening the application itself in the system screen, or from the Program editor.

The constants are defined in Const.oph.

See also GETCMD$ and OPL applications.

COMMITTRANS — Commits the current database transaction

Usage: COMMITTRANS

Commits the transaction on the current view.

See also BEGINTRANS, ROLLBACK, INTRANS.

COMPACT — Compacts a database file

Usage: COMPACT file$

Compacts the database file$, rewriting the file in place. All views on the database and the hence the file itself should be closed before calling this command. This should not be done too often since it uses considerable processor power.

Compaction can also be done automatically on closing a file by setting the appropriate flag using SETFLAGS.

CONTINUE — Jump to loop test condition

Usage: CONTINUE

Makes a program immediately go to the UNTIL... line of a DO...UNTIL loop or the WHILE... line of a WHILE...ENDWH loop i.e. to the test condition.

Example:

See also BREAK.

CONST — Declares a constant

Usage: CONST KConstantName=constantValue

Declares constants which are treated as literals, not stored as data. The declarations must be made outside any procedure, usually at the beginning of the module. KConstantName has the normal type-specification indicators (%, &, $ or nothing for floating-point numbers). CONST values have global scope, and are not overridden by locals or globals with the same name: in fact the translator will not allow the declaration of locals or globals of the same name. By convention, all constants should be named with a leading K to distinguish them from variables.

It should be noted that it is not possible to define constants with values smaller than -32768 (for integers) and -214748648 (for long integers) in decimals, but hexadecimal notation may be used instead (i.e. values of $8000 and &80000000 respectively).

COPY — Copies files

Usage: COPY src$,dest$

Copies the file src$, which may be of any type, to the file dest$. Any existing file with the name dest$ is deleted. You can copy across devices. You can also use wildcards if you wish to copy more than one file at a time.

If src$ contains wildcards, dest$ may specify either a filename similarly containing wildcards or just the device and directory to which the files are to be copied under their original names.

Example: To copy all the files from internal memory (in \opl) to d:\me\:

    COPY "c:\opl\*","d:\me\"

(Remember the final backslash on the directory name.)

There are more details of full file specifications in More on file specification.

COS — Cosine

Usage: c=COS(x)

Returns the cosine of x, where x is an angle in radians.

To convert from degrees to radians, use the RAD function.

COUNT — Counts records in the current data file

Usage: c%=COUNT

Returns the number of records in the current data file. This number will be 0 if the file is empty.

If you try to count the number of records in a view while updating the view an ‘Incompatible update mode’ error will be raised (This will occur between assignment and APPEND / UPDATE or between MODIFY / INSERT and PUT).

CREATE — Creates a table in a database

Usage: CREATE tableSpec$,log,f1,f2,...

Creates a table in a database. The database is also created if necessary. Immediately after calling CREATE, the file and view (or table) is open and ready for access.

tableSpec$ contains the database filename and optionally a table name and the field names to be created within that table. For example:

    CREATE "clients FIELDS name(40), tel TO phone", D, n$, t$

The filename is clients. The table to be created within the file is phone. The comma-separated list, between the keywords FIELDS and TO, specifies the field names whose types are specified by the field handles (i.e. n$, t$).

The name field has a length of 40 bytes, as specified within the brackets that follow it. The tel field has the default length of 255 bytes. This mechanism is necessary for creating some indexes. See dBase.opx — Database handling for more details on index creation.

The filename may be a full file specification of up to 255 characters. A field name may be up to a maximum of 64 characters long. Text fields have a default length of 255 bytes.

log specifies the logical file name A to Z. This is used as an abbreviation for the file name when you use other data file commands such as USE.

See also Database File Handling.

CURSOR — Sets the text cursor

Usage: any of

    CURSOR ON
    CURSOR OFF
    CURSOR id%
    CURSOR id%,asc%,w%,h%
    CURSOR id%,asc%,w%,h%,type%

CURSOR ON switches the text cursor on at the current cursor position. Initially, no cursor is displayed.

You can switch on a graphics cursor in a window by following CURSOR with the ID of the window. This replaces any text cursor. At the same time, you can also specify the cursor’s shape, and its position relative to the baseline of text.

asc% is the ascent — the number of pixels (-128 to 127) by which the top of the cursor should be above the baseline of the current font. h% and w% (both from 0 to 255) are the cursor’s height and width.

If you do not specify them, the following default values are used:

asc% | Current font’s ascent.
h% | Current font’s height.
w% | KCursorTypeNotFlashing%

If type% is given, it can have these effects:

KCursorTypeNotFlashing% | 2 | Not flashing.
KCursorTypeGrey% | 4 | Grey.

These constants are supplied in Const.oph.

You can add these values together to combine effects — if type% is 6 a grey non-flashing cursor is drawn. Using 1 for type% just displays a default graphics cursor, as though no type had been specified.

An error is raised if id% specifies a bitmap rather than a window.

CURSOR OFF switches off any cursor.


DATETOSECS — dXINPUT

Contents

  • DATETOSECS — Gets the number of seconds since 1/1/1970
  • DATIM$ — Current date and time
  • DAY — Current day of the month
  • DAYNAME$ — Converts a number to a day name
  • DAYS — Gets the number of days since 1/1/1900
  • DAYSTODATE — Converts the number of days since 1/1/1900 to a date
  • dBUTTONS — Defines exit keys
  • dCHECKBOX — Defines a checkbox
  • dCHOICE — Defines a choice list
  • dDATE — Defines a date edit box
  • DECLARE EXTERNAL — Forces error reporting if procedures are used before they are declared
  • DECLARE OPX — Declares an OPX name
  • dEDIT — Defines a string edit box
  • dEDITMULTI — Defines a multi-line edit box
  • DEFAULTWIN — Change the default window’s colour mode
  • DEG — Converts from radians to degrees
  • DELETE — Deletes files
  • DELETE — Deletes a table from a database
  • dFILE — Defines a filename edit box or selector
  • dFLOAT — Defines an edit box for a floating-point number
  • DIALOG — Presents a dialog
  • dINIT — Initialises a dialog
  • DIR$ — Lists files that match a specification
  • dLONG — Defines an edit box for a long integer
  • DO...UNTIL — Conditional loop
  • DOW — Gets the day of the week from a date
  • dPOSITION — Positions a dialog
  • dTEXT — Defines text to be displayed in a dialog
  • dTIME — Define an exit box for a time
  • dXINPUT — Define an exit box for a secret string

DATETOSECS — Gets the number of seconds since 1/1/1970

Usage: s&=DATETOSECS(yr%,mo%,dy%,hr%,mn%,sc%)

Returns the number of seconds since 00:00 on 1/1/1970 at the date/time specified.

Raises an error for dates before 1/1/1970.

The value returned is an unsigned long integer. (Values up to +2147483647, which is 03:14:07 on 19/1/2038, are returned as expected. Those from +2147483648 upwards are returned as negative numbers, starting from -2147483648 and increasing towards zero.)

See also SECSTODATE, HOUR, MINUTE, SECOND.

DATIM$ — Current date and time

Usage: d$=DATIM$

Returns the current date and time from the system clock as a string — for example: "Fri 16 Oct 1992 16:25:30". The string returned always has this format — 3 mixed-case characters for the day, then a space, then 2 digits for the day of the month, and so on.

The string returned by DATIM$ can be parsed with MID$ using the following values for offsets within the string:

KDatimOffDayName% | 1 | Offset of the day name (Fri).
KDatimOffDay% | 5 | Offset of the day of the month (16).
KDatimOffMonth% | 8 | Offset of the month name (Oct).
KDatimOffYear% | 12 | Offset of the year number (1992).
KDatimOffHour% | 17 | Offset of the hour (16).
KDatimOffMinute% | 20 | Offset of the minute (25).
KDatimOffSecond% | 23 | Offset of the second (30).

These constants are supplied in Const.oph.

Date.opx provides a large set of procedures for manipulating dates and for accurate timing. See Date.opx — Date and time manipulation for more details.

DAY — Current day of the month

Usage: d%=DAY

Returns the current day of the month (1 to 31) from the system clock.

DAYNAME$ — Converts a number to a day name

Usage: d$=DAYNAME$(x%)

Converts x%, a number from 1 to 7, to the day of the week, expressed as a three letter string. E.g. d$=DAYNAME$(1) returns MON.

Example:

    PROC Birthday:
          LOCAL d&,m&,y&,dWk%
          DO
                dINIT
                dTEXT "","Date of birth",2
                dTEXT "","eg 23 12 1963",$202
                dLONG d&,"Day",1,31
                dLONG m&,"Month",1,12
                dLONG y&,"Year",1900,2155
                IF DIALOG=0 :BREAK :ENDIF
                dWk%=DOW(d&,m&,y&)
                CLS :PRINT DAYNAME$(dWk%),
                PRINT d&,m&,y&
                dINIT dTEXT "","Again?",$202
                dBUTTONS "No",%N,"Yes",%Y
          UNTIL DIALOG<>%y
    ENDP

See also DOW.

DAYS — Gets the number of days since 1/1/1900

Usage: d&=DAYS(day%,month%,year%)

Returns the number of days since 1/1/1900.

Use this to find out the number of days between two dates.

Example:

    PROC deadline:
          LOCAL a%,b%,c%,deadlin&
          LOCAL today&,togo%
          PRINT "What day? (1-31)"
          INPUT a%
          PRINT "What month? (1-12)"
          INPUT b%
          PRINT "What year? (19??)"
          INPUT c%
          deadlin&=DAYS(a%,b%,1900+c%)
          today&=DAYS(DAY,MONTH,YEAR)
          togo%=deadlin&-today&
          PRINT togo%,"days to go"
          GET
    ENDP

See also dDATE, SECSTODATE.

Date.opx provides a large set of procedures for manipulating dates and for accurate timing. See Date.opx — Date and time manipulation for more details.

DAYSTODATE — Converts the number of days since 1/1/1900 to a date

Usage: DAYSTODATE days&,year%,month%,day%

This converts days&, the number of days since 1/1/1900, to the corresponding date, returning the day of the month to day%, the month to month% and the year to year%. This is useful for converting the value set by dDATE, which also gives days since 1/1/1900.

dBUTTONS — Defines exit keys

Usage: dBUTTONS p1$,k1%, p2$,k2%, p3$,k3%,...

Defines exit keys to go at the bottom or side of a dialog.

One or more exit keys can be defined with a p$,k% pair. Each pair specifies an exit key; p$ is the text to be displayed on it, while k% is the keycode of the shortcut key. DIALOG returns the keycode of the key pressed (in lower case for letters).

For alphabetic keys, use the % sign - %A means ‘the code of A’, and so on. The shortcut key is then Ctrl+alphabetic_key. Character codes lists the codes for keys (such as Tab) which are not part of the character set. If you use the code for one of these keys, its name (e.g. Tab, or Enter) will be shown in the key.

The following option flags can be applied to a button by adding the appropriate constant to the shortcut’s keycode:

KDButtonNoLabel% | $100 | Button is displayed with no shortcut key label.
KDButtonPlainKey% | $200 | The key by itself — without the Ctrl modification — is used for the shortcut key.

There are also constants for some key values:

KDButtonDel% | 8 | Del
KDButtonTab% | 9 | Tab
KDButtonEnter% | 13 | Enter
KDButtonEsc% | 27 | Esc
KDButtonSpace% | 32 | Space

These constants are supplied in Const.oph.

If a k% argument is negative, then the key is a ‘Cancel’ key. The corresponding positive value is used for the key to display and the value for DIALOG to return, but if you do press this key to exit, the var variables used in the commands like dEDIT, dTIME etc. will not be set. You must negate the shortcut together with any added flags.

The Esc key will always cancel a dialog box, with DIALOG returning 0. If you want to show the Esc key as one of the exit keys, use -KDButtonEsc% as the k% argument so that the var variables will not be set if Esc is pressed.

There can be only one dBUTTONS item per dialog.

The buttons take up two lines on the screen. dBUTTONS may be used anywhere between dINIT and DIALOG; the position of its use does not affect the position of the buttons in the dialog.

This example presents a simple query, returning ‘False’ for No, or ‘True’ for Yes, providing shortcut keys of N and Y respectively and without labels beneath the keys.

    PROC query:
          dINIT
          dTEXT "","FORGET CHANGES",2
          dTEXT "","Sure?",$202
          dBUTTONS "No",-(%N OR $300),"Yes",%Y OR $300
          RETURN DIALOG=%y
    ENDP

See also dINIT.

dCHECKBOX — Defines a checkbox

Usage: dCHECKBOX chk%,prompt$

Creates a dialog checkbox entry. This is similar to a choice list with two items, except that the list is replaced by a checkbox with the tick either on or off. The state of the checkbox is maintained across calls to the dialog.

Initially you should set the live variable chk% to 0 to set the tick symbol off and to any other value to set it on. chk% is then automatically set to 0 if the box is unchecked or -1 if it is checked when the dialog is closed.

See also dINIT.

dCHOICE — Defines a choice list

Usage:

    dCHOICE var choice%,p$,list$

or:

    dCHOICE var choice%,p$,list1$+",..."
    dCHOICE var choice%,"",list2$+",..."
    ...
    dCHOICE var choice%,"",listN$

Defines a choice list to go in a dialog.

p$ will be displayed on the left side of the line. list$ should contain the possible choices, separated by commas - for example, "No,Yes". One of these will be displayed on the right side of the line, and the left and right arrows can be used to move between the choices.

choice% must be a LOCAL or a GLOBAL variable. It specifies which choice should initially be shown — 1 for the first choice, 2 for the second, and so on. When you finish using the dialog, choice% is given a value indicating which choice was selected — again, 1 for the first choice, and so on.

dCHOICE supports an unrestricted number of items (up to memory limits). To extend a dCHOICE list, add a comma after the last item on the line followed by "..." (three full-stops), as shown in the usage above. choice% must be the same on all the lines, otherwise an error is raised. For example, the following specifies items i1, i2, i3, i4, i5, i6:

    dCHOICE ch%,prompt$,"i1,i2,..."
    dCHOICE ch%,"","i3,14,..."
    dCHOICE ch%,"","i5,i6"

See also dINIT.

dDATE — Defines a date edit box

Usage: dDATE var lg&,p$,min&,max&

Defines an edit box for a date, to go in a dialog.

p$ will be displayed on the left side of the line.

lg&, which must be a LOCAL or a GLOBAL variable, specifies the date to be shown initially. Although it will appear on the screen like a normal date, for example 15/03/92, lg& must be specified as "days since 1/1/1900".

min& and max& give the minimum and maximum values which are to be allowed. Again, these are in days since 1/1/1900. An error is raised if min& is higher than max&.

When you finish using the dialog, the date you entered is returned in lg&, in days since 1/1/1900.

The system setting determines whether years, months or days are displayed first.

See also DAYS, SECSTODATE, DAYSTODATE, dINIT.

DECLARE EXTERNAL — Forces error reporting if procedures are used before they are declared

Usage: DECLARE EXTERNAL

Causes the translator to report an error if any variables or procedures are used before they are declared. It should be used at the beginning of the module to which it applies, before the first procedure. It is useful for detecting ‘Undefined externals’ errors at translate-time rather than at runtime.

For example, with DECLARE EXTERNAL commented out, the following translates and raises the error Undefined externals, i at runtime. Adding the declaration causes the error to be detected at translate-time instead.

    REM DECLARE EXTERNAL
    PROC main:
          LOCAL i%
          i%=10
          PRINT i
          GET
    ENDP

If you use this declaration, you will need to declare all subsequent variables and procedures used in the module, using EXTERNAL.

See also EXTERNAL.

DECLARE OPX — Declares an OPX name

Usage:

    DECLARE OPX opxname,opxUid&,opxVersion&
    ...
    END DECLARE

Declares an OPX. opxname is the name of the OPX, opxUid& its UID and opxVersion& its version number.

Declarations of the OPX’s procedures should be made inside this structure.

See About OPXs for more details.

dEDIT — Defines a string edit box

Usage:

    dEDIT var str$,p$,len%

or:

    dEDIT var str$,p$

Defines a string edit box, to go in a dialog.

p$ will be displayed on the left side of the line.

str$ is the string variable to edit. Its initial contents will appear in the dialog. The length used when str$ was defined is the maximum length you can type in.

len%, if supplied, gives the width of the edit box (allowing for widest possible character in the font). The string will scroll inside the edit box, if necessary. If len% is not supplied, the edit box is made wide enough for the maximum width str$ could possibly be.

See also dTEXT.

dEDITMULTI — Defines a multi-line edit box

Usage: dEDITMULTI var pData&,p$,widthInChars%,numLines%,maxLen%

Defines a multi-line edit box to go into a dialog. Normally the resulting text would be used in a subsequent dialog, saved to file or printed using the Printer OPX (see Printer.opx — Printer and text handling). It is also possible to paste text into the buffer from other applications and vice versa, although any formatting or embedded objects contained in text pasted in will be removed.

pData& is the address of a buffer to take the edited data. It could be the address of an array as returned by ADDR, or of a heap cell, as returned by ALLOC (see ADDR and ALLOC). The buffer may not be specified directly as a string and may not be read as such. Instead it should be peeked, byte by byte (see PEEK). The leading 4 bytes at ptrData& contain the initial number of bytes of data following. These bytes are also set by dEDITMULTI to the actual number of bytes edited. For this reason it is convenient to use a long integer array as the buffer, with at least 1+(maxLen%+3)/4 elements. The first element of the array then specifies the initial length.

If an allocated cell is used (probably because more than 64K is required), the first 4 bytes of the cell must be set to the initial length of the data. If this length is not set then an error will be raised. For example if a cell of 100000 bytes is allocated, you would need to poke a zero long integer in the start to specify that there is initially no text in the cell. For example:

    p&=ALLOC(100000)
    POKEL p&,0            REM Text starts at p&+4

Special characters such as line breaks and tab characters may appear in the buffer:

KParagraphDelimiter% | $06 | Paragraph delimiter.
KLineBreak% | $07 | Line break.
KPageBreak% | $08 | Page break.
KTabCharacter% | $09 | Horizontal tab.
KNonBreakingTab% | $0a | Non-breaking horizontal tab.
KNonBreakingHyphen% | $0b | Non-breaking hyphen.
KPotentialHyphen% | $0c | Words will break here with a hyphen at the end of the line, if necessary.
KNonBreakingSpace% | $10 | Non-breaking space.
KPictureCharacter% | $0e | A picture.
KVisibleSpaceCharacter% | $0f | Visible space.

These constants are supplied in Const.oph.

The prompt, p$ will be displayed on the left side of the edit box. widthInChars% specifies the width of the edit box within which the text is wrapped, using a notional average character width. The actual number of characters that will fit depends on the character widths, with e.g. more ‘i’s fitting than ‘w’s. numLines% specifies the number of full lines displayed. Any more lines will be scrolled. maxLen% specifies the length in bytes of the buffer provided (excluding the bytes used to store the length).

The Enter key is used by a multi-line edit box which has the focus before being offered to any buttons. This means that Enter can’t be used to exit the dialog, unless another item is provided that can take the focus without using the Enter key. Normal practice is to provide a button that does not use the Enter key to exit a dialog whenever it contains a multi-line edit box. The Esc key will always cancel a dialog however, even when it contains a multi-line edit box.

The following example presents a three-line edit box which is about 10 characters wide and allows up to 399 characters:

    CONST KLenBuffer%=399
    PROC dEditM:
          LOCAL buffer&(101)
          REM 101=1+(399+3)/4 in integer arithmetic
          LOCAL pLen&,pText&
          LOCAL i%
          LOCAL c%
          pLen&=ADDR(buffer&(1))
          pText&=ADDR(buffer&(2))
          WHILE 1
                dINIT "Try dEditMulti"
                dEDITMULTI pLen&,"Prompt",10,3,KLenBuffer%
                dBUTTONS "Done",%d      REM button needed to exit dialog
                IF DIALOG=0 :BREAK :ENDIF
                PRINT "Length:";buffer&(1)
                PRINT "Text:"
                i%=0
                WHILE i%<buffer&(1)
                      c%=PEEKB(pText&+i%)
                      IF c%>=32
                            PRINT CHR$(c%);
                      ELSE
                            REM just print a dot for special characters
                            PRINT ".";
                      ENDIF
                      i%=i%+1
                ENDWH
          ENDWH
    ENDP

See also dINIT.

DEFAULTWIN — Change the default window’s colour mode

Usage: DEFAULTWIN mode%

Changes the default window’s colour mode. The default window has ID=1, and uses a mode specific to the hardware capabilities of the EPOC device it is running on. For example, a 4-grey window (2-bit, KColorDefWinWin4GrayMode%) is created on grey-scale machines, and a 256-color (8-bit, KColorDefWin256ColorMode%) window is created on colour screen machines.

The default can be overriden using DEFAULTWIN. mode% specifies the new colour mode.

KColorDefWin2GrayMode% | 0 | Two-grey mode.
KColorDefWin4GrayMode% | 1 | Four-grey mode.
KColorDefWin16GrayMode% | 2 | 16 grey mode.
KColorDefWin256GrayMode% | 3 | 256 grey mode.
KColorDefWin16ColorMode% | 4 | 16 colour mode.
KColorDefWin256ColorMode% | 5 | 256 colour mode.

N.B. the existing constants, KDefWin4ColourMode% and KDefWin16ColourMode% are retained for backwards compatibility (see below).

These constants are supplied in Const.oph.

Using high-colour mode uses more power than using modes with fewer colours. See the Graphics for more information.

You are advised to call DEFAULTWIN once near the start of your program an nowhere else if you need to change the colour mode of the default window. If it fails with an ‘Out of memory’ error, the program can then exit cleanly without losing vital information.

Compatibility

EPOC Release 3 supports only KColorDefWin4ColourMode% (=1) and KDefWin16ColourMode% (=2), actually displaying both in shades of grey. These correspond to the values of the new KColorDefWin4GrayMode% and KColorDefWin16GrayMode%, so code translated under ER5 which uses the new constants for 16-grey and 4-grey modes will run on older releases (although the source will not compile on them). This is because it is the value of a constant which is translated into an opo or an app, not the constant’s name.

Code translated under ER5 which uses anything other than 2-, 4- or 16-grey modes will fail when you try to run it on ER3.

See also gGREY, gCOLOR, gCREATE.

DEG — Converts from radians to degrees

Usage: d=DEG(x)

Converts from radians to degrees.

Returns x, an angle in radians, as a number of degrees. The formula used is: 180*x/PI

All the trigonometric functions (SIN,COS etc.) work in radians, not degrees. You can use DEG to convert an angle returned by a trigonometric function back to degrees:

Example:

    PROC xarctan:
          LOCAL arg,angle
          PRINT "Enter argument:";
          INPUT arg
          PRINT "ARCTAN of",arg,"is"
          angle=ATAN(arg)
          PRINT angle,"radians"
          PRINT DEG(angle),"degrees"
          GET
    ENDP

To convert from degrees to radians, use RAD.

DELETE — Deletes files

Usage: DELETE filename$

Deletes any type of file.

You can use wildcards for example, to delete all the files in D:\OPL

    DELETE "D:\OPL\*"

See also RMDIR.

DELETE — Deletes a table from a database

Usage: DELETE dbase$,table$

This deletes the table table$ from the database dbase$. To do this all views of the database, and hence the database itself, must be closed.

dFILE — Defines a filename edit box or selector

Section Contents

  • Flags
  • Restriction by UID

Usage:

    dFILE var file$,p$,f%

or:

    dFILE var file$,p$,f%, uid1&,uid2&,uid3&

Defines a filename edit box or selector, to go in a dialog. A ‘Folder’ and ‘Disk’ selector are automatically added on the following lines.

By default no prompts are displayed for the file, folder and disk selectors. A comma-separated prompt list should be supplied. For example, for a filename editor with the standard prompts use:

    dFILE f$,"File,Folder,Disk",1

Flags

f% controls the type of file editor or selector, and the kind of input allowed. You can add together any of the following values (from Const.oph):

 | 0 | use a selector
KDFileEditBox% | 1 | use an edit box
KDFileAllowFolders% | 2 | allow directory names
KDFileFoldersOnly% | 4 | directory names only
KDFileEditorDisallowExisting% | 8 | disallow existing files
KDFileQueryExisting% | 16 | query existing files
KDFileAllowNullStrings% | 32 | allows null string input
KDFileAllowWildCards% | 128 | obey/allow wildcards
KDFileSelectorWithRom% | 256 | allow ROM files to be selected
KDFileSelectorWithSystem% | 512 | allow files in the System folder to be selected

The first of the list is the most crucial. If you add 1 into f%, you will see a file edit box, as when creating a new file. If you do not add 1, you will see the ‘matching file’ selector, used when choosing an existing file.

If performing a ‘copy to’ operation, you might use 1+2+16, to specify a file edit box, in which you can type the name of a directory to copy to, and which will produce a query if you type the name of an existing file.

If asking for the name of a directory to remove, you might use 4, to allow an existing directory name only.

‘Query existing’ is ignored if ‘disallow existing’ is set. These two, as well as ‘allow null string input’, only work with file edit boxes, not ‘matching file’ selectors.

Restriction by UID

For file selectors, dFILE supports file restriction by UID, or by type from the user’s point of view. Documents are identified by three UIDs which identify which application created the document and what kind of file it is. Specifying all three UIDs will restrict the files as much as is possible, and specifying fewer will provide less restriction. You can supply 0 for uid1& and uid2& if you only want to restrict the list to uid3&. This may be useful when dealing with documents from one of your own applications: you can easily find out the third UID as it will be the UID you specified in the APP statement. Note that UIDs are ignored for editors. For example, if your application has UID KUidMyApp&, then the following will list only your application-specific documents:

    dFILE f$,p$,f%,0,KUidOplDoc&,KUidMyApp&
    REM KUidOplDoc& for OPL docs

Some OPL-related UID values are given in Const.oph.

KUidOplInterpreter& | 268435575 | The OPL interpreter.
KUidOplApp& | 268435572 | An OPL app.
KUidOplDoc& | 268435573 | An OPL document.
KUidOPO& | 268435571 | An OPO.
KUidOplFile& | 268435594 | An OPL file.
KUidOpxDll& | 268435549 | An OPX.

You can always press Tab to produce the full file selector with a dFILE item.

file$ must be declared to be KDFileNameLen% bytes long, since file names may be up to this length. If it is shorter an error will be raised.

KDFileNameLen%

255

Maximum file name length for dFILE.

See also dINIT.

dFLOAT — Defines an edit box for a floating-point number

Usage: dFLOAT var fp,p$,min,max

Defines an edit box for a floating-point number, to go in a dialog.

p$ will be displayed on the left side of the line.

min and max give the minimum and maximum values which are to be allowed. An error is raised if min is higher than max.

fp must be a LOCAL or a GLOBAL variable. It specifies the value to be shown initially. When you finish using the dialog, the value you entered is returned in fp.

See also dINIT.

DIALOG — Presents a dialog

Usage: n%=DIALOG

Presents the dialog prepared by dINIT and commands such as dTEXT and dCHOICE. If you complete the dialog by pressing Enter, your settings are stored in the variables specified in dLONG, dCHOICE etc., although you can prevent this with dBUTTONS.

If you used dBUTTONS when preparing the dialog, the keycode which ended the dialog is returned. Otherwise, DIALOG returns the line number of the item which was current when Enter was pressed. The top item (or the title line, if present), has line number 1.

If you cancel the dialog by pressing Esc, the variables are not changed, and KDlgCancel% is returned:

KDlgCancel%

0

Return value: dialog was cancelled.

See also dINIT.

dINIT — Initialises a dialog

Usage: any of

    dINIT
    dINIT title$
    dINIT title$,flags%

Prepares for definition of a dialog, cancelling any existing one. Use dTEXT, dCHOICE etc. to define each item in the dialog, then DIALOG to display the dialog.

If title$ is supplied, it will be displayed at the top of the dialog. Any supplied title$ will be positioned in a grey box at the top of the dialog. flags% can be any added combination of the following constants:

KDlgButRight% | Buttons on the right rather than at the bottom
KDlgNoTitle% | No title bar
KDlgFillScreen% | Use the full screen
KDlgNoDrag% | Don’t allow the dialog box to be dragged
KDlgDensePack% | Pack the dialog contents (not buttons) densely.

These constants are supplied in Const.oph.

It should be noted that dialogs without titles cannot be dragged regardless of the ‘No drag’ setting. Dense packing enables more lines to fit on the screen for larger dialogs.

If an error occurs when adding an item to a dialog, the dialog is deleted and dINIT needs calling again. This is necessary to avoid having partially specified dialog lines. The following code will raise a ‘Structure fault’ error:

    REM  ** Faulty OPL fragment **
          dINIT
          ONERR e1
          REM bad arg list gives argument error:
          dCHOICE ch%, "ChList", "a,b,,,,c"
    e1::
          ONERR OFF
          dLONG l&,"Long",0,12345
          DIALOG

DIR$ — Lists files that match a specification

Usage: d$=DIR$(filespec$)
then d$=DIR$("")

Lists filenames, including subdirectory names, matching a file specification. You can include wildcards in the file specification. If filespec$ is just a directory name, include the final backslash on the end for example, "\TEMP\" . Use the function like this:

  • DIR$(filespec$) returns the name of the first file matching the file specification.
  • DIR$("") then returns the name of the second file in the directory.
  • DIR$("") again returns the third, and so on.
  • When there are no more matching files in the directory, DIR$("") returns a null string.

Example, listing all the files whose names begin with A in C:\ME\

    PROC dir:
          LOCAL d$(255)
          d$=DIR$("C:\ME\A*")
          WHILE d$<>""
                PRINT d$
                d$=DIR$("")
          ENDWH
          GET
    ENDP

dLONG — Defines an edit box for a long integer

Usage: dLONG var lg&,p$,min&,max&

Defines an edit box for a long integer, to go in a dialog.

p$ will be displayed on the left side of the line.

min& and max& give the minimum and maximum values which are to be allowed. An error is raised if min& is higher than max&.

lg& must be a LOCAL or a GLOBAL variable. It specifies the value to be shown initially. When you finish using the dialog, the value you entered is returned in lg&.

See also dINIT.

DO...UNTIL — Conditional loop

Usage:

    DO
          statements...
          ...
    UNTIL condition

DO forces the set of statements which follow it to execute repeatedly until the condition specified by UNTIL is met.

This is the easiest way to repeat an operation a certain number of times.

  • Every DO must have its matching UNTIL to end the loop.
  • If you set a condition which is never met, the program will go round and round, locked in the loop forever.

You can escape by pressing Ctrl+Esc, provided you haven’t set ESCAPE OFF. If you have set ESCAPE OFF, you will have to return to go to the Task list, select your program in the list and tap ‘Close file’.

See also Control structures and WHILE...ENDWH.

DOW — Gets the day of the week from a date

Usage: d%=DOW(day%,month%,year%)

Returns the day of the week from 1 (Monday) to 7 (Sunday) given the date.

day% must be between 1 and 31, month% from 1 to 12 and year% from 1900 to 2155.

For example, D%=DOW(4,7,1992) returns KSaturday. Values for DOW are supplied in Const.oph:

KMonday% | 1
KTuesday% | 2
KWednesday% | 3
KThursday% | 4
KFriday% | 5
KSaturday% | 6
KSunday% | 7

These constants are supplied in Const.oph.

dPOSITION — Positions a dialog

Usage: dPOSITION x%,y%

Positions a dialog. Use dPOSITION at any time between dINIT and DIALOG.

dPOSITION uses two integer values. The first specifies the horizontal position, and the second, the vertical. dPOSITION -1,-1 positions to the top left of the screen; dPOSITION 1,1 to the bottom right; dPOSITION 0,0 to the centre, the usual position for dialogs.

dPOSITION 1,0, for example, positions to the right-hand edge of the screen, and centres the dialog half way up the screen.

Constants for these values are supplied in Const.oph.

See also dINIT.

dTEXT — Defines text to be displayed in a dialog

Usage: dTEXT p$,body$,t%
or dTEXT p$,body$

Defines a line of text to be displayed in a dialog.

p$ will be displayed on the left side of the line, and body$ on the right side. If you only want to display a single string, use a null string ("") for p$, and pass the desired string in body$. It will then have the whole width of the dialog to itself. An error is raised if body$ is a null string and the text line is not a separator (see below).

body$ is normally displayed left aligned (although usually in the right column). You can override this by specifying t%:

KDTextLeft% | 0 | Left-align body$.
KDTextRight% | 1 | Right-align body$.
KDTextCentre% | 2 | Centre body$.

Alignment of body$ is only supported when p$ is null, with the body being left aligned otherwise. In addition, you can add any or all of the following three values to t%, for these effects:

KDTextLineBelow% | $200 | Draw a line below this item.
KDTextAllowSelection% | $400 | Allow this item’s prompt (not its body text) to be selected.
KDTextSeparator% | $800 | Specify this item as a text separator. p$ and body$ must both be the null string for this to take effect. The separator counts as an item in the value returned by DIALOG.

These constants are supplied in Const.oph.

See also dEDIT, dINIT.

dTIME — Define an exit box for a time

Usage: dTIME var lg&,p$,t%,min&,max&

Defines an edit box for a time, to go in a dialog.

p$ will be displayed on the left side of the line.

lg&, which must be a LOCAL or a GLOBAL variable, specifies the time to be shown initially. Although it will appear on the screen like a normal time, for example 18:27, lg& must be specified as seconds after 00:00. A value of 60 means one minute past midnight; 3600 means one o’clock, and so on.

min& and max& give the minimum and maximum values which are to be allowed. Again, these are in seconds after 00:00. An error is raised if min& is higher than max&.

When you finish using the dialog, the time you entered is returned in lg&, in seconds after 00:00.

The display in the time editor can be controlled via the t% argument. Add together one or more of the following constants from Const.oph to form t%:

KDTimeWithSeconds% | 1 | Time editor shows seconds.
KDTimeDuration% | 2 | Editing a duration.
KDTimeNoHours% | 4 | Time editor does not show hours.
KDTime24Hour% | 8 | Time editor uses the 24 hour clock.

This can be bulky to specify however, so the following convenience constants are also defined.

KDTimeAbsNoSecs% | 0 | Absolute + no seconds.
KDTimeAbsWithSecs% | 1 | Absolute + seconds.
KDTimeDurationNoSecs% | 2 | Duration + no seconds.
KDTimeDurationWithSecs% | 3 | Duration + seconds.

For example, 03:45 represents an absolute time while 3 hours 45 minutes represents a duration.

Absolute times are displayed in 24-hour or a.m./p.m. format according to the current system setting. 8 displays the time in 24 hour clock, regardless of the system setting.

Absolute times always display a.m. or p.m. as appropriate, unless the 24 hour clock is being used. Durations never display a.m. or p.m. Note, however, that if you use the flag 4 (no hours) then the a.m./p.m. symbol will be displayed and the flag 2 must be added if you wish to hide it.

See also dINIT.

dXINPUT — Define an exit box for a secret string

Usage: dXINPUT var str$,p$

Defines a secret string edit box, such as for a password, to go in a dialog.

p$ will be displayed on the left side of the line.

str$ is the string variable to take the string you type.

KDXInputMaxLen%

16

Maximum length of str$.

This constant is supplied in Const.oph.

Initially the dialog does not show any characters for the string; the initial contents of str$ are ignored. A special symbol will be displayed for each character you type, to preserve the secrecy of the string.

See also dINIT.


EDIT — EXTERNAL

Contents

  • EDIT — Displays a string for editing
  • ELSE/ELSEIF/ENDIF — See IF
  • ENDA — See APP
  • ENDV — See VECTOR
  • ENDWH — See WHILE
  • EOF — Checks for end-of-file
  • ERASE — Erases a record in the current data file
  • ERR — Number of last error
  • ERR$ — Looks up an error message by number
  • ERRX$ — Gets an extended error message
  • ESCAPE OFF — Disables Ctrl+Esc
  • EVAL — Evaluates a mathematical expression
  • EXIST — Checks if a file exists
  • EXP — Exponential
  • EXTERNAL — Declares procedure prototypes and external variables

EDIT — Displays a string for editing

Usage: EDIT a$

Displays a string variable which you can edit directly on the screen. All the usual editing keys are available the arrow keys move along the line, Esc clears the line, and so on.

When you have finished editing, press Enter to confirm the changes. If you press Enter before you have made any changes, then the string will be unaltered.

If you use EDIT in conjunction with a PRINT statement, use a comma at the end of the PRINT statement, so that the string to be edited appears on the same line as the displayed string:

    ...
    PRINT "Edit address: ",
    EDIT A.address$
    UPDATE
    ....

TRAP EDIT

If the Esc key is pressed while no text is on the input line, the ‘Escape key pressed’ error (-144) will be returned by ERR provided that the EDIT has been trapped. You can use this feature to enable the user to press the Esc key to escape from inputting a string.

See also INPUT, dEDIT.

ELSE/ELSEIF/ENDIF — See IF

See IF.

ENDA — See APP

See APP.

ENDV — See VECTOR

See VECTOR

ENDWH — See WHILE

See WHILE.

EOF — Checks for end-of-file

Usage: e%=EOF

Finds out whether you’re at the end of a file yet.

Returns -1 (true) if the end of the file has been reached, or 0 (false) if it hasn’t.

When reading records from a file, you should test whether there are still records left to read, otherwise you may get an error.

Example:

    PROC eoftest:
          OPEN "myfile",A,a$,b%
          DO
                PRINT A.a$
                PRINT A.b%
                NEXT
                PAUSE -40
          UNTIL EOF
          PRINT "The last record"
          GET
          RETURN
    ENDP

ERASE — Erases a record in the current data file

Usage: ERASE

Erases the current record in the current file.

The next record is then current. If the erased record was the last record in a file, then following this command the current record will be null and EOF will return true.

ERR — Number of last error

Usage: e%=ERR

Returns the number of the last error which occurred, or 0 if there has been no error.

Example:

          ...
          PRINT "Enter age in years"
    age::
          TRAP INPUT age%
          IF ERR=-1
                PRINT "Number please:"
                GOTO age
          ENDIF
          ...

You can set the value returned by ERR to 0 (or any other value) by using TRAP RAISE 0. This is useful for clearing ERR.

See also ERR$,ERRX$. See Runtime errors — Handling errors reported while running programs for full details, and OPL error values for the list of error numbers and messages.

ERR$ — Looks up an error message by number

Usage: e$=ERR$(x%)

Returns the error message for the specified error code x%.

ERR$(ERR) gives the message for the last error which occurred. Example:

    TRAP OPEN "\FILE",A,field1$
    IF ERR
          PRINT ERR$(ERR)
          RETURN
    ENDIF

See also ERR, ERRX$. See Runtime errors — Handling errors reported while running programs for full details, and OPL error values for the list of error numbers and messages.

ERRX$ — Gets an extended error message

Usage: x$=ERRX$

Returns the current extended error message (when an error has been trapped), e.g.

    ‘Error in MODULE\PROCEDURE,EXTERN1,EXTERN2,...’

which would have been presented as an alert if the error had not been trapped. This allows the list of missing externals, missing procedure names, etc. to be found when an error has been trapped by a handler.

See Runtime errors — Handling errors reported while running programs for full details, and OPL error values for the list of error numbers and messages.

ESCAPE OFF — Disables Ctrl+Esc

Usage:

    ESCAPE OFF
    ...
    ESCAPE ON

ESCAPE OFF stops Ctrl+Esc being used to break out of the program when it is running. ESCAPE ON enables this feature again.

ESCAPE OFF takes effect only in the procedure in which it occurs, and in any sub-procedures that are called. Ctrl+Esc is always enabled when a program begins running.

If your program enters a loop which has no logical exit, and ESCAPE OFF has been used, you will have to go to the Task list, move to the program name, and select Close file.

EVAL — Evaluates a mathematical expression

Usage: d=EVAL(s$)

Evaluates the mathematical string expression s$ and returns the floating-point result. s$ may include any mathematical function or operator. Note that floating-point arithmetic is always performed.

EVAL runs in the "context" of the current procedure, so globals and externals can be used in s$, procedures in loaded modules can be called and the current values of gX and gY, can be used etc. LOCAL variables cannot be used in s$ (because the translator cannot deference them).

For example:

    DO
          AT 10,5 :PRINT "Calc:",
          TRAP INPUT n$
          IF n$="" :CONTINUE :ENDIF
          IF ERR=-114 :BREAK :ENDIF
          CLS :AT 10,4
          PRINT n$;"=";EVAL(n$)
    UNTIL 0

See also VAL.

EXIST — Checks if a file exists

Usage: e%=EXIST(filename$)

Checks to see that a file exists. Returns KTrue% if the file exists and KFalse% if it doesn’t.

Use this function when creating a file to check that a file of the same name does not already exist, or when opening a file to check that it has already been created:

    IF NOT EXIST("CLIENTS")
          CREATE "CLIENTS",A,names$
    ELSE
          OPEN "CLIENTS",A,names$
    ENDIF
    ...

EXP — Exponential

Usage: e=EXP(x)

Returns ex — that is, the value of the arithmetic constant e (2.71828...) raised to the power of x.

EXTERNAL — Declares procedure prototypes and external variables

Usage: EXTERNAL variable
or EXTERNAL prototype

Required if DECLARE EXTERNAL is specified in the module.

The first usage declares a variable as external. For example, EXTERNAL screenHeight%

The second usage declares the prototype of a procedure (prototype includes the final : and the argument list). The procedure may then be referred to before it is defined. This allows parameter type-checking to be performed at translate-time rather than at runtime and also provides the necessary information for the translator to coerce numeric argument types. This is reasonable because OPL does not support argument overloading. The same coercion occurs as when calling the built-in keywords.

Following the example of C and C++, you would normally provide a header file declaring prototypes of all the procedures and INCLUDE this header file at the beginning of the module which defines the declared procedures to ensure consistency. The header file would also be INCLUDEd in any other modules which call these procedures. Then you should use DECLARE EXTERNAL at the beginning of modules which include the header file so that the translator can ensure that these procedures are called with correct parameter types or types which can be coerced.

The following is an example of usage of DECLARE EXTERNAL and EXTERNAL:

    DECLARE EXTERNAL
    EXTERNAL myProc%:(i%,l&)
    REM or INCLUDE "myproc.oph" that defines all your procedures

    PROC test:
          LOCAL i%,j%,s$(10)

          REM j% is coerced to a long integer
          REM as specified by the prototype.
          myProc%:(i%,j%)

          REM translator ‘Type mismatch’ error:
          REM string can’t be coerced to numeric type
          myProc%:(i%,s$)

          REM wrong argument count gives translator error
          myProc%:(i%)
    ENDP

    PROC myProc%:(i%,l&)
          REM Translator checks consistency with prototype above
          ...
    ENDP

See DECLARE EXTERNAL.


FIND — FREEALLOC

Contents

  • FIND — Searches data file fields for matching string
  • FINDFIELD — Searches data file fields for matching string
  • FIRST — Positions to the first record
  • FIX$ — Converts a number to a string
  • FLAGS — Sets an application’s system flags
  • FLT — Converts an integer to a floating point number
  • FONT — Sets the text window’s font and style
  • FREEALLOC — Frees a previously allocated cell

FIND — Searches data file fields for matching string

Usage: f%=FIND(a$)

Warning: this language keyword is deprecated; its functionality has been replaced by DbFind&: in SysRam1.opx.

FINDFIELD — Searches data file fields for matching string

Usage: f%=FINDFIELD(a$,start%,no%,flags%)

Warning: this language keyword is deprecated; its functionality has been replaced by DbFindField&: in SysRam1.opx.

FIRST — Positions to the first record

Usage: FIRST

Positions to the first record in the current view.

See Database manipulation.

FIX$ — Converts a number to a string

Usage: f$=FIX$(x,y%,z%)

Returns a string representation of the number x, to y% decimal places. The string will be up to z% characters long.

Example: FIX$(123.456,2,7) returns "123.46".

  • If z% is negative then the string is right-justified for example FIX$(1,2,-6) returns " 1.00" where there are two spaces to the left of the 1.
  • If z% is positive then no spaces are added for example FIX$(1,2,6) returns "1.00".
  • If the number x will not fit in the width specified by z%, then the string will just be asterisks, for example FIX$(256.99,2,4) returns "****".

See also GEN$, NUM$, SCI$.

FLAGS — Sets an application’s system flags

Usage: FLAGS flags%

Used within an APP…ENDA construct to provide the OPL application’s system flags. Possible values for flags% are:

KFlagsAppFileBased% | 1 | This application can create files. It will be included in the list of applications offered when the user creates a new file from the System screen.
KFlagsAppIsHidden% | 2 | This application does not appear on the Extras bar. It is very unusual to have this flag set.

These constants can be added together to combine their effects. They are supplied in Const.oph.

FLAGS may only be used within the APP…ENDA construct.

See also APP and OPL applications.

FLT — Converts an integer to a floating point number

Usage: f=FLT(x&)

Converts an integer expression (either integer or long integer) into a floating-point number. Example:

    PROC gamma:(v)
          LOCAL c
          c=3E8
          RETURN 1/SQR(1-(v*v)/(c*c))
    ENDP

You could call this procedure like this: gamma:(FLT(a%)) if you wanted to pass it the value of an integer variable without having first to assign the integer value to a floating-point variable.

See also INT and INTF.

FONT — Sets the text window’s font and style

Usage: FONT id&,style%

Sets the text window font and style. The standard font IDs are:

KFontArialBold8& | 268435951 | KFontTimesBold8& | 268435962
KFontArialBold11& | 268435952 | KFontTimesBold11& | 268435963
KFontArialBold13& | 268435953 | KFontTimesBold13& | 268435964
KFontArialNormal8& | 268435954 | KFontTimesNormal8& | 268435965
KFontArialNormal11& | 268435955 | KFontTimesNormal11& | 268435966
KFontArialNormal13& | 268435956 | KFontTimesNormal13& | 268435967
KFontArialNormal15& | 268435957 | KFontTimesNormal15& | 268435968
KFontArialNormal18& | 268435958 | KFontTimesNormal18& | 268435969
KFontArialNormal22& | 268435959 | KFontTimesNormal22& | 268435970
KFontArialNormal27& | 268435960 | KFontTimesNormal27& | 268435971
KFontArialNormal32& | 268435961 | KFontTimesNormal32& | 268435972
KFontCalc13n& | 268435493 | KFontCourierBold8& | 268436062
KFontCalc18n& | 268435494 | KFontCourierBold11& | 268436063
KFontCalc24n& | 268435495 | KFontCourierBold13& | 268436064
KFontMon18n& | 268435497 | KFontCourierNormal8& | 268436065
KFontMon18b& | 268435498 | KFontCourierNormal11& | 268436066
KFontMon9n& | 268435499 | KFontCourierNormal13& | 268436067
KFontMon9b& | 268435500 | KFontCourierNormal15& | 268436068
KFontTiny1& | 268435501 | KFontCourierNormal18& | 268436069
KFontTiny2& | 268435502 | KFontCourierNormal22& | 268436070
KFontTiny3& | 268435503 | KFontCourierNormal27& | 268436071
KFontTiny4& | 268435504 | KFontCourierNormal32& | 268436072
KFontEiksym15& | 268435661 |  |
KFontSquashed& | 268435701 |  |
KFontDigital35& | 268435752 |  |

Standard font styles are:

KgStyleNormal% | 0 | Normal style.
KgStyleBold% | 1 | Bold.
KgStyleUnder% | 2 | Underline.
KgStyleInverse% | 4 | Inverse video.
KgStyleDoubleHeight% | 8 | Double height.
KgStyleMonoFont% | 16 | Mono-spaced (typewriter) font.
KgStyleItalic% | 32 | Italic.

All these constants are provided in Const.oph.

See The text and graphics windows for more details.

FREEALLOC — Frees a previously allocated cell

Usage: FREEALLOC pcell&

Frees a previously allocated cell at pcell&.

See also SETFLAGS if you require the 64K limit to be enforced. If the flag is set to restrict the limit, pcell& is guaranteed to fit into a short integer.


gAT — gY

Contents

  • gAT — Sets the drawing position using absolute co-ordinates
  • gBORDER — Draws a border
  • gBOX — Draws a box
  • gBUTTON — Draws a 3D button
  • gCIRCLE — Draws a circle
  • gCLOCK — Draws or removes a clock
  • gCLOSE — Closes a drawable
  • gCLS — Clears the current drawable
  • gCOLOR — Sets the pen colour
  • gCOLORBACKGROUND — Sets the background colour
  • gCOLORINFO — Gets the EPOC device’s colour information
  • gCOPY — Copies a rectangular area
  • gCREATE — Creates a window
  • gCREATEBIT — Creates a bitmap
  • gELLIPSE — Draws an ellipse
  • GEN$ — Converts a number to a string
  • GET — Waits for and returns the keycode for the next key pressed
  • GET$ — Waits for and returns the next key pressed as a string
  • GETCMD$ — Gets new command line arguments
  • GETDOC$ — Gets the name of the current document
  • GETEVENT — Deprecated version of GETEVENT32
  • GETEVENT32 — Synchronous wait for event
  • GETEVENTA32 — Waits for an event asynchronously
  • GETEVENTC — Cancels an outstanding GETEVENT32
  • gFILL — Draws a filled rectangle
  • gFONT — Sets the current drawable’s font
  • gGMODE — Sets the effect of subsequent drawing commands
  • gGREY — Changes pen colour between black and grey
  • gHEIGHT — Height of the current drawable
  • gIDENTITY — ID of the current drawable
  • gINFO32 — Gets information about the current drawable
  • gINVERT — Draws an inverted rectangle
  • GIPRINT — Displays an information message
  • gLINEBY — Draws a line
  • gLINETO — Draws a line to an absolute position
  • gLOADBIT — Loads a bitmap
  • gLOADFONT — Loads a font
  • GLOBAL — Declares global variables
  • gMOVE — Moves the current position
  • gORDER — Moves the selected window
  • gORIGINX — Window’s X position
  • gORIGINY — Window’s Y position
  • GOTO — Jumps to a labelled line
  • GOTOMARK — Makes a bookmarked record the current record
  • gPATT — Draws a pattern-filled rectangle
  • gPEEKLINE — Reads a horizontal line from a drawable
  • gPOLY — Draws a polygon
  • gPRINT — Prints a list into a drawable
  • gPRINTB — Prints text into a cleared box
  • gPRINTCLIP — Prints text which fits within defined area
  • gRANK — Gets foreground/background position of the current window
  • gSAVEBIT — Saves the current drawable
  • gSCROLL — Scrolls pixels
  • gSETPENWIDTH — Sets the pen width
  • gSETWIN — Changes position/size of the current window
  • gSTYLE — Sets the style of text used in subsequent print commands
  • gTMODE — Sets the character display mode
  • gTWIDTH — Calculates the screen width of a string
  • gUNLOADFONT — Unloads a font
  • gUPDATE — Controls screen updates
  • gUSE — Sets the current drawable
  • gVISIBLE — Sets the visibility of the current window
  • gWIDTH — Current drawable’s width
  • gX — X position in the current drawable
  • gXBORDER — Draws a border
  • gXPRINT — Prints a string with precise highlighting or underlining
  • gY — Y position in the current drawable

gAT — Sets the drawing position using absolute co-ordinates

Usage: gAT x%,y%

Sets the current position using absolute co-ordinates. gAT 0,0 moves to the top left of the current drawable.

See also gMOVE.

gBORDER — Draws a border

Usage: gBORDER flags%,width%,height%
or gBORDER flags%

gBORDER is included for compatibility with older versions of OPL, however it is recommended that programmers use gCREATE and gXBORDER in preference to this function (see below).

Draws a one-pixel wide, black border around the edge of the current drawable. If width% and height% are supplied, a border shape of this size is drawn with the top left corner at the current position. If they are not supplied, the border is drawn around the whole of the current drawable.

flags% controls three attributes of the border: a shadow to the right and beneath, a one-pixel gap all around, and the type of corners used. Its value can be built from:

KBordSglShadow% | 1 | Single pixel shadow.
KBordSglGap% | 2 | Removes a single pixel shadow.
KBordDblShadow% | 3 | Double pixel shadow.
KBordDblGap% | 4 | Removes a double pixel shadow.
KBordGapAllRound% | $100 | One pixel gap all round.
KBordRoundCorners% | $200 | More rounded corners.
KBordLosePixel% | $400 | Less rounded corners (only one pixel missing at the corner).

These constants are supplied in Const.oph.

These shadows do not appear in the same way that shadows on other objects such as dialogs and menu panes appear. To display such shadows on a window, you must specify them when using gCREATE. Hence you should use gCREATE (and gXBORDER) in preference to gBORDER.

You can combine the values to control the three different effects. (1, 2, 3 and 4 are mutually exclusive you cannot use more than one of them.) For example, for rounded corners and a double pixel shadow, use flags%=$203.

Set flags%=0 for no shadow, no gap, and sharper corners.

For example, to de-emphasise a previously emphasised border, use gBORDER with the shadow turned off:

    gBORDER 3             REM show border
    GET
    gBORDER 4             REM border off
    ...

See also gXBORDER.

gBOX — Draws a box

Usage: gBOX width%,height%

Draws a box from the current position, width% to the right and height% down. The current position is unaffected.

gBUTTON — Draws a 3D button

Usage: any of

    gBUTTON text$,type%,w%,h%,state%
    gBUTTON text$,type%,w%,h%,state%,bmpId&
    gBUTTON text$,type%,w%,h%,state%,bmpId&,maskId&
    gBUTTON text$,type%,w%,h%,state%,bmpId&,maskId&,layout%

Draws a 3-D black and grey button at the current position in a rectangle of the supplied width w% and height h%, which fully encloses the button in all its states. text$ specifies up to 64 characters to be drawn in the button in the current font and style. You must ensure that the text will fit in the button.

The type% argument specifies the type of button to be drawn. For EPOC, this type% should be KButtS5%, although different values are supported by gBUTTON for backwards compatibility. Not all button states are supported by older button types.

KButtS5%

2

The standard EPOC button type. This is the style of button used on the Psion Series 5 and other EPOC devices.

The state% argument gives the button state:

KButtS5Raised% | 0 | A raided button.
KButtS5SemiPressed% | 1 | A semi-depressed (flat) button.
KButtS5Sunken% | 2 | A fully-depressed (sunken) button.

These constants, as well as the constants for legacy buttons are provided in Const.oph.

Button bitmaps

Bitmaps may be used on buttons. Three extra optional arguments can be passed which give the bitmap ID, the mask ID and the layout for the button respectively. maskId% can be 0 to specify no mask, but bmpId% must always be specified.

The layout% argument specifies the relative positions of text and icon on a button:

KButtLayoutTextRightPictureLeft% | 0 | Text on right, picture on left.
KButtLayoutTextBottomPictureTop% | 1 | Text below, picture above.
KButtLayoutTextTopPictureBottom% | 2 | Text above, picture below.
KButtLayoutTextLeftPictureRight% | 3 | Text on left, picture on right.

The following constants can be added to layout% above to specify how a button’s excess space is to be allocated:

KButtExcessShare% | $00 | Excess space is shared equally.
KButtExcessToText% | $10 | Excess is allocated to text only.
KButtExcessToPicture% | $20 | Excess goes to the picture only.

These constants are provided in Const.oph.

When the layout is such that the text is at the top or the bottom, then text and picture are centred vertically and horizontally in the space allotted to them. If the layout has text to the left or right, then the text is left aligned in the space allotted to it and the picture is right or left aligned respectively. Both text and picture are centred vertically in this case.

For a picture only with no text use text$="".

‘Invalid arguments’ error is raised if you use OPL windows for gBUTTON. Read-only bitmaps may also be loaded using the Bitmap OPX. See Bmp.opx — Sprites and bitmaps for more details of how to do this.

N.B.: a button is a purely graphical entity and so doesn’t own the bitmaps. Therefore the bitmap may not be unloaded while the button is still in use.

gCIRCLE — Draws a circle

Usage:      gCIRCLE radius%
or      gCIRCLE radius%,fill%

Draws a circle with the centre at the current position in the current drawable. If the value of radius% is negative then no circle is drawn.

If fill% is supplied and if fill%<>0 then the circle is filled with the current pen colour.

See gELLIPSE, gCOLOR.

gCLOCK — Draws or removes a clock

Usage: any of

    gCLOCK ON/OFF
    gCLOCK ON,mode%
    gCLOCK ON,mode%,offset&
    gCLOCK ON,mode%,offset&,format$
    gCLOCK ON,mode%,offset&,format$,font&
    gCLOCK ON,mode%,offset&,format$,font&,style%

Displays or removes a clock showing the system time. The current position in the current window is used. Only one clock may be displayed in each window.

mode% controls the type of clock:

KgClockS5System% | 6 | Black and grey medium, system setting.
KgClockS5Analog% | 7 | Black and grey medium, analog.
KgClockS5Digital% | 8 | Second type medium, digital.
KgClockS5LargeAnalog% | 9 | Black and grey, extra large, analog.
KgClockS5Formatted% | 11 | Formatted digital.

The digital clock (mode%=KgClockS5Digital%) automatically displays the day of the week and day of the month below the time. The extra large analog clock (mode%=KgClockS5LargeAnalog%) automatically displays a second hand.

Warning: Do not use gSCROLL to scroll the region containing a clock. When the time is updated, the old position would be used. The whole window may, however, be moved using gSETWIN.

Digital clocks display in 24-hour or 12-hour mode according to the system-wide setting.

offset& specifies an offset in minutes from the system time to the time displayed. This allows you to display a clock showing a time other than the system time. A flag which has the value $100, may be ORed with mode% so that offset& may be specified in seconds rather than minutes. The offset is a long integer to enable a whole day to be specified when the offset is in seconds.

If these arguments are not supplied, mode% is taken as 1, and offset& as 0.

The system setting for the clock type (i.e. digital or analog) can be changed by an OPL program using the procedure LCSETCLOCKFORMAT: in the Date OPX (see Date.opx — Date and time manipulation). This function should be used to implement, for example, tapping a toolbar clock to change its type as in the built-in EPOC applications.

format$, font% and style% are used only for formatted digital clocks (mode% 11 on EPOC). The values for font& and style% are as for gFONT and gSTYLE. The default font for gCLOCK is the system font. The default style is normal (0).

For the formatted digital clock, a format string (up to 255 characters long) specifies how the clock is to be displayed. The format string contains a number of format specifiers in the form of a % followed by a letter. Upper or lower case may be used.

The format string may contain the following symbols to obtain the required effects:

%%

Insert a single % character in the string

%*

Abbreviate following item. (The asterisk should be inserted between the % and the number or letter, e.g. %*1). In most cases this amounts to omitting any leading zeros, for example if it is the first of the month "%F %*M" will display as 1 rather than 01.

%:n

Insert a system time separator character. n is an integer between zero and three inclusive which indicates which time separator character is to be used. For European time settings, only n=1 and n=2 are used, giving the hours/minutes separator and minutes/seconds separator respectively.

%/n

Insert a system date separator character. n is an integer between zero and three inclusive which indicates which date separator character is to be used. For European time settings, only n=1 and n=2 are used, giving the day/month separator and month/year separator respectively.

%1

Insert the first component of a three component date (i.e. a date including day, month and year) where the order of the components is determined by the system settings. The possibilities are: dd/mm/yyyy, (European), mm/dd/yyyy (American), yyyy/mm/dd (Japanese).

%2

Insert the second component of a three component date where the order has been determined by the system settings. See %1.

%3

Insert the third component of a three component date where the order has been determined by the system settings. See %1.

%4

Insert the first component of a two component date (i.e. a date including day and month only) where the order has been determined by system settings. The possibilities are: dd/mm, (European), mm/dd (American), mm/dd (Japanese).

%5

Insert the second component of a two component date where the order has been determined by the system settings. See %4.

%A

Insert am or pm according to the current language and time of day. Text is printed even if 24 hour clock is in use. Text may be specified to be printed before or after the time, and a trailing or leading space as appropriate will be added. The abbreviated version (%*A) removes this space.

Optionally, a minus or plus sign may be inserted between the % and the A. This operates as follows: %-A causes am/pm text to be inserted only if the system setting of the am/pm symbol position is set to display before the time. Similarly, %+A causes am/pm text to be inserted only if the system setting of the am/pm symbol is set to display after the time. No am/pm text will be inserted before the time if a + is inserted in the string. For example you could use, "%-A%H%:1%T%+A" to insert the am/pm symbol either before or after the time, according to the system setting. %+A and %-A cannot be abbreviated.

%B

As %A, except that the am/pm text is only inserted if the system clock setting is 12 hour. (This should be used in conjunction with %J.)

%D

Insert the two-digit day number in month (in conjunction with %1 etc.).

%E

Insert the day name. Abbreviation is language specific (3 letters in English).

%F

Use this at the beginning of a format string to make the date/time formatting independent of the system setting. This fixes the order of the following day/month/year component(s) in their given order, removing the need to use %1 to %5, allowing individual components of the date to be printed. (No abbreviation.)

%H

Insert the two-digit hour component of the time in 24 hour clock format.

%I

Insert the two-digit hour component of the time in 12 hour clock format. Any leading zero is automatically suppressed, regardless of whether an asterisk is inserted or not.

%J

Insert the two-digit hour component of time in either 12 or 24 hour clock format depending on the corresponding system setting. When the clock has been set to 12 hour format, the hour’s leading zero is automatically suppressed regardless of whether an asterisk has been inserted between the % and J.

%M

Insert the two-digit month number (in conjunction with %1 etc.).

%N

Insert the month name (in conjunction with %1 etc.). When using system settings (i.e. not using %F) this causes all months following %N in the string to be written in words. When using fixed format (i.e. when using %F) %N may be used alone to insert a month name. Abbreviation is language specific (3 letters in English).

%S

Insert the two-digit second component of the time.

%T

Insert the two-digit minute component of the time.

%W

Insert the two-digit week number in year, counting the first (part) week as week 1.

%X

Insert the date suffix. When using system settings (i.e. not using %F), this causes a suffix to be put on any date following %X in the string. When using fixed format (i.e. using %F), %X following any date appends a suffix for that particular date. Cannot be abbreviated.

%Y

Insert the four digit year number (in conjunction with %1 etc.). The abbreviation is the last two digits of the year.

%Z

Insert the three digit day number in year.

Some examples of the use of these format strings are as follows. The example use is 1:30:05 pm on Wednesday, 1st January 1997, with the system setting of European dates and with am/pm after the time:

"%-A%I:%T:%S%+A" will print the time in 12 hour clock, including seconds, with the am/pm either inserted before or after the time, depending on the system setting. So the example time would appear as, 1:30:05 pm.

"%F%E %*D%X %N %Y" will print the day of the week followed by the date with suffix, the month as a word and the year. For example, Wednesday 1st January 1997.

"%E %D%X%N%Y %1 %2 %3" will use the locale setting for ordering the elements of the date, but will use a suffix on the day and the month in words. For example, Wednesday 01st January 1997.

"%*E %*D%X%*N%*Y %1 %2 '%3" will be similar to 3., but will abbreviate the day of the week, the day, the month and the year, so the example becomes "Wed 1st Jan 97".

"%M%Y%D%1%/0%2%/0%3" will appear as 01/01/1997. This demonstrates that the ordering of the %D, %M and %Y is irrelevant when using locale-dependent formatting. Instead the ordering of the date components is determined by the order of the %1, %2, and %3 formatting commands.

style% may take any of the values used to specify gSTYLE, other than 2 (underlined).

A note should also be made that a ‘General Failure’ error will result if you attempt to use an invalid format. Invalid formats include using %: and %/ followed by 0 or 3 when in European locale setting (when these separators are without meaning) and using %+ and %- followed by characters other than A or B.

gCLOSE — Closes a drawable

Usage: gCLOSE id%

Closes the specified drawable that was previously opened by gCREATE, gCREATEBIT or gLOADBIT.

If the drawable closed was the current drawable, the default window (ID=1) becomes current.

An error is raised if you try to close the default window.

gCLS — Clears the current drawable

Usage: gCLS

Clears the whole of the current drawable and sets the current position to 0,0, its top left corner.

gCOLOR — Sets the pen colour

Usage: gCOLOR red%,green%,blue%

Sets the pen colour of the current window. The red%,green%,blue% values specify a colour which will be mapped to white, black or one of the greys on non-colour screens. Note that if the values of red%, green% and blue% are equal, then a pure grey results, ranging from black (0) to white (255).

See also gCOLORBACKGROUND, gCOLORINFO.

gCOLORBACKGROUND — Sets the background colour

Usage: gCOLORBACKGROUND red%,green%,blue%

Sets the background, or ‘paper’ colour of the current graphics window. Subsequent graphics commands in the window will use this background colour. The red%,green%,blue% values specify a colour which will be mapped to white, black or one of the greys on non-colour screens. Note that if the values of red%, green% and blue% are equal, then a pure grey results, ranging from black (0) to white (255).

For example:

    gUSE 1
    gCOLOR $ff,0,0
    gCOLORBACKGROUND 0,0,$ff
    gAT 20,20
    gPRINTB "Red text on a blue background",250

Compatibility

gCOLORBACKGROUND does not exist in EPOC releases before ER5. If gCOLORBACKGROUND is used, the translated OPL program will not run correctly under ER3 or earlier EPOC releases, and the OPL source will not be translatable under ER3.

See also gCOLORINFO, gCOLOR, and testColorSupport.opl in gCOLORINFO’s Compatibility note.

gCOLORINFO — Gets the EPOC device’s colour information

Usage: gCOLORINFO var cinfo&()

Interrogates the system to find the maximum number of colours available on the EPOC device. cinfo&() must be at least seven elements long, and on gCOLORINFO’s return will contain information indexed by the following values:

gColorInfoADisplayMode% | 1 | Default window mode.
gColorInfoANumColors% | 2 | Number of colours supported.
gColorInfoANumGreys% | 3 | Number of greys supported.

The remaining four elements are reserved for future use.

The default window mode will be one of the following values:

KDisplayModeNone% | 0 |
KDisplayModeGray2% | 1 | Two greys.
KDisplayModeGray4% | 2 | Four greys.
KDisplayModeGray16% | 3 | 16 greys.
KDisplayModeGray256% | 4 | 256 greys.
KDisplayModeColor16% | 5 | 16 colours.
KDisplayModeColor256% | 6 | 256 colours.
KDisplayModeColor64K% | 7 | 65,536 colours (16-bit colour).
KDisplayModeColor16M% | 8 | 16,777,216 colours (24-bit colour).
KDisplayModeRGB% | 9 |
KDisplayModeColor4K% | 10 | 4,096 colours (12-bit colour).

For example, to find out about the colour depth of the display on your EPOC device:

    include "Const.oph"
    proc ColTest:
          local c&(3)
          gColorInfo c&()
          print c&(gColorInfoADisplayMode%),
          print c&(gColorInfoANumColors%),
          print c&(gColorInfoANumGreys%)
          get
    endp

Compatibility

ER5 colour support keywords such as gCOLORINFO keyword cannot be used if the program is expected to run on earlier EPOC devices, as the program will report an error when the unsupported keyword is reached. However, this error can be anticipated and the program structured to cope accordingly:

    REM testColorSupport.opl
    REM (C) 1998-1999 Symbian Ltd. All rights reserved.

    INCLUDE "Const.oph"

    DECLARE EXTERNAL
    EXTERNAL Main:
    EXTERNAL ColorAvailable%:

    PROC Main:
      REM This will run on ER1 to ER5 devices (but will only
      REM translate on ER5).
      REM Attempt to find the color capabilities of the device.
      IF ColorAvailable%:
        PRINT "This device has color support."
      ELSE
        PRINT "No color support on this device."
      ENDIF
      GET
    ENDP

    PROC ColorAvailable%:
      LOCAL cinfo&(7)
      ONERR ErrorHandler::
      gCOLORINFO cInfo&()
      IF cInfo&(gColorInfoANumColors%)
        RETURN KTrue%
      ENDIF
      RETURN KFalse%
    ErrorHandler::
      ONERR OFF
      IF ERR=-96 REM Illegal Opcode
        REM gCOLORINFO not supported
        RETURN KFalse% REM No color support.
       ENDIF
      RAISE ERR       REM Not expecting this error.
    ENDP

See also gCOLORBACKGROUND, gCOLOR.

gCOPY — Copies a rectangular area

Usage: gCOPY id%,x%,y%,w%,h%,mode%

Copies a rectangle of the specified size (width w%, height h%) from the point x%,y% in drawable id%, to the current position in the current drawable.

It is inadvisable to use gCOPY to copy from windows as it is very slow. It should only be used for copying from bitmaps to windows or other bitmaps.

As this command can copy both set and clear pixels, the same modes are available as when displaying text. Possible values for mode% are:

KtModeSet% | 0 | Set.
KtModeClear% | 1 | Clear.
KtModeInvert% | 2 | Invert.
KtModeReplace% | 3 | Replace.

Set, Clear and Invert act only on set pixels in the pattern; Replace copies the entire rectangle, with set and clear pixels.

The current position is not affected in either window.

gCREATE — Creates a window

Usage: either of:

    id%=gCREATE(x%,y%,w%,h%,v%)
    id%=gCREATE(x%,y%,w%,h%,v%,flags%)

Creates a window with specified position and size (width w%, height h%), and makes it both current and foreground. The current position is set initially to (0, 0), the top left corner.

The v% argument specifies whether the window is initially visible:

KgCreateInvisible% | 0 | Invisible window.
KgCreateVisible% | 1 | Visible window.

gCREATE returns the ID of the window. Window IDs are used as arguments to other functions and keywords, and refer to the newly created window.

Window mode flags

The flags% argument specifies the graphics mode and shadowing style to use on the window. The defaults are 2-colour, with no shadow.

It is simplest to specify flags% as a hexadecimal number, as its value is a bitwise OR of significant values.

The least significant four bits of flags% (masked by $000F) gives the colour mode. The next 4 bits (masked by $00F0) specify the window’s shadowing. The following constant values can be added, or ORed to give the first eight bits of flags%:

KColorgCreate2GrayMode% | $0000 | 2 grey mode.
KColorgCreate4GrayMode% | $0001 |
KColorgCreate16GrayMode% | $0002 |
KColorgCreate256GrayMode% | $0003 | 256 grey mode.
KColorgCreate16ColorMode% | $0004 | 16 colour mode.
KColorgCreate256ColorMode% | $0005 | 256 colour mode.
KgCreateHasShadow% | $0010 | Window has a shadow.

These constants are provided in Const.oph. The old constants, KgCreate2ColourMode%, KgCreate4ColourMode%, and KgCreate16ColourMode% are still retained for backwards compatibility.

Note: It is not an error to create a window with features not supported on the hardware, but it is inefficient and should be avoided. This is similar to the concept of copying a 4-grey bitmap into a 2-grey window on greyscale machines: processor time is wasted dithering the colours down to the same level as the window.)

Bits 8-11 (masked by $0F00) give the shadow height relative to the window behind it as a left-shifted four-bit number. A height of N units gives a shadow of N * 2 pixels.

Examples:

flags% | description
$412 | 16 colour-mode ($2), shadowed window ($1), with height 4 units ($4) above the previous window with a shadow of 8 pixels.
$010 | 2 colour-mode (black and white) shadowed window at the same height as the previous window.
$101 | 4 colour mode window with no shadow (height ignored if shadow disabled).
$111 | 4 colour mode window with shadow of 1 unit above window behind, i.e. 2 pixel shadow.

Note that 63 windows may be open at any time and it is recommended that you use many small windows rather than a few large ones.

See also gCLOSE, gCOLOR, DEFAULTWIN.

gCREATEBIT — Creates a bitmap

Usage:

    id%=gCREATEBIT(w%,h%)
    id%=gCREATEBIT(w%,h%,mode%)

Creates a bitmap with the specified width and height, and makes it the current drawable. Sets the current position to 0,0, its top left corner.

Returns id% which identifies this bitmap for other keywords.

gCREATEBIT may be used with an optional third parameter which specifies the graphics mode of the bitmap to be created. The values of these are as given in gCREATE. By default the graphics mode of a bitmap is 2-colour.

See also gCLOSE, gCREATE.

gELLIPSE — Draws an ellipse

Usage: gELLIPSE hRadius%,vRadius%
or      gELLIPSE hRadius%,vRadius%,fill%

Draws an ellipse with the centre at the current position in the current drawable. hRadius% is the horizontal distance in pixels from the centre of the ellipse to the left (and right) of the ellipse. vRadius% is the vertical distance from the centre of the ellipse to the top (and bottom). If the length of either radius is less than zero, then no ellipse is drawn.

If fill% is supplied and if fill%<>0 then the ellipse is filled with the current pen colour.

See gCIRCLE, gCOLOR.

GEN$ — Converts a number to a string

Usage: g$=gen$(x,y%)

Returns a string representation of the number x. The string will be up to y% characters long.

Example GEN$(123.456,7) returns "123.456" and GEN$(243,5) returns "243".

  • If y% is negative then the string is right-justified - for example GEN$(1,-6) returns " 1" where there are five spaces to the left of the 1.
  • If y% is positive then no spaces are added for example GEN$(1,6) returns "1".
  • If the number x will not fit in the width specified by y%, then the string will just be asterisks, for example GEN$(256.99,4) returns "****".

See also FIX$, NUM$, SCI$.

GET — Waits for and returns the keycode for the next key pressed

Usage: g%=GET

Waits for a key to be pressed and returns the character code for that key.

For example, if the A key is pressed with Caps Lock off, the integer returned is 97 (a), or 65 (A) if A was pressed with the Shift key down.

The character codes of special keys, such as Pg Dn, are given in Appendix D.

You can use KMOD to check whether modifier keys (Shift, Ctrl, Fn and Caps) were used.

See also KEY and Character codes.

GET$ — Waits for and returns the next key pressed as a string

Usage: g$=GET$

Waits until a key is pressed and then returns which key was pressed, as a string.

For example, if the A key is pressed in lower case mode, the string returned is "a".

You can use KMOD to check whether any modifier keys (Shift, Ctrl, Fn and Caps) were used.

See also KEY$.

GETCMD$ — Gets new command line arguments

Usage: w$=GETCMD$

Returns new command-line arguments to an OPL application, after a change files or quit event has occurred. Usually this is called after GETEVENT32 has returned a system command.

The command line arguments are returned as a string. The first character of the return value has the following meaning:

KGetCmdLetterCreate$ | "C" | Close down the current file, and create the specified new file.
KGetCmdLetterOpen$ | "O" | Close down the current file, and open the specified existing file.
KGetCmdLetterExit$ | "X" | Close down the current file (if any) and quit the app.

These constants are defined in Const.oph.

If the first character is KGetCmdLetterCreate$ or KGetCmdLetterOpen$, then the rest of the returned string is a filename.

You can only call GETCMD$ once for each system message.

EPOC Connect now restarts applications after closing them for a backup. OPL applications will receive a KGetCmdLetterExit$ when the application is closed by EPOC Connect, and a KGetCmdLetterOpen$ when the application is reopened, but applications which already understand these system commands will require no code changes.

Compatibility

No code changes need to be made to use this additional functionality as GETCMD$ exists in EPOC releases prior to ER5. Code translated under ER5 using GETCMD$ will run on ER3 machines without re-translation.

See CMD$, and OPL applications for more details of OPL applications.

GETDOC$ — Gets the name of the current document

Usage: docname$=GETDOC$

Returns the name of the current document.

See also SETDOC.

GETEVENT — Deprecated version of GETEVENT32

This keyword is included for compatibility with older versions of the OPL language.

It is strongly recommended that you use GETEVENT32 rather than GETEVENT. GETEVENT is supported only for backward compatibility and cannot be used to handle pen events in a satisfactory way.

GETEVENT32 — Synchronous wait for event

Section Contents

  • Keypress events
  • Foreground, background and switch on events
  • Command events (exit or file switch)
  • Key down and key up events
  • Pen point events
  • Event notes

Usage: GETEVENT32 ev&()

Waits for an event to occur, and returns with ev&() specifying the event. The data returned in ev&() depends on the type of event that occurred.

All events return a 32-bit time stamp. The window ID mentioned below refers to the value returned by the gCREATE keyword. The modifier values and scancode values for a keypress (which specify a location on the keyboard) are given in the Character codes.

Const.oph supplies the following constants for indexing ev&():

KEvAType% | 1 | Type of the event.
KEvATime% | 2 | 32-bit time stamp.

These event index numbers and their meanings are the same for all possible kinds of event. ev&(KEvAType%) is always the event type, and ev&(KEvATime%) is always the time stamp for the event. The meanings of other values in ev&() are dependant on the type of the event.

Keypress events

Note that keycodes are returned in the first element of ev&(), ev&(KEvAType%). To recognise a keypress event, you have to use a bit mask. Keypress events are masked by KEvNotKeyMask&.

For a keypress event, (ev&(KEvAType%) AND KEvNotKeyMask&) is always 0.

KEvNotKeyMask&

&400

Masks out non-keypress events.

The index values for a key event are:

 | 1 | Key code (cooked).
 | 3 | Scan code (raw).
KEvAKMod% | 4 | Index for the key modifier.
KEvAKRep% | 5 | Index for the repeat value.

ev&(KEvATime%) is the time stamp, as with any other event.

Foreground, background and switch on events

For these events, ev&(KEvAType%) is one of:

KEvFocusGained& | &401 | Program has moved to foreground.
KEvFocusLost& | &402 | Program has moved to background.
KEvSwitchOn& | &403 | Machine is switched on.

Note that KEvSwitchOn& is only returned by GETEVENT32 if the appropriate flag is set by a call to SETFLAGS. GETEVENT32 ignores the machine being switched on if the flag is not set.

Command events (exit or file switch)

This kind of event should be handled specially by programmers. For this event, ev&(KEvAType%) is

KEvCommand&

&404

A command.

A command is passed to an application when the EPOC machine wants the application to switch files or exit. If this event is received, GETCMD$ should be called to find out what action should be taken.

Key down and key up events

For these events, ev&(KEvAType%) is either of:

KEvKeyDown& | &406 | Key pressed down.
KEvKeyUp& | &407 | Key released.

It is only possible to extract the scancode of a key up or key down event. However, for each user keypress, three events are generated: Key up, key down and key press. The keycode can be extracted from the key press event (see above).

ev&() indices for these event types are:

3 | Key down or key up event’s scancode.
4 | Key modifiers.

Pen point events

For pen events, ev&(KEvAType%) is one of:

KEvPtr& | &408 | Pen event.
KEvPtrEnter& | &409 | Pen point enters a window.
KEvPtrExit& | &40A | Pen point leaves a window.

The ev&() for a pointer event is a nine-element array indexed by the following values:

KEvAPtrOplWindowId% | 3 | ID of parent window.
KEvAPtrWindowId% | 3 | Synonym for KEvAPtrOplWindowId%.
KEvAPtrType% | 4 | Type of pointer event (see below).
KEvAPtrModifiers% | 5 | Modifiers.
KEvAPtrPositionX% | 6 | X coordinate.
KEvAPtrPositionY% | 7 | Y coordinate.
KEvAPtrScreenPosX% | 8 | X coordinate relative to the parent window.
KEvAPtrScreenPosY% | 9 | Y coordinate relative to the parent window.

ev&(KEvAPtrType%) contains the type of the pointer event. A given EPOC device may not support all types of pointer event type because of the wide range of possible pointer input devices. ev&(KEvAPtrType%) will contain one of tje following values:

KEvPtrPenDown& | 0 | Pen down.
KEvPtrPenUp& | 1 | Pen up.
KEvPtrButton1Down& | 0 | Button 1 down.
KEvPtrButton1Up& | 1 | Button 1 up.
KEvPtrButton2Down& | 2 | Button 2 down.
KEvPtrButton2Up& | 3 | Button 2 up.
KEvPtrButton3Down& | 4 | Button 3 down.
KEvPtrButton3Up& | 5 | Button 3 up.
KEvPtrDrag& | 6 | Pointer drag (while button held down).
KEvPtrMove& | 7 | Pointer move (without any button being pressed).
KEvPtrButtonRepeat& | 8 | Button repeat.
KEvPtrSwitchOn& | 9 | Machine turned on by a screen touch.

Event notes

  • Constants for event codes and subscripts are supplied in Const.oph.
  • Some pointer events, and pointer enters and exits, can be filtered out to avoid being swamped by unwanted event types. See POINTERFILTER.
  • For unknown events, ev&(1) contains &1400 added to the code returned by the window server. ev&(2) is the timestamp, ev&(3)is the window ID, and the rest of the data returned by the window server is put into ev&(4), ev&(5), etc.
  • If a non-key event such as ‘foreground’ occurs while a keyboard keyword such as GET, INPUT, MENU or DIALOG is being used, the event is discarded. So GETEVENT must be used if non-key events are to be monitored. If you need to use these keywords in applications, use LOCK ON / LOCK OFF around them, so that the System screen won’t send messages to switch files or shutdown while the application cannot respond.

See also GETEVENTA32.

GETEVENTA32 — Waits for an event asynchronously

Usage: GETEVENTA32 status%,ev&()

Asynchronous version of GETEVENT32. GETEVENTA32 returns the same codes to the array ev&() as GETEVENT32.

The exist status of GETEVENTA32 is placed into status% when an event is received. For this reason, status% should probably be a global variable.

See GETEVENTC, GETEVENT32, GETEVENT. See also Asynchronous requests and semaphores for details of asynchronous I/O functions.

GETEVENTC — Cancels an outstanding GETEVENT32

Usage: GETEVENTC(var stat%)

Cancels the previously called GETEVENTA32 function with status stat%. Note that GETEVENTC consumes the signal (unlike IOCANCEL), so IOWAITSTAT should not be used after GETEVENTC.

See the Asynchronous requests and semaphores for details.

gFILL — Draws a filled rectangle

Usage: gFILL width%,height%,gMode%

Fills a rectangle of the specified size from the current position, according to the graphics mode specified.

The current position is unaffected.

gFONT — Sets the current drawable’s font

Usage: gFONT fontUid&

Sets the font for current drawable to fontId&. The font may be one of the predefined fonts in the ROM or a user-defined font. See Graphics for more details of fonts.

Constants for the font UIDs are supplied in Const.oph.

User-defined fonts must first be loaded by gLOADFONT, then the font UIDs of the loaded fonts may be used with gFONT. Note that this is not the ID returned by gLOADFONT (which is the font file ID), but the UID defined in the font file itself.

See also gLOADFONT, FONT.

gGMODE — Sets the effect of subsequent drawing commands

Usage: gGMODE mode%

Sets the effect of all subsequent drawing commands gLINEBY, gBOX etc. on the current drawable.

KgModeSet% | 0 | Pixels will be set.
KgModeClear% | 1 | Pixels will be cleared.
KgModeInvert% | 2 | Pixels will be inverted.

These constants are supplied in Const.oph.

When you first use drawing commands on a drawable, they set pixels in the drawable. Use gGMODE to change this. For example, if you have drawn a black background, you can draw a white box outline inside it with either gGMODE 1 or gGMODE 2, followed by gBOX.

gGREY — Changes pen colour between black and grey

Usage: gGREY mode%

Changes the pen colour between black and grey. mode% has the following effects:

mode%=1 sets the foreground colour of the current drawable to light grey. This is the same colour as would be achieved by using gCOLOR $aa,$aa,$aa.

mode% of any other value sets the foreground colour to black (the default).

See also DEFAULTWIN and gCREATE.

gHEIGHT — Height of the current drawable

Usage: height%=gHEIGHT

Returns the height of the current drawable.

gIDENTITY — ID of the current drawable

Usage: id%=gIDENTITY

Returns the ID of the current drawable.

The default window has ID=1.

gINFO32 — Gets information about the current drawable

Usage: gINFO32 var i&()

Gets general information about the current drawable and about the graphics cursor (whichever window it is in). changed. The information is returned in the array i%() which must be at least 32 integers long. i&() must have 48 elements, although elements 37 to 48 are currently unused.

i%(1) | Reserved.
i%(2) | Reserved.
i%(3) | Height of font.
i%(4) | Descent of font.
i%(5) | Ascent of font.
i%(6) | Width of '0' character.
i%(7) | Maximum character width.
i%(8) | Flags for font (see below).
i%(9) | The font UID as used in gFONT.
i%(10-17) | Unused.
i%(18) | Current graphics mode (gGMODE).
i%(19) | Current text mode (gTMODE).
i%(20) | Current style (gSTYLE).
i%(21) | Cursor state (ON=1,OFF=0).
i%(22) | ID of window containing cursor (-1 for text cursor).
i%(23) | Cursor width.
i%(24) | Cursor height.
i%(25) | Cursor ascent.
i%(26) | Cursor x position in window.
i%(27) | Cursor y position in window.
i%(28) | 1 if drawable is a bitmap.
i%(29) | Cursor effects.
i%(30) | Graphics colour mode of the current window. This will be one of the values described in DEFAULTWIN.
i%(31) | gCOLOR red% of foreground
i%(32) | gCOLOR green% of foreground
i%(33) | gCOLOR blue% of foreground
i&(34) | gCOLOR red% of background
i&(35) | gCOLOR green% of background
i&(36) | gCOLOR blue% of background

The value given for i%(8) is a combination of the following values:

1 | Font uses standard ASCII characters (32-126).
2 | Font uses Code Page 1252 characters (128-255).
4 | Font is bold.
8 | Font is italic.
16 | Font has serifs.
32 | Font is monospaced.
$8000 | Font is stored expanded for quick drawing.

i%(29) has bit 1 set (i%(29) AND 2) if not the cursor is not flashing, and bit 2 set (i%(29) AND 4) if it is grey.

If the cursor is off (i%(21)=0), or is a text cursor (i%(22)=-1), i%(23) to i%(27) and i%(29)should be ignored.

See also gFONT, gCOLOR, gCREATE.

gINVERT — Draws an inverted rectangle

Usage: gINVERT width%,height%

Inverts the rectangle width% to the right and height% down from the cursor position, except for the four corner pixels.

GIPRINT — Displays an information message

Usage: GIPRINT str$,c%
or GIPRINT str$

Displays an information message for about two seconds, in the bottom right corner of the screen. For example, GIPRINT "Not Found" displays Not Found. If a string is too long for the screen, it will be clipped.

If c% is given, it controls the corner in which the message appears. Corner constants for the information message are as given for BUSY.

Only one message can be shown at a time. You can make the message go away - for example, if a key has been pressed - with GIPRINT "".

gLINEBY — Draws a line

Usage: gLINEBY dx%,dy%

Draws a line from the current position to a point dx% to the right and dy% down from the starting point. Negative dx% and dy% mean left and up respectively. The end point is not drawn, so for gLINEBY dx%,dy%, point gX+dx%,gY+dy% is not drawn. Note, however, that OPL specially plots the point when the start and end-point coincide.

The current position moves to the end of the line drawn. gLINEBY 0,0 sets the pixel at the current position.

See also gLINETO, gPOLY.

gLINETO — Draws a line to an absolute position

Usage: gLINETO x%,y%

Draws a line from the current position to the point x%,y%. The current position moves to x%,y%. The end point is not drawn, so for gLINETO x%,y%, point x%,y% is not drawn. Note, however, that OPL specially plots the point when the start and end-point coincide.

To plot a single point on all machines, use gLINETO to the current position (or gLINEBY 0,0).

See also gLINEBY, gPOLY.

gLOADBIT — Loads a bitmap

Usage: any of

    id%=gLOADBIT(name$,write%,index%)
    id%=gLOADBIT(name$,write%)
    id%=gLOADBIT(name$)

Loads a bitmap from the named bitmap file and makes it the current drawable. Sets the current position to 0,0, its top left corner.

gLOADBIT loads EPOC Picture files, which are naturally in the same file format that is saved by gSAVEBIT. EPOC Picture files can also be generated by exporting files created by the Sketch application. These are called multi-bitmap files (MBMs), though often containing just one bitmap as in the case of gSAVEBIT or Sketch files, and are often given an extension .MBM.

The bitmap is kept as a local copy in memory.

gLOADBIT returns id% which identifies this bitmap for other keywords.

A write% argument of KgLoadBitReadOnly% sets read-only access. Attempts to write to the bitmap in memory will be ignored, but the bitmap can be used by other programs without using more memory. Using KgLoadBitWriteable% for write% allows you to write to and re-save the bitmap, which is the default.

KgLoadBitReadOnly% | 0 | Read-only access
KgLoadBitWriteable% | 1 | Read and write access.

Constants are supplied in Const.oph.

For bitmap files which contain more than one bitmap, index% specifies which one to load. For the first bitmap, use index%=0, which is also the default value.

See also gCLOSE.

gLOADFONT — Loads a font

Usage: fileId%=gLOADFONT(file$)

Loads the user-defined fonts specified in the file file$ and returns the file ID of the font file, which can be used only with gUNLOADFONT. The maximum number of font files which may be loaded at any one time is 16.

To use the fonts in a loaded font file you need to use their published UIDs which will be defined in the font file itself, for example:

    fileId%=gLOADFONT("Music1")
    gFONT KMusic1Font1&
    ...
    gUNLOADFONT fileId%

gFONT itself is very efficient, so you should normally load all required fonts at the start of a program.

Note that the built-in fonts are automatically available, and do not need loading.

See gUNLOADFONT.

GLOBAL — Declares global variables

Usage: GLOBAL variables

Declares variables to be used in the current procedure (as does the LOCAL command) and (unlike LOCAL) in any procedures called by the current procedure, or procedures called by them.

The variables may be of 4 types, depending on the symbol they end with:

  • Variable names not ending with $, %, & or () are floating-point variables, for example price, x
  • Those ending with a % are integer variables, for example x%, sales92%
  • Those ending with an & are long integer variables, for example x&, sales92&.
  • Those ending with a $ are string variables. String variable names must be followed by the maximum length of the string in brackets for example names$(12), a$(3)

Array variables have a number immediately following them in brackets which specifies the number of elements in the array. Array variables may be of any type, for example: x(6),y%(5),f$(5,12),z&(3).

When declaring string arrays, you must give two numbers in the brackets. The first declares the number of elements, the second declares their maximum length. For example surname$(5,8) declares five elements, each up to 8 characters long.

Variable names may be any combination of up to 32 numbers and alphabetic characters and the underscore character. They must start with a alphabetic character or an underscore.

The length of a variable name includes the %, & or $ sign, but not the () in string and array variables.

More than one GLOBAL or LOCAL statement may be used, but they must be on separate lines, immediately after the procedure name.

See also LOCAL.

gMOVE — Moves the current position

Usage: gMOVE dx%,dy%

Moves the current position dx% to the right and dy% downwards, in the current drawable.

A negative dx% causes movement to the left; a negative dy% causes upward movement.

See also gAT.

gORDER — Moves the selected window

Usage: gORDER id%,position%

Sets the window specified by id% to the selected foreground/background position, and redraws the screen. Position 1 is the foreground window, position 2 is next, and so on. Any position greater than the number of windows is interpreted as the end of the list.

On creation, a window is at position 1 in the list.

Raises an error if id% is a bitmap.

See also gRANK.

gORIGINX — Window’s X position

Usage: x%=gORIGINX

Returns the gap between the left side of the screen and the left side of the current window.

Raises an error if the current drawable is a bitmap.

gORIGINY — Window’s Y position

Usage: y%=gORIGINY

Returns the gap between the top of the screen and the top of the current window.

Raises an error if the current drawable is a bitmap.

GOTO — Jumps to a labelled line

Usage:

    GOTO label or  GOTO label::
    ...
    label::

Goes to the line following the label:: and continues from there. The label

  • Must be in the current procedure
  • Must start with a letter and end with a double colon, although the double colon is not necessary in the GOTO statement
  • May be up to 32 characters long, excluding the colons.

GOTOMARK — Makes a bookmarked record the current record

Usage: GOTOMARK b%

Makes the record with bookmark b%, as returned by BOOKMARK, the current record. b% must be a bookmark in the current view.

gPATT — Draws a pattern-filled rectangle

Usage: gPATT id%,width%,height%,mode%

Fills a rectangle of the specified size from the current position with repetitions of the drawable id%.

As with gCOPY, this command can copy both set and clear pixels, so the same modes are available as when displaying text. Set mode%=0 for set, 1 for clear, 2 for invert or 3 for replace. 0, 1 and 2 act only on set pixels in the pattern; 3 copies the entire rectangle, with set and clear pixels.

If you set id%=-1 a pre-defined grey pattern is used.

The current position is unaffected.

gPEEKLINE — Reads a horizontal line from a drawable

Usage: gPEEKLINE id%,x%,y%,d%(),ln%,mode%

Reads a horizontal line from the black plane of the drawable id%, length ln%, starting at x%,y%. The leftmost 16 pixels are read into d%(1), with the first pixel read into the least significant bit.

gPEEKLINE has an extra optional parameter mode% to specify the colour mode:

mode% | colour mode | colour of pixel which sets bits
-1 | black and white | black
0 | black and white | white
1 | 4-colour mode | white
2 | 16-colour mode | white

The default mode% is -1. For 4 and 16-colour modes, 2 and 4 bits per pixel respectively are used. This is to enable the colour of the pixel to be ascertained from the bits which are set. White results in all 2 or 4 bits being set, while black sets none of them. For example, in a 4-colour window, with the colour set by

    gCOLOR 16,16,16

a pixel of a line would peek as 0001 in binary. Similarly, a pixel of a line with the colour set to

    gCOLOR 80,80,80

would result in the value 0101 in binary when peeked.

The array d%() must be long enough to hold the data. You can work out the number of integers required with ((ln%+15)/16) (using whole-number division).

If the optional parameter mode% is used, the array size allowed must be adjusted accordingly: it must be at least twice as long as the array needed for black and white if the line you wish to peek in 4-colour mode and four times as long in 16-colour mode.

gPOLY — Draws a polygon

Usage: gPOLY a%()

Draws a sequence of lines, as if by gLINEBY and gMOVE commands.

The array is set up as follows:

a%(1) | starting x position
a%(2) | starting y position
a%(3) | number of pairs of offsets
a%(4) | dx1%
a%(5) | dy1%
a%(6) | dx2%
a%(7) | dy2% etc.
... | }
... | } Further pairs...

The following constants can be used for the first five array indices:

KgPolyAStartX% | 1
KgPolyAStartY% | 2
KgPolyANumPairs% | 3
KgPolyANumDx1% | 4
KgPolyANumDy1% | 5

Each pair of numbers dx1%,dy1%, for example specifies a line or a movement. To draw a line, dy% is the amount to move down, while dx% is the amount to move to the right multiplied by two.

To specify a movement (i.e. without drawing a line) work out the dx%,dy% as for a line, then add 1 to dx%.

(For drawing/movement up or left, use negative numbers.)

gPOLY is quicker than combinations of gAT, gLINEBY and gMOVE.

Example, to draw three horizontal lines 50 pixels long at positions 20,10, 20,30 and 20,50:

    a%(1)=20 :a%(2)=10             REM 20,10
    a%(3)=5                               REM 5 operations
    a%(4)=50*2  :a%(5)=0             REM draw right 50
    a%(6)=0*2+1 :a%(7)=20             REM move down 20
    a%(8)=-50*2 :a%(9)=0            REM draw left 50
    a%(10)=0*2+1 :a%(11)=20            REM draw left 50
    a%(12)=50*2 :a%(13)=0            REM draw right 50
    gPOLY a%()

gPRINT — Prints a list into a drawable

Usage: gPRINT list of expressions

Displays a list of expressions at the current position in the current drawable. All variable types are formatted as for PRINT.

Unlike PRINT, gPRINT does not end by moving to a new line. A comma between expressions is still displayed as a space, but a semicolon has no effect. gPRINT without a list of expressions does nothing.

See also gPRINTB, gPRINTCLIP, gTWIDTH, gXPRINT, gTMODE.

gPRINTB — Prints text into a cleared box

Usage: any of

    gPRINTB t$,w%,al%,tp%,bt%,m%
    gPRINTB t$,w%,al%,tp%,bt%
    gPRINTB t$,w%,al%,tp%
    gPRINTB t$,w%,al%
    gPRINTB t$,w%

Displays text t$ in a cleared box of width w% pixels. The current position is used for the left side of the box and for the baseline of the text.

al% controls the alignment of the text in the box:

KgPrintBRightAligned% | 1 | Right alignment.
KgPrintBLeftAligned% | 2 | Left alignment.
KgPrintBDefAligned% | 2 | Default alignment (left).
KgPrintBCentredAligned% | 3 | Centred.

tp% and bt% are the clearances between the text and the top/bottom of the box. Together with the current font size, they control the height of the box. An error is raised if tp% plus the font ascent is greater than 255.

m% controls the margins. For left alignment, m% is an offset from the left of the box to the start of the text. For right alignment, m% is an offset from the right of the box to the end of the text. For centring, m% is an offset from the left or right of the box to the region in which to centre, with positive m% meaning left and negative meaning right.

KgPrintBDefTop% | 0 | Default top clearance.
KgPrintBDefBottom% | 0 | Default bottom clearance.
KgPrintBDefMargin% | 0 | Default margin.

These constants are supplied in Const.oph.

See also gPRINT, gPRINTCLIP, gTWIDTH, gXPRINT.

gPRINTCLIP — Prints text which fits within defined area

Usage: w%=gPRINTCLIP(text$,width%)

Displays text$ at the current position, displaying only as many characters as will fit inside width% pixels. Returns the number of characters displayed.

See also gPRINT, gPRINTB, gTWIDTH, gXPRINT, gTMODE.

gRANK — Gets foreground/background position of the current window

Usage: rank%=gRANK

Returns the foreground/background position — from 1 to 64 — of the current window. Raises an error if the current drawable is a bitmap.

See also gORDER.

gSAVEBIT — Saves the current drawable

Usage: gSAVEBIT name$,width%,height%
or gSAVEBIT name$

Saves the current drawable as the named bitmap file. If width% and height% are given, then only the rectangle of that size from the current position is copied.

gSAVEBIT does not add a default filename extension to the input argument name if none is provided on the EPOC machine.

gSCROLL — Scrolls pixels

Usage: gSCROLL dx%,dy%,x%,y%,wd%,ht%
or gSCROLL dx%,dy%

Scrolls pixels in the current drawable by offset dx%,dy%. Positive dx% means to the right, and positive dy% means down. The drawable itself does not change its position.

If you specify a rectangle in the current drawable, at x%,y% and of size wd%,ht%, only this rectangle is scrolled.

The areas dx% wide and dy% deep which are "left behind" by the scroll are cleared.

The current position is not affected.

gSETPENWIDTH — Sets the pen width

Usage: gSETPENWIDTH width%

Sets the pen width in the current drawable to width% pixels.

gSETWIN — Changes position/size of the current window

Usage: gSETWIN x%,y%,width%,height%
or gSETWIN x%,y%

Changes position and, optionally, the size of the current window.

An error is raised if the current drawable is a bitmap.

The current position is unaffected.

If you use this command on the default window, you must also use the SCREEN command to ensure that the area for PRINT commands to use is wholly contained within the default window.

gSTYLE — Sets the style of text used in subsequent print commands

Usage: gSTYLE style%

Sets the style of text displayed in subsequent gPRINT, gPRINTB and gPRINTCLIP commands on the current drawable. Values for style%:

KgStyleNormal% | 0 | Normal.
KgStyleBold% | 1 | Bold.
KgStyleUnder% | 2 | Underline.
KgStyleInverse% | 4 | Inverse.
KgStyleDoubleHeight% | 8 | Double height.
KgStyleMonoFont% | 16 | Monospaced font.
KgStyleItalic% | 32 | Italic.

You can combine these styles by adding their values for example, to set bold, underlined and double height, use:

    gSTYLE KgStyleBold%+KgStyleUnder%+KgStyleDoubleHeight%

This command does not affect non-graphics commands, like PRINT.

gTMODE — Sets the character display mode

Usage: gTMODE mode%

Sets the way characters are displayed by subsequent gPRINT and gPRINTCLIP commands on the current drawable. Values for mode%:

KtModeSet% | 0 | Pixels will be set.
KtModeClear% | 1 | Pixels will be cleared.
KtModeInvert% | 2 | Pixels will be inverted.
KtModeReplace% | 3 | Pixels will be replaced.

When you first use graphics text commands on a drawable, each dot in a letter causes a pixel to be set in the drawable, i.e. the default gTMODE is KtModeSet%.

When mode% is clear or invert, graphics text commands work in a similar way, but the pixels are cleared or inverted. When mode% is replace, entire character boxes are drawn on the screen — pixels are set in the letter and cleared in the background box.

This command does not affect other text display commands.

Constants for the modes are supplied in Const.oph.

gTWIDTH — Calculates the screen width of a string

Usage: width%=gTWIDTH(text$)

Returns the width of text$ in the current font and style.

See also gPRINT, gPRINTB, gPRINTCLIP, gXPRINT.

gUNLOADFONT — Unloads a font

Usage: gULOADFONT fileId%

Unloads a user-defined font that was previously loaded using gLOADFONT. Raises an error if the font has not been loaded.

The built-in fonts are not held in memory and cannot be unloaded.

See also gLOADFONT.

gUPDATE — Controls screen updates

Usage: any of

    gUPDATE ON
    gUPDATE OFF
    gUPDATE

The screen is usually updated whenever you display anything on it. gUPDATE OFF switches off this feature. The screen will then be updated as few times as possible (though note that some keywords will always cause an update.) You can still force an update by using the gUPDATE command on its own.

This can result in a considerable speed improvement in some cases. You might, for example, use gUPDATE OFF, then a sequence of graphics commands, followed by gUPDATE. You should certainly use gUPDATE OFF if you are about to write exclusively to bitmaps.

gUPDATE ON returns to normal screen updating.

gUPDATE affects anything that displays on the screen. If you are using a lot of PRINT commands, gUPDATE OFF may make a noticeable difference in speed.

Note that with gUPDATE OFF, the location of errors which occur while the procedure is running may be incorrectly reported. For this reason, gUPDATE OFF is best used in the final stages of program development, and even then you may have to remove it to locate some errors.

gUSE — Sets the current drawable

Usage: gUSE id%

Makes the drawable id% current. Graphics drawing commands will now go to this drawable. gUSE does not bring a drawable to the foreground (see gORDER).

gVISIBLE — Sets the visibility of the current window

Usage: gVISIBLE ON
or       gVISIBLE OFF

Makes the current window visible or invisible.

Raises an error if the current drawable is a bitmap.

gWIDTH — Current drawable’s width

Usage: width%=gWIDTH

Returns the width of the current drawable.

gX — X position in the current drawable

Usage: x%=gX

Returns the x current position (in from the left) in the current drawable.

gXBORDER — Draws a border

Usage: gXBORDER type%,flags%,w%,h%
or gXBORDER type%,flags%

Draws a border in the current drawable of a specified type, fitting inside a rectangle of the specified size or with the size of the current drawable if no size is specified.

type% should always be the constant value KgXBorderS5Type%. Other border types are implemented for backwards compatibility, but should not be used under EPOC.

KgXBorderS5Type%

2

The standard EPOC border type.

Values for flags% are:

none | $00
single black | $01
shallow sunken | $42
deep sunken | $44
deep sunken with outline | $54
shallow raised | $82
deep raised | $84
deep raised with outline | $94
vertical bar | $22
horizontal bar | $2a

Constants for these flags and types are supplied in Const.oph. The following values of flags% apply to all border types:

  • 0 for normal corners
  • Adding $100 leaves 1 pixel gap around the border.
  • Adding $200 for more rounded corners
  • Adding $400 for losing a single pixel.
  • If both $400 and $200 are mistakenly supplied, $200 has priority.

See also gBORDER.

gXPRINT — Prints a string with precise highlighting or underlining

Usage: gXPRINT string$,flags%

Displays string$ at the current position, with precise highlighting or underlining. The current font and style are still used, even if the style itself is inverse or underlined. If text mode 3 (replace) is used both set and cleared pixels in the text are drawn.

Possible values for flags% are:

KgXPrintNormal% | 0 | Normal, as with gPRINT.
KgXPrintInverse% | 1 | Inverse.
KgXPrintInverseRound% | 2 | Inverse, omitting corner pixels.
KgXPrintThinInverse% | 3 | Thin inverse.
KgXPrintThinInverseRound% | 4 | Thin inverse, omitting corner pixels.
KgXPrintUnderlined% | 5 | Underlined.
KgXPrintThinUnderlined% | 6 | Thin underlined.

These constants are supplied in Const.oph.

Where lines of text are separated by a single pixel, the thin options maintain the separation between lines.

gXPRINT does not support the display of a list of expressions of various types.

gY — Y position in the current drawable

Usage: y%=gY

Returns the y current position (down from the top) in the current drawable.


HEX$ — HOUR

Contents

  • HEX$ — Converts an integer to a hex string
  • HOUR — Gets the current hour

HEX$ — Converts an integer to a hex string

Usage: h$=HEX$(x&)

Returns a string containing the hexadecimal (base 16) representation of integer or long integer x&.

For example HEX$(255) returns the string "FF".

Notes

To enter integer hexadecimal constants (16 bit) put a $ in front of them. For example $FF is 255 in decimal. (Don’t confuse this use of $ with string variable names.)

To enter long integer hexadecimal constants (32 bit) put a & in front of them. For example &FFFFF is 1048575 in decimal.

Counting in hexadecimal is done like this: 0 1 2 3 4 5 6 7 8 9 A B C D E F 10... where A stands for decimal 10, B for decimal 11, C for decimal 12 ... up to F for decimal 15. After F comes 10, which is equivalent to decimal 16. To understand numbers greater than hexadecimal 10, again compare hexadecimals with decimals. In these examples, 102 means 10 × 10, 103 means 10 × 10 × 10 and so on.

253 in decimal is:

(2 × 102)+(5 × 101)+(3 × 100) = (2 × 100)+(5 × 10)+(3 × 1) = 200+50+3

By analogy, &253 in hexadecimal is:

(&2 × 162)+(&5 × 161)+(&3 × 160) =(2 × 256)+(5 × 16)+(3 × 1) =512+80+3 = 595 in decimal.

Similarly, &A6B in hexadecimal is:

(&A × 162)+(&6 × 161)+(&B × 160) =(10 × 256)+(6 × 16)+(11 × 1) =2560+96+11 = 2667 in decimal.

You may also find this table useful for converting between hex and decimal:

hex | decimal |
&1 | 1 | =160
&10 | 16 | =161
&100 | 256 | =162
&1000 | 4096 | =163

For example, &20F9 is

(2 × &1000)+(0 × &100)+(15 × &10)+9 which in decimal is: (2 × 4096)+(0 × 256)+(15 × 16)+9 = 8441.

All hexadecimal constants are integers ($) or long integers (&). So arithmetic operations involving hexadecimal numbers behave in the usual way. For example, &3/&2 returns 1, &3/2.0 returns 1.5, 3/$2 returns 1.

HOUR — Gets the current hour

Usage: h%=HOUR

Returns the number of the current hour from the system clock as an integer between 0 and 23.


IABS — IOYIELD

Contents

  • IABS — Absolute value of an integer expression
  • ICON — Sets an application’s icon
  • IF...ENDIF — Conditional loop
  • INCLUDE — Includes a header file
  • INPUT — Reads a value from the keyboard
  • INSERT — Inserts a blank record into a database
  • INT — Gets the integer part of a floating point value (as an integer)
  • INTF — Gets the integer part of a floating point value (as a floating point number)
  • INTRANS — True if the current view is in a transaction
  • IOA — Asynchronous I/O request
  • IOC — I/O request with guaranteed completion
  • IOCANCEL — Cancels an outstanding IO request
  • IOCLOSE — Closes a file
  • IOOPEN — Creates or opens a file
  • IOREAD — Reads from a file
  • IOSEEK — Seeks to a position in a file opened for random access
  • IOSIGNAL — Signals completion of asynchronous I/O function
  • IOW — Synchronous I/O request
  • IOWAIT — Waits for an asynchronous I/O function to complete
  • IOWAITSTAT — Waits for an IOC or IOA to complete
  • IOWAITSTAT32 — Waits for asynchronous OPX procedure 32 bit status word to complete
  • IOWRITE — Writes bytes in a buffer to a file
  • IOYIELD — Ensures asynchronous functions have a chance to run

IABS — Absolute value of an integer expression

Usage: i&=IABS(x&)

Returns the absolute value, i.e. without any sign, of the integer or long integer expression x&.

For example IABS(-10) is 10.

See also ABS, which returns the absolute value as a floating-point value.

ICON — Sets an application’s icon

Usage: ICON mbm$

Gives the name of the bitmap file mbm$, also known as an EPOC Picture file, to use as the icon for an OPL Application.

If the ICON command is not used inside the APP…ENDA structure, then a default icon is used, but the rest of the information in the APP..ENDA construct is still used to specify the other features of the OPL application.

mbm$ is a multi-bitmap file which can contain up to three bitmap/mask pairs - the sizes are 24, 32 and 48 squares. These different sizes are used for the different zoom levels in the system screen. The sizes are read from the MBM and the most suitable size is zoomed if the exact sizes required are not provided or if some are missing.

In fact, you can use ICON more than once within the APP...ENDA construct. The translator only insists that all icons are paired with a mask of the same size in the final ICON list. This allows you to use pairs of MBMs containing just one bitmap as produced by the Sketch application. For example, you could specify them individually:

    APP ...
    ICON "icon24.mbm"
    ICON "mask24.mbm"
    ICON "icon32.mbm"
    ICON "mask32.mbm"
    ICON "icon48.mbm"
    ICON "mask48.mbm"
    ENDA

or with pairs in each MBM:

    APP ...
    ICON "iconMask24"
    ICON "iconMask32"
    ICON "iconMask48"
    ENDA

or with all the bitmaps as just one MBM, as would normally be the case if prepared on the PC using bmconv and aiftool (see ).

This command can only be used between APP and ENDA.

See OPL applications for more details of OPL applications.

IF...ENDIF — Conditional loop

Usage:

    IF condition1
          ...
    ELSEIF condition2
          ...
    ELSE
          ...
    ENDIF

Does either

  • the statements following the IF condition

or

  • the statements following one of the ELSEIF conditions (there may be as many ELSEIF statements as you like none at all if you want)

or

  • the statements following ELSE (or, if there is no ELSE, nothing at all). There may be either one ELSE statement or none.

After the ENDIF statement, the lines following ENDIF carry on as normal.

IF, ELSEIFs, ELSE and ENDIF must be in that order.

Every IF must be matched with a closing ENDIF.

You can also have an IF...ENDIF structure within another, for example:

    IF condition1
          ...
    ELSE
          ...
          IF condition2
                ....
          ENDIF
          ...
    ENDIF

condition is an expression returning a logical value for example a<b. If the expression returns logical true (non-zero) then the statements following are executed. If the expression returns logical false (zero) then those statements are ignored. For more details about logical expressions, see Operators and logical expressions.

INCLUDE — Includes a header file

Usage: INCLUDE file$

Includes a file, file$, which may contain CONST definitions, prototypes for OPX procedures and prototypes for module procedures. The included file may not include module procedures themselves. Procedure and OPX procedure prototypes allow the translator to check parameters and coerce numeric parameters (that are not passed by reference) to the required type.

Including a file is logically identical to replacing the INCLUDE statement with the file’s contents.

The filename of the header may or may not include a path. If it does include a path, then OPL will only scan the specified folder for the file. However, the default path for INLCUDE is \System\Opl\, so when INCLUDE is called without specifying a path, OPL looks for the file firstly in the current folder and then in \System\Opl\ in all drives from Y: to A: and then in Z:, excluding any remote drives.

See CONST, EXTERNAL. See also Using OPL Extensions (OPXs).

INPUT — Reads a value from the keyboard

Usage: INPUT variable
or INPUT log.field

Waits for a value to be entered at the keyboard, and then assigns the value entered to a variable or data file field.

You can edit the value as you type it in. All the usual editing keys are available: the arrow keys move along the line, Esc clears the line and so on.

If inappropriate input is entered, for example a string when the input was to be assigned to an integer variable, a ? is displayed and you can try again. However, if you used TRAP INPUT, control passes on to the next line of the procedure, with the appropriate error condition being set and the value of the variable remaining unchanged.

INPUT is usually used in conjunction with a PRINT statement:

    PROC exch:
          LOCAL pds,rate
          DO
                PRINT "Pounds Sterling?",
                INPUT pds
                PRINT "Rate (DM)?",
                INPUT rate
                PRINT "=",pds*rate,"DM"
                GET
          UNTIL 0
    ENDP

Note the commas at the end of the PRINT statements, used so that the cursor waiting for input appears on the same line as the messages.

TRAP INPUT

If a bad value is entered (for example "abc" for a%) in response to a TRAP INPUT, the ? is not displayed, but the ERR function can be called to return the value of the error which has occurred. If the Esc key is pressed while no text is on the input line, the ‘Escape key pressed’ error (number -114) will be returned by ERR (provided that the INPUT has been trapped). You can use this feature to enable someone to press the Esc key to escape from inputting a value.

See also EDIT. This works like INPUT, except that it displays a string to be edited and then assigned to a variable or field. It can only be used with strings.

INSERT — Inserts a blank record into a database

Usage: INSERT

Inserts a new, blank record into the current view of a database. The fields can then be assigned to before using PUT or CANCEL.

INT — Gets the integer part of a floating point value (as an integer)

Usage: i&=INT(x)

Returns the integer (in other words the whole number) part of the floating-point expression x. The number is returned as a long integer.

Positive numbers are rounded down, and negative numbers are rounded up for example INT(-5.9) returns -5 and INT(2.9) returns 2. If you want to round a number to the nearest integer, add 0.5 to it (or subtract 0.5 if it is negative) before you use INT.

See also INTF.

INTF — Gets the integer part of a floating point value (as a floating point number)

Usage: i=INTF(x)

Used in the same way as the INT function, but the value returned is a floating-point number. For example, INTF(1234567890123.4) returns 1234567890123.0

You may also need this when an integer calculation may exceed integer range.

See also INT.

INTRANS — True if the current view is in a transaction

Usage: i&=INTRANS

Finds out whether the current view is in a transaction. Returns -1 if it is in a transaction or 0 if it is not.

See also BEGINTRANS.

IOA — Asynchronous I/O request

Usage: r%=IOA(h%,f%,var status%,var a1,var a2)

This has the same form as IOC, but it returns an error value of the request is not completed successfully. IOC should be used in preference to IOA.

See also: I/O functions and commands.

IOC — I/O request with guaranteed completion

Usage: IOC(h%,f%,var status%,var a1,var a2)

Make an I/O request with guaranteed completion. The device driver opened with handle h% performs the asynchronous I/O function f% with two further arguments, a1 and a2. The argument status% is set by the device driver. If an error occurs while making a request, status% is set to an appropriate values, but IOC always returns zero, not an error value. .An IOWAIT or IOWAITSTAT must be performed for each IOC. IOC should be used in preference to IOA.

See also: I/O functions and commands.

IOCANCEL — Cancels an outstanding IO request

Usage: r%=IOCANCEL(h%)

Cancels any outstanding asynchronous I/O request (IOC or IOA). Note, however, that the request will still complete, so the signal must be consumed using IOWAITSTAT.

See also: I/O functions and commands.

IOCLOSE — Closes a file

Usage: r%=IOCLOSE(h%)

Closes a file with the handle h%.

See also: I/O functions and commands.

IOOPEN — Creates or opens a file

Usage: r%=IOOPEN(var h%,name$,mode%)

Creates or opens a file called name$. Defines h% for use by other I/O functions. mode% specifies how to open the file. For unique file creation, use IOOPEN(var h%,addr%,mode%)

See also: I/O functions and commands.

IOREAD — Reads from a file

Usage: r%=IOREAD(h%,addr&,maxLen%)

Reads from the file with the handle h%. address% is the address of a buffer large enough to hold a maximum of maxLen% bytes. The value returned to r% is the actual number of bytes read or, if negative, is an error value.

See also: I/O functions and commands.

IOSEEK — Seeks to a position in a file opened for random access

Usage: r%=IOSEEK(h%,mode%,var off&)

Seeks to a position in a file that has been opened for random access. mode% specifies how the offset argument off& is to be used. Values for mode% may be found in the I/O functions and commands. off& may be positive to move forwards or negative to move backwards. IOSEEK sets the variable off& to the absolute position set.

Note the following example when you use #:

    ret%=IOSEEK(h%,mode%,#ptrOff&)

passing the long integer ptrOff&.

See also 32-bit addressing, I/O functions and commands.

IOSIGNAL — Signals completion of asynchronous I/O function

Usage: IOSIGNAL

Signals an asynchronous I/O function’s completion.

See also: I/O functions and commands.

IOW — Synchronous I/O request

Usage: r%=IOW(h%,func%,var a1,var a2)

The device driver opened with handle h% performs the synchronous I/O function func% with the two further arguments.

See also: I/O functions and commands.

IOWAIT — Waits for an asynchronous I/O function to complete

Usage: IOWAIT

Waits for an asynchronous I/O function to signal completion.

See also: I/O functions and commands.

IOWAITSTAT — Waits for an IOC or IOA to complete

Usage: IOWAITSTAT var stat%

Waits for an asynchronous function, called with IOC or IOA, to complete.

See also: I/O functions and commands.

IOWAITSTAT32 — Waits for asynchronous OPX procedure 32 bit status word to complete

Usage: IOWAITSTAT32 var stat&

Takes a 32-bit status word. IOWAITSTAT32 should be called only when you need to wait for completion of a request made using a 32-bit status word when calling an asynchronous OPX procedure.

N.B.: The initial value of a 32-bit status word while it is still pending (i.e. waiting to complete) is &80000001 (KStatusPending32& in Const.oph. For a 16-bit status word the ‘pending value’ is -46 (KErrFilePending%).

See also: I/O functions and commands.

IOWRITE — Writes bytes in a buffer to a file

Usage: r%=IOWRITE(h%,addr&,length%)

Writes length% bytes in a buffer at address% to the file with the handle h%.

See also: I/O functions and commands.

IOYIELD — Ensures asynchronous functions have a chance to run

Usage: IOYIELD

Ensures that any asynchronous handler set up with IOC or IOA is given a chance to run. IOYIELD must always be called before polling status words, i.e. before reading a 16-bit status word if IOWAIT or IOWAITSTAT have not been used first.

See also: I/O functions and commands.


KEY — KMOD

Contents

  • KEY — Gets the last key pressed as a character code
  • KEY$ — Gets the last key pressed as a string
  • KEYA — Reads the keyboard asynchronously
  • KEYC — Cancels a KEYA
  • KILLMARK — Removes a bookmark
  • KMOD — Gets the state of the modifier keys

KEY — Gets the last key pressed as a character code

Usage: k%=KEY

Returns the character code of the key last pressed, if there has been a keypress since the last use of the keyboard by INPUT, EDIT, GET, GET$, KEY, KEY$, MENU and DIALOG.

If no key has been pressed, zero is returned.

See Character codes for a list of special key codes. You can use KMOD to check whether modifier keys (Shift, Ctrl, Fn, and Caps Lock) were used.

This command does not wait for a key to be pressed, unlike GET.

KEY$ — Gets the last key pressed as a string

Usage: k$=KEY$

Returns the last key pressed as a string, if there has been a keypress since the last use of the keyboard by INPUT, EDIT, GET, GET$, KEY, KEY$, MENU and DIALOG.

If no key has been pressed, a null string ("") is returned.

See Character codes for a list of special key codes. You can use KMOD to check whether modifier keys (Shift, Ctrl, Fn, and Caps Lock) were used.

This command does not wait for a key to be pressed, unlike GET$.

KEYA — Reads the keyboard asynchronously

Usage: err%=KEYA(var stat%,var key%(1))

This is an asynchronous keyboard read function.

See Scanning the keyboard directly for details.

Cancel with KEYC.

KEYC — Cancels a KEYA

Usage: err%=KEYC(var stat%)

Cancels the previously called KEYA function with status stat%. Note that KEYC consumes the signal (unlike IOCANCEL), so IOWAITSTAT should not be used after KEYC.

See Scanning the keyboard directly for details.

KILLMARK — Removes a bookmark

Usage: KILLMARK b%

Removes the bookmark b%, which has previously been returned by BOOKMARK, from the current view of a database.

See BOOKMARK, GOTOMARK.

KMOD — Gets the state of the modifier keys

Usage: k%=KMOD

Returns a code representing the state of the modifier keys (whether they were pressed or not) at the time of the last keyboard access, such as a KEY function. The modifiers have these codes:

KKmodShift% | 2 | Shift down.
KKmodControl% | 4 | Ctrl down.
KKmodCaps% | 16 | Caps lock on.
KKmodFn% | 32 | Fn down.

These constants are supplied in Const.oph.

If there was no modifier, the function returns 0. If a combination of modifiers was pressed, the sum of their codes is returned — for example 20 is returned if Ctrl (4) was held down and Caps lock (16) was on.

Always use immediately after a KEY/KEY$/GET/GET$ statement.

The value returned by KMOD has one binary bit set for each modifier, as shown above. By using the logical operator AND on the value returned by KMOD you can check which of the bits are set, in order to see which modifier keys were held down. For more details on AND, see Operators and logical expressions.

Example:

    PROC modifier:
          LOCAL k%,mod%
          PRINT "Press a key" :k%=GET
          CLS :mod%=KMOD
          PRINT "Key code",k%,"with"
          IF mod%=0
                PRINT "no modifier"
          ENDIF
          IF mod% AND KModShift%
                PRINT "Shift down"
          ENDIF
          IF mod% AND KModControl%
                PRINT "Control down"
          ENDIF
          IF mod% AND KModCaps%
                PRINT "Caps Lock on"
          ENDIF
          IF mod% AND KModFn%
                PRINT "Fn down"
          ENDIF
    ENDP


LAST — LPRINT

Contents

  • LAST — Positions to the last record
  • LCLOSE — Closes the device opened with LOPEN
  • LEFT$ — Gets the leftmost characters of a string
  • LEN — Length of a string
  • LENALLOC — Gets the length of a previously allocated cell
  • LN — Natural logarithm
  • LOADM — Loads a translated OPL module
  • LOC — Locates a sub-string within a string
  • LOCAL — Declares procedure-local variables
  • LOCK — Blocks system requests to change files or quit
  • LOG — Logarithm
  • LOPEN — Opens a device for printing
  • LOWER$ — Converts a string to lower case
  • LPRINT — Prints a list to the device opened using LOPEN

LAST — Positions to the last record

Usage:      LAST

Positions to the last record in a view.

See filing.db.

LCLOSE — Closes the device opened with LOPEN

Usage: LCLOSE

Closes the device opened with LOPEN. The device is also closed automatically when a program ends.

LEFT$ — Gets the leftmost characters of a string

Usage: b$=LEFT$(a$,x%)

Returns the leftmost x% characters from the string a$.

For example if n$ has the value Charles, then b$=LEFT$(n$,3) assigns Cha to b$.

LEN — Length of a string

Usage: a%=LEN(a$)

Returns the number of characters in a$.

E.g. if a$ has the value 34 Kopechnie Drive then LEN(a$) returns 18.

You might use this function to check that a data file string field is not empty before displaying:

    IF LEN(A.client$)
          PRINT A.client$
    ENDIF

LENALLOC — Gets the length of a previously allocated cell

Usage: len&=LENALLOC(pcell&)

Returns the length of the previously allocated cell at pcell&. An error will be raised if the cell address argument is not in the range known by the heap.

See also SETFLAGS if you require a 64K memory limit to be enforced. If the flag is set to restrict the limit, len& is guaranteed to fit into an integer.

ARM

Cells are allocated lengths that are the smallest multiple of four greater than the size requested because the ARM processor requires a four-byte word alignment for its memory allocation. The ARM processor is used in the Psion Series 5 and other EPOC devices.

LN — Natural logarithm

Usage: a=LN(x)

Returns the natural (base e) logarithm of x.

Use LOG to return the base 10 log of a number.

LOADM — Loads a translated OPL module

Usage: LOADM module$

Loads a translated OPL module so that procedures in that module can be called. Until a module is loaded with LOADM, calls to procedures in that module will give an error.

module$ is a string containing the name of the module. Specify the full file name only where necessary.

Example: LOADM "MODUL2"

Up to 8 modules can be in memory at any one time, including the top level module; if you try to LOADM a ninth module, you get an error. Use UNLOADM to remove a module from memory so that you can load a different one.

By default, LOADM always uses the folder of the top level module. It is not affected by the SETPATH command.

LOC — Locates a sub-string within a string

Usage: a%=LOC(a$,b$)

Returns an integer showing the position in a$ where b$ occurs, or zero if b$ doesn’t occur in a$. The search matches upper and lower case.

Example: LOC("STANDING","AND") would return the value 3 because the substring AND starts at the third character of the string STANDING.

LOCAL — Declares procedure-local variables

Usage: LOCAL variables

Used to declare variables which can be referenced only in the current procedure. Other procedures may use the same variable names to create new variables. Use GLOBAL to declare variables common to all called procedures.

The variables may be of 4 types, depending on the symbol they end with:

  • Variable names not ending with $, %, & or () are floating-point variables, for example price, x
  • Those ending with a % are integer variables, for example x%, sales92%
  • Those ending with an & are long integer variables, for example x&, sales92&.
  • Those ending with a $ are string variables. String variable names must be followed by the maximum length of the string in brackets, for example names$(12), a$(3)

Array variables have a number immediately following them in brackets which specifies the number of elements in the array. Array variables may be of any type, for example: x(6),y%(5),f$(5,12),z&(3)

When declaring string arrays, you must give two numbers in the brackets. The first declares the number of elements, the second declares their maximum length. For example surname$(5,8) declares five elements, each up to 8 characters long.

Variable names may be any combination of up to 32 numbers, alphabetic letters and the underscore character. They must start with a letter or an underscore. The length includes the %, & or $ sign, but not the () in string and array variables.

More than one GLOBAL or LOCAL statement may be used, but they must be on separate lines, immediately after the procedure name.

See also GLOBAL, CONST and Constants and variables — Storing values for later use.

LOCK — Blocks system requests to change files or quit

Usage: LOCK ON
or LOCK OFF

Marks an application as locked or unlocked. When an app is locked with LOCK ON, the System screen will not send it events to change files or quit.

If, for example, you move to the task list or the document name in the System screen try to stop that running app by using the ‘Close file’ button or Ctrl+E, a message will appear, indicating that the app cannot close down at that moment.

You should use LOCK ON if your application uses a command, such as EDIT, MENU or DIALOG, which accesses the keyboard. You might also use it when the app is about to go busy for a considerable length of time, or at any other point where a clean exit is not possible. Do not forget to use LOCK OFF as soon as possible afterwards.

An application is initially unlocked.

LOG — Logarithm

Usage: a=LOG(x)

Returns the base 10 logarithm of x.

Use LN to find the base e (natural) log.

LOPEN — Opens a device for printing

Usage: LOPEN device$

Opens the device to which LPRINTs are to be sent.

No LPRINTs can be sent until a device has been opened with LOPEN.

You can open any of these devices:

  • The serial port, with LOPEN "TTY:A"
  • A file on the EPOC device. Any existing file of the name given will be overwritten when you print to it.

Only one device may be open at any one time. Use LCLOSE to close the device. LOPENned devices also close automatically when a program finishes running.

See also: Serial ports and printing.

LOWER$ — Converts a string to lower case

Usage: b$=LOWER$(a$)

Converts any upper case characters in the string a$ to lower case and returns the completely lower case string.

E.g. if a$="CLARKE", LOWER$(a$) returns the string "clarke"

Use UPPER$ to convert a string to upper case.

LPRINT — Prints a list to the device opened using LOPEN

Usage: LPRINT list of expressions

Prints a list of items, in the same way as PRINT, except that the data is sent to the device most recently opened with LOPEN.

The expressions may be quoted strings, variables, or the evaluated results of expressions. The punctuation of the LPRINT statement (commas, semicolons and new lines) determines the layout of the printed text, in the same way as PRINT statements.

If no device has been opened with LOPEN you will get an error.

See PRINT for displaying to the screen.

See LOPEN for opening a device for LPRINT.

See also Printer.opx — Printer and text handling for details of more advanced printing features.


MAX — mPOPUP

Contents

  • MAX — Maximum value
  • mCARD — Defines a menu card
  • mCASC — Defines a menu cascade
  • MEAN — Calculates a mean value
  • MENU — Displays a menu
  • MID$ — Gets the middle part of a string
  • MIN — Minimum value
  • mINIT — Initialises menus
  • MIME — Associates an OPL application with a MIME type
  • MINUTE — Gets the current minute
  • MKDIR — Creates a new folder
  • MODIFY — Changes a record without moving it
  • MONTH — Gets the current month
  • MONTH$ — Converts a numeric month to a string
  • mPOPUP — Presents a popup menu

MAX — Maximum value

Usage: m=MAX(list)
or m=MAX(array(),element)

Returns the greatest of a list of numeric items. The list can be either:

  • A list of variables, values and expressions, separated by commas

or

  • The elements of a floating-point array.

When operating on an array, the first argument must be the array name followed by (). The second argument, separated from the first by a comma, is the number of array elements you wish to operate on for example m=MAX(arr(),3) would return the value of the largest of elements arr(1), arr(2) and arr(3).

mCARD — Defines a menu card

Usage: mCARD title$,n1$,k1%
or mCARD title$,n1$,k1%,n2$,k2% etc.

Defines a menu. When you have defined all of the menus, use MENU to display them.

title$ is the name of the menu. From one to eight items on the menu may be defined, each specified by two arguments. The first is the item name, and the second the keycode for a shortcut key. This specifies a key which, when pressed together with Ctrl will select the option. If the keycode is for an upper case key, the shortcut key will be Shift+Ctrl.

The options can be divided into logical groups by displaying a separating line under the final option in a group. To do this, pass the negative value corresponding to the shortcut key keycode for the final option in the group. For example, -%A specifies shortcut key Shift+Ctrl+A and displays a separating line under the associated option in the menu.

Menu items without shortcuts can be specified using shortcut values between 1 and 32. For these items the value specified is still returned if the item is selected.

Other properties can be specified by adding one or more of the following flags to the shortcut keycode:

KMenuDimmed% | $1000 | Menu item is dimmed.
KMenuSymbolOn% | $2000 | Checkbox option button symbol on.
KMenuSymbolIndeterminate% | $4000 | Checkbox or option button symbol indeterminate.
KMenuCheckBox% | $0800 | Item has a checkbox.
KMenuOptionStart% | $0900 | Item starts an option button list.
KMenuOptionMiddle% | $0A00 | In the middle of an option button list.
KMenuOptionEnd% | $0B00 | Ends an option button list.

These constants are supplied in Const.oph.

The start, middle and end option buttons are for specifying a group of related items that can be selected exclusively (i.e. if one item is selected then the others are deselected). The number of middle option buttons is variable. A single menu card can have more than one set of option buttons and checkboxes, but option buttons in a set should be kept together. For speed, OPL does not check the consistency of these items’ specification.

If a separating line is required when any of these effects had been added, you must be sure to negate the whole value, not just the shortcut key keycode. For example:

    mCARD "Options","View1",%A OR $2900,"View2",-(%B OR $B00), "Another option",%C

Here, the second shortcut key keycode and its flag value is correctly negated to display a separating line.

A ‘Too wide’ error is raised if the menu title length is greater than or equal to 40. Shortcut values must be alphabetic character codes or numbers between the values of 1 and 32. Any other values will raise an ‘Invalid arguments’ error.

If any menu item fails to be added successfully, a menu is discarded. It is therefore incorrect to ignore mCARD errors by having an ONERR label around an mCARD call. If you do, the menu is discarded and a ‘Structure fault’ will be raised on using mCARD without first using mINIT again. See MENU for an example of this.

If more menu items are displayed in a menu card or cascade than are displayable on the screen, the menu will be drawn with a scroll bar. It is recommended that programmers do not define menus which scroll to keep the pen actions the user has to make to use the program to a minimum: see Defining the menus.

Compatibility

No changes need to be made to existing code to use this new functionality.

See also: mCASC and Menus.

mCASC — Defines a menu cascade

Usage: mCASC title$,item1$,hotkey1%,item2$,hotkey2%

Creates a cascade for a menu, on which less important menu items can be displayed. The cascade must be defined before use in a menu card. For example, a ‘Bitmap’ cascade under the File menu of a possible OPL drawing application could be defined like this:

    mCASC "Bitmap","Load",%L,"Merge",%M
    mCARD "File","New",%n,"Open",%o,"Save",%s,"Bitmap>",16,"Exit",%e

The trailing > character specifies that a previously defined cascade item is to be used in the menu at this point: it is not displayed in the menu item. A cascade has a filled arrow head displayed along side it in the menu. The cascade title in mCASC is also used only for identification purposes and is not displayed in the cascade itself. This title needs to be identical to the menu item text apart from the >. For efficiency, OPL doesn’t check that a defined cascade has been used in a menu and an unused cascade will simply be ignored. To display a > in a cascaded menu item, you can use >>.

Shortcut keys used in cascades may be added to the appropriate constant values as for mCARD to enable checkboxes, option buttons and dimming of cascade items.

As is typical for cascade titles, a shortcut value of 16 is used in the example above. This prevents the display or specification of any shortcut key. However, it is possible to define a shortcut key for a cascade title if required, for example to cycle through the options available in a cascade.

If more menu items are displayed in a menu card or cascade than are displayable on the screen, the menu will be drawn with a scroll bar. It is recommended that programmers do not define menus which scroll to keep the pen actions the user has to make to use the program to a minimum: see Defining the menus.

See also: mCARD, MENU, mINIT, and Menus.

MEAN — Calculates a mean value

Usage: m=MEAN(list)
or m=MEAN(array(),element)

Returns the arithmetic mean (average) of a list of numeric items. The list can be either:

  • A list of variables, values and expressions, separated by commas

or

  • The elements of a floating-point array.

When operating on an array, the first argument must be the array name followed by (). The second argument, separated from the first by a comma, is the number of array elements you wish to operate on for example m=MEAN(arr(),3) would return the average of elements arr(1), arr(2) and arr(3).

This example displays 15.0:

    a(1)=10
    a(2)=15
    a(3)=20
    PRINT MEAN(a(),3)

MENU — Displays a menu

Usage: val%=MENU
or val%=MENU(var init%)

Displays the menus defined by mINIT, mCARD and mCASC, and waits for you to select an item. Returns the shortcut key keycode of the item selected, as defined in mCARD, in lower case.

If you cancel the menu by pressing Esc, MENU returns 0.

If the name of a variable is passed, it sets the initial menu pane and item to be highlighted. init% should be 256*(menu%)+item%; for both menu% and item%, 0 specifies the first, 1 the second and so on. If init% is 517 (=256*2+5), for example, this specifies the 6th item on the third menu.

If init% was passed, MENU writes back to init% the value for the item which was last highlighted on the menu. You can then use this value when calling the menu again.

It is necessary to use MENU(init%), passing back the same variable each time the menu is opened if you wish the menu to reopen with the highlight set on the last selected item.

It is incorrect to ignore mCARD and mCASC errors by having an ONERR label around an mCARD or mCASC call. If you do, the menu is discarded and a ‘Structure fault’ will be raised on using mCARD, mCASC or MENU without first using mINIT again.

The following bad code will not display the menu:

    REM  ** example of bad code **
          mINIT
          ONERR errIgnore1
          mCARD "Xxx","ItemA",0      REM bad shortcut
    errIgnore1::
          ONERR errIgnore2
          mCARD "Yyy",""
          REM ‘Structure fault’ error (mINIT discarded)
    errIgnore2::
          ONERR OFF
          MENU                              REM ‘Structure fault’ again

If more menu items are displayed in a menu card or cascade than are displayable on the screen, the menu will be drawn with a scroll bar. It is recommended that programmers do not define menus which scroll to keep the pen actions the user has to make to use the program to a minimum: see Defining the menus.

See also: mCARD, mCASC, mINIT and Menus.

MID$ — Gets the middle part of a string

Usage: m$=MID$(a$,x%,y%)

Returns a string comprising y% characters of a$, starting at the character at position x%.

E.g. if name$="McConnell" then MID$(name$,3,4) would return the string Conn.

MIN — Minimum value

Usage: m=MIN(list)

or m=MIN(array(),element)

Returns the smallest of a list of numeric items. The list can be either:

  • A list of variables, values and expressions, separated by commas

or

  • The elements of a floating-point array.

When operating on an array, the first argument must be the array name followed by (). The second argument, separated from the first by a comma, is the number of array elements you wish to operate on for example m=MIN(arr(),3) would return the minimum of elements arr(1), arr(2) and arr(3).

mINIT — Initialises menus

Usage: mINIT

Prepares for definition of menus, cancelling any existing menus. Use mCARD and mCASC to define each menu, then MENU to display them.

It is incorrect to ignore mCARD or mCASC errors by having an ONERR label around an mCARD or mCASC call. If you do, the menu is discarded and a ‘Structure fault’ will be raised if there is an occurrence of mCARD, mCASC or MENU without first using mINIT again. See MENU for an example of this.

See also: mCARD, mCASC and Menus.

MIME — Associates an OPL application with a MIME type

Usage: MIME pri%, dtype$

Associates an OPL application with the Internet MIME content type dtype$, using priority pri%. This command can only be used in the scope of an APP...ENDA construct. The priority value specifies how proficient the application is at handling the named data type. dtype% is the name of the data type this app is declaring that it can handle, e.g. text/html, image/png or text/plain.

Declaring a MIME association indicates to the system that the application allows the user to view or manipulate files and data of the named type.

pri% can take any of the following values:

KDataTypePriorityUserSpecified% | KMaxInt% | Reserved for future use.
KDataTypePriorityHigh% | 10000 | This app is superbly capable of handling this data type.
KDataTypePriorityNormal% | 0 | Typical priority. App is proficient at handling this data type.
KDataTypePriorityLow% | -10000 | App is merely capable of handling this document type.
KDataTypePriorityLastResort% | -20000 | App should only handle this data type if there are no other apps available which can use it.
KDataTypePriorityNotSupported% | KMinInt% |

These constants are supplied in Const.oph. Note that KDataTypePriorityUserSpecified% is reserved for future use.

The .aif file (application information file) for the app is used to store this information once the app has been translated. Only one MIME association is allowed per application, so only one MIME statement can be made in an OPL application’s APP...ENDA declaration.

There are recognisers in the ROM for the following MIME types:

  • text/plain
  • text/html
  • image/jpeg
  • image/gif
  • text/X-vCard
  • text/X-vCalendar

Compatibility

An translated application using the MIME keyword and its .aif file can be installed and run successfully on a pre-ER5 device; however on pre-ER5 machines, the MIME recognition functionality will not be present.

It is not possible to translate OPL source code using the MIME keyword under versions of EPOC prior to ER5.

See also OPL applications and OPL and MIME [image] .

MINUTE — Gets the current minute

Usage: m%=MINUTE

Returns the current minute number from the system clock (0 to 59).

E.g. at 8.54am MINUTE returns 54.

MKDIR — Creates a new folder

Usage: MKDIR name$

Creates a new folder/directory. For example, MKDIR "C:\MINE\TEMP" creates a C:\MINE\TEMP folder, also creating C:\MINE if it is not already there.

MODIFY — Changes a record without moving it

Usage: MODIFY

Allows the current record of a view to be modified without moving the record. The fields can then be assigned to before using PUT or CANCEL.

MONTH — Gets the current month

Usage: m%=MONTH

Returns the current month from the system clock as an integer between 1 and 12.

E.g. on 12th March 1992 m%=MONTH returns 3 (KMarch%) to m%.

KJanuary% | 1 | KJuly% | 7
KFebruary% | 2 | August% | 8
KMarch% | 3 | September% | 9
KApril% | 4 | October% | 10
KMay% | 5 | November% | 11
KJune% | 6 | December% | 12

These constants are supplied in Const.oph.

MONTH$ — Converts a numeric month to a string

Usage: m$=MONTH$(x%)

Converts x%, a number from 1 to 12, to the month name, expressed as a three-letter mixed case string.

E.g. MONTH$(KJanuary%) returns the string Jan.

See MONTH for the month number constants.

mPOPUP — Presents a popup menu

Usage: mPOPUP(x%,y%,posType%,item1$,key1%,item2$,key2%,...)

Presents a popup menu. mPOPUP returns the value of the keypress used to exit the popup menu, this being 0 if Esc is pressed.

Note that mPOPUP defines and presents the menu itself, and should not and need not be called from inside the mINIT...MENU structure.

posType% is the position type controlling which corner of the popup menu x%,y% specifies and can take the values:

KMPopupPosTopLeft% | 0 | Top left.
KMPopupPosTopRight% | 1 | Top right.
KMPopupPosBottomLeft% | 2 | Bottom left.
KMPopupPosBottomRight% | 3 | Bottom right.

These constants are supplied in Const.oph.

item$ and key% can take the same values as for mCARD, with key% taking the same constant values to specify checkboxes, option buttons and dimmed items. However, cascades in popup menus are not supported.

For example

    mPOPUP (0,0,0,"Continue",%c,"Exit",%e)

specifies a popup menu with 0,0 as its top left-hand corner with the items ‘Continue’ and ‘Exit’, with the shortcut keys Ctrl+C and Ctrl+E respectively.

See also mCARD.


NEXT — NUM$

Contents

  • NEXT — Positions to the next record
  • NUM$ — Converts a floating point number to a string

NEXT — Positions to the next record

Usage: NEXT

Positions to the next record in the current data file.

If NEXT is used after the end of a file has been reached, no error is reported but the current record is null and the EOF function returns true.

NUM$ — Converts a floating point number to a string

Usage: n$=NUM$(x,y%)

Returns a string representation of the integer part of the floating-point number x, rounded to the nearest whole number. The string will be up to y% characters wide.

  • If y% is negative then the string is right-justified for example NUM$(1.9,-3) returns " 2" where there are two spaces to the left of the 2.
  • If y% is positive no spaces are added: e.g. NUM$(-3.7,3) returns "-4".
  • If the string returned to n$ will not fit in the width y%, then the string will just be asterisks; for example NUM$(256.99,2) returns "**".

See also FIX$, GEN$, SCI$.


OFF — OPENR

Contents

  • OFF — Switches the EPOC machine off
  • ONERR — Establishes an error handler
  • OPEN — Opens an existing table in a database
  • OPENR — Opens a table as read only in an existing database

OFF — Switches the EPOC machine off

Usage: OFF
or OFF x%

Switches the machine off.

When you switch back on, the statement following the OFF command is executed, for example:

    OFF :PRINT "Hello again"

If you specify an integer, x%, greater than 5, the machine switches off for that number of seconds and then automatically turns back on and continues with the next line of the program. However, during this time the machine may be switched on by an alarm, and of course you can turn it on as usual.

The minimum time to switch off is 5 seconds. EPOC also prevents switch off if there is an absolute timer outstanding and due to go off in less than 5 seconds.

Warning: Be careful how you use this command. If, due to a programming mistake, a program uses OFF in a loop, you may find it impossible to switch the machine back on, and have to reset it.

ONERR — Establishes an error handler

Usage:

    ONERR label::
    ...
    ONERR OFF

or just:

    ONERR label
    ...
    ONERR OFF

ONERR label:: establishes an error handler in a procedure. When an error is raised, the program jumps to the label:: instead of the program stopping and an error message being displayed.

The label may be up to 32 characters long starting with a letter or an underscore. It ends with a double colon (::), although you don’t need to use this in the ONERR statement.

ONERR OFF disables the ONERR command, so that any errors occurring after the ONERR OFF statement no longer jump to the label.

It is advisable to use the command ONERR OFF immediately after the label:: which starts the error handling code.

See Runtime errors — Handling errors reported while running programs for full details.

OPEN — Opens an existing table in a database

Usage: OPEN query$,log,f1,f2,...

Opens an existing table (or a ‘view’ of a table) from an existing database, giving it the logical view name log and handles for the fields f1, f2. log can be any letter in the range A to Z.

query$ specifies the database file, the required table and fields to be selected.

For example:

    OPEN "clients SELECT name, tel FROM phone",D,n$,t$

The database name here is clients and the table name is phone. The field names are enclosed by the keywords SELECT and FROM and their types should correspond with the list of handles (i.e. n$ indicates that the name field is a string).

Replacing the list of field names with * selects all the fields from the table.

query$ is also used to specify an ordered view and if a suitable index has been created, then it will be used. See dBase.opx — Database handling. For example,

    OPEN "people SELECT name,number FROM phoneBook ORDER BY name
             ASC, number DESC",G,n$,num%

would open a view with name fields in ascending alphabetical order and if any names were the same then the number field would be used to order these records in descending numerical order.

If the specification of the database includes embedded spaces, for example in the name of the folder, the name must be enclosed in quotes, so for example the following correctly fails:

    OPEN "c:\folder with spaces\file with spaces",a,name$

whereas the following works:

    OPEN """c:\folder with spaces\file with spaces""",a,name$

See also Database File Handling.

See also CREATE, USE and OPENR.

OPENR — Opens a table as read only in an existing database

Usage: OPEN query$,log,f1,f2,...

This command works exactly like OPEN except that the opened file is read-only. In other words, you cannot APPEND, UPDATE or PUT the records it contains.

This means that you can run two separate programs at the same time, both sharing the same file.


PARSE$ — PUT

Contents

  • PARSE$ — Parses a filename
  • PAUSE — Waits for a length of time
  • PEEKB — Reads a short integer from a byte of memory
  • PEEKW — Reads an integer from memory
  • PEEKL — Reads a long integer from memory
  • PEEKF — Reads a floating-point value from memory
  • PEEK$ — Reads a string from memory
  • PI — Returns the value of PI
  • POINTERFILTER — Sets the pointer event mask
  • POKEB — Stores a short integer in a byte of memory
  • POKEW — Stores an integer in memory
  • POKEL — Stores a long integer in memory
  • POKEF — Stores a floating-point value in memory
  • POKE$ — Stores a string in memory
  • POS — Gets the position in the current view
  • POSITION — Sets the position in the current view
  • PRINT — Displays a list of expressions
  • PUT — Writes changes into a database

PARSE$ — Parses a filename

Usage: p$=PARSE$(f$,rel$,var off%())

Returns a full file specification from the filename f$, filling in any missing information from rel$.

The offsets to the filename components in the returned string is returned in off%() which must be declared with at least 6 integers. Index values for off%() are:

KParseAOffFSys% | 1 | Filing system name offset.
KParseAOffDev% | 2 | Device name offset.
KParseAOffPath% | 3 | Path offset.
KParseAOffFilename% | 4 | Filename offset.
KParseAOffExt% | 5 | File extension offset.
KParseAOffWild% | 6 | Flags for wildcards in returned string. See below.

The flag values in offset%(KParseAOffWild%) are:

KParseWildNone% | 0 | No wildcards.
KParseWildFilename$ | 1 | Wildcard in filename.
KParseWildExt$ | 2 | Wildcard in file extension.
KParseWildBoth$ | 3 | Wildcard in both.

These constants are supplied in Const.oph.

If rel$ is not itself a complete file specification, the current filing system, device and/or path are used as necessary to fill in the missing parts.

f$ and rel$ should be separate strings.

    p$=PARSE$("NEW","C:\Documents\*.MBM",x%())

sets p$ to C:\Documents\NEW.MBM and x%() to (1,1,3,14,17,0).

PAUSE — Waits for a length of time

Usage: PAUSE x%

Pauses the program for a certain time, depending on the value of x%:

0 | waits for a key to be pressed
+ve | pauses for x% twentieths of a second
-ve | pauses for x% twentieths of a second or until a key is pressed

So PAUSE 100 would make the program pause for 100/20 = 5 seconds, and PAUSE -100 would make the program pause for 5 seconds or until a key is pressed.

If x% is less than or equal to 0, a GET, GET$, KEY or KEY$ will return the key press which terminated the pause. If you are not interested in this keypress, but in the one which follows it, clear the buffer after the PAUSE with a single KEY function: PAUSE -10 :KEY

You should be especially careful about this if x% is negative, since then you cannot tell whether the pause was terminated by a keypress or by the time running out.

PAUSE should not be used in conjunction with GETEVENT or GETEVENT32 because events are discarded by PAUSE.

PEEKB — Reads a short integer from a byte of memory

    p%=PEEKB(x&)

The PEEK functions find the values stored in specific bytes. PEEKB returns the integer value of the byte at address x&.

PEEKW — Reads an integer from memory

    p%=PEEKW(x&)

Returns the integer at address x&.

PEEKL — Reads a long integer from memory

    p&=PEEKL(x&)

Returns the long integer value at address x&.

PEEKF — Reads a floating-point value from memory

    p=PEEKF(x&)

Returns the floating-point value at address x&.

PEEK$ — Reads a string from memory

    p$=PEEK$(x&)

Returns the string at address x&.

PI — Returns the value of PI

Usage: p=PI

Returns the value of (3.14... ).

POINTERFILTER — Sets the pointer event mask

Usage:      POINTERFILTER filter%,mask%

Filters pointer events in the current window out or back in. Add the following flags together to achieve the desired filter% and mask%:

 | $0 | None.
KPointerFilterEnterExit% | $1 | Enter/exit.
KPointerFilterMove% | $2 | Move.
KPointerFilterDrag% | $4 | Drag.

These constants are supplied in Const.oph.

The bits set in filter% specify the settings to be used, 1 to filter out the event and 0 to remove the filter. Only those bits set in mask% will be used for filtering. This allows the current setting of a particular bit to be left unchanged if that bit is zero in the mask. (i.e. mask% dictates what to change and filter% specifies the setting to which it should be changed). For example,

    mask% = KPointerFilterEnterExit% + KPointerFilterDrag%
    REM     allows enter/exit and drag settings to be changed
    POINTERFILTER KPointerFilterEnterExit%, mask%
    REM filters out enter/exit, but not dragging
    ...
    POINTERFILTER KPointerFilterDrag%, mask%
    REM filters out drag and reinstates enter/exit

Initially the events are not filtered out.

See also GETEVENT32, GETEVENTA32.

POKEB — Stores a short integer in a byte of memory

    POKEB x&,y%

The POKE commands store values in specific bytes. POKEB stores the integer value y% (less than 256) in the single byte at address x&.

POKEW — Stores an integer in memory

    POKEW x&,y%

Stores the integer y% across two consecutive bytes, with the least significant byte in the lower address, that is x&.

POKEL — Stores a long integer in memory

    POKEL x&,y&

Stores the long-integer y& in bytes starting at address x&.

POKEF — Stores a floating-point value in memory

    POKEF x&,y

Stores the floating-point value y in bytes starting at address x&.

POKE$ — Stores a string in memory

    POKE$ x&,y$

Stores the string y$ in bytes starting at address x&.

Use ADDR to find out the address of your declared variables.

POS — Gets the position in the current view

Usage: p%=POS

Returns the number of the current record in the current view. POS (and POSITION) exist mainly for compatibility with older versions of OPL and you are advised to use bookmarks instead.

A file has no limit on the number of records. However, integers can only be in the range -32768 to +32767. Record numbers above 32767 are therefore returned like this:

record value | returned by POS
32767 | 32767
32768 | 32768
32769 | 32767
32770 | 32766
... | ...
65534 | 2

To display record numbers, you can use this check:

    IF POS<0
          PRINT 65536+POS
    ELSE
          PRINT POS
    ENDIF

N.B. the number of the current record may be greater than or equal to 65535 and hence values may need to be truncated to fit into p%, giving inaccurate results. You are particularly advised to use bookmarks when dealing with a large number of records. Note, however, that the value returned by POS can become inaccurate if used in conjunction with bookmarks and multiple views on a table. Accuracy can be restored by using FIRST or LAST on the current view.

See BOOKMARK, GOTOMARK, KILLMARK.

POSITION — Sets the position in the current view

Usage: POSITION x%

Makes record number x% the current record in the current view. By using bookmarks and editing the same table via different views, positional accuracy can be lost and POSITION x% could access the wrong record. Accuracy can be restored by using FIRST or LAST on the current view.

POSITION (and POS) exist mainly for compatibility with older versions of OPL and you are advised to use bookmarks instead.

See BOOKMARK, GOTOMARK, KILLMARK.

PRINT — Displays a list of expressions

Usage: PRINT list of expressions

Displays a list of expressions on the screen. The list can be punctuated in one of these ways:

If items to be displayed are separated by commas, there is a space between them when displayed.

If they are separated by semicolons, there are no spaces.

Each PRINT statement starts a new line, unless the preceding PRINT ended with a semicolon or comma.

There can be as many items as you like in this list. A single PRINT on its own just moves to the next line.

Examples: On 1st January 1997,

code | display
PRINT "TODAY is", :PRINT DAY;".";MONTH;".";YEAR | TODAY is 1.1.1997
PRINT 1 | 1
PRINT "Hello" | Hello
PRINT "Number",1 | Number 1

See also LPRINT, gUPDATE, gPRINT, gPRINTB, gPRINTCLIP, gXPRINT.

PUT — Writes changes into a database

Usage: PUT

Marks the end of a database’s INSERT or MODIFY phase and makes the changes permanent.

See INSERT, MODIFY, CANCEL.


RAD — RND

Contents

  • RAD — Converts from degrees to radians
  • RAISE — Raises an error
  • RANDOMIZE — Seeds the random number generator
  • REALLOC — Changes the size of a previously allocated cell
  • REM — Comment marker
  • RENAME — Renames files
  • REPT$ — Repeats a string
  • RETURN — Returns from a procedure
  • RIGHT$ — Gets the rightmost characters of string
  • ROLLBACK — Cancels the current transaction on the current view
  • RMDIR — Removes directories
  • RND — Gets a pseudo-random floating point number

RAD — Converts from degrees to radians

Usage: r=RAD(x)

Converts x from degrees to radians.

All the trigonometric functions assume angles are specified in radians, but it may be easier for you to enter angles in degrees and then convert with RAD.

Example:

    PROC xcosine:
          LOCAL angle
          PRINT "Angle (degrees)?:";
          INPUT angle
          PRINT "COS of",angle,"is",
          angle=RAD(angle)
          PRINT COS(angle)
          GET
    ENDP

(The formula used is (PI*x)/180).

To convert from radians to degrees use DEG.

RAISE — Raises an error

Usage: RAISE x%

Raises an error.

The error raised is error number x%. This may be one of the errors listed in OPL error values, or a new error number defined by you.

The error is handled by the error processing mechanism currently in use — either OPL’s own, which stops the program and displays an error message, or the ONERR handler if you have ONERR on.

RANDOMIZE — Seeds the random number generator

Usage: RANDOMIZE x&

Gives a ‘seed’ (start-value) for RND.

Successive calls of the RND function produce a sequence of pseudo-random numbers. If you use RANDOMIZE to set the seed back to what it was at the beginning of the sequence, the same sequence will be repeated.

For example, you might want to use the same ‘random’ values to test new versions of a procedure. To do this, precede the RND statement with the statement RANDOMIZE value. Then to repeat the sequence, use RANDOMIZE value again.

Example:

    PROC SEQ:
          LOCAL g$(1)
          WHILE 1
                PRINT "S: set seed to 1"
                PRINT "Q: quit"
                PRINT "other key: continue"
                g$=UPPER$(GET$)
                IF g$="Q"
                      BREAK
                ELSEIF g$="S"
                      PRINT "Setting seed to 1"
                      RANDOMIZE 1
                      PRINT "First random no:"
                ELSE
                      PRINT "Next random no:"
                ENDIF
                PRINT RND
          ENDWH
    ENDP

REALLOC — Changes the size of a previously allocated cell

Usage: pcelln&=REALLOC(pcell&,size&)

Change the size of a previously allocated cell at pcell& to size&, returning the new cell address or zero if there is not enough memory.

See also SETFLAGS if you require the 64K limit to be enforced. If the flag is set to restrict the limit, pcelln& is guaranteed to fit into an integer.

See also Dynamic memory allocation.

ARM

Cells are allocated lengths that are the smallest multiple of four greater than the size requested because the ARM processor requires a four-byte word alignment for its memory allocation. The ARM processor is used in the Psion Series 5 and other EPOC devices.

REM — Comment marker

Usage: REM text

Precedes a remark you include to explain how a program works. All text after the REM up to the end of the line is ignored.

When you use REM at the end of a line you need only precede it with a space, not a space and a colon.

Examples:

    INPUT a :b=a*.175  REM b=TAX
    INPUT a :b=a*.175  : REM b=TAX

RENAME — Renames files

Usage: RENAME file1$,file2$

Renames file1$ as file2$. You can rename any type of file.

You cannot use wildcards.

You can rename across directories RENAME "\dat\xyz.abc","\xyz.abc" is OK. If you do this, you can choose whether or not to change the name of the file.

Example:

    PRINT "Old name:" :INPUT a$
    PRINT "New name:" :INPUT b$
    RENAME a$,b$

REPT$ — Repeats a string

Usage: r$=REPT$(a$,x%)

Returns a string comprising x% repetitions of a$.

For example, if a$="ex", r$=REPT$(a$,5) returns exexexexex.

RETURN — Returns from a procedure

Usage: RETURN
or RETURN variable

Terminates the execution of a procedure and returns control to the point where that procedure was called (ENDP does this automatically).

RETURN variable does this as well, but also passes the value of variable back to the calling procedure. The variable may be of any type. You can return the value of any single array element - for example RETURN x%(3). You can only return one variable.

RETURN on its own, and the default return through ENDP, causes the procedure to return the value 0 or a null string.

Example:

RIGHT$ — Gets the rightmost characters of string

Usage: r$=RIGHT$(a$,x%)

Returns the rightmost x% characters of a$.

Example:

    PRINT "Enter name/ref",
    INPUT c$
    ref$=RIGHT$(c$,4)
    name$=LEFT$(c$,LEN(c$)-4)

ROLLBACK — Cancels the current transaction on the current view

Usage: ROLLBACK

Cancels the current transaction on the current view. Changes made to the database with respect to this particular view since BEGINTRANS was called will be discarded.

See also BEGINTRANS, COMMITTRANS.

RMDIR — Removes directories

Usage: RMDIR str$

Removes the directory given by str$. You can only remove empty directories.

RND — Gets a pseudo-random floating point number

Usage: r=RND

Returns a pseudo-random floating-point number in the range 0 (inclusive) to 1 (exclusive).

To produce random numbers between 1 and n e.g. between 1 and 6 for a dice use the following statement: f%=1+INT(RND*n)

RND produces a different number every time it is called within a program. A fixed sequence can be generated by using RANDOMIZE. You might begin by using RANDOMIZE with an argument generated from MINUTE and SECOND (or similar), to seed the sequence differently each time.

Example:

    PROC rndvals:
          LOCAL i%
          PRINT "Random test values:"
          DO
                PRINT RND
                i%=i%+1
                GET
          UNTIL i%=10
    ENDP


SCI$ — SUM

Contents

  • SCI$ — Converts a number to scientific format
  • SCREEN — Changes the size of the text window
  • SCREENINFO — Gets information about the text screen
  • SECOND — Gets the current time in seconds
  • SECSTODATE — Converts seconds to date
  • SETDOC — Sets a file to be a document
  • SETFLAGS — Sets an application’s flags
  • SETPATH — Sets the path for file access
  • SIN — Sine
  • SPACE — Gets space available on the current file’s device
  • SQR — Square root
  • STD — Standard deviation
  • STOP — Stops the running program
  • STYLE — Sets the text window character style
  • SUM — Sums a list of numeric items

SCI$ — Converts a number to scientific format

Usage: s$=SCI$(x,y%,z%)

Returns a string representation of x in scientific format, to y% decimal places and up to z% characters wide.

Examples:

    SCI$(123456,2,8)="1.23E+05"
    SCI$(1,2,8)="1.00E+00"
    SCI$(1234567,1,-8)=" 1.2E+06"

If the number does not fit in the width specified then the returned string contains asterisks.

If z% is negative then the string is right-justified.

See also FIX$, GEN$, NUM$.

SCREEN — Changes the size of the text window

Usage: SCREEN width%,height%
or SCREEN width%,height%,x%,y%

Changes the size of the window in which text is displayed. x%,y% specify the character position of the top left corner; if they are not given, the text window is centred in the screen.

An OPL program can initially display text to the whole screen.

See SCREENINFO.

SCREENINFO — Gets information about the text screen

Usage: SCREENINFO var info%()

Gets information on the text screen (as used by PRINT, SCREEN etc.)

This keyword allows you to mix text and graphics. It is required because while the default window is the same size as the physical screen, the text screen is slightly smaller and is centred in the default window. The few pixels gaps around the text screen, referred to as the left and top margins, depend on the font in use.

On return, info%() contains the information. info%() must have at least 10 elements. The information is returned at the following indices in info%().

KSinfoALeft% | 1 | Left margin in pixels.
KSinfoATop% | 2 | Top margin in pixels.
KSinfoAScrW% | 3 | Text screen width in character units.
KSinfoAScrH% | 4 | Text screen height in character units.
KSinfoAReserved1% | 5 | Reserved (window server id for default window).
KSinfoAFont% | 6 | Unused (font ID for older systems).
KSinfoAPixW% | 7 | Pixel width of text window character cell.
KSinfoAPixH% | 8 | Pixel height of text window character cell.
KSinfoAReserved2% | 9 | Least significant 16 bits of the font ID.
KSinfoAReserved3% | 10 | Most significant 16 bits of the font ID.

These constants are supplied in Const.oph.

The font ID is a 32-bit integer under EPOC, and therefore would not fit into a single element of info%(). Hence, the least significant 16 bits of the font ID are returned to info%(9) and the most significant 16 bits to info%(10).

Initially SCREENINFO returns the values for the initial text screen. Subsequently any keyword which changes the size of the text screen font, such as FONT or SCREEN, will change some of these values and SCREENINFO should therefore be called again.

See also FONT, SCREEN.

SECOND — Gets the current time in seconds

Usage: s%=SECOND

Returns the current time in seconds from the system clock (0 to 59).

E.g. at 6:00:33 SECOND returns 33.

SECSTODATE — Converts seconds to date

Usage: SECSTODATE s&,var yr%,var mo%,var dy%,var hr%,var mn%, var sc%,var yrday%

Sets the variables passed by reference to the date corresponding to s&, the number of seconds since 00:00 on 1/1/1970. yrday% is set to the day in the year (1-366).

s& is an unsigned long integer. To use values greater than +2147483647, subtract 4294967296 from the value.

See also DATETOSECS, HOUR, MINUTE, SECOND, dDATE, DAYS.

SETDOC — Sets a file to be a document

Usage: SETDOC file$

Sets the file file$ to be a document. This command should be called immediately before the creation of file$ if it is to be recognised as a document. SETDOC may be used with the commands CREATE, gSAVEBIT and IOOPEN.

The string passed to SETDOC must be identical to the name passed to the following CREATE or gSAVEBIT otherwise a non-document file will be created. Example of document creation:

    SETDOC "myfile"
    CREATE "myfile",a,a$,b$

SETDOC should also be called after successfully opening a document to allow the System screen to display the correct document name in its task list.

SETDOC also adds the current document name to the Recent files list on the System screen. Selecting a document from the Recent files list will cause the EPOC to launch the document just as if it had been started from the system screen with a tap-while-selected. Applications which already use SETDOC require no code changes or re-translations to use this new feature.

In case of failure in creating or opening the required file, you should take the following action:

  • Creating — try to re-open the last file and if this fails display an appropriate error dialog and exit. On reopening, call SETDOC back to the original file so the Task list is correct.
  • Opening — as for creating, but calling SETDOC again is not strictly required.

Database documents, created using CREATE, and multi-bitmap documents, created using gSAVEBIT, will automatically contain your application UID in the file header. For binary and text file documents created using IOOPEN and LOPEN, it is the programmer’s responsibility to save the appropriate header in the file. This is a fairly straight-forward process and the following suggests one way of finding out what the header should be:

  1. Create a database or bitmap document in a test run of you application using SETDOC as shown above
  2. Use a hex editor or hex dump program to find the 1st 16 bytes, or run the program below which reads the four long integer UIDs from the test document.
  3. Write these four long integers to the start of the file you create using IOOPEN.
    INCLUDE "Const.oph"
    DECLARE EXTERNAL
    EXTERNAL readUids:(file$)

    PROC main:
          LOCAL f$(255)
          WHILE 1
                dINIT "Show UIDs in document header"
                dPOSITION 1,0
                dFILE f$,"Document,Folder,Drive",0
                IF DIALOG=0
                      RETURN
                ENDIF
                readUids:(f$)
          ENDWH
    ENDP

    PROC readUids:(f$)
          LOCAL ret%,h%
          LOCAL uid&(4),i%
          ret%=IOOPEN(h%,f$,KIoOpenModeOpen% OR KIoOpenFormatBinary%)
          IF ret%>=0
                ret%=IOREAD(h%,ADDR(uid&()),16)
                PRINT "Reading ";f$
                IF ret%=16
                      WHILE i%<4
                            i%=i%+1
                            PRINT "  Uid"+num$(i%,1)+"=",hex$(uid&(i%))
                      ENDWH
                ELSE
                      PRINT "  Error reading: ";
                      IF ret%<0
                            PRINT err$(ret%)
                      ELSE
                            PRINT "Read ";ret%;" bytes only ";
                            PRINT "(4 long integers required)"
                      ENDIF
                ENDIF
                IOCLOSE(h%)
          ELSE
                PRINT "Error opening: ";ERR$(ret%)
          ENDIF
    ENDP

Creating text file documents using IOOPEN or LOPEN has two special requirements:

  • You will need to save the required header as the first text record. This will insert the standard text file line delimiters CR LF (hex 0D 0A) at the end of the record.
  • The specific 16 bytes required for your application may itself however contain CR LF. Since you should know when this is the case, you will need to read records until you have reached byte 16 in the document. This is clearly not a desirable state of affairs but is inescapable given that text files were not designed to have headers. It is recommended that you request a new UID for your application if it contains CR LF.

See also GETDOC$ and OPL applications.

SETFLAGS — Sets an application’s flags

Usage: SETFLAGS flags&

Sets flags to produce various effects when running programs. Use CLEARFLAGS to clear any flags which have been set. flags& is formed by adding one or more of the following values.

KRestrictTo64K& | 1 | restricts the memory available to your application to 64K, emulating an older 16-bit machine. This setting should be used at the beginning of your program only, if required. Changing this setting repeatedly will have unpredictable effects.
KAutoCompact& | 2 | enables auto-compaction on closing databases. This can be slow, but it is advisable to use this setting when lots of changes have been made to a database.
KTwoDigitExponent& | 4 | enables raising of overflow errors when floating-point values are greater than or equal to 1.0E+100 in magnitude, instead or allowing 3-digit exponents (for backwards compatibility)
KSendSwitchOnMessage& | $10000 | enables GETEVENT, GETEVENT32 and GETEVENT32A to return the event code $403 to ev&(1) when the machine switches on

These constants are supplied in Const.oph.

By default these flags are cleared.

See Advanced Topics and Database File Handling.

See also GETEVENT32, CLEARFLAGS.

SETPATH — Sets the path for file access

Usage: SETPATH name$

Sets the current path for file access for example,

    SETPATH "C:\Documents\".

SETPATH needs the final backslash to be passed otherwise it ignores everything beyond the last backslash. LOADM continues to use the path of the initial program, but all other file access will use the new path.

SIN — Sine

Usage: s=SIN(angle)

Returns the sine of angle, an angle expressed in radians.

To convert from degrees to radians, use the RAD function.

SPACE — Gets space available on the current file’s device

Usage: s&=SPACE

Returns the number of free bytes on the device on which the current (open) data file is held.

SQR — Square root

Usage: s=SQR(x)

Returns the square root of x.

STD — Standard deviation

Usage: s=STD(list)
or s=STD(array(),element)

Returns the standard deviation of a list of numeric items.

The list can be either:

  • A list of variables, values and expressions, separated by commas

or

  • The elements of a floating-point array.

When operating on an array, the first argument must be the array name followed by (). The second argument, separated from the first by a comma, is the number of array elements you wish to operate on for example m=STD(arr(),3) would return the standard deviation of elements arr(1), arr(2) and arr(3).

This function gives the sample standard deviation, using the formula:

To convert to population standard deviation, multiply the result by SQR((n-1)/n).

STOP — Stops the running program

Usage: STOP

Ends the running program.

Note that STOP may not be used during an OPX callback and will raise the error ‘STOP used in callback’ if it is. See Callbacks from OPX procedures.

STYLE — Sets the text window character style

Usage: STYLE style%

Sets the text window character style. style% can be 2 for underlined, or 4 for inverse.

See The text and graphics windows for more details.

SUM — Sums a list of numeric items

Usage: s=SUM(list)
or s=SUM(array(),element)

Returns the sum of a list of numeric items.

The list can be either:

  • A list of variables, values and expressions, separated by commas

or

  • The elements of a floating-point array.

When operating on an array, the first argument must be the array name followed by (). The second argument, separated from the first by a comma, is the number of array elements you wish to operate on for example m=SUM(arr(),3) would return the sum of elements arr(1), arr(2) and arr(3).


TAN — TRAP RAISE

Contents

  • TAN — Tangent
  • TESTEVENT — Tests if an event has occurred
  • TRAP — Traps errors
  • TRAP RAISE — Clears the trap flag

TAN — Tangent

Usage: t=TAN(angle)

Returns the tangent of angle, an angle expressed in radians.

To convert from radians to degrees, use the DEG function.

TESTEVENT — Tests if an event has occurred

Usage: t%=TESTEVENT

Returns ‘True’ if an event has occurred, otherwise returns ‘False’. The event is not read by TESTEVENT - it may be read with GETEVENT, GETEVENT32, or GETEVENTA32.

Warning: it is recommended that you use either GETEVENT32 or GETEVENTA32 without TESTEVENT as TESTEVENT may use a lot of power, especially when used in a loop as will often be the case.

TRAP — Traps errors

Section Contents

  • Trapping data file commands
  • Trapping file commands
  • Trapping directory commands
  • Trapping data entry commands
  • Trapping graphics commands

Usage: TRAP command

TRAP is an error handling command. It may precede any of these commands:

Trapping data file commands

APPEND, UPDATE, BACK, NEXT, LAST, FIRST, POSITION, USE, CREATE, OPEN, OPENR, CLOSE, DELETE, MODIFY, INSERT, PUT, CANCEL

Trapping file commands

COPY, ERASE, RENAME, LOPEN, LCLOSE, LOADM, UNLOADM

Trapping directory commands

MKDIR, RMDIR

Trapping data entry commands

EDIT, INPUT

Trapping graphics commands

gSAVEBIT, gCLOSE, gUSE, gUNLOADFONT, gFONT, gPATT, gCOPY

For example, TRAP FIRST.

Any error resulting from the execution of the command will be trapped. Program execution will continue at the statement after the TRAP statement, but ERR will be set to the error code.

TRAP overrides any ONERR.

TRAP RAISE — Clears the trap flag

Usage: TRAP RAISE x%

Sets the value of ERR to x% and clears the trap flag.

For a full explanation of the use of RAISE, see Runtime errors — Handling errors reported while running programs.


UADD — USUB

Contents

  • UADD — Adds two unsigned integers
  • UNLOADM — Unloads a module
  • UNTIL — See DO
  • UPDATE — Deletes the current record and saves as a new record at the end of the file
  • UPPER$ — Converts a string to upper case
  • USE — Selects a data file
  • USUB — Subtracts two unsigned integers

UADD — Adds two unsigned integers

Usage: i%=UADD(val1%, val2%)

Add val1% and val2%, as if both were unsigned integers with values from 0 to 65535. Prevents integer overflow for pointer arithmetic when the 64K memory restriction is set (see SETFLAGS), e.g. UADD(ADDR(text$),1) should be used instead of ADDR(text$)+1.

One argument would normally be a pointer and the other an offset expression.

Note that UADD and USUB should not be used on the for pointer arithmetic unless SETFLAGS has been used to enforce the 64K memory limit. In general, long integer arithmetic should be used for pointer arithmetic.

See also USUB.

UNLOADM — Unloads a module

Usage: UNLOADM module$

Removes from memory the module module$ loaded with LOADM.

module$ is a string containing the name of the translated module.

The procedures in an unloaded module cannot then be called by another procedure.

UNLOADM causes any procedures in the module that are not still running to be unloaded from memory too. Running procedures are unloaded on return. It is considered bad practice, however, to use UNLOADM on a module with procedures that are still running.

Once LOADM has been called, procedures loaded stay in memory until the module is unloaded. Modules are not flushed automatically.

UNTIL — See DO

See DO.

UPDATE — Deletes the current record and saves as a new record at the end of the file

Usage: UPDATE

Warning: This function is deprecated and included only for compatibility with older versions of the OPL language. INSERT, PUT, and CANCEL should be used in preference to APPEND and UPDATE, although APPEND and UPDATE are still supported. However, note that APPEND can generate a lot of extra (intermediate) erased records. COMPACT should be used to remove them, or alternatively use SETFLAGS to set auto-compaction on.

Deletes the current record in the current data file and saves the current field values as a new record at the end of the file.

This record, now the last in the file, remains the current record.

Example:

    A.count=129
    A.name$="Brown"
    UPDATE

Use APPEND to save the current field values as a new record.

UPPER$ — Converts a string to upper case

Usage: u$=UPPER$(a$)

Converts any lower case characters in a$ to upper case, and returns the completely upper case string. Example:

    ...
    CLS :PRINT "Y to continue"
    PRINT "or N to stop."
    g$=UPPER$(GET$)
    IF g$="Y"
          nextproc:
    ELSEIF g$="N"
          RETURN
    ENDIF
    ...

Use LOWER$ to convert to lower case.

USE — Selects a data file

Usage: USE logical name

Selects the data file with the given logical name (A-Z). The file must previously have been opened with OPEN, OPENR or CREATE and not yet be closed.

All the record handling commands (such as POSITION and UPDATE, and GOTOMARK, INSERT, MODIFY, CANCEL and PUT) then operate on this file.

USUB — Subtracts two unsigned integers

Usage: i%=USUB(val1%,val2%)

Subtract val2% from val1%, as if both were unsigned integers with values from 0 to 65535. Prevents integer overflow for pointer arithmetic when the 64K memory restriction is set (see SETFLAGS)

Note that UADD and USUB should not be used for pointer arithmetic unless SETFLAGS has been used to enforce a 64K memory limit. In general long integer arithmetic should be used.

See also UADD.


VAL — VECTOR

Contents

  • VAL — Converta numeric string to floating point number
  • VAR — Gets variance of a list of items
  • VECTOR — Jumps to a numbered label

VAL — Converta numeric string to floating point number

Usage: v=VAL(numeric string)

Returns the floating-point number corresponding to a numeric string.

The string must be a valid number e.g. not "5.6.7" or "196f". Expressions, such as "45.6*3.1", are not allowed. Scientific notation such as "1.3E10", is OK.

E.g. VAL("470.0") returns 470

See also EVAL.

VAR — Gets variance of a list of items

Usage: v=VAR(list)
or v=VAR(array(),element)

Returns the variance of a list of numeric items.

The list can be either:

  • A list of variables, values and expressions, separated by commas

or

  • The elements of a floating-point array.

When operating on an array, the first argument must be the array name followed by (). The second argument, separated from the first by a comma, is the number of array elements you wish to operate on for example m=VAR(arr(),3) would return the variance of elements arr(1), arr(2) and arr(3).

This function gives the sample variance, using the formula:

To convert to population variance, multiply the result by (n-1)/n

VECTOR — Jumps to a numbered label

Usage:

    VECTOR i%
          label1,label2,...,labelN
    ENDV

VECTOR i% jumps to label number i% in the list. If i% is 1 this will be the first label, and so on. The list is terminated by the ENDV statement. The list may spread over several lines, with a comma separating labels in any one line but no comma at the end of each line.

If i% is not in the range 1 to N, where N is the number of labels, the program continues with the statement after the ENDV statement.

See also GOTO.


WEEK — WHILE...ENDWH

Contents

  • WEEK — Gets the week in which a specified day falls
  • WHILE...ENDWH — Conditional loop

WEEK — Gets the week in which a specified day falls

Usage: w%=WEEK(day%,month%,year%)

Returns the week number in which the specified day falls, as an integer between 1 and 53.

day% must be between 1 and 31, month% between 1 and 12, year% between 0 and 9999.

Each week is taken to begin on the ‘Start of week’ day, as specified in the Control Panel. When a year begins on a different day to the start of the week, it counts as week 1 if there are four or more days before the next week starts.

The System setting of the ‘Start of week’ may be checked from inside OPL by using the LCSTARTOFWEEK&: procedure in the Date OPX. The week number in the year may also be calculated by different rules and also with your own choice of the start of year by using the procedure DTWEEKNOINYEAR&: in Date OPX.

See Date.opx — Date and time manipulation for more details.

WHILE...ENDWH — Conditional loop

Usage:

    WHILE expression
          ...
    ENDWH

Repeatedly performs the set of instructions between the WHILE and the ENDWH statement, so long as expression returns true (non-zero).

If expression is not true, the program jumps to the line after the ENDWH statement.

Every WHILE must be closed with a matching ENDWH.

See also DO...UNTIL and Control structures.


YEAR

YEAR — Gets the current year

Usage: y%=YEAR

Returns the current year as an integer from the system clock.

For example, on 5th May 1997 YEAR returns 1997.

EPOC SDK Home Glossary Previous Up


Using OPL Extensions (OPXs)

  • About OPXs
  • Bmp.opx — Sprites and bitmaps
  • Contact.opx — The Contacts engine
  • Date.opx — Date and time manipulation
  • dBase.opx — Database handling
  • dbUtils.opx — Additional DBMS functionality
  • Printer.opx — Printer and text handling
  • SysRam1.opx — Additional OPL functionality
  • System.opx — EPOC system functions


About OPXs

Contents

  • OPX header files
  • Compatibility
  • Callbacks from OPX procedures

OPL can use language extensions provided in separate DLLs written specially for OPL support. These DLLs have the file extension .opx.

It is not within the scope of this manual to cover how to develop OPXs yourself, as it requires knowledge of the C++ language. If you require details of how to do this, you should obtain a copy of the EPOC C++ Software Development Kit (SDK) from Symbian Ltd.

A maximum of 255 OPXs can be used in any one OPL module and any OPX may have up to 65535 procedures defined in it. If these values are exceeded then errors are reported at translate-time (see Error Handling).

With OPXs, the OPL programmer is sometimes given direct access to objects via pointers (for efficiency). Otherwise sprites, for example, could not be set up using an array of IDs. These objects can be explicitly deleted to free memory or else they will be deleted when the program exits.

OPX header files

The OPX supplier provides an OXH header file. This provides the declaration for the OPX, specifying its name UID and version number (see below), followed by its procedure prototypes.

The new INCLUDE keyword is used to include these header files. Alternatively, the declaration can be inserted directly into the OPL file, i.e.

    DECLARE OPX <opxName>,<uid>,<version>
          <protoType1> : <ordinal1>
          <protoType2> : <ordinal2>
          ...
    END DECLARE

where,

<name> is the name of the OPX without the .OPX extension. The OPX is stored in a \System\Opx\ folder on any drive, with the drives scanned from Y: to A: and then Z: if no path is specified. This allows ROM OPXs (in Z:) to be overridden if required.

<uid> is the UID of the OPX. The specification of a UID as well as a name guards against OPXs being with the same name being confused, which could otherwise cause serious problems. The UID is checked on loading the OPX and a ‘Not supported’ error will result if the UIDs in the header file and in the OPX itself do not match.

<version> is the version number of the OPX. The version number of an OPX will be increased when any new procedures are added. OPL will refuse to load an OPX which reports that it can’t support the version number given in the declaration. The version number expressed in hex is e.g. $0100 to represent version 1.00, $0102 for version 1.02 etc. In general, an OPX supplier will increment the 2 low digits (the so-called minor version number) for backward compatible changes, and will increment the 2 high digits for major incompatible changes.

<prototype> specifies the name, return type and parameters of an OPX procedure in the same way as for an OPL procedure when using the EXTERNAL keyword. Numeric parameters to OPX procedure can be passed by reference using BYREF. This means that the value of the variable can be changed by the OPX procedure. The OPX procedure prototype is followed additionally by a colon and then the

<ordinal> specifies the ordinal number of the procedure in the OPX itself. This is used to call the correct procedure, i.e. the OPX is linked by ordinal.

If an OPX procedure name clashes with one of your OPL procedures, or with that of another OPX procedure, you can make a copy of the OXH file and change the name of the offending procedures, but not the return type, parameter list or ordinal. You should then include this new OXH file in your module and the new name can then be used to refer to the procedure in your code.

For example, consider the OPX declaration,

    DECLARE OPX XXOpx,XXOpxUid&,XXOpxVersion&
          XXClose%:(id&) : 1
          ProcWithLongParam:(aLong&) : 2
          AddOneToParams:(BYREF par1%,BYREF par2&, BYREF par3) : 3
    END DECLARE

If a short integer is passed to ProcWithLongParam:, the translator will automatically convert it to a long integer.

The AddOneToParams: procedure adds one to each of the parameters. This is possible because the parameters are passed by reference using BYREF. Parameters passed by reference must be variables rather than constant values because the OPX will write back to the variable. The variable type must always be the same as given in the declaration.

Compatibility

ER5 WINS OPXs are not useable on the ER3 EPOC Emulator, and ER3 WINS OPXs will not work on the ER5 Emulator. However, ER5 MARM OPXs will work on ER3 EPOC devices, and ER3 MARM OPXs will work under ER5.

Callbacks from OPX procedures

An OPX procedure can call back to a module procedure. This is often useful if the OPX needs some information that is not known when the OPX procedure is initially called, or if it requires a large amount of data which needs to be sent piecemeal.

The OPX provider will specify the exact form of the procedure which you must provide.

Note that STOP may not be used during an OPX callback and will raise the error ‘STOP used in callback’ if it is. See STOP in Keyword Reference.


Bmp.opx — Sprites and bitmaps

Contents

  • Overview
    • Compatibility
  • BITMAPLOAD&:
  • BITMAPUNLOAD:
  • BITMAPDISPLAYMODE&:
  • SPRITECREATE&:
  • SPRITEAPPEND:
  • SPRITECHANGE:
  • SPRITEDRAW:
  • SPRITEPOS:
  • SPRITEDELETE:
  • SPRITEUSE:

Overview

To use this OPX, you must include the header file Bmp.oxh, which contains the following declaration:

    DECLARE OPX BMP,&10000258,$100
          BITMAPLOAD&:(name$,index&) : 1
          BITMAPUNLOAD:(id&) : 2
          BITMAPDISPLAYMODE&:(id&) : 3
          SPRITECREATE&:(winId%,x&,y&,flags&) : 4
          SPRITEAPPEND:(time&,bitmap&,maskBitmap&,invertMask&,dx&,dy&) : 5
          SPRITECHANGE:(index&,time&,bitmap&,maskBitmap&,invertMask&,dx&,dy&) : 6
          SPRITEDRAW:() : 7
          SPRITEPOS:(x&,y&) : 8
          SPRITEDELETE:(id&) : 9
          SPRITEUSE:(id&) : 10
    END DECLARE

Compatibility

ER5 WINS OPXs are not useable on the ER3 EPOC Emulator, and ER3 WINS OPXs will not work on the ER5 Emulator. However, ER5 MARM OPXs will work on ER3 EPOC devices, and ER3 MARM OPXs will work under ER5.

BITMAPLOAD&:

Usage: id&=BITMAPLOAD&:(name$,index&)

Loads a bitmap from the file name$ (in the current directory if no other is specified). If the file contains more than one bitmap, then index& specifies which bitmap to load. The first (or only) bitmap is specified by index& having the value 0. The value returned is the ID of the open bitmap, which may be used to refer to it when calling sprite procedures or when using gBUTTON, for example.

See BITMAPUNLOAD:.

BITMAPUNLOAD:

Usage: BITMAPUNLOAD:(id&)

Unloads the bitmap whose ID is id&. You can call BITMAPUNLOAD: immediately after passing the bitmap ID to gBUTTON or, if used with the Sprite OPX procedures, after drawing the sprite, as the access count on a bitmap is incremented to ensure it is not unloaded prematurely.

See BITMAPLOAD&:.

BITMAPDISPLAYMODE&:

Usage: mode&=BITMAPDISPLAYMODE&:(id&)

Returns the graphics mode of the bitmap with ID id&. The graphics mode is that specified at its creation (see gCREATEBIT), i.e. 0 for 2-colour mode, 1 for 4-colour mode and 2 for 16-colour mode.

SPRITECREATE&:

Usage: id&=SPRITECREATE&:(winId%,x&,y&,flags&)

Initialises a sprite in the window given by winId% with its top left-hand corner at x&,y&. The value of flags& determines whether or not the sprite’s members are flashing. If (flags& AND 1)=1 then they are flashing and if the value is 0 then they are not. The value returned is the ID of the sprite which should be used when referring to it in other sprite procedures.

See SPRITEAPPEND:, SPRITECHANGE:, SPRITEDRAW:, SPRITEPOS:, SPRITEDELETE:, SPRITEUSE:.

SPRITEAPPEND:

Usage: SPRITEAPPEND:(time&,bitmap&,maskBitmap&,invertMask&,dx&,dy&)

Appends members or frames to the current sprite, which must have been created using CREATESPRITE&: before attempting to append to it. bitmap& is the ID of the bitmap to be used for this member of the sprite, and maskBitmap& is the ID of the bitmap to be used as a mask. The bitmap and mask must be of identical sizes. invertMask& takes the value of 1 or 0 to determine whether the mask is to be inverted or not respectively. For example, if you are using identical bitmap and mask and invertMask&=1 then the member will appear as the bitmap, whereas if invertMask&=0, the member will be blank. time& is the period of time in microseconds for which the member appears in the sprite and dx&,dy& is the offset position of the top left-hand of the bitmap from the top left-hand corner of the sprite.

See SPRITECHANGE:.

SPRITECHANGE:

Usage: SPRITECHANGE:(id&,time&,bitmap&,maskBitmap&,invertMask&,dx&,dy&)

Changes a member of a sprite originally set up with SPRITEAPPEND.

id& specifies the number of the sprite member which is to be changed. This number is determined by the order in which the members were originally appended, the first member to be appended being labelled 0. bitmap& is the ID of the bitmap to be used for this member of the sprite, and maskBitmap& is the ID of the bitmap to be used as a mask. The bitmap and mask must be of identical sizes. invertMask& takes the value of 1 or 0 to determine whether the mask is to be inverted or not respectively. For example, if you are using identical bitmap and mask and invertMask&=1 then the member will appear as the bitmap, whereas if invertMask&=0, the member will be blank. time& is the period of time in microseconds for which the member appears in the sprite and dx&,dy& is the offset position of the top left-hand of the bitmap from the top left-hand corner of the sprite.

A sprite may not be changed unless it has already been drawn.

See SPRITEAPPEND:, SPRITEDRAW:.

SPRITEDRAW:

Usage: SPRITEDRAW:

Draws the sprite once it has been set up. It need only be called once, and any changes made to the sprite are made as soon as the procedure making the change is called. The sprite will be drawn in the window and at the position specified by the arguments passed to SPRITECREATE.

See SPRITECREATE&:, SPRITEAPPEND:, SPRITECHANGE:, SPRITEPOS:.

SPRITEPOS:

Usage: SPRITEPOS:(x&,y&)

Repositions the whole of the current sprite to the point x&,y&.

See SPRITECREATE&:,SPRITEDRAW:.

SPRITEDELETE:

Usage: SPRITEDELETE:(id&)

Deletes the sprite with ID id&.

SPRITEUSE:

Usage: SPRITEUSE:(id&)

Sets the current sprite to be that with ID id& in order that it may be changed.

See SPRITECHANGE:, SPRITEPOS:.

Note that using many sprites at one time may cause undesirable effects. Firstly, sprites maybe animated at a slower speed than requested, and secondly the response time to any key or pointer event can be lengthened considerably. The number of sprites which can be drawn at one time without these effects occurring depends mainly on the animation speed: the faster it is the less sprites may be used successfully at one time. As a general rule, it is advisable not to use more than around 20 sprites at any one time when the animation speed is 0.2 sec, but you should experiment to find out what is suitable for your particular program.


Contact.opx — The Contacts engine

Contents

  • Overview
    • Compatibility
  • COCreateContactFile:
  • COOpenContactFile:
  • COCloseContactFile:
  • COCountContacts&:
  • COSortContactFile:
  • COFindContact&:
  • COSortedContactFileAt:
  • COContactId&:
  • COReadContact:
  • COOpenContact:
  • COCloseContact:
  • COCreateContact:
  • COAddNewContact:
  • CODeleteContact:
  • COOpenContactTemplate:
  • COCloseContactTemplate:
  • COContactFieldDisable:
  • COContactFieldIsDisabled%:
  • COSetContactHidden:
  • COIsContactHidden%:
  • COSetContactSystem:
  • COIsContactSystem%:
  • COCompressContactFile:
  • COCompressNeeded%:
  • COContactFieldCount&:
  • COContactFieldArrayAt:
  • COContactFieldFind%:
  • COContactFieldReset:
  • COContactFieldCreate:
  • COContactFieldInsert:
  • COContactFieldAdd:
  • COContactFieldDelete:
  • COContactFieldMove:
  • COContactFieldContent:
  • COContactFieldSetHidden:
  • COContactFieldIsHidden%:
  • COContactFieldSetReadOnly:
  • COContactFieldIsReadOnly%:
  • COContactFieldSetLabel:
  • COContactFieldLabel$:
  • COContactFieldSetMapping:
  • COContactFieldAddType:
  • COContactFieldSetText:
  • COContactFieldSetLong:
  • COContactFieldText$:
  • COContactFieldLength&:
  • COContactFieldLong:

Overview

The Contacts Engine is an EPOC Release 5 resource which provides a central repository for address book information. Clients of the Contacts Engine include the Contacts application and Messaging. Contact data may be synchronized with PC based Personal Information Managers using EPOC Connect.

One of the major benefits of using the Contacts Engine in preference to the Data Model is that the Contacts Engine is server based, rather than file based. This means that multiple applications may have simultaneous access to the data.

Contact OPX gives access to the Contacts Engine. To use this OPX, you must include the header file Contact.oxh, which contains the following declaration:

    CONST KUidContactOpx&=&10003ED7
    CONST KOpxContactVersion%=$100
    DECLARE OPX Contact,KUidContactOpx&,KOpxContactVersion%
          COCreateContactFile:(aFileName$):1
          COOpenContactFile:(aFileName$):2
          COCloseContactFile: :3
          COCountContacts&: :4
          COSortContactFile:(aMappingArray&):5
          COFindContact&:(aString$,aMappingArray&):6
          COSortedContactFileAt:(aIndex&):7
          COContactId&: :8
          COReadContact:(aContactItemId&):9
          COOpenContact:(aContactItemId&):10
          COCloseContact: :11
          COCreateContact: :12
          COAddNewContact: :13
          CODeleteContact: :14
          COOpenContactTemplate: :15
          COCloseContactTemplate: :16
          COContactFieldDisable:(aBool%) :17
          COContactFieldIsDisabled%: :18
          COSetContactHidden:(aHidden%):19
          COIsContactHidden%: :20
          COSetContactSystem:(aSystem%):21
          COIsContactSystem%: :22
          COCompressContactFile: :23
          COCompressNeeded%: :24
          COContactFieldCount&: :25
          COContactFieldArrayAt:(aIndex&):26
          COContactFieldFind%:(aTypeArrayHandle&):27
          COContactFieldReset: :28
          COContactFieldCreate: :29
          COContactFieldInsert:(aIndex&):30
          COContactFieldAdd: :31
          COContactFieldDelete: :32
          COContactFieldMove:(aPosFrom&,aPosTo&):33
          COContactFieldContent:(aContentTypeArray&):34
          COContactFieldSetHidden:(aHidden%):35
          COContactFieldIsHidden%: :36
          COContactFieldSetReadOnly:(aReadOnly%):37
          COContactFieldIsReadOnly%: :38
          COContactFieldSetLabel:(aLabel$):39
          COContactFieldLabel$: :40
          COContactFieldSetMapping:(aMapping&):41
          COContactFieldAddType:(aType&):42
          COContactFieldSetText:(aString$):43
          COContactFieldSetLong:(aStringAddr&,aLength&):44
          COContactFieldText$: :45
          COContactFieldLength&: :46
          COContactFieldLong:(aBufHandle&) :47
    END DECLARE

Compatibility

This OPX is introduced in ER5, and is not available to users of earlier devices.

COCreateContactFile:

Usage: COCreateContactFile: (aFileName$)

Creates a new contacts file with the path and filename aFileName$. Note that filenames other than \system\data\contacts.cdb can not be accessed by the Contacts application.

See COOpenContactFile:.

COOpenContactFile:

Usage: COOpenContactFile: (aFileName$)

Opens an existing contacts file with the path and filename aFileName$. aFileName$ will usually refer to \system\data\contacts.cdb on one of the drives. Due to the Contacts Engine’s server architecture there is no requirement to close the Contacts application in order for an OPL application to gain read/write access to the database. Individual records are locked when write access is needed.

See COCloseContactFile:.

COCloseContactFile:

Usage: COCloseContactFile:

Closes the contacts database which has previously been opened or created.

See COOpenContactFile:, COCreateContactFile:.

COCountContacts&:

Usage: numContacts& = COCountContacts&:

Returns the number of contacts in the contacts database.

COSortContactFile:

Usage: COSortContactFile: (aMappingArray&)

Sorts the contacts database by one or more fields. The fields to sort by are specified by an array of long integers. The first entry in the array is a count of the number of elements in the array, including itself. The remaining entries in the array specify the UIDs of the fields to sort by. Use ADDR() to pass the address of this array as a parameter. Rather than physically sort the records in the database, the OPX creates an internal index array which can be accessed using COSortedContactFileAt:. The following field UIDs are defined in Contacts.oxh:

    CONST KUidCntFieldAddressValue        =&1000130C
    CONST KUidCntFieldPostOfficeValue     =&10004DF4
    CONST KUidCntFieldExtendedAddressValue=&10004DF5
    CONST KUidCntFieldLocalityValue       =&10004DF6
    CONST KUidCntFieldRegionValue         =&10004DF7
    CONST KUidCntFieldPostCodeValue       =&10004DF8
    CONST KUidCntFieldCountryValue        =&10004DF9
    CONST KUidCntFieldCompanyNameValue    =&1000130D
    CONST KUidCntFieldPhoneNumberValue    =&1000130E
    CONST KUidCntFieldGivenNameValue      =&1000137C
    CONST KUidCntFieldFamilyNameValue     =&1000137D
    CONST KUidCntFieldAdditionalNameValue =&1000178A
    CONST KUidCntFieldSuffixNameValue     =&1000178B
    CONST KUidCntFieldPrefixNameValue     =&1000178C
    CONST KUidCntFieldHiddenValue         =&1000178D
    CONST KUidCntFieldEMailValue          =&1000178E
    CONST KUidCntFieldMsgValue            =&1000178F
    CONST KUidCntFieldSmsValue            =&10001790
    CONST KUidCntFieldFaxValue            =&10001791
    CONST KUidCntFieldDefinedTextValue    =&10001792
    CONST KUidCntFieldNoteValue           =&1000401C
    CONST KUidCntFieldBirthdayValue       =&10004034
    CONST KUidCntFieldUrlValue            =&10004035
    CONST KUidCntFieldStorageInlineValue  =&10004036
    CONST KUidCntFieldNoneValue           =&00000000

See COSortedContactFieldAt:

COFindContact&:

Usage: numberFound& = COFindContact&: (aString$, aMappingArray&)

Searches from the beginning of the contacts database for aString$. The fields to be searched are specified in an array of UIDs. The setting up of this array is described above in SortContactFile:

See COSortContactFile:, COSortedContactFileAt:.

COSortedContactFileAt:

Usage: COSortedContactFileAt: (aIndex&)

Moves the current contact pointer. This is set using the index array previously created by a call to COSortContactFile: or COFindContact:. Valid values for aIndex& range from 1 to COCountContacts&: in the case of a sort. For a search, COFindContact returns the number of matching records which acts as an upper bound for aIndex&.

See COSortContactFile:, COFindContact:.

COContactId&:

Usage: contactId& = COContactId&:

Return the ID of the current contact. The returned ID may be stored and used in subsequent calls to COReadContact: and COOpenContact:.

COReadContact:

Usage: COReadContact: (aContactId&)

Moves to the contact record aContactId& and prepares it for read access.

See COOpenContact:, COContactId&:.

COOpenContact:

Usage: COOpenContact: (aContactId&)

Opens the contact record aContactId& for read/write access. As a result of this call, the record will be locked and unavailable for use by other applications. A call must subsequently be made to COCloseContact: to unlock the record.

See COReadContact:.

COCloseContact:

Usage: COCloseContact:

Close the previously opened contact. Current data will be written to the database, and the lock on the record will be removed. A call to COOpenContact: must always be followed by COCloseContact:.

COCreateContact:

Usage: COCreateContact:

Creates a new contact. The fields created are based upon the template. Once data has been added to the contact, it should be written to the database with a call to COAddNewContact:

See COOpenContactTemplate:.

COAddNewContact:

Usage: COAddNewContact:

Add the current contact to the contacts file. This will normally follow a call to COCreateContact:, and the addition of some contact data.

CODeleteContact:

Usage: CODeleteContact:

Sets the deleted flag in the current contact. This will not affect the database until the contact has been closed.

COOpenContactTemplate:

Usage: COOpenContactTemplate:

The contacts engine has a special purpose record: the template. The template is used for creating new empty records. COCreateContact: copies the fields in the template to create the blank record. COOpenContactTemplate: opens the database template. Once a template has been opened, all record and field oriented procedures operate on the template until a call to COCloseContactTemplate: is made.

COCloseContactTemplate:

Usage: COCloseContactTemplate:

Writes the contact template to the contacts database. Any further calls to field procedures will act on the current contact.

See COOpenContactTemplate:.

COContactFieldDisable:

Usage: COContactFieldDisable:(aState%)

In a template, fields may be disabled. A field marked as disabled in the template will not be created in a new contact. aState% is set to 1 to disable a field, and 0 to enable it.

COContactFieldIsDisabled%:

Usage: COContactFieldIsDisabled%:

Checks whether the current field in the template is marked as disabled. A non-zero value is returned if the field is disabled.

COSetContactHidden:

Usage: COSetContactHidden: (aHidden%)

Set the hidden attribute of the current contact. aHidden% is 1 to set the hidden attribute or 0 to clear it. This will not affect the database until the contact has been closed.

See COIsContactHidden%:.

COIsContactHidden%:

Usage: hidden% = COIsContactHidden%:

Checks whether the current contact has the hidden attribute set. Returns a non-zero value if the hidden attribute is set or zero otherwise.

See COSetContactHidden:.

COSetContactSystem:

Usage: COSetContactSystem: (aSystem%)

Set the system attribute of the current contact. aSystem% is 1 to set the system attribute or 0 to clear it. This will not affect the database until the contact has been closed.

See COIsContactSystem%:.

COIsContactSystem%:

Usage: system% = COIsContactSystem%:

Checks whether the current contact has the system attribute set. Returns a non-zero if the system attribute is set or zero otherwise.

See COSetContactSystem:.

COCompressContactFile:

Usage: COCompressContactFile:

Compress the contacts file. Space taken up by deleted contacts is released. Note that the engine may hold on to deleted records until after synchronization, and may not perform a compress at all if the gains are deemed to be small.

See COCompressNeeded%:.

COCompressNeeded%:

Usage: compressNeeded% = COCompressNeeded%:

Checks whether compression is advisable because a lot of space is occupied by deleted records. The call returns a non-zero value if compression is advised.

See COCompressContactFile:.

COContactFieldCount&:

Usage: numberOfFields& = COContactFieldCount&:

Returns the number of fields in the current contact.

COContactFieldArrayAt:

Usage: COContactFieldArrayAt: (aIndex&)

Sets the current field to field number aIndex&. Field numbers range from 1 to COContactFieldCount&:.

COContactFieldFind%:

Usage: index% = COContactFieldFind%: (aTypeArrayHandle&)

Searches for a particular field within the current / template contact field array. The field to search for is specified by an array of long integers. The first entry in the array is a count of the number of elements in the array, including itself. The second entry is a UID from this list (defined in Contacts.oxh):

    CONST KUidCntFieldAddressValue        =&1000130C
    CONST KUidCntFieldPostOfficeValue     =&10004DF4
    CONST KUidCntFieldExtendedAddressValue=&10004DF5
    CONST KUidCntFieldLocalityValue       =&10004DF6
    CONST KUidCntFieldRegionValue         =&10004DF7
    CONST KUidCntFieldPostCodeValue       =&10004DF8
    CONST KUidCntFieldCountryValue        =&10004DF9
    CONST KUidCntFieldCompanyNameValue    =&1000130D
    CONST KUidCntFieldPhoneNumberValue    =&1000130E
    CONST KUidCntFieldGivenNameValue      =&1000137C
    CONST KUidCntFieldFamilyNameValue     =&1000137D
    CONST KUidCntFieldAdditionalNameValue =&1000178A
    CONST KUidCntFieldSuffixNameValue     =&1000178B
    CONST KUidCntFieldPrefixNameValue     =&1000178C
    CONST KUidCntFieldHiddenValue         =&1000178D
    CONST KUidCntFieldEMailValue          =&1000178E
    CONST KUidCntFieldMsgValue            =&1000178F
    CONST KUidCntFieldSmsValue            =&10001790
    CONST KUidCntFieldFaxValue            =&10001791
    CONST KUidCntFieldDefinedTextValue    =&10001792
    CONST KUidCntFieldNoteValue           =&1000401C
    CONST KUidCntFieldBirthdayValue       =&10004034
    CONST KUidCntFieldUrlValue            =&10004035
    CONST KUidCntFieldStorageInlineValue  =&10004036
    CONST KUidCntFieldNoneValue           =&00000000

The third value is a VCard mapping. This is used when synchronizing to other applications using the VCard format:

    CONST KIntCntFieldVCardMapADR             =&1000401D
    CONST KIntCntFieldVCardMapPOSTOFFICE      =&10004DEA
    CONST KIntCntFieldVCardMapEXTENDEDADR     =&10004DEB
    CONST KIntCntFieldVCardMapLOCALITY        =&10004DEC
    CONST KIntCntFieldVCardMapREGION          =&10004DED
    CONST KIntCntFieldVCardMapPOSTCODE        =&10004DEE
    CONST KIntCntFieldVCardMapCOUNTRY         =&10004DEF
    CONST KIntCntFieldVCardMapAGENT           =&1000401E
    CONST KIntCntFieldVCardMapBDAY            =&1000401F
    CONST KIntCntFieldVCardMapEMAILINTERNE    =&10004020
    CONST KIntCntFieldVCardMapGEO             =&10004021
    CONST KIntCntFieldVCardMapLABEL           =&10004022
    CONST KIntCntFieldVCardMapLOGO            =&10004023
    CONST KIntCntFieldVCardMapMAILER          =&10004024
    CONST KIntCntFieldVCardMapNOTE            =&10004025
    CONST KIntCntFieldVCardMapORG             =&10004026
    CONST KIntCntFieldVCardMapPHOTO           =&10004027
    CONST KIntCntFieldVCardMapROLE            =&10004028
    CONST KIntCntFieldVCardMapSOUND           =&10004029
    CONST KIntCntFieldVCardMapTEL             =&1000402A
    CONST KIntCntFieldVCardMapTELFAX          =&1000402B
    CONST KIntCntFieldVCardMapTITLE           =&1000402C
    CONST KIntCntFieldVCardMapURL             =&1000402D
    CONST KIntCntFieldVCardMapUnusedN         =&1000402E
    CONST KIntCntFieldVCardMapUnusedFN        =&1000402F
    CONST KIntCntFieldVCardMapNotRequired     =&10004030
    CONST KIntCntFieldVCardMapUnknownXDash    =&10004031
    CONST KIntCntFieldVCardMapUnknown         =&10004032
    CONST KIntCntFieldVCardMapUID             =&10004033

The remaining entries in the array are used to specify the field more explicitly than is possible using just the VCard mapping above. For example KIntCntFieldVCardMapTEL on it’s own is not sufficient to differentiate a home phone number from a work number. These entries are known as VCard types. Useful VCard types are:

    CONST KIntCntFieldVCardTypeWORK=&100039DA
    CONST KIntCntFieldVCardTypeHOME=&100039DB
    CONST KIntCntFieldVCardTypeMSG=&100039DC
    CONST KIntCntFieldVCardTypeVOICE=&100039DD
    CONST KIntCntFieldVCardTypeFAX=&100039DE
    CONST KIntCntFieldVCardTypePREF=&10003E70
    CONST KIntCntFieldVCardTypeCELL=&10003E71
    CONST KIntCntFieldVCardTypePAGER=&10003E72
    CONST KIntCntFieldVCardTypeBBS=&100039D5
    CONST KIntCntFieldVCardTypeMODEM=&100039D6
    CONST KIntCntFieldVCardTypeCAR=&100039D7
    CONST KIntCntFieldVCardTypeISDN=&100039D8
    CONST KIntCntFieldVCardTypeVIDEO=&100039D9
    CONST KIntCntFieldVCardTypeDOM=&10003E80

By way of example, here are some common fields and the arrays needed to find them:

Field | Entries in array
Title | 3 KUidCntFieldPrefixNameValue KIntCntFieldVCardMapUnusedN
First name | 3 KUidCntFieldGivenNameValue KIntCntFieldVCardMapUnusedN
Middle name | 3 KUidCntFieldAdditionalNameValue KIntCntFieldVCardMapUnusedN
Last name | 3 KUidCntFieldFamilyNameValue KIntCntFieldVCardMapUnusedN
Suffix | 3 KUidCntFieldSuffixNameValue KIntCntFieldVCardMapUnusedN
Mobile | 5 KUidCntFieldPhoneNumberValue KIntCntFieldVCardMapTEL KIntCntFieldVCardTypeHOME KIntCntFieldVCardTypeCELL
Home tel | 4 KUidCntFieldPhoneNumberValue KIntCntFieldVCardMapTEL KIntCntFieldVCardTypeHOME
Home fax | 5 KUidCntFieldFaxValue KIntCntFieldVCardMapTEL KIntCntFieldVCardTypeHOME KIntCntFieldVCardTypeFAX
Pager | 5 KUidCntFieldPhoneNumberValue KIntCntFieldVCardMapTEL KIntCntFieldVCardTypePAGER KIntCntFieldVCardTypeHOME
Home Email | 4 KUidCntFieldEMailValue KIntCntFieldVCardMapEMAILINTERNE KIntCntFieldVCardTypeHOME
Home PO box | 4 KUidCntFieldPostOfficeValue KIntCntFieldVCardMapPOSTOFFICE KIntCntFieldVCardTypeHOME
Home ext address | 4 KUidCntFieldExtendedAddressValue KIntCntFieldVCardMapEXTENDEDADR KIntCntFieldVCardTypeHOME
Home address | 4 KUidCntFieldAddressValue KIntCntFieldVCardMapADR KIntCntFieldVCardTypeHOME
Home city | 4 KUidCntFieldLocalityValue KIntCntFieldVCardMapLOCALITY KIntCntFieldVCardTypeHOME
Home region | 4 KUidCntFieldRegionValue KIntCntFieldVCardMapREGION KIntCntFieldVCardTypeHOME
Home p’code | 4 KUidCntFieldPostcodeValue KIntCntFieldVCardMapPOSTCODE KIntCntFieldVCardTypeHOME
Home country | 4 KUidCntFieldCountryValue KIntCntFieldVCardMapCOUNTRY KIntCntFieldVCardTypeHOME
Company | 3 KUidCntFieldCompanyNameValue KIntCntFieldVCardMapORG
Job title | 2 KIntCntFieldVCardMapTITLE
Work mobile | 5 KUidCntFieldPhoneNumberValue KIntCntFieldVCardMapTEL KIntCntFieldVCardTypeCELL KIntCntFieldVCardTypeWORK
Work tel | 4 KUidCntFieldPhoneNumberValue KIntCntFieldVCardMapTEL KIntCntFieldVCardTypeWORK
Work fax | 5 KUidCntFieldFaxValue KIntCntFieldVCardMapTEL KIntCntFieldVCardTypeWORK KIntCntFieldVCardTypeFAX
Work pager | 5 KUidCntFieldPhoneNumberValue KIntCntFieldVCardMapTEL KIntCntFieldVCardTypePAGER KIntCntFieldVCardTypeWORK
Work email | 4 KUidCntFieldEMailValue KIntCntFieldVCardMapEMAILINTERN KIntCntFieldVCardTypeWORK
Web page | 3 KUidCntFieldUrlValue KIntCntFieldVCardMapURL
Work PO box | 4 KUidCntFieldPostOfficeValue KIntCntFieldVCardMapPOSTOFFICE KIntCntFieldVCardTypeWORK
Work ext address | 4 KUidCntFieldExtendedAddressValue KIntCntFieldVCardMapEXTENDEDADR KIntCntFieldVCardTypeWORK
Work address | 4 KUidCntFieldAddressValue KIntCntFieldVCardMapADR KIntCntFieldVCardTypeWORK
Work city | 4 KUidCntFieldLocalityValue KIntCntFieldVCardMapLOCALITY KIntCntFieldVCardTypeWORK
Work region | 4 KUidCntFieldRegionValue KIntCntFieldVCardMapREGION KIntCntFieldVCardTypeWORK
Work p’code | 4 KUidCntFieldPostcodeValue KIntCntFieldVCardMapPOSTCODE KIntCntFieldVCardTypeWORK
Work country | 4 KUidCntFieldCountryValue KIntCntFieldVCardMapCOUNTRY KIntCntFieldVCardTypeWORK
Birthday | 3 KUidCntFieldBirthdayValue KIntCntFieldVCardMapBDAY
Notes | 3 KUidCntFieldNoteValue KIntCntFieldVCardMapNOTE

COContactFieldReset:

Usage: COContactFieldReset:

Deletes all the fields in the current contact. Attempting to use this procedure on the template will result in a KErrAccess% error.

COContactFieldCreate:

Usage: COContactFieldCreate:

Creates an empty field which can be added / inserted to the current contact / template.

See COContactFieldInsert:, COContactFieldAdd:

COContactFieldInsert:

Usage: COContactFieldInsert: (aIndex&)

Inserts a field into the current contact at the position aIndex&. The field should be created first with COContactFieldCreate: Field numbering starts at 1.

COContactFieldAdd:

Usage: COContactFieldAdd:

Appends an empty new field to the current contact. The field should be created first with COContactFieldCreate:

COContactFieldDelete:

Usage: COContactFieldDelete:

Deletes the current field from the current contact. Any subsequent fields are renumbered.

COContactFieldMove:

Usage: COContactFieldMove: (aPosFrom&, aPosTo&)

Moves a field in the current contact from aPosFrom& to aPosTo&. Field numbering starts at 1.

COContactFieldContent:

Usage: COContactFieldContent: (contentTypeArray&)

Returns a description of the current field in terms of a UID and VCard mappings. The address of a long integer array is passed in contentTypeArray&, which is filled with data as described in COContactFieldFind%:.

COContactFieldSetHidden:

Usage: COContactFieldSetHidden: (aHidden%)

Sets the hidden attribute of the current contact. aHidden% is 1 to set the hidden attribute or 0 to clear it. Setting a field to hidden in the template has a useful effect in the Contacts application. The field will not be added to new records, but will be available in the “Add item” list.

See COContactFieldIsHidden%:.

COContactFieldIsHidden%:

Usage: hidden% = COContactFieldIsHidden%:

Checks whether the current field is hidden. Returns 1 if the hidden attribute is set or 0 otherwise.

See COContactFieldSetHidden:.

COContactFieldSetReadOnly:

Usage: COContactFieldSetReadOnly: (aReadOnly%)

Sets the read only attribute of the current contact. aHidden% is 1 to set the read only attribute or 0 to clear it.

See COContactFieldIsReadOnly%:.

COContactFieldIsReadOnly%:

Usage: readOnly% = COContactFieldIsReadOnly%:

Checks whether the current field is read only. Returns a non-zero value if the read only attribute is set.

See COContactFieldSetReadOnly:.

COContactFieldSetLabel:

Usage: COContactFieldSetLabel: (aLabel$)

Sets the label of the current field.

See COContactFieldLabel$:.

COContactFieldLabel$:

Usage: label$ = COContactFieldLabel$:

Returns the label of the current field.

See COContactFieldSetLabel:

COContactFieldSetMapping:

Usage: COContactFieldSetMapping: (aMapping&)

Sets a field’s VCard mapping. There is one mapping per field.

See COContactFieldFind%:, COContactFieldAddType:

COContactFieldAddType:

Usage: COContactFieldAddType: (aType&)

Sets a field’s Uid or VCard type. There may be multiple VCard types specified for each field. The first call to this procedure adds the Uid, subsequent calls add VCard types.

See COContactFieldFind%:, COContactFieldSetMapping:.

COContactFieldSetText:

Usage: COContactFieldSetText: (aString$)

Assigns a text value to the current field. If a value needs to be set which is longer than the OPL string limit of 255 characters, use COContactFieldSetLong:

COContactFieldSetLong:

Usage: COContactFieldSetLong:(aStringAddr&,aLength)

Assigns a text value to the current field. The value is specified by passing the address of a buffer containing the value, and the length of the text held within it. For short strings, it may be more straightforward to use COContactFieldSetText.

COContactFieldText$:

Usage: string$= COContactFieldText$:

Retrieves the text value of the current field. If the value is longer than 255 characters, it is truncated. To retrieve longer values, use COContactFieldLong:.

COContactFieldLength&:

Usage: length&=COContactFieldLength&:

Returns the length of the current field in characters.

COContactFieldLong:

Usage: COContactFieldLong:(aBufHandle&)

Retrieves the text value of the current field. The value is written to a buffer starting at aBufHandle&. COContactFieldLength& may be used to ensure the buffer is large enough hold the value.

See COContactFieldText$:.


Date.opx — Date and time manipulation

Contents

  • Overview
    • Compatibility
  • DTNEWDATETIME&:
  • DTDELETEDATETIME:
  • DTYEAR&:
  • DTMONTH&:
  • DTDAY&:
  • DTHOUR&:
  • DTMINUTE&:
  • DTSECOND&:
  • DTMICRO&:
  • DTSETYEAR:
  • DTSETMONTH:
  • DTSETDAY:
  • DTSETHOUR:
  • DTSETMINUTE:
  • DTSETSECOND:
  • DTSETMICRO:
  • DTNOW&:
  • DTDATETIMEDIFF:
  • DTYEARSDIFF&:
  • DTMONTHSDIFF&:
  • DTDAYSDIFF&:
  • DTHOURSDIFF&:
  • DTMINUTESDIFF&:
  • DTSECONDSDIFF&:
  • DTMICROSDIFF&:
  • DTWEEKNOINYEAR&:
  • DTDAYNOINYEAR&:
  • DTDAYNOINWEEK&:
  • DTDAYSINMONTH&:
  • DTSETHOMETIME:
  • LCCOUNTRYCODE&:
  • LCDECIMALSEPARATOR$:
  • LCSETCLOCKFORMAT:
  • LCCLOCKFORMAT&:
  • LCSTARTOFWEEK&:
  • LCTHOUSANDSSEPARATOR$:

Overview

To use this OPX, you must include the header file Date.oxh, which contains the following declaration:

    DECLARE OPX DATE,KUidOpxDate&,KOpxDateVersion%
          DTNewDateTime&:(year&,month&,day&,hour&,minute&,second&,
                              micro&) : 1
          DTDeleteDateTime:(id&) : 2
          DTYear&:(id&) : 3
          DTMonth&:(id&) : 4
          DTDay&:(id&) : 5
          DTHour&:(id&) : 6
          DTMinute&:(id&) : 7
          DTSecond&:(id&) : 8
          DTMicro&:(id&) : 9
          DTSetYear:(id&,year&) : 10
          DTSetMonth:(id&,month&) : 11
          DTSetDay:(id&,day&) : 12
          DTSetHour:(id&,hour&) : 13
          DTSetMinute:(id&,minute&) : 14
          DTSetSecond:(id&,second&) : 15
          DTSetMicro:(id&,micro&) : 16
          DTNow&: : 17
          DTDateTimeDiff:(start&,end&,BYREF year&,BYREF month&,
                BYREF day&,BYREF hour&,BYREF minute&,
                BYREF second&,BYREF micro&) : 18
          DTYearsDiff&:(start&,end&) : 19
          DTMonthsDiff&:(start&,end&) : 20
          DTDaysDiff&:(start&,end&) : 21
          DTHoursDiff&:(start&,end&) : 22
          DTMinutesDiff&:(start&,end&) : 23
          DTSecsDiff&:(start&,end&) : 24
          DTMicrosDiff&:(start&,end&) : 25
          DTWeekNoInYear&:(id&,yearstart&,rule&) : 26
          DTDayNoInYear&:(id&,yearstart&) : 27
          DTDayNoInWeek&:(id&) : 28
          DTDaysInMonth&:(id&) : 29
          DTSetHomeTime:(id&) : 30
          LCCountryCode&: : 31
          LCDecimalSeparator$: : 32
          LCSetClockFormat:(format&) : 33
          LCClockFormat&: : 34
          LCStartOfWeek&: : 35
          LCThousandsSeparator$: : 36
    END DECLARE

Compatibility

ER5 WINS OPXs are not useable on the ER3 EPOC Emulator, and ER3 WINS OPXs will not work on the ER5 Emulator. However, ER5 MARM OPXs will work on ER3 EPOC devices, and ER3 MARM OPXs will work under ER5.

DTNEWDATETIME&:

Usage: id&=DTNEWDATETIME&:(year&,month&,day&,hour&,minute&,second&,micro&)

Creates a new date/time object which contains all the supplied date/time components and returns a handle id& for it.

The year is stored as the usual four figure year, e.g. 1997.

The month is stored as 1 for January, 2 for February, etc.

The day is stored as the day number in the month.

The hour is the hour of the day in 12 or 24 hour clock according to the system setting.

The minutes, seconds and microseconds are stored as the usual values 0 to 59 for minutes and seconds and 0 to 999999 for microseconds.

See DTDELETEDATETIME:.

DTDELETEDATETIME:

Usage: DELETEDATETIME:(id&)

Deletes the date/time object with handle id&. This should be called when a date/time object is no longer needed. Date/time objects will be deleted automatically on unloading the Date OPX or the module which uses it.

See DTNEWDATETIME&:, DTNOW&:.

DTYEAR&:

Usage: y&=DTYEAR&:(id&)

Returns the year component y& which is stored in the date/time object with handle id&.

See DTNEWDATETIME&:.

DTMONTH&:

Usage: m&=DTMONTH&:(id&)

Returns the month component m& which is stored in the date/time object with handle id&.

See DTNEWDATETIME&:.

DTDAY&:

Usage: day&=DTDAY&:(id&)

Returns the day component day& which is stored in the date/time object with handle id&.

See DTNEWDATETIME&:.

DTHOUR&:

Usage: h&=DTHOUR&:(id&)

Returns the hour component h& which is stored in the date/time object with handle id&.

See DTNEWDATETIME&:

DTMINUTE&:

Usage: m&=DTMINUTE&:(id&)

Returns the minutes component m& which is stored in the date/time object with handle id&.

See DTNEWDATETIME&:.

DTSECOND&:

Usage: s&=DTSECOND&:(id&)

Returns the seconds component s& which is stored in the date/time object with handle id&.

See DTNEWDATETIME&:.

DTMICRO&:

Usage: m&=DTMICRO&:(id&)

Returns the microseconds component m& which is stored in the date/time object with handle id&.

See DTNEWDATETIME&:.

DTSETYEAR:

Usage: DTSETYEAR:(y&,id&)

Sets the year component which is stored in the date/time object with handle id& to y&.

See DTNEWDATETIME&:.

DTSETMONTH:

Usage: DTSETMONTH:(m&,id&)

Sets the month component which is stored in the date/time object with handle id& to m&.

See DTNEWDATETIME&:.

DTSETDAY:

Usage: DTSETDAY:(day&,id&)

Sets the day component which is stored in the date/time object with handle id& to day&.

See DTNEWDATETIME&:.

DTSETHOUR:

Usage: DTSETHOUR:(h&,id&)

Sets the hour component which is stored in the date/time object with handle id& to h&.

See DTNEWDATETIME&:.

DTSETMINUTE:

Usage: DTSETMINUTE:(m&,id&)

Sets the minutes component which is stored in the date/time object with handle id& to m&.

See DTNEWDATETIME&:.

DTSETSECOND:

Usage: DTSETSECOND:(s&,id&)

Sets the seconds component which is stored in the date/time object with handle id& to s&.

See DTNEWDATETIME&:.

DTSETMICRO:

Usage: DTSETMICRO:(m&,id&)

Sets the microseconds component which is stored in the date/time object with handle id& to m&.

See DTNEWDATETIME&:.

DTNOW&:

Usage: id&=DTNOW&:

Creates a new date/time object which contains all the date/time components of the current time and returns a handle id& for it.

Example: Timing a loop

    ...
    start&=DTNow&:
    WHILE condition
          ...
    ENDWH
    end&=DTNow&:
    PRINT "Time to do loop was",DTMicrosDiff&:(start&,end&)
    ...

See DTNEWDATETIME&:.

DTDATETIMEDIFF:

Usage: DTDATETIMEDIFF:(start&,end&,BYREF year&,BYREF month&,BYREF day&,BYREF hour&,BYREF minute&,BYREF second&,BYREF micro&)

Calculates the exact difference between two date/time objects with handles start& and end& in the form of a date/time object. The difference is returned in the variables year&, month& etc.

DTYEARSDIFF&:

Usage: diff&=DTYEARSDIFF&:(start&,end&)

Returns the difference diff& in whole years between the two date/time objects with handles start& and end&.

See DTNEWDATETIME&:.

DTMONTHSDIFF&:

Usage: diff&=DTMONTHSDIFF&:(start&,end&)

Returns the difference diff& in whole months between the two date/time objects with handles start& and end&.

See DTNEWDATETIME&:.

DTDAYSDIFF&:

Usage: diff&=DTDAYSDIFF&:(start&,end&)

Returns the difference diff& in whole days between the two date/time objects with handles start& and end&.

See DTNEWDATETIME&:.

DTHOURSDIFF&:

Usage: diff&=DTHOURSDIFF&:(start&,end&)

Returns the difference diff& in whole hours between the two date/time objects with handles start& and end&.

See DTNEWDATETIME&:.

DTMINUTESDIFF&:

Usage: diff&=DTMINUTESDIFF&:(start&,end&)

Returns the difference diff& in whole minutes between the two date/time objects with handles start& and end&.

See DTNEWDATETIME&:.

DTSECONDSDIFF&:

Usage: diff&=DTSECONDSDIFF&:(start&,end&)

Returns the difference diff& in whole seconds between the two date/time objects with handles start& and end&.

See DTNEWDATETIME&:.

DTMICROSDIFF&:

Usage: diff&=DTMICROSDIFF&:(start&,end&)

Returns the difference diff& in whole microseconds between the two date/time objects with handles start& and end&.

See DTNEWDATETIME&:, DTNOW&:.

DTWEEKNOINYEAR&:

Usage: w&=DTWEEKNOINYEAR&:(id&,yearstart&,rule&)

Returns the week number in the year of the date/time object with handle id&. The first day of the year is specified by the date/time object with handle yearstart&. This would usually be set to 1 January in the appropriate year, but also allows you to set the star of the year to the beginning of the financial year or the academic year, for example.

rule& can take three values (0,1,2), allowing the week number to be calculated by one of three different rules:

value | meaning
0 | the first day of the year is always in week one,
1 | requires the first week of the year to have at least four days in it,
2 | requires the first week of the year to have the full seven days.

The Agenda application and applications use the rule with value 1 by default.

DTDAYNOINYEAR&:

Usage: DTDAYNOINYEAR&:(id&,yearstart&)

Returns the day number in the year of the date/time object with handle id&. The first day of the year is specified by the date/time object with handle yearstart&.

DTDAYNOINWEEK&:

Usage: n&=DTDAYNOINWEEK&:(id&)

Returns the day number in the week (1-7) of the date/time object with handle id&.

DTDAYSINMONTH&:

Usage: n&=DTDAYSINMONTH&:(id&)

Returns the number of days in the month of the month specified by the month component of the date/time object with handle id&.

DTSETHOMETIME:

Usage: DTSETHOMETIME:(id&)

Sets the system time to the time specified in the date/time object with handle id&.

LCCOUNTRYCODE&:

Usage: cc&=LCCOUNTRYCODE&:

Returns the country code for the current system home country (LC stands for ‘Locale’), which may be used to select country-specific data. The country code for any given country is the international dialling prefix for that country

LCDECIMALSEPARATOR$:

Usage: decSep$=LCDECIMALSEPARATOR$:

Returns the decimal separator (the character used in decimal numbers to separate whole part from fractional part) according to the local system setting.

LCSETCLOCKFORMAT:

Usage: LCSETCLOCKFORMAT:(format&)

Sets the system clock format to either digital or analog. If format&=0 then the clock is set to analog or if it is 1 then the clock is set to digital.

LCCLOCKFORMAT&:

Usage: format&=LCCLOCKFORMAT&:

Returns the current system clock format The procedure returns 0 if the system clock is analog and 1 if it is digital.

LCSTARTOFWEEK&:

Usage: start&=LCSTARTOFWEEK&:

Returns the day of the week which set as the first day of the week in the system setting. A return value of 1 indicates Monday, 2 Tuesday, and so on.

LCTHOUSANDSSEPARATOR$:

Usage: thouSep$=LCTHOUSANDSSEPARATOR$:

Returns the thousands separator (the character used to separate every three digits of a large number) according to the local system setting.


dBase.opx — Database handling

Contents

  • Overview
    • Compatibility
  • DBADDFIELD:
  • DBADDFIELDTRUNC:
  • DBCREATEINDEX:
  • DBDELETEKEY:
  • DBDROPINDEX:
  • DBGETFIELDCOUNT&:
  • DBGETFIELDNAME$:
  • DBGETFIELDTYPE&:
  • DBISDAMAGED&:
  • DBISUNIQUE&:
  • DBMAKEUNIQUE:
  • DBNEWKEY&:
  • DBRECOVER:
  • DBSETCOMPARISON:

Overview

To use this OPX, you must include the header file dBase.oxh, which contains the following declaration:

    DECLARE OPX DBASE,KUidOpxDBase&,KOpxDBaseVersion%
          DbAddField:(keyPtr&,fieldName$,order&) : 1
          DbAddFieldTrunc:(keyPtr&,fieldName$,order&,trunc&) : 2
          DbCreateIndex:(index$,keyPtr&,dbase$,table$) : 3
          DbDeleteKey:(keyPtr&) : 4
          DbDropIndex:(index$,dbase$,table$) : 5
          DbGetFieldCount&:(dbase$,table$) : 6
          DbGetFieldName$:(dbase$,table$,fieldNum&) : 7
          DbGetFieldType&:(dbase$,table$,fieldNum&) : 8
          DbIsDamaged&:(dbase$) : 9
          DbIsUnique&:(keyPtr&) : 10
          DbMakeUnique:(keyPtr&) : 11
          DbNewKey&: : 12
          DbRecover:(dbase$) : 13
          DbSetComparison:(KeyPtr&,comp&) : 14
    END DECLARE

Compatibility

ER5 WINS OPXs are not useable on the ER3 EPOC Emulator, and ER3 WINS OPXs will not work on the ER5 Emulator. However, ER5 MARM OPXs will work on ER3 EPOC devices, and ER3 MARM OPXs will work under ER5.

DBADDFIELD:

Usage: DBADDFIELD:(key&,field$,order&)

Adds the field, field$, to the key, key& (see DBNEWKEY&: for creating a new key). This new key can then be used to create an index on a table. order& specifies how this field should be ordered:

value | meaning | constant declaration in dBase.oxh
1 | ascending | CONST KDbAscending&=1
0 | descending | CONST KDbDescending&=1

You can use this procedure repeatedly to add more than one field to the same key. The order in which the fields are added dictates the significance of these fields in building up the index. The first field added to a key is the primary field; if there were any identical values in this field then the secondary field would be used and so on. For example, if the primary field in an ‘Address’ table was ‘Surname’ and there were two people with the surname Brown, then the secondary field or tertiary fields like ‘Forename’ and ‘Age’ might be used to define how the index will be ordered.

When using string fields in an index they cannot be longer than 240 bytes. To limit the size of a string field see CREATE under Keyword Reference. If a string field is the last field in a key (or first and only) then it may be truncated to a specified length - see DBADDFIELDTRUNC:.

Note that the size of an index can become huge if the key is long. The key length k is the length in bytes of the sum of all the fields in the key. An integer or a long integer field is 4 bytes, a floating-point field 8 bytes and a text field depends on the length assigned to it (see also the previous paragraph). The size of the index depends at least linearly on k and hence may be large if the key is long.

When the key has been built as required, it can be used to create an index.

See DBCREATEINDEX:.

DBADDFIELDTRUNC:

Usage: DBADDFIELDTRUNC:(key&,field$,order&,trunc&)

Adds a truncated string field field$ to the key key&. Only the last field added to a key (or first and only) can be truncated. order& specifies how this field should be ordered and may take the values:

value | meaning | constant declaration in dBase.oxh
1 | ascending | CONST KDbAscending&=1
0 | descending | CONST KDbDescending&=1

trunc& is the truncation length and determines how many bytes of the string field will be used in building up the index (up to 240).

This procedure is useful for building up indexes on OPL16 databases whose string fields have a set length of 255 bytes. When the key has been built up as required it can be used to create an index.

See DBADDFIELD:, DBCREATEINDEX:.

DBCREATEINDEX:

Usage: DBCREATEINDEX:(index$,key&,file$,table$)

Creates an index with the name index$ on the table table$ in the database file$. The index is used for sorting and vastly increases the speed in table lookup. The index is based on key&, the supplied key. The database must be closed when this procedure is used.

The opening of an ordered view on a table must be requested in the SQL query in the OPEN command. If a suitable index has been created then it will be used.

See DBNEWKEY:, DBADDFIELD:, DBADDFIELDTRUNC:, DBMAKEUNIQUE:, DBSETCOMPARISON:, DBDROPINDEX:, OPEN, SQL specification.

DBDELETEKEY:

Usage: DBDELETEKEY:(key&)

Deletes the key key&. This should be called as soon as the key is no longer required. Any keys left undeleted when all modules that declare or include a declaration of the Dbase OPX have been unloaded will be automatically deleted

See DBNEWKEY&.

DBDROPINDEX:

Usage: DBDROPINDEX:(index$,file$,table$)

Drops the index index$ of the table table$ of the database file$. The database must be closed to use this procedure.

See DBCREATEINDEX:.

DBGETFIELDCOUNT&:

Usage: n&=DBGETFIELDCOUNT&:(dbase$,table$)

Returns the number of fields in one of the records in the table table$ of the database dbase$. This number can then be used to analyse the contents of the record.

See DBGETFIELDNAME$:, DBGETFIELDTYPE&:.

DBGETFIELDNAME$:

Usage: name$=DBGETFIELDNAME$:(dbase$,table$,fieldNum&)

Returns the name of the field whose number is fieldNum& in the table table$ of the database dbase$. This is useful for analysing the records of a table.

See DBGETFIELDCOUNT&:, DBGETFIELDTYPE&:.

DBGETFIELDTYPE&:

Usage: type&=DBGETFIELDTYPE&:(dbase$,table$,fieldNum&)

Returns the type of the field whose number is fieldNum& in the table table$ of the database dbase$. This is useful for analysing the records of a table.

The values that me be returned (many of which aren’t supported by OPL databases), are as follows:

value | type
0 | bit
1 | signed byte (8 bits)
1 | unsigned byte (8 bits)
2 | integer (16 bits)
3 | unsigned integer (16 bits)
4 | long integer (32 bits)
5 | unsigned long integer (32 bits)
6 | 64-bit integer
7 | single precision floating-point number (32 bits)
8 | double precision floating-point number (64 bits)
9 | date/time object
10 | ASCII text
11 | Unicode text
12 | Binary
13 | LongText8
14 | LongText16
15 | LongBinary

Types 2,4,8,10 correspond to OPL’s %,&, floating point and $ types respectively.

See DBGETFIELDCOUNT&, DBGETFIELDNAME&

DBISDAMAGED&:

Usage: i&=DbIsDamaged&:(dbase$)

Returns 1 if the database dbase$ considers that it may have damaged indexes and 0 if not. If the database is damaged, then this does not make it unusable, but attempting to use any damaged index will result in an error. Recovering the database will restore any damaged indexes.

See DBRECOVER:.

DBISUNIQUE&:

Usage: i&=DBISUNIQUE&:(key&)

Returns -1 if the key key& is unique or 0 if it is not.

See DBMAKEUNIQUE:.

DBMAKEUNIQUE:

Usage: DBMAKEUNIQUE:(key&)

Sets the key key& to be unique. The index created will then not allow any records to be added if they exactly match the indexed fields of another record.

See DBNEWKEY:, DBADDFIELD:, DBCREATEINDEX:.

DBNEWKEY&:

Usage: k&=NEWKEY&:

Returns a handle to a key which can be used for creating indexes.

See DBDELETEKEY:, DBCREATEINDEX:, DBADDFIELD:, DBADDFIELDTRUNC:.

DBRECOVER:

Usage: DBRECOVER:(dbase$)

Recovers a damaged database dbase$, restoring any damaged indices.

See DBISDAMAGED&:.

DBSETCOMPARISON:

Usage: DBSETCOMPARISON:(key&,comp&)

The text comparison is used to determine the order of an index. The argument comp& sets the text comparison mode of a key key&, and takes one of the constant values supplied in the header file dBase.oxh:

    CONST KDbCompareNormal&=0
    CONST KDbCompareFolded&=1
    CONST KDbCompareCollated&=2


dbUtils.opx — Additional DBMS functionality

Contents

  • Overview
    • Compatibility
  • DbRefresh: — Refreshes the current restricted view

Overview

This OPX is supplied with the EPOC Release 5 OPL SDK, and does not exist in EPOC Release 5 ROMs. To use this OPX, you must include the header file dbUtils.oxh which contains the following declaration:

    CONST KUidOpxdbUtils&=&10004C87
    CONST KOpxdbUtilsVersion%=$0100
    DECLARE OPX dbUtils,KUidOpxdbUtils&,KOpxdbUtilsVersion%
          DbRefresh: : 1
    END DECLARE

Compatibility

This OPX is introduced in ER5, and is not available to users of earlier devices.

DbRefresh: — Refreshes the current restricted view

Usage: DbRefresh:

Refreshes the current restricted DBMS view. It is only required in ER5 (and beyond) when using the WHERE keyword to restrict a view to a subset of the current table. The view does not dynamically update, so it must be refreshed manually in order to pick up any changes to the table contents.

DBMS has been optimised for ER5, but one problem of implementing the speed improvement is that a restricted view (that is, a view using the WHERE keyword to restrict the records to a subset of the current table) is no longer dynamically updated. A restricted view must be refreshed to pick up any changes to the table contents.

This means once a restricted view is created, any changes to the records in the view should be followed by a call to DbRefresh:, otherwise the view will be out-of-date, and any further database commands may give inaccurate information.

For example, a view is created on a table and restricted to show only a subset of the table. A new record that is expected to appear in the view is added. For ER5 devices, using COUNT to find the number of rows in the table returns one less than expected, as the new record has not been recognised. DbRefresh: is called, and the COUNT now accurately reflects the number of records expected.

Note that on EPOC releases ER1 to ER4, an index would have been required to create the restricted view. For ER5, the index is no longer required for these views, and any such index is ignored.

Finally, although DbRefresh: is not required when running on ER1-ER4, calling it on these devices has no ill effects.

For example:

    SELECT ... WHERE b=c ORDER BY a ...
    PRINT COUNT    REM Prints 0
    AddNewRecord:  REM Adds a record to the table.
    PRINT COUNT    REM Still 0
    DbRefresh:
    PRINT COUNT    REM Prints 1.


Printer.opx — Printer and text handling

Contents

  • Overview
    • Compatibility
  • SENDSTRINGTOPRINTER:
  • INSERTSTRING:
  • SENDNEWPARATOPRINTER:
  • INSERTNEWPARA:
  • SENDSPECIALCHARTOPRINTER:
  • INSERTSPECIALCHAR:
  • SETALIGNMENT:
  • INITIALISEPARAFORMAT:
  • SETLOCALPARAFORMAT:
  • SETGLOBALPARAFORMAT:
  • REMOVESPECIFICPARAFORMAT:
  • SETFONTNAME:
  • SETFONTHEIGHT:
  • SETFONTPOSITION:
  • SETFONTWEIGHT:
  • SETFONTPOSTURE:
  • SETFONTSTRIKETHROUGH:
  • SETFONTUNDERLINE:
  • SETGLOBALCHARFORMAT:
  • REMOVESPECIFICCHARFORMAT:
  • SENDBITMAPTOPRINTER:
  • INSERTBITMAP:
  • SENDSCALEDBITMAPTOPRINTER:
  • INSERTSCALEDBITMAP:
  • PRINTERDOCLENGTH&:
  • SENDRICHTEXTTOPRINTER:
  • RESETPRINTING:
  • PAGESETUPDIALOG:
  • PRINTPREVIEWDIALOG:
  • PRINTRANGEDIALOG:
  • PRINTDIALOG:
  • SENDBUFFERTOPRINTER:

Overview

The Printer OPX provides access to print and text handling. An object to be printed is first created dynamically by sending text, bitmaps and formatting information. Printing itself is then handled by calling standard print dialogs. One procedure is provided for each of the four dialogs usually called from standard applications.

    DECLARE OPX PRINTER,KUidOpxPrinter&,KOpxPrinterVersion%
          SendStringToPrinter:(string$) : 1
          InsertString:(string$,pos&) : 2
          SendNewParaToPrinter: : 3
          InsertNewPara:(pos&) : 4
          SendSpecialCharToPrinter:(character%) : 5
          InsertSpecialChar:(character%,pos&) : 6
          SetAlignment:(alignment%) : 7
          InitialiseParaFormat:(Red&, Green&, Blue&,
                LeftMarginInTwips&,  RightMarginInTwips&,
                IndentInTwips&, HorizontalAlignment%,
                VerticalAlignment%, LineSpacingInTwips&,
                LineSpacingControl%, SpaceBeforeInTwips&,
                SpaceAfterInTwips&, KeepTogether%, KeepWithNext%,
                StartNewPage%, WidowOrphan%, Wrap%,
                BorderMarginInTwips&, DefaultTabWidthInTwips&) : 8
          SetLocalParaFormat: : 9
          SetGlobalParaFormat: : 10
          RemoveSpecificParaFormat: : 11
          SetFontName:(name$) : 12
          SetFontHeight:(height%) : 13
          SetFontPosition:(pos%) : 14
          SetFontWeight:(weight%) : 15
          SetFontPosture:(posture%) : 16
          SetFontStrikethrough:(strikethrough%) : 17
          SetFontUnderline:(underline%) : 18
          SetGlobalCharFormat: : 19
          RemoveSpecificCharFormat: : 20
          SendBitmapToPrinter:(bitmapHandle&) : 21
          InsertBitmap:(bitmapHandle&,pos&) : 22
          SendScaledBitmapToPrinter:(bitmapHandle&,xScale&,yScale&) : 23
          InsertScaledBitmap:(bitmapHandle&,pos&,xScale&,yScale&) : 24
          PrinterDocLength&: : 25
          SendRichTextToPrinter:(richTextAddress&) : 26
          ResetPrinting: : 27
          PageSetupDialog: : 28
          PrintPreviewDialog: : 29
          PrintRangeDialog: : 30
          PrintDialog: : 31
          SendBufferToPrinter:(addr&) : 32
    END DECLARE

Compatibility

ER5 WINS OPXs are not useable on the ER3 EPOC Emulator, and ER3 WINS OPXs will not work on the ER5 Emulator. However, ER5 MARM OPXs will work on ER3 EPOC devices, and ER3 MARM OPXs will work under ER5.

SENDSTRINGTOPRINTER:

Usage: SENDSTRINGTOPRINTER:(string$)

Append a string to whatever has already been sent to the printer.

See INSERTSTRING:, SENDNEWPARATOPRINTER:.

INSERTSTRING:

Usage: INSERTSTRING:(string$,pos&)

Insert string$ at position pos& in the buffer. Inserting at position zero puts the string ahead of anything already sent or inserted.

See SENDSTRINGTOPRINTER:, INSERTNEWPARA:.

SENDNEWPARATOPRINTER:

Usage: SENDNEWPARATOPRINTER:

Paragraphs delimit paragraph formatting, such as centring. This procedure is equivalent to

    SENDSPECIALCHARTOPRINTER:(KParagraphDelimiter%)

See SENDSPECIALCHARTOPRINTER:, INSERTNEWPARA:, SENDSTRINGTOPRINTER:.

INSERTNEWPARA:

Usage: INSERTNEWPARA:(pos&)

Inserts a new paragraph at position pos& in the buffer.

See SENDNEWPARATOPRINTER:, INSERTSTRING:.

SENDSPECIALCHARTOPRINTER:

Usage: SENDSPECIALCHARTOPRINTER:(character%)

Sends a special character, for example line and page breaks etc., to the printer. Constants for special characters are defined in Const.oph as follows:

    CONST KParagraphDelimiter%=$06
    CONST KLineBreak%=$07
    CONST KPageBreak%=$08
    CONST KTabCharacter%=$09
    CONST KNonBreakingTab%=$0a
    CONST KNonBreakingHyphen%=$0b
    CONST KPotentialHyphen%=$0c
    CONST KNonBreakingSpace%=$10
    CONST KVisibleSpaceCharacter%=$0f

See SENDNEWPARATOPRINTER:, INSERTSPECIALCHAR:.

INSERTSPECIALCHAR:

Usage: INSERTSPECIALCHAR:(character%,pos&)

Inserts a special character at pos& in the buffer.

See SENDSPECIALCHARTOPRINTER:.

SETALIGNMENT:

Usage: SETALIGNMENT:(alignment%)

Sets alignment state of a paragraph. Default is KPrintLeftAlign%.

The setting does not take effect until either SETLOCALPARAFORMAT: or SETGLOBALPARAFORMAT: is called. The allowable alignments, defined in Printer.oxh, are:

    CONST KPrintLeftAlign%=0
    CONST KPrintCenterAlign%=1
    CONST KPrintRightAlign%=2
    CONST KPrintJustifiedAlign%=3
    CONST KPrintUnspecifiedAlign%=4

See INITIALISEPARAFORMAT:.

INITIALISEPARAFORMAT:

Usage: INITIALISEPARAFORMAT:(Red%, Green%, Blue%,
LeftMarginInTwips&, RightMarginInTwips&, IndentInTwips&, HorizontalAlignment%, VerticalAlignment%, LineSpacingInTwips&, LineSpacingControl%, SpaceBeforeInTwips&, SpaceAfterInTwips&, KeepTogether%, KeepWithNext%, StartNewPage%, WidowOrphan%, Wrap%, BorderMarginInTwips&, DefaultTabWidthInTwips&)

Sets a state for formatting. The setting does not take effect until either SETLOCALPARAFORMAT or SETGLOBALPARAFORMAT is called.

Red%,Green%,Blue% set the background colour. Each value can be in the range 0 to 255. Default colour is white, with all three arguments equal to 255.

LeftMarginInTwips& sets left text margin relative to left page margin. Default is zero.

RightMarginInTwips& sets right text margin, relative to right page margin. Default is zero.

IndentInTwips& sets left, right and first line indent. Default is zero.

HorizontalAlignment% sets horizontal alignment of paragraph. Default is left alignment. See SETALIGNMENT for values.

VerticalAlignment% sets vertical alignment of paragraph (for use by spreadsheet applications). Default is top alignment. Allowable values, supplied in Printer.oxh, are:

    CONST KPrintTopAlign%=0
    CONST KPrintBottomAlign%=2
    CONST KPrintUnspecifiedAlign%=4

LineSpacingInTwips& sets inter-line spacing in twips. Default is 200 (10 point).

LineSpacingControl% sets the control for LineSpacingInTwips& value. Default is KLineSpacingAtLeastInTwips&. Allowable values are:

    CONST KLineSpacingAtLeastInTwips% = 0
    CONST KLineSpacingExactlyInTwips% = 1

SpaceBeforeInTwips& sets the space above a paragraph. Default is zero.

SpaceAfterInTwips& sets the space below a paragraph. Default is zero.

KeepTogether% prevents a page break within paragraph when KTrue%. Default is KFalse%. (Constants are defined in Const.oph.)

KeepWithNext% prevents a page break between this paragraph and the following paragraph when KTrue%. Default is KFalse%.

StartNewPage% inserts a page break immediately before this paragraph when KTrue%. Default is KFalse%.

WidowOrphan% prevents the printing of the last line of a paragraph by itself on the top of a new page (widow) or the first line of a paragraph by itself on the bottom of the page (orphan). Default is KFalse%.

Wrap% forces the paragraph to line wrap at the right margin when KTrue%. KFalse% disables line wrap. Default is KTrue%.

BorderMarginInTwips& sets distance in twips between paragraph border and enclosed text (must be non-negative). Default is zero.

DefaultTabWidthInTwips& specifies the spacing between the default tab stops. Default is 360.

SETLOCALPARAFORMAT:

Usage: SETLOCALPARAFORMAT:

Sets the initialised global paragraph formatting as local.

See SETGLOBALPARAFORMAT:.

SETGLOBALPARAFORMAT:

Usage: SETGLOBALPARAFORMAT:

Sets the local paragraph format as global (after initialising formatting).

See SETLOCALPARAFORMAT:, REMOVESPECIFICPARAFORMAT:.

REMOVESPECIFICPARAFORMAT:

Usage: REMOVESPECIFICPARAFORMAT:

Unsets local paragraph formatting, using global formatting instead

See SETGLOBALPARAFORMAT:, SETLOCALPARAFORMAT:.

SETFONTNAME:

Usage: SETFONTNAME:(name$)

Gives a new font name. Takes immediate effect locally, but requires the use of SETGLOBALCHARFORMAT: to set as the global default.

SETFONTHEIGHT:

Usage: SETFONTHEIGHT:(height%)

Gives a new font height in twips

(1 twip = 1/20 points or 1/1440 inches)

Takes immediate effect locally, but requires the use of SETGLOBALCHARFORMAT: to set as the global default.

SETFONTPOSITION:

Usage: SETFONTPOSITION:(POS%)

Sets font position as normal, superscript or subscript. The following constants can be used for this:

    CONST KPrintPosNormal%=0
    CONST KPrintPosSuperscript%=1
    CONST KPrintPosSubscript%=2

Takes immediate effect locally, but requires the use of SETGLOBALCHARFORMAT: to set as the global default.

SETFONTWEIGHT:

Usage: SETFONTWEIGHT:(weight%)

Sets the font weight (normal or bold). Allowable values are:

    CONST KStrokeWeightNormal%=0
    CONST KStrokeWeightBold%=1

Takes immediate effect locally, but requires the use of SETGLOBALCHARFORMAT: to set as the global default.

SETFONTPOSTURE:

Usage: SETFONTPOSTURE:(posture%)

Sets font posture using the following constants:

    CONST KPostureUpright%=0
    CONST KPostureItalic%=1

Takes immediate effect locally, but requires the use of SETGLOBALCHARFORMAT: to set as the global default.

SETFONTSTRIKETHROUGH:

Usage: SETFONTSTRIKETHROUGH:(strikethrough%)

Set strike-through on or off using:

    CONST KStrikethroughOff%=0
    CONST KStrikethroughOn%=1

Takes immediate effect locally, but requires the use of SETGLOBALCHARFORMAT: to set as the global default.

SETFONTUNDERLINE:

Usage: SETFONTUNDERLINE:(underline%)

Set underline on or off using:

    CONST KUnderlineOff%=0
    CONST KUnderlineOn%=1

Takes immediate effect locally, but requires the use of SETGLOBALCHARFORMAT: to set as the global default.

SETGLOBALCHARFORMAT:

Usage: SETGLOBALCHARFORMAT:

Sets the currently active character format to be the global default.

See REMOVESPECIFICCHARFORMAT:.

REMOVESPECIFICCHARFORMAT:

Usage: REMOVESPECIFICCHARFORMAT:

Unsets local character formatting, replacing it with the global formatting instead.

See SETGLOBALCHARFORMAT:.

SENDBITMAPTOPRINTER:

Usage: SENDBITMAPTOPRINTER:(bitmapHandle&)

Appends a bitmap from its handle bitmapHandle&.

See INSERTBITMAP:, SENDSCALEDBITMAPTOPRINTER:.

INSERTBITMAP:

Usage: INSERTBITMAP:(bitmapHandle&,pos&)

Inserts a bitmap specified by bitmapHandle& at position pos& in the buffer to be sent to the printer. The handle is the same as that returned by gLOADBIT.

See SENDBITMAPTOPRINTER:, INSERTSCALEDBITMAP:.

SENDSCALEDBITMAPTOPRINTER:

Usage: SENDSCALEDBITMAPTOPRINTER:(bitmapHandle&,xScale&,yScale&)

Appends a scaled bitmap specified by bitmapHandle& and scaled according to xScale& and yScale& to the buffer sent to the printer. The handle is the same as that returned by gLOADBIT. Default scaling is xScale& = yScale& = 1000.

See SENDBITMAPTOPRINTER:, INSERTSCALEDBITMAP:.

INSERTSCALEDBITMAP:

Usage: INSERTSCALEDBITMAP:(bitmapHandle&,pos&,xScale&,yScale&)

Inserts a scaled bitmap specified by bitmapHandle& and scaled according to xScale& and yScale& at position pos& in the buffer sent to the printer. The handle is the same as that returned by gLOADBIT.

See INSERTBITMAP:, SENDSCALEDBITMAPTOPRINTER:.

PRINTERDOCLENGTH&:

Usage: PRINTERDOCLENGTH&:

Returns the count of characters currently held in the buffer. It is not possible to insert characters beyond the length of the document buffer. Bitmaps and special characters each count as one character.

SENDRICHTEXTTOPRINTER:

Usage: SENDRICHTEXTTOPRINTER:(richTextAddress&)

Sends the address of a rich text object richTextAddress& to the printer. This is intended to be used on a pointer returned by another OPX. This new Rich Text will replace all content currently stored.

RESETPRINTING:

Usage: RESETPRINTING:

Deletes all text, bitmaps and formatting in the printing buffer.

PAGESETUPDIALOG:

Usage: PAGESETUPDIALOG:

Calls the standard page setup dialog.

See PRINTPREVIEWDIALOG:, PRINTRANGEDIALOG:, PRINTDIALOG:.

PRINTPREVIEWDIALOG:

Usage: PRINTPREVIEWDIALOG:

Calls the standard print preview dialog. This allows the data sent to the printer to be viewed. The other three dialogs can all be called from this dialog.

See PAGESETUPDIALOG:, PRINTRANGEDIALOG:, PRINTDIALOG:.

PRINTRANGEDIALOG:

Usage: PRINTRANGEDIALOG:

Calls a standard print range dialog.

See PAGESETUPDIALOG:, PRINTPREVIEWDIALOG:, PRINTDIALOG:.

PRINTDIALOG:

Usage: PRINTDIALOG:

Calls a standard print dialog.

See PAGESETUPDIALOG:, PRINTPREVIEWDIALOG:, PRINTRANGEDIALOG:.

SENDBUFFERTOPRINTER:

Usage: SENDBUFFERTOPRINTER:(addr&)

Appends the contents of a buffer to whatever has already been sent to the printer. The addr& parameter should be the address of a buffer into which text has been inserted by dEDITMULTI.


SysRam1.opx — Additional OPL functionality

Contents

  • Overview
    • Compatibility
  • DbFind&:
  • DbFindField&:
  • GetThreadIdFromCaption&:
  • ExternalPower&:
  • LCNearestLanguageFile$:
  • LCLanguage&:
  • OsVersionMajor&:
  • OsVersionMinor&:
  • OsVersionBuild&:
  • RomVersionMajor&:
  • RomVersionMinor&:
  • RomVersionBuild&:
  • GetFileSize&:
  • DTDatNameFull$:
  • DTMonthNameFull$:
  • DTIsLeapYear&:
  • LCDateSeparator$:
  • LCTimeSeparator$:
  • LCAmPmSpaceBetween&:

Overview

This OPX is supplied with the EPOC OPL SDK, and does not exist in current EPOC ROMs. To use this OPX, you must include the header file SysRam1.oxh and distribute SysRam1.opx with your program.

SysRam1.opx contains utility functions for working with locale preference settings, OS and ROM version numbers, captions and dates; it also contains error-free versions of the FIND and FINDFIELD keywords.

Compatibility

ER5 WINS OPXs are not useable on the ER3 EPOC Emulator, and ER3 WINS OPXs will not work on the ER5 Emulator. However, ER5 MARM OPXs will work on ER3 EPOC devices, and ER3 MARM OPXs will work under ER5.

DbFind&:

Usage: f& = DbFind&:(string$)

Note: this procedure replaces FIND as FIND contains bugs when searching for large strings (or small strings when searching many fields).

Searches the current view for fields matching a$. The search starts from the current record, so use NEXT to progress to subsequent records. DbFind&: makes the next record containing string$ the current record and returns the number of the record found. Capitals and lower-case letters match.

You can use the wildcards:

? | matches any single character
* | matches any group of characters

To find a record with a field containing Dr and either BROWN or BRAUN, use:

    F& = DbFind&:("*DR*BR??N*")

DbFind&:("BROWN") will find only those records with a field consisting solely of the string "BROWN".

You can only search string fields.

DbFind&: returns the position of the found record in the current view.

See also DbFindField&:.

DbFindField&:

Usage: f& = DbFindField&:(string$,start&,num&,flags&)

Note: this procedure replaces FINDFIELD as FINDFIELD contains bugs when searching for large strings (or small strings when searching many fields).

Like DbFind&:, finds a string, makes the record with this string the current record, and returns the number of this record.

string$ is the string for which to search: the search will be carried out in num& fields in each record, starting at the field with number start& (1 is the number of the first field). start& and num& may refer to string fields only and other types will be ignored. The flags& argument specifies the type of search as explained below. If you want to search in all fields, use 1 for start& and for num& use the number of fields you used in the OPEN/CREATE command.

flags& can be built by using or more of the following values:

KFindBackwards% | 0 | Backwards from current record.
KFindForwards% | 1 | Forwards from current record.
 | 2 | Add to above to mean: Search starts at the appropriate end of the file.
KFindBackwardsFromEnd% | 2 | Backwards from end of file (2+KFindBackwards%).
KFindForwardsFromStart% | 3 | Backwards from start of file (2+KFindForwards%).
KFindCaseDependent% | 16 | Search is case-dependent. This means that the record will exactly match the search string in case as well as characters

These constants are supplied in Const.oph.

Add KFindCaseDependent% to the value of flags& given above to make the search case-dependent, where case-dependent means that the record will exactly match the search string in case as well as characters. Otherwise the search will be case-independent which means that upper case and lower case characters will match.

DbFindField&: returns the position of the found record in the database.

See also Database manipulation.

GetThreadIdFromCaption&:

Usage: t& = GetThreadIdFromCaption&:(Caption$,previous&)

Finds the thread Id of an application by its caption as specified in the APP...ENDA construct. This allows OPL apps to properly handle help files. See GetThreadIdfromOpenDoc of System.opx for more information.

ExternalPower&:

Usage: p& = ExternalPower&:

Returns -1 if external power (mains) is present or 0 if not.

LCNearestLanguageFile$:

Usage: LCNearestLanguageFile$:(file$)

The last two characters of the filename supplied are replaced with the language code if such a file exists, otherwise file$ is left unmodified.

LCLanguage&:

Usage: c& = LCLanguage&:

Returns the machines language code. Constants for the language codes are described in CAPTION.

OsVersionMajor&:

Usage: ov& = OsVersionMajor&:

Returns the major version number for the Operating System.

OsVersionMinor&:

Usage: ov& = OsVersionMinor&:

Returns the minor version number for the Operating System.

OsVersionBuild&:

Usage: ov& = OsVersionBuild&:

Returns the build number of the Operating System.

RomVersionMajor&:

Usage: rv& = RomVersionMajor&:

Returns the major version number for the ROM.

RomVersionMinor&:

Usage: rv& = RomVersionMinor&:

Returns the minor version number for the ROM.

RomVersionBuild&:

Usage: rv& = RomVersionBuild&:

Returns the build number of the ROM.

GetFileSize&:

Usage: s& = GetFileSize&:(file$)

Returns the size in bytes of the supplied file, file$.

DTDatNameFull$:

Usage: d$ = DTDayNameFull$:(Day&)

Returns a day name in full. The Day& argument is the day number, as for DAYNAME$.

DTMonthNameFull$:

Usage: m$ = DTMonthNameFull$:(Month&)

Returns a month name in full. The Month& argument is the day number, as for MONTHNAME$.

DTIsLeapYear&:

Usage: leapy& = DTIsLeapYear&:(year&)

Returns -1 if year& is a leap year or 0 if it isn’t.

LCDateSeparator$:

Usage: dsep$ = LCDateSeparator$:(index&)

Returns the local date separator. index& can be between 0 and 3 inclusive and corresponds to the position of the separator, as follows; 0 day 1 month 2 year 3.

LCTimeSeparator$:

Usage: tsep$ = LCTimeSeparator$:(index&)

Returns the local time separator. index& can be between 0 and 3 inclusive and corresponds to the position of the separator, as follows; 0 hour 1 minute 2 second 3.

LCAmPmSpaceBetween&:

Usage: sp& = LCAmPmSpaceBetween&:

Returns -1 if there should be a space between the time string and AM/PM in the current locale, or 0 if there should not.


System.opx — EPOC system functions

Contents

  • Overview
    • Compatibility
  • BACKLIGHTON&:
  • SETBACKLIGHTON:
  • SETBACKLIGHTONTIME:
  • SETBACKLIGHTBEHAVIOR:
  • ISBACKLIGHTPRESENT&:
  • SETAUTOSWITCHOFFBEHAVIOR:
  • SETAUTOSWITCHOFFTIME:
  • SETACTIVE:
  • RESETAUTOSWITCHOFFTIMER:
  • SWITCHOFF:
  • SETSOUNDENABLED:
  • SETSOUNDDRIVERENABLED:
  • SETKEYCLICKENABLED:
  • SETPOINTERCLICKENABLED:
  • SETDISPLAYCONTRAST:
  • MAXDISPLAYCONTRAST&:
  • ISREADONLY&:
  • ISHIDDEN&:
  • ISSYTEM&:
  • SETREADONLY:
  • SETHIDDENFILE:
  • SETSYSTEMFILE:
  • VOLUMESIZE&:
  • VOLUMESPACEFREE&:
  • VOLUMEUNIQUEID&:
  • MEDIATYPE&:
  • GETFILETIME:
  • SETFILETIME:
  • DISPLAYTASKLIST:
  • SETCOMPUTEMODE:
  • RUNAPP&:
  • RUNEXE&:
  • LOGONTOTHREAD:
  • TERMINATECURRENTPROCESS:
  • TERMINATEPROCESS:
  • KILLCURRENTPROCESS:
  • KILLPROCESS:
  • PLAYSOUND:
  • PLAYSOUNDA:
  • STOPSOUND&:
  • MOD&:
  • XOR&:
  • LOADRSC&:
  • UNLOADRSC:
  • READRSC$:
  • READRSCLONG&:
  • CHECKUID$:
  • SETPOINTERGRABON:
  • MACHINENAME$:
  • MACHINEUNIQUEID:
  • ENDTASK&:
  • KILLTASK&:
  • GETTHREADIDFROMOPENDOC&:
  • GETTHREADIDFROMAPPUID&:
  • SETFOREGROUND:
  • SETBACKGROUND:
  • SETFOREGROUNDBYTHREAD&:
  • SETBACKGROUNDBYTHREAD&:
  • GETNEXTWINDOWGROUPNAME$:
  • GETNEXTWINDOWID&:
  • SENDKEYEVENTTOAPP&:
  • IRDACONNECTTOSEND&:
  • IRDACONNECTTORECEIVE:
  • IRDAWRITE:
  • IRDAREAD$:
  • IRDAREADA:
  • IRDAWAITFORDISCONNECT:
  • IRDADISCONNECT:
  • MAINBATTERYSTATUS&:
  • BACKUPBATTERYSTATUS&:
  • CAPTUREKEY&:
  • CANCELCAPTUREKEY:
  • SETPOINTERCAPTURE:
  • CLAIMPOINTERGRAB:
  • OPENFILEDIALOG$:
  • CREATEFILEDIALOG$:
  • SAVEASFILEDIALOG$:

Overview

To use this OPX, you must included the header file System.oxh, which contains the following declaration:

    DECLARE OPX SYSTEM,KUidOpxSystem&,KOpxSystemVersion%
          BackLightOn&: : 1
          SetBackLightOn:(state&) : 2
          SetBackLightOnTime:(seconds&) : 3
          SetBacklightBehavior:(behaviour&) : 4
          IsBacklightPresent&: : 5
          SetAutoSwitchOffBehavior:(behaviour&) : 6
          SetAutoSwitchOffTime:(seconds&) : 7
          SetActive:(state&) : 8
          ResetAutoSwitchOffTimer: : 9
          SwitchOff: : 10
          SetSoundEnabled:(state&) : 11
          SetSoundDriverEnabled:(state&) : 12
          SetKeyClickEnabled:(state&) : 13
          SetPointerClickEnabled:(state&) : 14
          SetDisplayContrast:(value&) : 15
          MaxDisplayContrast&: : 16
          IsReadOnly&:(file$) : 17
          IsHidden&:(file$) : 18
          IsSystem&:(file$) : 19
          SetReadOnly:(file$,state&) : 20
          SetHiddenFile:(file$,state&) : 21
          SetSystemFile:(file$,state&) : 22
          VolumeSize&:(drive&) : 23
          VolumeSpaceFree&:(drive&) : 24
          VolumeUniqueID&:(drive&) : 25
          MediaType&:(drive&) : 26
          GetFileTime:(file$,DateTimeId&) : 27
          SetFileTime:(file$,DateTimeId&) : 28
          DisplayTaskList: : 29
          SetComputeMode:(State&) : 30
          RunApp&:(lib$,doc$,tail$,cmd&) : 31
          RunExe&:(name$) : 32
          LogonToThread:(threadId&,BYREF statusWord&) : 33
          TerminateCurrentProcess:(reason&) : 34
          TerminateProcess:(proc$,reason&) : 35
          KillCurrentProcess:(reason&) : 36
          KillProcess:(proc$,reason&) : 37
          PlaySound:(file$,volume&) : 38
          PlaySoundA:(file$,volume&,BYREF statusWord&) : 39
          StopSound&: : 40
          Mod&:(left&,right&) : 41
          XOR&:(left&,right&) : 42
          LoadRsc&:(file$) : 43
          UnLoadRsc:(id&) : 44
          ReadRsc$:(id&) : 45
          ReadRscLong&:(id&) : 46
          CheckUid$:(Uid1&,Uid2&,Uid3&) : 47
          SetPointerGrabOn:(WinId&,state&) : 48
          MachineName$: : 49
          MachineUniqueId:(BYREF high&,BYREF low&) : 50
          EndTask&:(threadId&,previous&)  : 51
          KillTask&:(threadId&,previous&) : 52
          GetThreadIdFromOpenDoc&:(doc$,BYREF previous&) : 53
          GetThreadIdFromAppUid&:(uid&,BYREF previous&) : 54
          SetForeground: : 55
          SetBackground: : 56
          SetForegroundByThread&:(threadId&,previous&) : 57
          SetBackgroundByThread&:(threadId&,previous&) : 58
          GetNextWindowGroupName$:(threadId&,BYREF previous&) : 59
          GetNextWindowId&:(threadId&,previous&) : 60
          SendKeyEventToApp&:(threadId&,previous&,code&,scanCode&,modifiers&,repeats&) : 61
          IrDAConnectToSend&:(protocol$,port&) : 62
          IrDAConnectToReceive:(protocol$,port&,BYREF statusW&) : 63
          IrDAWrite:(chunk$,BYREF statusW&) : 64
          IrDARead$: : 65
          IrDAReadA:(stringAddr&,BYREF statusW&): 66
          IrDAWaitForDisconnect: : 67
          IrDADisconnect: : 68
          MainBatteryStatus&: :69
          BackupBatteryStatus&: :70
          CaptureKey&:(keyCode&,mask&,modifier&) :71
          CancelCaptureKey:(handle&) :72
          SetPointerCapture:(winId&,flags&) :73
          ClaimPointerGrab:(winId&,state&) :74
          OpenFileDialog$:(seedFile$,uid1&,uid2&,uid3&) : 75
          CreateFileDialog$:(seedPath$) : 76
          SaveAsFileDialog$:(seedPath$,BYREF useNewFile%) : 77
    END DECLARE

Compatibility

ER5 WINS OPXs are not useable on the ER3 EPOC Emulator, and ER3 WINS OPXs will not work on the ER5 Emulator. However, ER5 MARM OPXs will work on ER3 EPOC devices, and ER3 MARM OPXs will work under ER5.

BACKLIGHTON&:

Usage: backLight&=BACKLIGHTON&:

Returns -1 if the backlight is switched on or 0 if it is switched off.

SETBACKLIGHTON:

Usage: SETBACKLIGHTON:(state&)

Switches the backlight on if state&=1 or off if state&=0.

SETBACKLIGHTONTIME:

Usage: SETBACKLIGHTONTIME:(seconds&)

Sets the time in seconds (seconds&) that the backlight should remain on after it has been switched on.

SETBACKLIGHTBEHAVIOR:

Usage: SETBACKLIGHTBEHAVIOR:(behavior&)

Sets the backlight’s turning off behaviour.

behavior&=0 sets the turning off of the backlight to be on a timer,

behavior&=1 sets the backlight not to be on a timer.

ISBACKLIGHTPRESENT&:

Usage: ret&=ISBACKLIGHTPRESENT&:

Returns -1 if there is a backlight present and 0 if there is not.

SETAUTOSWITCHOFFBEHAVIOR:

Usage: SETAUTOSWITCHOFFBEHAVIOR:(behavior&)

Sets the machine’s auto switch off behaviour.

behavior& |
0 | disables the machine’s auto switch off mechanism.
1 | sets the machine auto switch off to occur only when its batteries are low.
2 | sets the machines auto switch off to occur always.

SETAUTOSWITCHOFFTIME:

Usage: SETAUTOSWITCHOFFTIME:(seconds&)

Sets the time in seconds (seconds&) for which the machine may remain switched on when it is not being used.

SETACTIVE:

Usage: SETACTIVE:(state&)

Sets the current process active if state&=1 or not active if state&=0. This will determine whether or not the machine can automatically turn off when the user is not using the machine: if the process is active then the machine will not automatically turn off.

RESETAUTOSWITCHOFFTIMER:

Usage: RESETAUTOSWITCHOFFTIMER:

‘Tickles’ the machine’s auto-switch-off timer, restarting its count down to switching off. This is useful when using the serial port for a long task, for example; but use of this feature in a loop when the termination condition is never met can lead to power drain.

SWITCHOFF:

Usage: SWITCHOFF:

Switches off the machine.

As with the keyword OFF, you should be careful not to use SWITCHOFF: in a loop. If you do, it may be impossible to switch the machine back on, and you may then have to reset it.

SETSOUNDENABLED:

Usage: SETSOUNDENABLED:(state&)

Enables the machine’s sound if state&=1 or disables it if state&=0.

SETSOUNDDRIVERENABLED:

Usage: SETSOUNDDRIVERENABLED:(state&)

Switches the machines sound driver on if state&=1 or off if state&=0.

SETKEYCLICKENABLED:

Usage: SETKEYCLICKENABLED:(state&)

Determines whether or not a keypress makes a click. state&=1 enables the click and state&=0 disables it.

SETPOINTERCLICKENABLED:

Usage: SETPOINTERCLICKENABLED:(state&)

Determines whether or not a pointer event makes a click. (A pointer event occurs whenever the machine’s screen is pressed.) state&=1 enables the click and state&=0 disables it.

SETDISPLAYCONTRAST:

Usage: SETDISPLAYCONTRAST:(value&)

Sets the contrast on the machine’s screen. value& specifies the contrast value, which can be between zero and the maximum display contrast.

See MAXDISPLAYCONTRAST&:.

MAXDISPLAYCONTRAST&:

Usage: maxContrast&=MAXDISPLAYCONTRAST&:

Returns the maximum value to which the machines display contrast can be set.

See SETDISPLAYCONTRAST:.

ISREADONLY&:

Usage: readOnly&=ISREADONLY&:(file$)

Returns -1 if the file, file$, is a read-only file and 0 if it is not.

ISHIDDEN&:

Usage: hidden&=ISHIDDEN&:(file$)

Returns -1 if the file, file$, is hidden by the system and 0 if it is not.

ISSYTEM&:

Usage: system&=ISSYTEM&:(file$)

Returns -1 if the file, file$, is a system file and 0 if it is not.

SETREADONLY:

Usage: SETREADONLY:(file$,state&)

Sets the file, file$, to be read only if state&=1 or not read-only if state&=0.

SETHIDDENFILE:

Usage: SETHIDDENFILE:(file$,state&)

Sets the file, file$, to be hidden by the system if state&=1 or not to be hidden if state&=0.

SETSYSTEMFILE:

Usage: SETSYSTEMFILE:(file$,state&)

Sets the file, file$, to be a system file if state&=1 or not to be a system file if state&=0.

VOLUMESIZE&:

Usage: VOLUMESIZE&:(drive&)

Returns the size in bytes of the storage space on the drive specified by drive&. drive& can take values 0 to 25. 0 specifies the A:, 1 specifies B:, 2 specifies C: and so on.

VOLUMESPACEFREE&:

Usage: free&=VOLUMESPACEFREE&:(drive&)

Returns the size in bytes of the storage space that is available for use on the drive specified by drive&. drive& can take values 0 to 25. 0 specifies the A:, 1 specifies B:, 2 specifies C: and so on.

VOLUMEUNIQUEID&:

Usage: volUid&=VOLUMEUNIQUEID&:(drive&)

Returns the unique identification number of the media on the drive specified by drive&. drive& can take values 0 to 25. 0 specifies the A:, 1 specifies B:, 2 specifies C: and so on.

See MEDIATYPE&:.

MEDIATYPE&:

Usage: media&=MEDIATYPE&:(drive&)

Returns the media type present on the drive specified by drive&. drive& can take values 0 to 25. 0 specifies the A:, 1 specifies B:, 2 specifies C: and so on. The value returned may be any of the following,

value | meaning | constant declaration in System.oxh
0 | no media present | CONST KMediaNotPresent&=0
1 | media unknown | CONST KMediaUnknown&=1
2 | floppy disk | CONST KMediaFloppy&=2
3 | hard disk | CONST KMediaHardDisk&=3
4 | CD-ROM | CONST KMediaCdRom&=4
5 | RAM | CONST KMediaRam&=5
6 | flash | CONST KMediaFlash&=6
7 | ROM | CONST KMediaRom&=7
8 | remote | CONST KMediaRemote&=8

GETFILETIME:

Usage: GETFILETIME:(file$,dateTimeId&)

Returns the time that the file, file$, was last modified into dateTimeId&. It is necessary to pass this procedure the ID of a date/time object which the procedure will then set to the required time. To obtain and read a date/time object, see the ‘Date OPX’ section.

SETFILETIME:

Usage: SETFILETIME:(file$,dateTimeId&)

Sets the time that the file, file$, was last modified to dateTimeId&. It is necessary to pass this procedure the ID of a date/time object which the procedure will use to set the time. To get a date/time object, which provides microsecond accuracy, see Date.opx — Date and time manipulation.

DISPLAYTASKLIST:

Usage: DISPLAYTASKLIST:

Displays the system-wide task list. The user may then close a file, go to another task or close the dialog.

SETCOMPUTEMODE:

Usage: SETCOMPUTEMODE:(state&)

Changes the priority control for the current program.

The following values are available for state&:

value | meaning | constant declaration in System.oxh
0 | compute mode disabled | CONST KComputeModeDisabled&=0
1 | compute mode on | CONST KComputeModeOn&=1
2 | compute mode off | CONST KComputeModeOff&=2

This puts the current process into compute mode (state&=KComputeModeOn&) or takes it out of compute mode (state&=KComputeModeOff&). In compute mode, a process runs at the lower background priority even when it is the foreground process. Disabling compute mode control (state&=KComputeModeDisabled&) prevents the window server from changing the program’s priority when it moves between background and foreground.

OPL runs in compute mode by default to support simple OPOs which cannot always be assumed to be well-behaved programs.

This default behaviour is necessary because OPL programs would not otherwise give any background programs a chance to run, simply by running in a tight loop. If your program doesn’t run in a tight loop, i.e. if it calls GETEVENT32, GET, etc. regularly, you can use SETCOMPUTEMODE:(KComputeModeOff&).

Note that TBarInit: in Toolbar.opo sets compute mode off, since any program that has a toolbar shouldn’t be running in a tight loop at any time. (See Toolbars.)

RUNAPP&:

Usage: thread&=RUNAPP&:(lib$,doc$,tail$,cmd&)

Runs an application and returns a thread ID for the application. The thread ID can be used to logon to the application, to find out when and why it finished. This ID can also be used to locate the window group, end the task etc.

lib$ is the C++ application name.

doc$ is the document name, if any, to pass to the application.

tail$ is the tail end, needed only by certain applications such as OPL.

cmd& can take values:

value | meaning
0 | open
1 | create
2 | run
3 | background

The values 0, 1 and 2 are the same as for CMD$(3) (see Keyword Reference). The value 3 will run the application in the background.

For example, to run an OPL program:

    k&=RUNAPP&:("OPL","","RZ:\System\Opl\Toolbar.opo",2)

Note that tail$ contains a leading R: this is required by OPL.

To open the Data help file:

    k&=RUNAPP&:("Data","Z:\System\Data\Help","",0)

See also OPL applications.

See LOGONTOTHREAD:.

RUNEXE&:

Usage: RUNEXE&:(file$)

Runs an executable EXE file file$ and returns its thread ID. The thread ID can then be used to logon to the thread and find out when and why it finished.

See LOGONTOTHREAD:.

LOGONTOTHREAD:

Usage: LOGONTOTHREAD:(threadId&,statusWord&)

Logs on to the thread with ID threadId& and sets the status word statusWord& when the thread has completed. As for other 32-bit status words, statusW& will be set to &80000001 for pending and 0 for successful completion.

TERMINATECURRENTPROCESS:

Usage: TERMINATEPROCESS:(reason&)

Terminates the current process giving it the reason reason&. This causes the process to receive a shutdown message. reason& may take any value, with zero used to mean no errors.

TERMINATEPROCESS:

Usage: TERMINATEPROCESS:(proc$,reason&)

Terminates the process proc$ giving it the reason reason&. This causes the process to receive a shutdown message. reason& may take any value, with zero used to mean no errors.

KILLCURRENTPROCESS:

Usage: KILLCURRENTPROCESS:(reason&)

Kills the current process giving it the reason reason&. The process is killed without receiving a shutdown message. reason& may take any value, with zero used to mean no errors.

KILLPROCESS:

Usage: KILLPROCESS:(proc$,reason&)

Kills the process proc$ giving it the reason reason&. The process is killed without receiving a shutdown message. reason& may take any value, with zero used to mean no errors.

PLAYSOUND:

Usage: PLAYSOUND:(file$,volume&)

Plays the file file$, which may be a sound file or an alarm file. Does not return until the sound has completed.

volume& specifies the volume at which the file should be played, 0 specifies no volume and 3 specifies maximum volume. The play will be synchronous (i.e. the OPL program will stop running until the file has finished playing). For asynchronous sound playing see PLAYSOUNDA:.

PLAYSOUNDA:

Usage: PLAYSOUNDA:(file$,volume&,statusWord&)

Plays the file file$, which may be a sound file or an alarm file, asynchronously. It returns immediately, with the status word being set on completion or cancellation of the sound.

volume& specifies the volume at which the file should be played, 0 specifies no volume and 3 specifies maximum volume. The play will be asynchronous (i.e. the OPL program will continue running while the sound file is playing). statusWord& is the variable which will contain information about the state of the sounds file play. For synchronous sound playing see PLAYSOUND:.

It should be noted that the asynchronous signal must always be consumed with any of IOYIELD, IOWAIT or IOWAITSTAT32 before another PLAYSOUNDA: or PLAYSOUND: is used.

STOPSOUND&:

Usage: STOPSOUND&:

Stops the sound file that is currently playing. The return value is 1 if there was a sound file playing and 0 if not.

See PLAYSOUND:, PLAYSOUNDA:.

MOD&:

Usage: rem&=MOD&:(left&,right&)

Returns left& modulo right& (i.e. the remainder of left& divided by right&).

XOR&:

Usage: res&=XOR&:(left&,right&)

Returns the exclusive OR of left& and right&. A bit in the result has value 1 if the corresponding bit is set in either left& or in right&, but not in both, otherwise it is 0.

E.g. with left&=5 (binary 00000101) and right&=3 (binary 00000011), XOR&:(left&,right&) returns 6 (binary 00000110).

left& | 00000101
right& | 00000011
XOR&:(left&,right&) | 00000110

This is often used to invert particular bits in an integer. So left&=XOR&:(left&,3) inverts bits 0 and 1 in left&, where bit 0 is the rightmost bit, and leaves the other bits alone.

LOADRSC&:

Usage: id&=LOADRSC&:(file$)

Loads the resource file file$ and returns a handle for it.

See UNLOADRSC:, READRSC$:.

UNLOADRSC:

Usage: UNLOADRSC:(id&)

Unloads the resource file whose handle is id&.

See LOADRSC&:.

READRSC$:

Usage: string$=READRSC$:(id&)

Reads the resource in a resource file specified by id& which must already be loaded.

See LOADRSC&:.

READRSCLONG&:

Usage: long&=READRSCLONG&:(id&)

Reads a 32-bit value from a resource file specified by the id& which must already be loaded.

See LOADRSC&:.

CHECKUID$:

Usage: CHECKUID$:(Uid1&,Uid2&,Uid3&)

Returns a string which is a unique product of the three supplied UIDs.

SETPOINTERGRABON:

Usage: SETPOINTERGRABON:(WinId&,state&)

Enables (or disables) pointer grabs in a window. After this function has been called with state&=1, any "down" event in this window will cause a pointer grab, terminated by the next corresponding "up" event. The terminating "up" event is also sent to the window with the grab.

This function would typically be used for "drag-and-drop", and would typically be called after window creation so that pointer grab is enabled for the lifetime of the window.

state&=0 disables the grab.

See CLAIMPOINTERGRAB:.

MACHINENAME$:

Usage: name$=MACHINENAME$:

Returns the machine name.

MACHINEUNIQUEID:

Usage: MACHINEUNIQUEID:(BYREF high&,BYREF low&)

Sets high& and low& (which are passed BYREF) to high and low parts of the machine's unique ID.

ENDTASK&:

Usage: ret&=ENDTASK&:(threadId&,previous&)

Sends a shutdown message to a window group in the thread, threadId&.

previous& specifies the window group in the thread that is previous to the one required. Hence, setting previous& to 0 will specify the first window group in the thread.

The value returned by this procedure is the value of the window group on which action was taken, or -1 if a window group following that specified by previous& was not present. This return value could be passed back to this procedure to end the next window group in the thread.

An error will be raised if the window group is busy, does not respond to such requests or is in a system thread.

See KILLTASK&:.

KILLTASK&:

Usage: ret&=KILLTASK&:(threadId&,previous&)

Shuts down the window group that follows the window group specified by previous& in the thread, threadId&. It will ignore any wishes of the window group not to be shutdown.

The value returned by this procedure is the value of the window group on which action was taken, or -1 if a window group following that specified by previous& was not present. This return value could be passed back to this procedure to end the next window group in the thread.

See ENDTASK&:.

GETTHREADIDFROMOPENDOC&:

Usage: threadId&=GETTHREADIDFROMOPENDOC&:(doc$,BYREF previous&)

Returns the thread ID threadId& of the thread that contains the open document doc$.

doc$ should contain the full path of the open document and could for example be c:\opl\prog.opo.

previous&, passed by reference, is useful for situations where the document may be open more than once. Setting previous& to zero will cause this procedure to find the first window group that contains doc$. If one is found, previous& will be set to the window group value of that found document. This value could then passed back to this procedure as previous&, so the next window group instance of doc$ will be found, and so on. If this procedure sets previous& to -1 then doc$ could not be found after previous&. An error will also be raised if the open document is not found.

GETTHREADIDFROMAPPUID&:

Usage: threadId&=GETTHREADIDFROMAPPUID&:(uid&,BYREF previous&)

Returns the thread ID threadId& of the thread that contains a running instance of the application with UID uid&.

previous&, passed by reference, is useful for situations where the application may be running more than once. Setting previous& to zero will cause this procedure to find the first window group that is an instance of this application. If one is found, previous& will be set to the value of that window group. This value could then passed back to this procedure as previous&, so the next instance of the application can be found, and so on. If no instance of this application can be found following previous& then previous& will be set to -1. An error will also be raised if a running instance of the application is not found.

SETFOREGROUND:

Usage: SETFOREGROUND:

Moves the calling process to foreground.

See SETBACKGROUND:.

SETBACKGROUND:

Usage: SETBACKGROUND:

Moves the calling process to background.

See SETFOREGROUND:.

SETFOREGROUNDBYTHREAD&:

Usage: ret&=SETFOREGROUNDBYTHREAD&:(threadId&,previous&)

Moves the window group after previous& in the thread threadId& to foreground. Using previous&=0 specifies the first window group in the thread.

The value returned will be the window group on which action was taken, or -1 if the following window group was not found. This return value could be passed back to this procedure as previous& to put the next window group in threadId& to foreground.

See SETBACKGROUNDBYTHREAD&:.

SETBACKGROUNDBYTHREAD&:

Usage: ret&=SETBACKGROUNDBYTHREAD&:(threadId&,previous&)

Moves the window group after previous& in the thread threadId& to background. Using previous&=0 specifies the first window group in the thread.

The value returned will be the window group on which action was taken, or -1 if the following window group was not found. This return value could be passed back to this procedure again as a value for previous& to put the next window group in threadId& to background.

See SETFOREGROUNDBYTHREAD&:.

GETNEXTWINDOWGROUPNAME$:

Usage: name$=GETNEXTWINDOWGROUPNAME$:(threadId&,BYREF previous&)

Returns the name of the window group that follows the window group previous& in the thread threadId&. If previous&=0 the procedure will return the name of the first window group found.

See GETNEXTWINDOWID&:.

GETNEXTWINDOWID&:

Usage: winId&=GETNEXTWINDOWID&:(threadId&,BYREF previous&)

Returns the ID of the window group that follows the window group previous& in the thread threadId&. If previous& is 0 the procedure will return the ID of the first window group found.

See GETNEXTWINDOWGROUPNAME$:.

SENDKEYEVENTTOAPP&:

Usage: SENDKEYEVENTTOAPP&:(threadId&,previous&,code&,scanCode&, modifiers&,repeats&)

Sends a key event to the window group (application) that follows the window group with ID previous& (or the first window group if previous&=0), in the thread with ID threadId&. The key event is specified by code&, scanCode&, modifiers& and repeats&.

The value returned is the window group to which the key was sent.

IRDACONNECTTOSEND&:

Usage: IRDACONNECTTOSEND&:(protocol$,port&)

Synchronously sends out an infrared (IR) beam which looks for another infrared device. If another infrared device is looking to receive a beam then the devices will connect, otherwise this procedure will raise an error after a couple of seconds.

protocol$ can take either of the constants defined in System.oxh. These are KIrTinyTP$, used for communicating with other EPOC devices and KIrmux$ which is used for IR printing.

The value 8 is recommended for port& when communicating with other EPOC devices. Both devices will need to be using the same value for port&. port& must be 2 for connecting to IR printers.

If connecting to another EPOC device with this procedure the other device must connect by using IRDACONNECTTORECEIVE&:.

After connecting to another EPOC device you can both send and receive information.

After connecting to an IR printer use IRDAWRITE: to send text. When IRDADIASCONNECT: is called the printer will begin printing.

See IRDACONNECTTORECEIVE:, IRDAWRITE:, IRDAREAD:, IRDADISCONNECT:, IRDAWAITFORDISCONNECT:.

IRDACONNECTTORECEIVE:

Usage: IRDACONNECTTORECEIVE:(protocol$,port&,BYREF statusW&)

Asynchronously waits, without timing-out, for another EPOC device to attempt to connect via infrared (IR). This procedure takes the status word statusW&. When connection occurs the status word is set to zero.

Both EPOC devices must be using the same port which is specified by port&. The recommended port is 8.

One of the devices must connect with this procedure and the other with IRDACONNECTTOSEND&.

protocol$ specifies the IR protocol and should take the constant KIrTinyTP$, defined in System.oxh, when communicating with other EPOC devices.

After connecting to another EPOC device you can both send and receive information.

See IRDAWRITE:, IRDAREAD:, IRDADISCONNECT:, IRDAWAITFORDISCONNECT:.

IRDAWRITE:

Usage: IRDAWRITE:(chunk$, BYREF statusW&)

Sends a string chunk$ via infrared to another device after connection has been made. The procedure is asynchronous and the success of sending the string is reported in statusW&.

See IRDACONNECTTOSEND&:, IRDACONNECTTORECEIVE:, IRDAREAD:, IRDADISCONNECT:, IRDAWAITFORDISCONNECT:.

IRDAREAD$:

Usage: chunk$=IRDAREAD$:

Reads a text string via infrared from another device after connection has been made. The procedure is synchronous.

See IRDACONNECTTOSEND&:, IRDACONNECTTORECEIVE:, IRDWRITE:, IRDADISCONNECT:, IRDAWAITFORDISCONNECT:.

IRDAREADA:

Usage: IRDAREADA:(stringAddr&, BYREF statusW&)

Reads a text string via infrared from another device after connection has been made. The procedure is asynchronous with status word statusW&. The string passed by address should have a maximum length of 255 bytes. To pass a string by address use, ADDR(string$).

See IRDACONNECTTOSEND&:, IRDACONNECTTORECEIVE:, IRDWRITE:, IRDADISCONNECT:, IRDAWAITFORDISCONNECT:.

IRDAWAITFORDISCONNECT:

Usage: IRDAWAITFORDISCONNECT:

Verifies, when disconnecting from another IR device, that the other device has received everything sent. It should therefore be called by the device that last sends some information.

This procedure should not be used with printers: use IRDADISCONNECT: instead.

See IRDACONNECTTOSEND&:, IRDACONNECTTORECEIVE:, IRDADISCONNECT:, IRDAWAITFORDISCONNECT:.

IRDADISCONNECT:

Usage: IRDADISCONNECT:

Disconnects from another IR device. It should be called by the device that is the last to receive some information. IRDAWAITFORDISCONNECT: is used by the last device to send some information, except when printing via IR when IRDADISCONNECT: should be used to disconnect from the printer and commence printing.

See IRDACONNECTTOSEND&:, IRDACONNECTTORECEIVE:, IRDADISCONNECT:, IRDAWAITFORDISCONNECT:.

MAINBATTERYSTATUS&:

Usage: MAINBATTERYSTATUS&:

Returns the current power of the main batteries. The following possible return values are supplied as constants in System.oxh:

    CONST KBatteryZero&=0
    CONST KBatteryVeryLow&=1
    CONST KBatteryLow&=2
    CONST KBatteryGood&=3

BACKUPBATTERYSTATUS&:

Usage: BACKUPBATTERYSTATUS&:

Returns the current power of the backup batteries. The following possible return values are supplied as constants in System.oxh:

    CONST KBatteryZero&=0
    CONST KBatteryVeryLow&=1
    CONST KBatteryLow&=2
    CONST KBatteryGood&=3

CAPTUREKEY&:

Usage: CAPTUREKEY&:(keyCode&,mask&,modifier&)

Allows the program that calls it to capture keys when it is not in foreground. The keys to be captured are specified using keycode&, mask& and modifier&. The value returned is a handle which can be passed to CANCELCAPTUREKEY: to cancel the capture.

The following constants are supplied in System.oxh to be used in conjunction with this procedure:

    CONST KModifierAutorepeatable&=&00000001
    CONST KModifierKeypad&=&00000002
    CONST KModifierLeftAlt&=&00000004
    CONST KModifierRightAlt&=&00000008
    CONST KModifierAlt&=&00000010
    CONST KModifierLeftCtrl&=&00000020
    CONST KModifierRightCtrl&=&00000040
    CONST KModifierCtrl&=&00000080
    CONST KModifierLeftShift&=&00000100
    CONST KModifierRightShift&=&00000200
    CONST KModifierShift&=&00000400
    CONST KModifierLeftFunc&=&00000800
    CONST KModifierRightFunc&=&00001000
    CONST KModifierFunc&=&00002000
    CONST KModifierCapsLock&=&00004000
    CONST KModifierNumLock&=&00008000
    CONST KModifierScrollLock&=&00010000
    CONST KModifierKeyUp&=&00020000
    CONST KModifierSpecial&=&00040000
    CONST KModifierDoubleClick&=&00080000
    CONST KModifierPureKeycode&=&00100000
    CONST KAllModifiers&=&001fffff

See CANCELCAPTUREKEY&:.

CANCELCAPTUREKEY:

Usage: CANCELCAPTUREKEY:(handle&)

Cancels an outstanding key capture which is specified by the handle handle&.

See CAPTUREKEY&:.

SETPOINTERCAPTURE:

Usage: SETPOINTERCAPTURE:(WinId&,flags&)

Sets the (OPL) window with window ID winId& to capture pointer events.

flags& can take a summed combination of the following:

value | meaning
0 | capture disabled
&01 | capture enabled
&02 | capture (not drag-and-drop)

When a window captures pointer events, the position of any events received will be relative to its origin, i.e. the top left corner of that window, i.e. the window’s 0,0 co-ordinate becomes the origin for pointer events. Events don’t need to be inside the window to be registered. For example, if the screen was touched 1 pixel above and 1 pixel to the left of a window that was capturing pointer events, the pointer event would be returned with the position of the event being -1,-1 .

"Capture (not drag-and-drop)" will cause events of the "drag-and-drop" nature to be sent to the window that would have received them had the pointer not been captured..

CLAIMPOINTERGRAB:

Usage: CLAIMPOINTERGRAB:(WinId&,state&)

Claims the pointer grab for the window with ID winId& from another window, if a pointer grab is already in effect in the other window. All subsequent events will be delivered to this window, instead of the window that originally had the pointer grab. The next "up" event terminates the pointer grab, and is also delivered to the window that claimed the grab, if state& is set to 1.

This function would typically be used where clicking in a window pops up another window, and where the popped-up window wishes to grab the pointer as though the original click had been in that window.

To summarise the values of state& for the OPL window,

value | meaning
0 | don't deliver the following "up" event to this window
1 | deliver the following "up" event to this window

See SETPOINTERGRABON:

OPENFILEDIALOG$:

Usage: file$=OPENFILEDIALOG$:(seedFile$,uid1&,uid2&,uid3&)

Displays the standard ‘Open file’ dialog. seedFile$ provides a starting file which is displayed when the dialog is opened. So, for example, if seedFile$="C:\Documents\Myfile" then the file MyFile will be initially displayed in the ‘Name’ selector box, the Documents folder will be initially displayed in the ‘Folder’ selector box and C will be displayed in the disk selector. You must always seed the dialog: you cannot pass a null seedFile$ string to OPENFILEDIALOG$:. If seedFile$ does not include a drive name, then an error is raised.

The selection of files may be restricted by UID by specifying appropriate values for uid1&, uid2& and uid3& in exactly the same way as when using the dFILE keyword. See the ‘Alphabetic Listing’ section for details of this.

The return value is the filename, including the full path of the file selected to be opened.

CREATEFILEDIALOG$:

Usage: file$=CREATEFILEDIALOG$:(seedPath$)

Displays the standard ‘Create new file’ dialog. seedPath$ provides a starting path which is displayed when the dialog is opened. So, for example, if seedPath$="C:\Documents\" then the Documents folder will be intially displayed in the ‘Folder’ selector box and C in the disk selector. If you supply a filename in seedPath$, then this will be displayed as a suggested filename in the ‘Name’ selector box. You must always seed the dialog: you cannot pass a null seedPath$ string to CREATEFILEDIALOG$:. If seedPath$ does not include a drive name, then an error is raised.

The return value is the filename, including the full path of the file to be created.

SAVEASFILEDIALOG$:

Usage: path$=SAVEASFILEDIALOG$:(seedPath$,BYREF useNewFile%)

Displays the standard ‘Save as’ dialog. seedPath$ provides a starting path which is displayed when the dialog is opened. So, for example, if seedPath$="C:\Documents\" then the Documents folder will be initially displayed in the ‘Folder’ selector box and C in the disk selector. If you supply a filename in seedPath$, then this will be displayed as a suggested filename in the ‘Name’ selector box. You must always seed the dialog: you cannot pass a null seedPath$ string to SAVEASFILEDIALOG$:. If seedPath$ does not include a drive name, then an error is raised.

UseNewFile% specifies the initial setting of the checkbox which determines whether a new file should be used when saving. This value is non-zero then the tick will be set initially, if it is zero, then it will not be. The procedure writes back a value to this variable which will be KTrue% if the symbol is set on exiting the dialog and KFalse% if not (see Const.oph). If you pass #0 as the value of this argument, then this item will not be displayed in the dialog at all (as in many EPOC applications) so that whether a new file is used on not is not decided by the user, but by the programmer.

The return value is the filename to save as, including the full path.

EPOC SDK Home Glossary Previous Up


OplTran

  • About OplTran
  • opltran.exe — Command line OPL translator


About OplTran

Contents

  • Overview
  • Example

Overview

OplTran is a command-line utility which enables OPL developers to translate OPL modules into .opo or .app files on a PC. The output files are implementation-independent; they will run both on the EPOC Emulator and may also be copied to a target EPOC machine, and run from there.

opltran is invoked using a batch file, opltran.bat, which is installed in directory \epoc32\tools. It is recommended that directory \epoc32\tools be added to your path if it is not there already. You may run opltran.bat by typing opltran at the command prompt from any directory.

Example

An OPL program may be translated in one of two ways. If it was written using the Program text editor on either the EPOC Emulator, or an EPOC machine, it may be translated by tapping the "Tran" button on Program's toolbar menu. If it was written using the above methods, or using any PC-based text editor, translate it using opltran.

For example, assuming that the OPL SDK, and opltran have been installed on drive h:, translate the program ophello.opl by typing the following at the command prompt from any directory on drive h:

    opltran h:\epoc32ex\opl\ophello -oh:\epoc32\wins\c\opl\hello

This translates ophello.opl (the .opl extension is added automatically), creates target directory hello and generates the output file ophello.opo in hello. The .opo program may be run from the EPOC Emulator. To invoke the emulator, run the program \epoc32\release\wins\deb\epoc.exe. ophello.opo is located in folder c:\opl\hello\. It may also be copied to an appropriate directory on an EPOC machine using a program such as EPOC Connect, and run from there.

The example program can also be translated using bldhello.bat from directory \epoc32ex\opl\.

    bldhello ophello


opltran.exe — Command line OPL translator

Contents

  • Purpose
  • Command-line syntax

Purpose

The opltran utility provides command-line OPL translation from the PC command line. It is invoked using the opltran.bat batch file, with up to five parameters; only one of which is mandatory.

OPL source files and include files may be in text format or native EPOC format. This allows programs developed on an EPOC machine to be transferred to and from the PC with the minimum of conversion.

Command-line syntax

opltran opl-filename [-i include-path] [-o output-path] [-s] [-e] [-q] [-conv]

Arguments

opl-filename

The name of the OPL source file to be translated. The name must be fully qualified (e.g. h:\epoc32ex\opl\ophello.opl), with the following exceptions:

  • if the OPL source file is located in the current directory, its filename alone may be specified
  • if unspecified, the drive letter will default to the drive on which opltran has been installed

Wild cards may be specified in order to translate multiple OPL files within the same directory, e.g. ? to match a single character or * to match a group of characters.

include-path

The directory in which to search for header files.

output-path

The target directory for the .opo output file.

-i

Set include path. Optional, but if supplied, specifies the directory in which to search for header files.

Directories are searched in the following order: first, the directory containing the opl-filename source file; second, the include-path provided by this argument, if specified; third, the directory \epoc32\winc\opl\; and finally, the directory \epoc32\release\wins\deb\z\system\opl\. The header file can be in text format, or native EPOC format.

-o

Set output path. Optional, but if supplied, specifies the target directory for the .opo output file.

If this parameter is not supplied, the output file is generated in the same directory as the source opl-filename. If the program is an OPL app, this parameter is ignored — the app will be generated in directory \epoc32\release\wins\deb\z\system\apps\appname\.

-s

Symbolic debugging information. Optional, but if supplied, causes debugging information to be incorporated in generated .opo or.app files. In a addition, a .sym file is created in the same directory as the .opo or .app, which provides symbolic debugging information.

-e

Alternate error format. Optional, but if supplied, translation errors are reported using an alternate format used by popular PC-based editors:

filename(lineNum) : error errNum : column colNum : error msg

For example, a syntax error (error 19) at line 10, column 5 of the file would be reported as:

    h:\epoc32ex\ophello.opl(10) : error 19 : column 5 : Syntax error

-q

Quiet mode. Optional, but if supplied, reports errors only.

-conv

Converter mode. Optional, but if supplied, converts source files from ASCII source to EPOC program file format, or visa versa. The direction of the conversion is dependent of the current source file format.

When the files are converted, the first letter of the extension is also changed, e.g. in a conversion from OPL to ASCII, opl, ohx and oph files become tpl, txh, and tph respectively.

Notes

  • A brief summary of the command-line syntax may be obtained by typing opltran at the command prompt.
  • The include and output paths must be fully qualified (although the drive letter defaults to the letter specified in the source file opl-filename). Relative paths are not recognised.
  • The search method used when including header files into the program allows opltran to use the native format OPL include files as supplied with the emulator in \epoc32\release\wins\deb\z\system\opl\, as well as additional generic include files stored as text or EPOC format in \epoc32\winc\opl\.
  • WINC file handling prevents writing to the PC Z: drive. As opltran runs in the WINC environment, writing opo/app files to Z: drive is not permitted. If you are translating OPL source on Z:, use the -ooutput_path option to direct the output to another drive.
  • When the -conv flag is specified, no translation is performed (e.g. the -i, -s, -e and -q flags are ignored).
  • opltran will silently overwrite any existing files, so ensure you have a backup of your source code before using the tool.
  • If an error is detected during translation, the tool stops with an exit status of 1. This can be detected with the batch errorlevel command. A descriptive error message is output in the following format:
Error filename line Num: error msg

e.g. Error LOC::h:\epoc32ex\ophello.opl 10: Syntax error

EPOC SDK Home Glossary Previous Up


Appendices

  • Operators and logical expressions
  • Serial ports and printing
  • Character codes
  • EPOC Error Values
  • Listing of Const.oph


Operators and logical expressions

Contents

  • Operators
    • Arithmetic operators
    • Comparison operators
    • Logical and bitwise operators
    • The % operator
    • Precedence
    • When there is equal precedence
    • Changing precedence with brackets
    • Precedence of integer and floating-point values
    • Type conversions and rounding down
  • Logical expressions
  • Logical and bitwise operators
    • When used with floating-point numbers
    • When used with integer or long integer values

Operators

Section Contents

  • Arithmetic operators
  • Comparison operators
  • Logical and bitwise operators
  • The % operator
    • Examples:
  • Precedence
  • When there is equal precedence
  • Changing precedence with brackets
  • Precedence of integer and floating-point values
  • Type conversions and rounding down

These operators are available in OPL:

Arithmetic operators

+ | add
- | subtract
* | multiply
/ | divide
** | raise to a power
- | unary minus (in negative numbers for example, -10)
% | percent
MOD | modulo — the remainder of the division of two numbers

Comparison operators

> | greater than
>= | greater than or equal to
< | less than
<= | less than or equal to
= | equal to
<> | not equal to

Logical and bitwise operators

AND | logical AND
OR | logical OR
NOT | logical NOT
XOR | exclusive OR

The % operator

The percentage operator can be used in expressions like this:

Expression | Meaning | Result
60+5% | 60 plus 5% of 60 | 63
60-5% | 60 minus 5% of 60 | 57
60*5% | 5% of 60 | 3
60/5% | of what number is 60 5%? | 1200

It can also be used like this:

105>5% | what number, when increased by 5%, becomes 105? | 100
105<5% | how much of 105 is a 5% increase? | 5

Examples:

To add 15% tax to 345:

345+15% Result = 396.75

To find out what the price was before tax:

396.75>15% Result = 345

To find out how much of a total price is tax:

396.75<15% Result = 51.75

Precedence

Highest: | **
 | - (unary minus)
 | NOT
 | * /
 | + - (subtraction)
 | = > < <> >= <=
Lowest: | AND OR

So 7+3*4 returns 19 (3 is first multiplied by 4, and 7 is added to the result) not 40 (4 times 10).

When there is equal precedence

In an expression where all operators have equal precedence, they are evaluated from left to right (with the exception of powers). For example, in a+b-c, a is added to b and then c is subtracted from the result.

Powers are evaluated from right to left for example, in a%**b%**c%, b% will first be raised to the power of c% and then a% will be raised to the power of the result.

Changing precedence with brackets

The result of an expression such as a+b+c is the same whether you first add a to b, or b to c. But how is a+b*c/d evaluated? You may want to use brackets to either:

  • Make it obvious what the order of calculation is

or

  • Change the order of calculation.

By default, a+b*c/d is evaluated in the order: b multiplied by c, then divided by d, then added to a. To perform the addition and the division before the multiplication, use brackets: (a+b)*(c/d). When in doubt, simply use brackets.

Precedence of integer and floating-point values

You are free to mix floating-point and integer values in expressions, but be aware how OPL handles the mix:

  • In each part of the calculation, OPL uses the simplest arithmetic possible. Two integers will use integer arithmetic, and this can give unexpected results: 7/2 gives the integer 3. Otherwise floating-point arithmetic is used (7.0 is a floating-point number, so 7.0/2 gives the floating-point number 3.5).
  • Finally, the evaluated result of the right-hand side of an expression is automatically converted to the same type as the variable to which it is assigned.

For example, your procedure might include the expression a%=b%+c This is handled like this: b% is converted to floating-point and added to c. The resulting floating-point value is then automatically converted to an integer in order to be assigned to the integer variable a%.

Such conversions may produce odd results for example a%=3.0*(7/2) makes a%=9, but a%=3.0*(7.0/2) makes a%=10. OPL does not report this as an error, so it’s up to you to ensure that it doesn’t happen unless you want it to.

Type conversions and rounding down

There are three numeric types floating-point, integer and long integer. You can assign any of these types to any other. The value on the right-hand side will be automatically converted to the type of the variable on the left-hand side. For example:

  • If you assign an integer value to a floating-point variable, there are no problems.
  • If you assign a floating-point value to an integer variable, the value is converted to an integer, always rounded towards zero for example, if you declare LOCAL c% and then say c%=3.75, the value 3.75 is converted to the value 3.

Rounding down towards zero can sometimes cause unusual results. For example, a%=2.9 would give a% the value 2, and a%=-2.3 would give a% the value -2.

When you run a module, if the left-hand side of an assignment has a narrower range than the right-hand side, you may get an error (for example, if you had x%=a& where a& had the value 320000).

To control how floating-point numbers are rounded when converted, use the INT function.

Logical expressions

The comparison operators and logical operators are based on the idea that a certain situation can be evaluated as either true or false. For example, if a%=6 and b%=8, a%>b% would be ‘False’.

These operators are useful for setting up alternative paths in your procedures. For example you could say:

    IF salary<expenses
          doBad:
    ELSE
          doGood:
    ENDIF

You can also make use of the fact that the result of these logical expressions is represented by an integer:

  • ‘True’ is represented by the integer -1
  • ‘False’ is represented by the integer 0 (zero).
operator | example | result returned | return value
< | a<b | True if a less than b | -1
 |  | False if a greater than or equal to b | 0
> | a>b | True if a greater than b | -1
 |  | False if a less than or equal to b | 0
<= | a<=b | True if a less than or equal to b | -1
 |  | False if a greater than b | 0
= | a>=b | True if a greater than or equal to b | -1
 |  | False if a less than b | 0
<> | a<>b | True if a not equal to b | -1
 |  | False if a equal to b | 0
= | a=b | True if a equal to b | -1
 |  | False if a not equal to b | 0

These integers can be assigned to a variable or displayed on the screen to tell you whether a particular condition is true or false, or used in an IF statement.

For example, in a procedure you might arrive at two sub-totals, a and b. You want to find out which is the greater. So use the statement, PRINT a>b. If zero is displayed, a and b are equal or b is the larger number; if -1 is displayed, a>b is true a is the larger.

Logical and bitwise operators

Section Contents

  • When used with floating-point numbers
  • When used with integer or long integer values
    • AND
    • OR
    • NOT

The operators AND, OR and NOT have different effects depending on whether they are used with floating-point numbers or integers:

When used with floating-point numbers

AND, OR and NOT are logical operators, and have the following effects:

example | result | integer returned
a AND b | True if both a and b are non-zero | -1
 | False if either a or b are zero | 0
a OR b | True if either a or b is non-zero | -1
 | False if both a and b are zero | 0
NOT a | True if a is zero | -1
 | False if a is non-zero | 0

When used with integer or long integer values

AND, OR and NOT are bitwise operators.

The way OPL holds integer numbers internally is as a binary code - 16-bit for integers, 32-bit for long integers. Bitwise means that an operation is performed on individual bits. A bit is set if it has the value 1, and clear if it has the value 0. Long integer values with AND, OR and NOT behave the same as integer values.

AND

Sets the result bit if both input bits are set, otherwise clears the result bit.

For example, the statement PRINT 12 AND 10 displays 8. To understand this, write 12 and 10 in binary:

12      0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0
10      0 0 0 0 0 0 0 0 0 0 0 0 1 0 1 0

AND acts on each pair of bits. Thus, working from left to right discounting the first 12 bits (since 0 AND 0 gives 0):

1 AND 1 1
1 AND 0 0
0 AND 1 0
0 AND 0 0

The result is therefore the binary number 1000, or 8.

OR

Sets the result bit if either input bit is set, otherwise clears the result bit.

What result would the statement PRINT 12 OR 10 give? Again, write down the numbers in binary and apply the operator to each pair of digits:

1 OR 1 1
1 OR 0 1
0 OR 1 1
0 OR 0 0

The result is the binary number 1110, or 14 in decimal.

NOT

Sets the result bit if the input bit is not set, otherwise clears the result bit.

NOT works on only one number. It returns the one’s complement, i.e. it replaces 0s with 1s and 1s with 0s.

So since 7 is 0000000000000111, NOT 7 is 1111111111111000. This is the binary representation of -8.

A quick way of calculating NOT for integers is to add 1 to the original number and reverse its sign. So NOT 23 is -24, NOT 0 is -1 and NOT -1 is 0.


Serial ports and printing

Contents

  • Introduction
  • Using the serial port
    • Serial port settings
    • Setting the serial port characteristics
    • Reading from the serial port
  • Printing to a file
    • Printing to a file on the local machine

Introduction

You can use LPRINT in an OPL program to send information from the serial port (for printing or otherwise). OPL provides more advanced formatting features and printing control using Printer OPX, see Printer.opx — Printer and text handling.

It is also possible to read information from the serial port.

Using the serial port

Section Contents

  • Serial port settings
  • Setting the serial port characteristics
    • The rsset: procedure:
    • Example of calling the procedure
    • Advanced use
  • Reading from the serial port
    • Example reading from serial port

In your OPL program, set up the port with the statement LOPEN "TTY:A".

Now LPRINT should send information down the serial link lead for example, to an attached printer. If it does not, the serial port settings are not correct.

Serial port settings

LOPEN "TTY:A" opens the serial port with the following default characteristics:

9600 baud
no parity
8 data bits
1 stop bit
RTS handshaking.

If your printer (or other device) does match these characteristics, the LOPEN statement sets the port up correctly, and subsequent LPRINT statements will print there successfully.

If your printer does not match these characteristics, you must use a procedure like the one listed below to change the characteristics of the serial port, before LPRINTs will print successfully to your printer.

Printers very often use DSR (DSR/DTR) handshaking, and you may need to set the port to use this.

Setting the serial port characteristics

Calling the procedure

The rsset: procedure listed below provides a convenient way to set up the serial port.

Each time you use an LOPEN "TTY:" statement, follow it with a call to the rsset: procedure. Otherwise the LOPEN will use the default characteristics.

Passing values to the procedure

Pass the procedure the values for the five port characteristics, like this:

    rsset:(baud%,parity%,data%,stop%,hand%,&0)

The final parameter, which should be &0 here, is only used when reading from the port.

To find the value you need for each characteristic, use the tables below. You must give values to all five parameters, in the correct order.

Baud

Baud | 50 | 75 | 110 | 134 | 150 | 300 | 600 | 1200 | 1800 | 2000 | 2400 | 3600 | 4800 | 7200 | 9600 | 19200
value | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16

Parity

Parity | NONE | EVEN | ODD
value | 0 | 1 | 2

Data bits

5, 6, 7 or 8

Stop bits

2 or 1

Handshaking

Handshaking | ALL | NONE | XON | RTS | XON+RTS | DSR | XON+DSR | RTS+DSR
value | 11 | 4 | 7 | 0 | 3 | 12 | 15 | 8

The rsset: procedure:

    PROC rsset:(baud%,parity%,data%,stop%,hand%,term&)
          LOCAL frame%,srchar%(6),dummy%,err%
          frame%=data%-5
          IF stop%=2 :frame%=frame% OR 16 :ENDIF
          IF parity% :frame%=frame% OR 32 :ENDIF
          srchar%(1)=baud% OR (baud%*256)
          srchar%(2)=frame% OR (parity%*256)
          srchar%(3)=(hand% AND 255) OR $1100
          srchar%(4)=$13
          POKEL ADDR(srchar%(5)),term&
          err%=IOW(-1,7,srchar%(1),dummy%)
          IF err% :RAISE err% :ENDIF
    ENDP

Take care to type this program in exactly as it appears here.

Example of calling the procedure

    PROC test:
          PRINT "Testing port settings"
          LOPEN "TTY:A"
          LOADM "rsset"
          rsset:(8,0,8,1,0,&0)
          LPRINT "Port OK" :LPRINT
          PRINT "Finished" :GET
          LCLOSE
    ENDP

rsset:(8,0,8,1,0,&0) sets 1200 Baud, no parity, 8 data bits, 1 stop bit, and RTS/CTS handshaking.

Advanced use

The section of the rsset: procedure which actually sets the port is this:

    srchar%(1)=baud% OR (baud%*256)
    srchar%(2)=frame% OR (parity%*256)
    srchar%(3)=(hand% AND 255) OR $1100
    srchar%(4)=$13
    POKEL ADDR(srchar%(5)),term&
    err%=IOW(-1,7,srchar%(1),dummy%)
    IF err% :RAISE err% :ENDIF

The elements of the array srchar% contain the values specifying the port characteristics. If you want to write a shorter procedure, you could work out what these values need to be for a particular setup you want, assign these values to the elements of the array, and then use the IOW function (followed by the error check) exactly as above.

Reading from the serial port

If you need to read from the serial port, you must also pass a parameter specifying terminating mask for the read function. If term& is not supplied, the read operation terminates only after reading exactly the number of bytes requested. In practice, however, you may not know exactly how many bytes to expect and you would therefore request a large maximum number of bytes. If the sender sends less than this number of bytes altogether, the read will never complete.

The extra parameter, term& , allows you to specify that one or more characters should be treated as terminating characters. The terminating character itself is read into your buffer too, allowing your program to act differently depending on its value.

The 32 bits of term& each represent the corresponding ASCII character that should terminate the read. This allows any of the ASCII characters 1 to 31 to terminate the read.

For example, to terminate the read when Control-Z (i.e. ASCII 26) is received, set bit 26 of term&. To terminate on Control-Z or <CR> or <LF> which allows text to be read a line at a time or until end of file set the bits 26, 10 and 13. In binary, this is:

0000 0100 0000 0000 0010 0100 0000 0000

Converting to a long integer gives &04002400 and this is the value to be passed in term& for this case.

Note:
  • Clearly term& cannot be used for binary data which may include a terminating character by chance. You can sometimes get around this problem by using term& and having the sender transmit a leading non-binary header specifying the exact number of full-binary data following. You could then reset the serial characteristics not to use term& , read the binary data, and so forth.

Example reading from serial port

This example assumes that each line sent has maximum length 255 characters and is terminated by a <CR> and that Control-Z signals the end of all the data.

    PROC testread:
          LOCAL ret%,pbuf&,pbuf1&,buf$(255),end%,len%
          PRINT "Test reading from serial port"
          LOPEN "TTY:A"
          LOADM "rsset"                  REM receive at 2400 without h/shake
          rsset:(11,0,8,1,0,&04002000)                  REM Control-Z or CR
          pbuf&=ADDR(buf$)
          DO            REM read max 255 bytes, after leading count byte
                len%=255
                pbuf1&=pbuf&+1
                ret%=IOW(-1,1,#pbuf1&,len%)
                POKEB pbuf&,len%      REM len% = length actually read
                                        REM including terminator char
                end%=LOC(buf$,CHR$(26)) REM non-zero for Control-Z
                IF ret%<0 and ret%<>-43
                      BEEP 3,500
                      PRINT
                      PRINT "Serial read error: ";ERR$(ret%)
                ENDIF
                IF ret%<>-43          REM if received with terminator
                      POKEB pbuf&,len%-1       REM remove terminator
                      PRINT buf$                      REM echo with CRLF
                ELSE
                      PRINT buf$;                  REM echo without CRLF
                ENDIF
          UNTIL end%
          PRINT "End of session" :PAUSE -30 :KEY
    ENDP
Note:
  • Note that passing -1 as the first argument to I/O keywords means that the LOPEN handle is to be used. Also, OPL strings have a leading byte giving the length of the rest of the string, so the data is read beyond this byte. The byte is then poked to the length which was read.

Printing to a file

Printing to a file on the local machine

In your OPL program, specify the destination file with an LOPEN statement like this:

LOPEN "D:\PRINT\MEMO"


Character codes

Contents

  • The EPOC character set
    • Entering characters at the keyboard
    • Modification of character codes
    • Other special keys
    • Character codes of special keys
  • Special character codes with PRINT
  • Keyboard modifiers

The EPOC character set

Section Contents

  • Entering characters at the keyboard
  • Modification of character codes
  • Other special keys
  • Character codes of special keys

The following are character code descriptions for the 8-bit character set used in the English version of EPOC. The definition is intended to be synonymous with code page 1252, which is also used by Microsoft for Windows systems.

Those items in the ‘character’ column which are given in italics are descriptions. Particularly note that the code for backspace will be the code returned when you press Del, that for carriage return will be returned when you press Enter and that for escape when you press Esc.

Entering characters at the keyboard

Any of the characters in the character set can be entered directly from the keyboard:

Look up the decimal code of the character you want from the preceding table.

Hold down the Ctrl key and type the three-digit code, then release the control key.

Make sure that you include any preceding zeros to make the code three digits long - for example use Ctrl+096 to enter a single left quote, ‘.

Modification of character codes

The keycode value is modified when pressing Ctrl at the same time as another key.

For alphabetic keys the Ctrl modified value is the ordinal position in the alphabet ignoring upper and lower case, i.e. 1 for Ctrl+A or Shift+Ctrl+A, 2 for Ctrl+B or Shift+Ctrl+B, etc. This value can be found by ANDing the ASCII value of the alphabetic character with (NOT $60). So the keycode of upper and lower case letters is the same when pressed together with Ctrl, with only the value of the modifier differing. For example, pressing Ctrl+J returns 10 which is (%j AND (NOT $60)).

Other special keys

The keycodes returned by GETEVENT32 etc. for these special keys are as follows:

Character codes of special keys

The GET and KEY functions return the character code of the key that was pressed. Some of the keys are not in the character set. They return these numbers:

Special character codes with PRINT

These values can be used with PRINT and CHR$():

7 | beep
8 | backspace
9 | tab
10 | line feed
12 | form feed (clear screen)
13 | carriage return (cursor to left of window)

For example, PRINT CHR$(8) moves the cursor backwards, one character to the left.

Keyboard modifiers

Keyboard modifier values are the same for all machines.

GETEVENT a%() returns the modifier for a keypress in (a%(2) AND $ff).

GETEVENT32 ev&() returns modifiers to ev&(4) for keypresses and in ev&(5) for pointer (pen) events.

The values which can be returned are as follows:

modifier | value | constant name
Shift | 2 | KKmodShift%
Control | 4 | KKmodControl%
Caps | 16 | KKmodCaps%
Fn | 32 | KKmodFn%


EPOC Error Values

The error values returned by EPOC are listed below. Note that these are different from the error values returned by OPL in general. They may, however, be returned in the status word of asynchronous OPX functions.

meaning | value | meaning | value
no error | 0 | not found | -1
general error | -2 | cancel | -3
no memory | -4 | not supported | -5
argument error | -6 | total loss of precision | -7
bad handle | -8 | overflow error | -9
underflow error | -10 | already exists | -11
path not found | -12 | died | -13
in use | -14 | server terminated | -15
server busy | -16 | completion | -17
not ready | -18 | unknown error | -19
corrupt | -20 | access denied | -21
locked | -22 | write error | -23
dismounted | -24 | end of file | -25
disk full | -26 | bad driver | -27
bad name | -28 | comms line fail | -29
comms frame error | -30 | comms overrun | -31
comms parity error | -32 | timed out | -33
could not connect | -34 | could not disconnect | -35
disconnected | -36 | bad library entry point | -37
bad descriptor | -38 | abort | -39
too big | -40 | divide by zero | -41
bad power | -42 | directory full | -43


Listing of Const.oph

    rem CONST.OPH version 1.02
    rem Constants for OPL
    rem Copyright (c) 1997-1999 Symbian Ltd. All rights reserved.

    rem Changes in 1.02:
    rem   Added subscripts for gCOLORINFO keyword
    rem   Added new colour modes for DEFAULTWIN and gCREATE
    rem   Added MIME priority values.
    rem Changes in 1.01:
    rem - some language codes added
    rem - consts for KKeyUpArrow%,KKeyDownArrow%,... apply to 16-bit
    rem   keywords GET, GETEVENT, KEY
    rem   KKeyUpArrow32%,KKeyDownArrow32%,... added for 32-bit
    rem   keywords GETEVENT32 etc.

    rem General constants
    const KTrue%=-1
    const KFalse%=0

    rem Data type ranges
    const KMaxStringLen%=255
    const KMaxFloat=1.7976931348623157E+308
    const KMinFloat=2.2250738585072015E-308 rem Minimum with full precision in mantissa
    const KMinFloatDenorm=5e-324  rem Denormalised (just one bit of precision left)
    const KMinInt%=$8000 rem -32768 (translator needs hex for maximum ints)
    const KMaxInt%=32767
    const KMinLong&=&80000000 rem -2147483648 (hex for translator)
    const KMaxLong&=2147483647

    rem Special keys
    const KKeyEsc%=27
    const KKeySpace%=32
    const KKeyDel%=8
    const KKeyTab%=9
    const KKeyEnter%=13
    rem Key constants for 16-bit keywords GETEVENT etc.
    const KGetMenu%=290    rem unfortunately must be named
     rem KGetMenu% because KKeyMenu% clashes with badly-named
     rem other constant which cannot be changed for
     rem compatibility reasons.
    const KKeyUpArrow%=256
    const KKeyDownArrow%=257
    const KKeyLeftArrow%=259
    const KKeyRightArrow%=258
    const KKeyPageUp%=260
    const KKeyPageDown%=261
    const KKeyPageLeft%=262
    const KKeyPageRight%=263

    const KKeyMenu%=4150         rem const kept for compatibility
    const KKeySidebarMenu%=10000 rem const kept for compatibility

    rem Key constants for 32-bit keywords GETEVENT32 etc.
    const KKeyMenu32%=4150
    const KKeySidebarMenu32%=10000
    const KKeyPageLeft32%=4098
    const KKeyPageRight32%=4099
    const KKeyPageUp32%=4100
    const KKeyPageDown32%=4101
    const KKeyLeftArrow32%=4103
    const KKeyRightArrow32%=4104
    const KKeyUpArrow32%=4105
    const KKeyDownArrow32%=4106

    rem Month numbers
    const KJanuary%=1
    const KFebruary%=2
    const KMarch%=3
    const KApril%=4
    const KMay%=5
    const KJune%=6
    const KJuly%=7
    const KAugust%=8
    const KSeptember%=9
    const KOctober%=10
    const KNovember%=11
    const KDecember%=12

    rem Graphics
    const KDefaultWin%=1
    const KgModeSet%=0
    const KgModeClear%=1
    const KgModeInvert%=2
    const KtModeSet%=0
    const KtModeClear%=1
    const KtModeInvert%=2
    const KtModeReplace%=3

    const KgStyleNormal%=0
    const KgStyleBold%=1
    const KgStyleUnder%=2
    const KgStyleInverse%=4
    const KgStyleDoubleHeight%=8
    const KgStyleMonoFont%=16
    const KgStyleItalic%=32

    rem For 32-bit status words IOWAIT and IOWAITSTAT32
    rem Use KErrFilePending% (-46) for 16-bit status words
    const KStatusPending32&=&80000001

    rem Error codes
    const KErrGenFail%=-1
    const KErrInvalidArgs%=-2
    const KErrOs%=-3
    const KErrNotSupported%=-4
    const KErrUnderflow%=-5
    const KErrOverflow%=-6
    const KErrOutOfRange%=-7
    const KErrDivideByZero%=-8
    const KErrInUse%=-9
    const KErrNoMemory%=-10
    const KErrNoSegments%=-11
    const KErrNoSemaphore%=-12
    const KErrNoProcess%=-13
    const KErrAlreadyOpen%=-14
    const KErrNotOpen%=-15
    const KErrImage%=-16
    const KErrNoReceiver%=-17
    const KErrNoDevices%=-18
    const KErrNoFileSystem%=-19
    const KErrFailedToStart%=-20
    const KErrFontNotLoaded%=-21
    const KErrTooWide%=-22
    const KErrTooManyItems%=-23
    const KErrBatLowSound%=-24
    const KErrBatLowFlash%=-25
    const KErrExists%=-32
    const KErrNotExists%=-33
    const KErrWrite%=-34
    const KErrRead%=-35
    const KErrEof%=-36
    const KErrFull%=-37
    const KErrName%=-38
    const KErrAccess%=-39
    const KErrLocked%=-40
    const KErrDevNotExist%=-41
    const KErrDir%=-42
    const KErrRecord%=-43
    const KErrReadOnly%=-44
    const KErrInvalidIO%=-45
    const KErrFilePending%=-46
    const KErrVolume%=-47
    const KErrIOCancelled%=-48
    rem OPL specific error
    const KErrSyntax%=-77
    const KOplStructure%=-85
    const KErrIllegal%=-96
    const KErrNumArg%=-97
    const KErrUndef%=-98
    const KErrNoProc%=-99
    const KErrNoFld%=-100
    const KErrOpen%=-101
    const KErrClosed%=-102
    const KErrRecSize%=-103
    const KErrModLoad%=-104
    const KErrMaxLoad%=-105
    const KErrNoMod%=-106
    const KErrNewVer%=-107
    const KErrModNotLoaded%=-108
    const KErrBadFileType%=-109
    const KErrTypeViol%=-110
    const KErrSubs%=-111
    const KErrStrTooLong%=-112
    const KErrDevOpen%=-113
    const KErrEsc%=-114
    const KErrMaxDraw%=-117
    const KErrDrawNotOpen%=-118
    const KErrInvalidWindow%=-119
    const KErrScreenDenied%=-120
    const KErrOpxNotFound%=-121
    const KErrOpxVersion%=-122
    const KErrOpxProcNotFound%=-123
    const KErrStopInCallback%=-124
    const KErrIncompUpdateMode%=-125
    const KErrInTransaction%=-126

    rem For ALERT
    const KAlertEsc%=1
    const KAlertEnter%=2
    const KAlertSpace%=3

    rem For BUSY and GIPRINT
    const KBusyTopLeft%=0
    const KBusyBottomLeft%=1
    const KBusyTopRight%=2
    const KBusyBottomRight%=3
    const KBusyMaxText%=80

    rem For CMD$
    const KCmdAppName%=1   rem Full path name used to start program
    const KCmdUsedFile%=2
    const KCmdLetter%=3
    rem For CMD$(3)
    const KCmdLetterCreate$="C"
    const KCmdLetterOpen$="O"
    const KCmdLetterRun$="R"

    rem For CURSOR
    const KCursorTypeNotFlashing%=2
    const KCursorTypeGrey%=4

    rem For DATIM$ - offsets
    const KDatimOffDayName%=1
    const KDatimOffDay%=5
    const KDatimOffMonth%=8
    const KDatimOffYear%=12
    const KDatimOffHour%=17
    const KDatimOffMinute%=20
    const KDatimOffSecond%=23

    rem For dBUTTON
    const KDButtonNoLabel%=$100
    const KDButtonPlainKey%=$200
    const KDButtonDel%=8
    const KDButtonTab%=9
    const KDButtonEnter%=13
    const KDButtonEsc%=27
    const KDButtonSpace%=32

    rem For dEDITMULTI and printing
    const KParagraphDelimiter%=$06
    const KLineBreak%=$07
    const KPageBreak%=$08
    const KTabCharacter%=$09
    const KNonBreakingTab%=$0a
    const KNonBreakingHyphen%=$0b
    const KPotentialHyphen%=$0c
    const KNonBreakingSpace%=$10
    const KPictureCharacter%=$0e
    const KVisibleSpaceCharacter%=$0f

    rem For DEFAULTWIN
    rem Old consts retained for compatibility:
    const KDefWin4ColourMode%=1
    const KDefWin16ColourMode%=2
    rem New color mode constants:
    const KColorDefWin2GrayMode%=0
    const KColorDefWin4GrayMode%=1
    const KColorDefWin16GrayMode%=2
    const KColorDefWin256GrayMode%=3
    const KColorDefWin16ColorMode%=4
    const KColorDefWin256ColorMode%=5

    rem For dFILE
    const KDFileNameLen%=255
          rem flags
    const KDFileEditBox%=$0001
    const KDFileAllowFolders%=$0002
    const KDFileFoldersOnly%=$0004
    const KDFileEditorDisallowExisting%=$0008
    const KDFileEditorQueryExisting%=$0010
    const KDFileAllowNullStrings%=$0020
    const KDFileAllowWildCards%=$0080
    const KDFileSelectorWithRom%=$0100
    const KDFileSelectorWithSystem%=$0200

    rem Opl-related Uids for dFILE
    const KUidOplInterpreter&=268435575
    const KUidOplApp&=268435572
    const KUidOplDoc&=268435573
    const KUidOPO&=268435571
    const KUidOplFile&=268435594
    const KUidOpxDll&=268435549

    rem For DIALOG
    const KDlgCancel%=0

    rem For dINIT (flags for dialogs)
    const KDlgButRight%=1
    const KDlgNoTitle%=2
    const KDlgFillScreen%=4
    const KDlgNoDrag%=8
    const KDlgDensePack%=16

    rem For DOW
    const KMonday%=1
    const KTuesday%=2
    const KWednesday%=3
    const KThursday%=4
    const KFriday%=5
    const KSaturday%=6
    const KSunday%=7

    rem For dPOSITION
    const KDPositionLeft%=-1
    const KDPositionCentre%=0
    const KDPositionRight%=1

    rem For dTEXT
    const KDTextLeft%=0
    const KDTextRight%=1
    const KDTextCentre%=2
    const KDTextBold%=$100       rem Ignored in Eikon
    const KDTextLineBelow%=$200
    const KDTextAllowSelection%=$400
    const KDTextSeparator%=$800

    rem For dTIME
    const KDTimeAbsNoSecs%=0
    const KDTimeAbsWithSecs%=1
    const KDTimeDurationNoSecs%=2
    const KDTimeDurationWithSecs%=3
    rem Flags for dTIME (for ORing combinations)
    const KDTimeWithSeconds%=1
    const KDTimeDuration%=2
    const KDTimeNoHours%=4
    const KDTime24Hour%=8

    rem For dXINPUT
    const KDXInputMaxLen%=16

    rem For FINDFIELD
    const KFindCaseDependent%=16
    const KFindBackwards%=0
    const KFindForwards%=1
    const KFindBackwardsFromEnd%=2
    const KFindForwardsFromStart%=3

    rem For FLAGS
    const KFlagsAppFileBased%=1
    const KFlagsAppIsHidden%=2

    rem For gBORDER and gXBORDER
    const KBordSglShadow%=1
    const KBordSglGap%=2
    const KBordDblShadow%=3
    const KBordDblGap%=4
    const KBordGapAllRound%=$100
    const KBordRoundCorners%=$200
    const KBordLosePixel%=$400

    rem For gBUTTON
    const KButtS3%=0
    const KButtS3Raised%=0
    const KButtS3Pressed%=1
    const KButtS3a%=1
    const KButtS3aRaised%=0
    const KButtS3aSemiPressed%=1
    const KButtS3aSunken%=2
    const KButtS5%=2
    const KButtS5Raised%=0
    const KButtS5SemiPressed%=1
    const KButtS5Sunken%=2

    const KButtLayoutTextRightPictureLeft%=0
    const KButtLayoutTextBottomPictureTop%=1
    const KButtLayoutTextTopPictureBottom%=2
    const KButtLayoutTextLeftPictureRight%=3
    const KButtTextRight%=0
    const KButtTextBottom%=1
    const KButtTextTop%=2
    const KButtTextLeft%=3
    const KButtExcessShare%=$00
    const KButtExcessToText%=$10
    const KButtExcessToPicture%=$20

    rem For gCLOCK
    const KgClockS5System%=6
    const KgClockS5Analog%=7
    const KgClockS5Digital%=8
    const KgClockS5LargeAnalog%=9
    const KgClockS5Formatted%=11

    rem For gCREATE
    const KgCreateInvisible%=0
    const KgCreateVisible%=1
    const KgCreateHasShadow%=$0010
    rem Old constants retained for compatibility:
    const KgCreate2ColourMode%=$0000
    const KgCreate4ColourMode%=$0001
    const KgCreate16ColourMode%=$0002
    rem Color mode constants:
    const KColorgCreate2GrayMode%=$0000
    const KColorgCreate4GrayMode%=$0001
    const KColorgCreate16GrayMode%=$0002
    const KColorgCreate256GrayMode%=$0003
    const KColorgCreate16ColorMode%=$0004
    const KColorgCreate256ColorMode%=$0005

    rem For gCOLORINFO - array subscripts
    const gColorInfoADisplayMode%=1
    const gColorInfoANumColors%=2
    const gColorInfoANumGreys%=3
    rem DisplayMode constants:
    const KDisplayModeNone%=0
    const KDisplayModeGray2%=1
    const KDisplayModeGray4%=2
    const KDisplayModeGray16%=3
    const KDisplayModeGray256%=4
    const KDisplayModeColor16%=5
    const KDisplayModeColor256%=6
    const KDisplayModeColor64K%=7
    const KDisplayModeColor16M%=8
    const KDisplayModeRGB%=9
    const KDisplayModeColor4K%=10

    rem For GETCMD$
    const KGetCmdLetterCreate$="C"
    const KGetCmdLetterOpen$="O"
    const KGetCmdLetterExit$="X"
    const KGetCmdLetterUnknown$="U"
    const KGetCmdLetterBackup$="S"
    const KGetCmdLetterRestart$="R"

    rem For gLOADBIT
    const KgLoadBitReadOnly%=0
    const KgLoadBitWriteable%=1

    rem For gRANK
    const KgRankForeground%=1
    const KgRankBackGround%=32767

    rem For gPOLY - array subscripts
    const KgPolyAStartX%=1
    const KgPolyAStartY%=2
    const KgPolyANumPairs%=3
    const KgPolyANumDx1%=4
    const KgPolyANumDy1%=5

    rem For gPRINTB
    const KgPrintBRightAligned%=1
    const KgPrintBLeftAligned%=2
    const KgPrintBCentredAligned%=3
    rem The defaults
    const KgPrintBDefAligned%=KgPrintBLeftAligned%
    const KgPrintBDefTop%=0
    const KgPrintBDefBottom%=0
    const KgPrintBDefMargin%=0

    rem For gXBORDER
    const KgXBorderS3Type%=0
    const KgXBorderS3aType%=1
    const KgXBorderS5Type%=2

    rem For gXPRINT
    const KgXPrintNormal%=0
    const KgXPrintInverse%=1
    const KgXPrintInverseRound%=2
    const KgXPrintThinInverse%=3
    const KgXPrintThinInverseRound%=4
    const KgXPrintUnderlined%=5
    const KgXPrintThinUnderlined%=6

    rem For KMOD
    const KKmodShift%=2
    const KKmodControl%=4
    const KKmodPsion%=8
    const KKmodCaps%=16
    const KKmodFn%=32

    rem For mCARD and mCASC
    const KMenuDimmed%=$1000
    const KMenuSymbolOn%=$2000
    const KMenuSymbolIndeterminate%=$4000
    const KMenuCheckBox%=$0800
    const KMenuOptionStart%=$0900
    const KMenuOptionMiddle%=$0A00
    const KMenuOptionEnd%=$0B00

    rem For mPOPUP position type
    rem Specifies which corner of the popup is given by the coordinates
    const KMPopupPosTopLeft%=0
    const KMPopupPosTopRight%=1
    const KMPopupPosBottomLeft%=2
    const KMPopupPosBottomRight%=3

    rem For PARSE$ - array subscripts
    const KParseAOffFSys%=1
    const KParseAOffDev%=2
    const KParseAOffPath%=3
    const KParseAOffFilename%=4
    const KParseAOffExt%=5
    const KParseAOffWild%=6
    rem Wild-card flags
    const KParseWildNone%=0
    const KParseWildFilename%=1
    const KParseWildExt%=2
    const KParseWildBoth%=3

    rem For SCREENINFO - array subscripts
    const KSInfoALeft%=1
    const KSInfoATop%=2
    const KSInfoAScrW%=3
    const KSInfoAScrH%=4
    const KSInfoAReserved1%=5
    const KSInfoAFont%=6
    const KSInfoAPixW%=7
    const KSInfoAPixH%=8
    const KSInfoAReserved2%=9
    const KSInfoAReserved3%=10

    rem For SETFLAGS
    const KRestrictTo64K&=&0001
    const KAutoCompact&=&0002
    const KTwoDigitExponent&=&0004
    const KSendSwitchOnMessage&=&010000

    rem For GetEvent32
    rem Array indexes
    const KEvAType%=1
    const KEvATime%=2

    rem event array keypress subscripts
    const KEvAKMod%=4
    const KEvAKRep%=5

    rem Pointer event array subscripts
    const KEvAPtrOplWindowId%=3
    const KEvAPtrWindowId%=3
    const KEvAPtrType%=4
    const KEvAPtrModifiers%=5
    const KEvAPtrPositionX%=6
    const KEvAPtrPositionY%=7
    const KEvAPtrScreenPosX%=8
    const KEvAPtrScreenPosY%=9

    rem Event types
    const KEvNotKeyMask&=&400
    const KEvFocusGained&=&401
    const KEvFocusLost&=&402
    const KEvSwitchOn&=&403
    const KEvCommand&=&404
    const KEvDateChanged&=&405
    const KEvKeyDown&=&406
    const KEvKeyUp&=&407
    const KEvPtr&=&408
    const KEvPtrEnter&=&409
    const KEvPtrExit&=&40A

    rem Pointer event types
    const KEvPtrPenDown&=0
    const KEvPtrPenUp&=1
    const KEvPtrButton1Down&=KEvPtrPenDown&
    const KEvPtrButton1Up&=KEvPtrPenUp&
    const KEvPtrButton2Down&=2
    const KEvPtrButton2Up&=3
    const KEvPtrButton3Down&=4
    const KEvPtrButton3Up&=5
    const KEvPtrDrag&=6
    const KEvPtrMove&=7
    const KEvPtrButtonRepeat&=8
    const KEvPtrSwitchOn&=9

    rem For PointerFilter
    const KPointerFilterEnterExit%=$1
    const KPointerFilterMove%=$2
    const KPointerFilterDrag%=$4

    rem code page 1252 ellipsis ("windows latin 1")
    const KScreenEllipsis%=133
    const KScreenLineFeed%=10

    rem For gCLOCK
    const KClockLocaleConformant%=6
    const KClockSystemSetting%=KClockLocaleConformant%
    const KClockAnalog%=7
    const KClockDigital%=8
    const KClockLargeAnalog%=9
    rem gClock 10 no longer supported (use slightly changed gCLOCK 11)
    const KClockFormattedDigital%=11

    rem For gFONT

    const KFontArialBold8&=       268435951
    const KFontArialBold11&=      268435952
    const KFontArialBold13&=      268435953
    const KFontArialNormal8&=     268435954
    const KFontArialNormal11&=    268435955
    const KFontArialNormal13&=    268435956
    const KFontArialNormal15&=    268435957
    const KFontArialNormal18&=    268435958
    const KFontArialNormal22&=    268435959
    const KFontArialNormal27&=    268435960
    const KFontArialNormal32&=    268435961

    const KFontTimesBold8&=       268435962
    const KFontTimesBold11&=      268435963
    const KFontTimesBold13&=      268435964
    const KFontTimesNormal8&=     268435965
    const KFontTimesNormal11&=    268435966
    const KFontTimesNormal13&=    268435967
    const KFontTimesNormal15&=    268435968
    const KFontTimesNormal18&=    268435969
    const KFontTimesNormal22&=    268435970
    const KFontTimesNormal27&=    268435971
    const KFontTimesNormal32&=    268435972

    const KFontCourierBold8&=      268436062
    const KFontCourierBold11&=     268436063
    const KFontCourierBold13&=     268436064
    const KFontCourierNormal8&=    268436065
    const KFontCourierNormal11&=   268436066
    const KFontCourierNormal13&=   268436067
    const KFontCourierNormal15&=   268436068
    const KFontCourierNormal18&=   268436069
    const KFontCourierNormal22&=   268436070
    const KFontCourierNormal27&=   268436071
    const KFontCourierNormal32&=   268436072

    const KFontCalc13n&=   268435493
    const KFontCalc18n&=   268435494
    const KFontCalc24n&=   268435495

    const KFontMon18n&=    268435497
    const KFontMon18b&=    268435498
    const KFontMon9n&=     268435499
    const KFontMon9b&=     268435500

    const KFontTiny1&=     268435501
    const KFontTiny2&=     268435502
    const KFontTiny3&=     268435503
    const KFontTiny4&=     268435504

    const KFontEiksym15&=  268435661

    const KFontSquashed&=  268435701
    const KFontDigital35&= 268435752

    rem For IOOPEN
    rem Mode category 1
    const KIoOpenModeOpen%=$0000
    const KIoOpenModeCreate%=$0001
    const KIoOpenModeReplace%=$0002
    const KIoOpenModeAppend%=$0003
    const KIoOpenModeUnique%=$0004

    rem Mode category 2
    const KIoOpenFormatBinary%=$0000
    const KIoOpenFormatText%=$0020

    rem Mode category 3
    const KIoOpenAccessUpdate%=$0100
    const KIoOpenAccessRandom%=$0200
    const KIoOpenAccessShare%=$0400

    rem Language code for CAPTION
    const KLangEnglish%=1
    const KLangFrench%=2
    const KLangGerman%=3
    const KLangSpanish%=4
    const KLangItalian%=5
    const KLangSwedish%=6
    const KLangDanish%=7
    const KLangNorwegian%=8
    const KLangFinnish%=9
    const KLangAmerican%=10
    const KLangSwissFrench%=11
    const KLangSwissGerman%=12
    const KLangPortuguese%=13
    const KLangTurkish%=14
    const KLangIcelandic%=15
    const KLangRussian%=16
    const KLangHungarian%=17
    const KLangDutch%=18
    const KLangBelgianFlemish%=19
    const KLangAustralian%=20
    const KLangBelgianFrench%=21
    const KLangAustrian%=22
    const KLangNewZealand%=23
    const KLangInternationalFrench%=24

    REM RGB color masking:
    const kRgbRedPosition&=&10000
    const kRgbGreenPosition&=$100
    const kRgbBluePosition&=$1
    const kRgbColorMask&=$ff

    REM RGB color values:
    const KRgbBlack&=&000000
    const KRgbDarkGray&=&555555
    const KRgbDarkRed&=&800000
    const KRgbDarkGreen&=&008000
    const KRgbDarkYellow&=&808000
    const KRgbDarkBlue&=&000080
    const KRgbDarkMagenta&=&800080
    const KRgbDarkCyan&=&008080
    const KRgbRed&=&ff0000
    const KRgbGreen&=&00ff00
    const KRgbYellow&=&ffff00
    const KRgbBlue&=&0000ff
    const KRgbMagenta&=&ff00ff
    const KRgbCyan&=&00ffff
    const KRgbGray&=&aaaaaa
    const KRgbDitheredLightGray&=&cccccc
    const KRgb1in4DitheredGray&=&ededed
    const KRgbWhite&=&ffffff

    REM MIME priority values:
    const KDataTypePriorityUserSpecified%=KMaxInt%
    const KDataTypePriorityHigh%=10000
    const KDataTypePriorityNormal%=0
    const KDataTypePriorityLow%=-10000
    const KDataTypePriorityLastResort%=-20000
    const KDataTypePriorityNotSupported%=KMinInt%

    rem End of Const.oph
EPOC SDK Home Glossary Previous Up


EPOC OPL Guide & Reference Glossary

Index A

Term | Topic | Meaning | See Also
application directory | Advanced Topics | The directory where the .app file which stores the translated OPL code for an application resides. This is <drivename>:/System/Apps/<appname>/. The application itself is called <appname>.app. |
application information file | Advanced Topics | A file containing information about an application located in the application directory. | application directory
argument | OPL Basics | A value used by a function; a function’s input. | value, function
array | OPL Basics | A list of values, all of the same type. | value
assign | OPL Basics | To give a value to a variable or constant. | value, variable, constant
asynchronous | Advanced Topics | A task which does not make the task which started it wait. | synchronous
atomic | Data File Handling | As a single, indivisible item. |


EPOC OPL Guide & Reference Glossary

Index B

Term Topic Meaning See Also

bitmap

Graphics and Interaction

A file, or an area of memory which is used to store a picture. The important features of a bitmap are its width, height and colour depth; shape information is held in a bitmap’s mask.

EPOC bitmaps are stored in multi-bitmap files (MBMs), which contain one or more bitmaps. MBMs are indexed by ID number.

mask, ID number

bitwise operator

OPL Basics

An operator that operates on the binary representations of its arguments.

bookmark

Data File Handling

A place marker in a database file.

database

bpp

Graphics and Interaction

Bits per pixel. The number of bits used to represent a unique colour in a given colour mode.

The number of bits used to represent a colour in a given window or screen is sometimes called its depth.

bug

Error Handling

An error in a program.


EPOC OPL Guide & Reference Glossary

Index C

Term | Topic | Meaning | See Also
call | OPL Basics | To invoke a function with its arguments. When a function is called, it returns a value. | value, function, argument
character code | OPL Basics | The number representing a letter or symbol. |
character set | OPL Basics | All the letters and symbols which can be displayed. |
coercion | OPL Basics | Translating from one variable type into another when required. This isn’t done always. |
colour mode | Graphics and Interaction | A number representing the number of colours or greys that can be displayed. Constants for colour modes are supplied in Const.oph. |
command | OPL Basics | A straightforward instruction to OPL with no return value. | value, return
commit | Data File Handling | To write the changes of a database transaction. After changes are committed, they cannot be undone (rolled back). | transaction, database
condition | OPL Basics | An expression with a logical value used for program flow control. | logical value, expression
constant | OPL Basics | Names which can be used like variables, but whose value cannot change. |
content type | Advanced Topics | What sort of file a particular file is. MIME content types are written as a string such as “text/html” or “image/jpeg”. | MIME


EPOC OPL Guide & Reference Glossary

Index D

Term Topic Meaning See Also

database

Data File Handling

A body of data which can be searched or browsed by OPL. In OPL, databases are arranged as one or more tables, and can be queried using SQL, a standard database query language. OPL can import the database format used by the EPOC Data application.

This system documentation also uses ‘database’ to refer to the disk file used to store the data.

record, field, SQL, table, view

DBMS

Data File Handling

The Database Management System. The EPOC DBMS is a service of the operating system that can be used by programs to access and share databases safely and efficiently.

database

declare

OPL Basics

To define the name of a variable and its scope.

denormal

OPL Basics

A floating-point number in the range 5E-324 to 2.2250738585072015E-308.

floating-point

deprecated

Keyword Reference

A marker meaning that an item is liable to either change or be removed in future versions, or that using the item in the current release is unwise.

OPL features and keywords which are included to maintain compatibility with previous versions of OPL, but which have no current use or which have been superseded by newer and better keywords are marked deprecated to indicate that they should no longer be used.

Deprecation does not necessarily imply that the keyword will be phased out.

dither

Graphics and Interaction

To emulate a colour in a colour mode that cannot display the colour exactly. The screen appearance of the colour is emulated by a mathematical stippling of pixels in colours that the mode can display exactly.

colour mode

DLL

Using OPXs

A Dynamically Loaded Library. A file used by EPOC to store compiled functions in native machine language (compiled from C++).

DLLs can be used by many different programs at once, so storing the code for a function in a DLL is efficient — you don’t have to keep copies of the same thing in each program you want to write.

OPXs are a special form of DLL that can be used by OPL programs.

The EPOC C++ SDK can be used to write DLLs for EPOC.

Linked by ordinal

document

Advanced Topics

A file which will run your application when started from the system screen. Documents can also store information, such as an OPL module.

Each document belongs to a particular application, and has an icon that looks like the application’s icon.


EPOC OPL Guide & Reference Glossary

Index E

Term | Topic | Meaning | See Also
EPOC Emulator | OPL Basics | The PC program distributed with this documentation which can be used to run and test out OPL programs. |
execute | Introducing OPL | To follow an instruction. When OPL acts on an instruction statement in a running program, the instruction is said to have been executed. | statement, run
expression | OPL Basics | A value formed by performing some combination of operations, values and functions. | function, operator, value


EPOC OPL Guide & Reference Glossary

Index F

Term | Topic | Meaning | See Also
field | Data File Handling | An item which can be filled in for each record in a database. Fields correspond to the columns in the table model of databases. | database, record, table, view
file extension | Advanced Topics | Everything after the final dot in a filename. Sometimes used to show the type of a file, although this is not necessary with native EPOC files (those with UIDs). | UID, MIME
floating-point | OPL Basics | A 64-bit signed floating-point value. | value, denormal
function | OPL Basics | A command with a return value. Functions can be used anywhere OPL expects a value. | value, return, argument


EPOC OPL Guide & Reference Glossary

Index G

Term | Topic | Meaning | See Also
global | OPL Basics | The scope of a variable which can be used everywhere. In OPL, global values declared in a procedure can be used and modified in all procedures called from that procedure. |


EPOC OPL Guide & Reference Glossary

Index H

Term | Topic | Meaning | See Also
header file | OPL Basics | An OPL file containing procedure prototypes and constants which can be included (via include) into another OPL module. | procedure prototypes
hexadecimal | OPL Basics | A number represented in base 16. In OPL these numbers are written preceded by a $ symbol. |


EPOC OPL Guide & Reference Glossary

Index I

Term | Topic | Meaning | See Also
ID number | Graphics and Interaction | An integer representing a bitmap in an MBM file. Unlike OPL array indices, MBM id numbers start at 0 (zero). | bitmap, mask
index | Data File Handling | A listing of a sort order on a table stored in the database file itself. This can be used to vastly increase the speed of data lookup. | key, table, database
integer | OPL Basics | A 16-bit signed integer value. | value, long integer
interpreter | OPL Basics | The program running on an EPOC device that runs an OPL program. | program


EPOC OPL Guide & Reference Glossary

Index J

Term Topic Meaning See Also


EPOC OPL Guide & Reference Glossary

Index K

Term | Topic | Meaning | See Also
key | Data File Handling | One or more columns in a database used for ordering it in an index. |
keyword | Introducing OPL | A word in a program with a special meaning to OPL. OPL keywords are usually program instructions, although other types of keywords exist. |
keyword | OPL Basics | A word with a special meaning to OPL that performs some action when used in a statement. You can’t use keywords for variable or constant names. | statement, variable, constant


EPOC OPL Guide & Reference Glossary

Index L

Term Topic Meaning See Also

label

OPL Basics

A marker in an OPL program. Labels can be jumped to with GOTO or VECTOR.

Linked by ordinal

Using OPXs

Refers to using DLLs in which functions are looked up by an ordinal (1, 2, 3, .... n) number rather than by name or physical offset.

Ordinal linking makes better use of disk space than linking by name, and is more robust than linking by physical offset.

DLL

literal

OPL Basics

A value written directly into the text of an OPL program.

string, integer, long integer, floating-point, array

little-endian

Advanced Topics

Denotes a format for multi-byte values where the byte with the smallest memory address is the least significant — the value is stored little-end-first.

The opposite of little-endian is, naturally enough, big-endian.

The name comes from the Lilliputian dispute over whether an egg should be opened at the round or pointed end from Swift’s Gulliver’s Travels.

logical operator

OPL Basics

An operator which takes logical arguments, and evaluates to a logical value.

logical value

logical value

OPL Basics

True or false. To OPL, 0 represents false, and anything else represents true.

OPL uses -1 to return a true value, but any non-zero value is valid.

long integer

OPL Basics

A 32-bit signed integer value.

value, integer


EPOC OPL Guide & Reference Glossary

Index M

Term Topic Meaning See Also

mask

Graphics and Interaction

A 2-bit colour bitmap which is used to store the shape of another bitmap. Masks are the same size as their related bitmap. A zero bit in a mask means that the related bitmap is transparent there, a one means that the other bitmap is not transparent in that pixel.

bitmap

MIME

Read This First

Multipurpose Internet Mail Extensions. A way of associating foreign (non-EPOC) files to their correct type and application.

Files which are foreign to EPOC are recognised by MIME recognisers located in System\Recogs\ under ER5. OPL applications can register themselves as being able to handle a given kind of MIME-recognised file using the ER5 OPL MIME keyword.

This is in addition to the standard UID-based recognition of files provided by EPOC.

See also OPL and MIME [image] and OPL applications.

file extension, document, content type

module

Introducing OPL

One or more procedures for OPL to follow. Each OPL module is stored in a single program file.

program, procedure

multi-bitmap file

Advanced Topics

An EPOC picture file or MBM. MBMs can contain one or more bitmaps and their masks.


EPOC OPL Guide & Reference Glossary

Index N

Term Topic Meaning See Also


EPOC OPL Guide & Reference Glossary

Index O

Term | Topic | Meaning | See Also
operator | OPL Basics | A symbol used to combine values, for example the standard arithmetic operators. | expression, value
OPL heap | Advanced Topics | All the memory available to OPL for variable storage. |
OplTran | OplTran | The PC command-line OPL translator. | WINC


EPOC OPL Guide & Reference Glossary

Index P

Term Topic Meaning See Also

passed by reference

Using OPXs

A trick used to allow modification of data passed as parameters to a procedure. Normally a copy of all the data is made when you pass a value to a function; if the procedure modifies the copy it gets, the original doesn’t change.

The BYREF keyword can be used to make a variable parameter into a reference. If a reference is copied, both copies refer to the same object, so if the variable is modified inside the function body the original is modified.

poll

Advanced Topics

To loop repeatedly waiting for an event.

procedure

Introducing OPL

A list of statements with a name that can be invoked as a unit. The statements in a procedure are usually executed one by one until the procedure ends, although this order can be altered with certain statements.

statement, execute

procedure prototype

OPL Basics

A procedure declaration with no body.

process

Advanced Topics

The execution of a program. Many processes can exist on an EPOC device at one time without interfering with one another.

program

Introducing OPL

Any list of instructions for a computer to follow. For OPL, program means both the program text which is editable in the Program application, and the translated version which can be run by the machine.

Each OPL program file contains a single module, and an entire program can be built from many modules.

translate, module, run

public name

Advanced Topics

The caption of an application; this is displayed in the list of open files and programs in the EPOC shell.


EPOC OPL Guide & Reference Glossary

Index Q

Term Topic Meaning See Also


EPOC OPL Guide & Reference Glossary

Index R

Term | Topic | Meaning | See Also
recogniser | Advanced Topics | What EPOC uses to recognise files. Recognisers are located in \System\Recogs\. | MIME
record | Data File Handling | An entry in a database. These correspond to the rows in a database table. Each record can have multiple fields. | database, field, table, view
return | OPL Basics | For a function; to provide a value in the place where the function was called. The return value is the function’s output. | function, value, call
RFC | Advanced Topics | Request For Comments. A document describing proposed changes to recognised Internet standards, or new standards for applications to adopt. | MIME
run | Introducing OPL | To start (a program). | program


EPOC OPL Guide & Reference Glossary

Index S

Term | Topic | Meaning | See Also
scalar | OPL Basics | A value that isn’t an array value, just a single item. |
source code | OPL Basics | A human-editable program Source code must be translated before the OPL interpreter can run it. | run, translator
SQL | Data File Handling | Structured Query Language, pronounced ‘sequel’. SQL can be used to query relational databases. | database
statement | Introducing OPL | One instruction for OPL to carry out. Statements are built from keywords, and possibly other information like numbers or text. | keyword
string | OPL Basics | A text value. | value
structure | OPL Basics | A grouping of statements that doesn’t actually change any data. Used for loop controls, application definitions, menus etc. | statement
synchronous | Advanced Topics | A task which makes the task which started it wait until it has completed. | asynchronous
system panic | Advanced Topics | An EPOC fatal error code. System panics do not bring the entire system down, but they do kill all processes belonging to the erroneous application or program. |


EPOC OPL Guide & Reference Glossary

Index T

Term | Topic | Meaning | See Also
table | Data File Handling | The physical representation of a set of records consisting of fields within a database file. The tabular model of databases is sometimes called the relational database model. | view, database
transaction | Data File Handling | A fundamental concept in the EPOC DBMS. A transaction is a single pass of related changes to a database file grouped together for efficiency and data integrity. EPOC DBMS transactions are atomic operations. | DBMS, database, commit, atomic
translate | Introducing OPL | To convert a program from human-readable and editable text into a form which OPL can run. | program
translator | OPL Basics | A program which translates OPL code from source form to runnable form. | source code


EPOC OPL Guide & Reference Glossary

Index U

Term | Topic | Meaning | See Also
UID | Advanced Topics | Unique Identifier. The native EPOC way of recognising documents, applications, etc. UIDs are allocated centrally by Symbian. See also OPL applications. | document


EPOC OPL Guide & Reference Glossary

Index V

Term | Topic | Meaning | See Also
value | OPL Basics | What OPL understands as the value of something. Sometimes value is used interchangeably with expression, as every expression has a value. | expression
variable | OPL Basics | A name which stands for a value. A variable’s value can be changed. | value
view | Data File Handling | The representation of a table which OPL can manipulate in memory. Changes made to a view can be efficiently written into the database file in a single pass, and a view doesn’t have to represent all the data in a table. | table, database, transaction


EPOC OPL Guide & Reference Glossary

Index W

Term Topic Meaning See Also

WINC

OplTran

A command-line EPOC environment like WINS without the GUI and with multiple processes. WINC is used for testing certain multi-process applications, and is a convenient platform for the OplTran program.

WINS

WINS

OplTran

The single-process PC EPOC environment used by the EPOC Emulator. The WINS environment is used for testing EPOC programs from a Windows development environment.

Unlike EPOC C++ code which has to be compiled afresh for each platform, translated OPL programs can run on all EPOC platforms and devices without re-translation.

WINC


EPOC OPL Guide & Reference Glossary

Index X

Term Topic Meaning See Also


EPOC OPL Guide & Reference Glossary

Index Y

Term Topic Meaning See Also


EPOC OPL Guide & Reference Glossary

Index Z

Term Topic Meaning See Also


EPOC OPL Guide & Reference: Glossary Index

A · B · C · D · E · F · G · H · I · J · K · L · M · N · O · P · Q · R · S · T · U · V · W · X · Y · Z · · Home


  • Read This First
    • About this SDK
    • What’s new in OPL for EPOC Release 5
    • EPOC SDK Products and support
    • Year 2000 Compliance
    • Licence agreement
    • Acknowledgements
    • Documentation conventions
  • Introducing OPL
    • About OPL
    • A first program
    • File management
    • Running modules
  • Programming in OPL
    • OPL Basics
      • Values and expressions
      • Commands
      • Control structures
      • Calling procedures
      • Including header files
    • Data File Handling
      • Database manipulation
      • SQL specification
      • OPL and disks
    • Graphics and Interaction
      • Graphics
      • Friendlier interaction
    • Error Handling
      • Syntax errors — Errors reported during translation
      • Runtime errors — Handling errors reported while running programs
      • OPL error values
    • Advanced Topics
      • About the advanced topics
      • Programs using more than one module
      • Calling procedures by strings
      • More on file specification
      • How OPL stores values
      • Safe pointer arithmetic
      • OPL applications
      • OPL and MIME
      • Foreground and background
      • Scanning the keyboard directly
      • I/O functions and commands
      • Dynamic memory allocation
  • Example Programs
    • About the example programs
    • Timer — Countdown timer
    • Dice — Rolls dice
    • Birthday — Calculates birthdays
    • Files — Data files
    • Reorder — Re-orders a database file
    • Watch — Simple stopwatch
    • Label — Inserts a new label into a database
    • Bounce — Displays a bouncing ball
    • Circles — Draws circles
    • Animate — Animated bitmaps
  • Keyword Reference
    • About OPL Keywords
    • ABS — ATAN
    • BACK — BYREF
    • CANCEL — CURSOR
    • DATETOSECS — dXINPUT
    • EDIT — EXTERNAL
    • FIND — FREEALLOC
    • gAT — gY
    • HEX$ — HOUR
    • IABS — IOYIELD
    • KEY — KMOD
    • LAST — LPRINT
    • MAX — mPOPUP
    • NEXT — NUM$
    • OFF — OPENR
    • PARSE$ — PUT
    • RAD — RND
    • SCI$ — SUM
    • TAN — TRAP RAISE
    • UADD — USUB
    • VAL — VECTOR
    • WEEK — WHILE...ENDWH
    • YEAR
  • Using OPXs
    • About OPXs
    • Bmp.opx — Sprites and bitmaps
    • Contact.opx — The Contacts engine
    • Date.opx — Date and time manipulation
    • dBase.opx — Database handling
    • dbUtils.opx — Additional DBMS functionality
    • Printer.opx — Printer and text handling
    • SysRam1.opx — Additional OPL functionality
    • System.opx — EPOC system functions
  • OplTran
    • About OplTran
    • opltran.exe — Command line OPL translator
  • Appendices
    • Operators and logical expressions
    • Serial ports and printing
    • Character codes
    • EPOC Error Values
    • Listing of Const.oph
  • Glossary
    • Glossary - A
    • Glossary - B
    • Glossary - C
    • Glossary - D
    • Glossary - E
    • Glossary - F
    • Glossary - G
    • Glossary - H
    • Glossary - I
    • Glossary - J
    • Glossary - K
    • Glossary - L
    • Glossary - M
    • Glossary - N
    • Glossary - O
    • Glossary - P
    • Glossary - Q
    • Glossary - R
    • Glossary - S
    • Glossary - T
    • Glossary - U
    • Glossary - V
    • Glossary - W
    • Glossary - X
    • Glossary - Y
    • Glossary - Z