The GFA-Basic Compendium
Subject: Documentation/Programming
Author: GFA Systemtechnik GmbH
HTML conversion created with STG2HTML v0.75
Written by Lonny Pursell and ENCOM
Note: Images are not supported.
Index
Main
GFA-Basic Editor/Interpreter Manual AES
GFA-Basic Compiler/Linker Manual VDI
GFA-Basic Addendum BIOS()
XBIOS()
Error Codes index GEMDOS()
Number Table Shift Table LINE-A
HYPertext Version Help
The Atari Compendium
The documentation for TOS (aka TOS.HYP)
Help
How to use this HYPertext
At the end of most pages are external links to 'The Atari Compendium'
(compend.hyp) which should be placed in the same directory as this
document. The external links are denoted by the '+' sign after them.
Example:
appl_init()+ would be an external link to the page 'appl_init()' in the
compend.hyp.
The external links provide additional information which may be more
accurate than the information provided in this document.
You migh also see a Memo at the end of various pages. These provide
information that I've discovered on my own or reported from other
GFA-Basic users.
Document not found
The requested document was not found.
Please recheck your typing and try again or check the index for the page
you were looking for.
GFA-Basic
GFA-Basic is the best BASIC for the Atari!
Lonny Pursell
WWW: http://www.bright.net/~gfabasic/
DR
Digital Research
HYPertext Version
Manual ported by Lonny Pursell and ENCOM [v2.84 7/27/2014]
WWW: http://www.bright.net/~gfabasic/
Tools used in porting:
GFA-Basic
ST-Guide
STeno
ScanX Pro
OCR
QED
GEMView
Time spent porting:
I spent about 2 months working on this project. On an average I spent 3 days
per week (6 hours a day) scanning and editing the text. The grand total is
approximately 144 hours. The raw data is about 736k.
Note: I have GFA-Basic v3.6TTe (last known version) so all comments
are based on this version.
Written by Lonny Pursell
(C)1998-2014 Lonny Pursell and ENCOM
All rights reserved.
Disclaimer
This package may NOT be freely distributed under any conditions whatsoever. It
was ported to HYPertext so that I could speed up my own personal software
developement. I claim absolutely no rights to the information contained within
or responsibility for anything resulting from improper distribution.
GFA-Basic Addendum
General Information
Known problems with GFA-Basic
Patches for GFA-Basic
N.AES Functions
N.AES Objects
GFA-Basic History
The Origins of GFA-Basic
GFA-Basic v3 float format
ST-Basic float format (CVS())
Debugging with GFA-Basic and MiNT
Misc Images
Optimizations not covered in the Compiler manual
Command line options
Cookie Jar
Fastload on TOS 1.00/1.02
Assembler Notes
Start-up/Shut-down modules
Command line options
The editor can be started with a command line:
Example:
TEST.GFA start editor and run source
-TEST.GFA start editor in edit mode
Optimizations not covered in the Compiler manual
IF/ENDIF versus SELECT/CASE
If you have an IF/ENDIF structure that does 2 or more tests on the same
variable, SELECT/CASE should be used. Why? Because SELECT/CASE holds the
value of the variable in a register for the entire structure, where as
IF/ENDIF fetches the value of the variable at each reference.
IF/ENDIF with Boolean tests
IF test!=TRUE !generates more code
IF test! !less code
IF test!=FALSE !generates more code
IF NOT test! !less code
Cookie Jar
Normally you need to go to supervisor mode to get the cookie jar address. To
avoid that one can use this legal BIOS() call. This is the best method for
MiNT and works equally well under all versions of TOS.
jar_adr%=BIOS(5,W:SHR&(&H5A0,2),L:TRUE)
The Cookie Jar+
Fastload on TOS 1.00/1.02
How to force a fastload on TOS 1.00/1.02 (exploit a bug in TOS)
______________________________________________________________________________
The binary must meet 2 requirements:
1) No relocation data (must be 100% pc relative)
2) The ABSFLAG in the header must be set to non-zero (word at offset 26)
The OS will load the file and relocate it.
Control will be passed to the binary like normal.
The OS fails to do 2 things (the bug):
The BSS and heap memory areas will not be cleared (thus its fastloaded).
The binary is not closed, it cannot be deleted or moved from the Desktop.
The binary should close itself before it terminates.
If not, the system will have 1 less file handle available to other apps.
______________________________________________________________________________
To close the binary you have 2 options:
Method #1 (used in PinHead v1.4)
Call fsfirst() with "*.*" in the current dir and open the 1st file you find.
Then simply close the file.
Now fclose(previous handle-1), the binary will then be closed.
Method #2 (used in DC Squish II v2.12)
Check the TOS version:
If its TOS 1.00:
If the word at offset $15D2 = $601A, then the next word is the handle.
If its TOS 1.02:
If the word at offset $1632 = $601A, then the next word is the handle.
Call fclose() with the file handle, the binary will then be closed.
TOS 1.04 and up do not have this bug and also supports fastload directly.
______________________________________________________________________________
This technique is probably only useful in small \auto folder programs as it is
sort of hard to write a rather large application that has no fixups.
The information regarding this trick was discovered by dis-assembling the
above mentioned programs and studying the code. Tests were made with old
versions of TOS to verify the mysterious offsets mentioned as well.
The Atari Compendium mentions a bug related to the ABSFLAG and some versions
of TOS, but does not state the nature of the problem. Well, now I know. ;o)
==============================================================================
Related information:
From the PinHead v1.4 documentation:
*************
* *
* NEW STUFF *
* *
*************
-------------
PinHead 1.4
-------------
PinHead Now Fastloads Itself!
-----------------------------
Version 1.4 of PinHead uses an undocumented feature of TOS 1.0 and
1.2 to "fastload" itself. This means that the speedup starts one
program sooner in your AUTO folder, since the PinHead program file does
not cause memory to be cleared when it runs.
(NOTE: Normally, the use of this undocumented feature would result
in the PinHead program file being left "open" by the system. PinHead
1.4 uses a special technique to avoid this bug in TOS, and you will have
no trouble deleting, renaming, or copying the PinHead program file after
it runs.)
From the DC Squish II manual, page 19, 1st paragraph:
When the FAST bit is OFF, both the BSS and the HEAP
memory areas are cleared. Early TOS versions, 1.0 and 1.2
do not know about the FAST bit an therefore 'always'
clear both the BSS and HEAP. There is a trick to make
GEMDOS load files 'fast' on TOS 1.0 & 1.2, and SQUISH
uses this technique to allow fast-equivalent execution
speed.
______________________________________________________________________________
GEMDOS Processes+
GFA-Basic History
From: Holger Herzog <Holger_Herzog@ZW.maus.de>
Organization: MAUS Zweibrƒcken +49-6332-16629
Newsgroups: <maus.computer.sprache.gfabasic>
Date: Friday, November 22, 2002 12:17 PM
Subject: Re: gfa history
Hi Lonny!
L>Does someone here know what "gfa" means in the title of "gfa-basic"? I
L>have wondered this since the day I discovered version 2.x back in the
L>days of the Atari 520st.
As far as I know, GFA (originally called "GfA") was a shortcut for
"Gesellschaft für Anwendungssoftware mbH". That means in english
(word by word): "Company for application software Ltd." So GfA was
the name of the company, and GfA-Basic was the name of the software.
But in fact, this name ("GfA") was in conflict with the name of a
further organization. I can't remember which one it was. But due to
that, the company was renamed into "GFA Systemtechnik GmbH" which
means: "GFA system engineering Ltd." So from then, "GfA" was called
"GFA". And "GFA" is now - AFAIK - only a symbol for the company that
sounds like the old shortcut, but without officially being a
shurtcut. Now, the basic also is called "GFA-Basic", not "GfA-Basic"
any longer.
Best regards!
Holger
Subject: [gfa-dev-atari] GFA / GfA
Date: Monday, January 28, 2008 8:29 AM
From: Holger Herzog <ich@holger-herzog.de>
Reply-To: GFA-Basic Dev Mailing-List <gfa@atari-users.net>
To: GFA-Basic Dev Mailing-List <gfa@atari-users.net>
Conversation: [gfa-dev-atari] GFA / GfA
Hi Lonny!
I'm not sure anymore if I'm right with "GF*A*" = "application
software" instead of "automation".
Once I've asked the GFA support why "GfA" was renamed as "GFA" and Mr.
Lars von Strèlen (Software Support, GFA Systemtechnik) replied:
-----
"GfA" was renamend as "GFA" in 1987. It happened, because the acronym
"GfA" was changed into the proper name "GFA-Systemtechnik".
Dƒsseldorf, 1991-06-20
----
The header shows:
GFA Systemtechnik GmbH
Software-Entwicklung, Software-Vertrieb, Verlag
Dƒsseldorf, Germany
This means:
GFA Systems Enginieering Ltd
Software Development, Software Sales, Publishing
Dƒsseldorf, Germany ;-)
CEOs are Mr. Thomas Nied and Dr.Ing. Heinrich Meckner
Later, GFA Systemtechnik GmbH moved to Münchengladbach, another
town in western Germany.
But I found exactly ONE curious invoice in my documents. The header
here is:
GFA Systemtechnik GmbH
Industrie-Automation
Prozeọleit-Systeme
Qualitètssicherungs-Systeme
And THIS means:
GFA Systemtechnik GmbH
Industrial Automation
Process Control Systems
Quality Assurance Systems
Date: 1992-02-17
The address still is Dƒsseldorf, not yet Münchengladbach. But the
local court is in Kiel (nothern Germany). I really don't understand
what this means. Because the CEO is still Mr. Thomas Nied.
I found nothing about Thomas Nied in google. Dr. Meckner seems having
worked for Krupp (a big steel company), but for both I found no
reference where I could get in contact.
So it *is* possible, that GfA meant "Gesellschaft fƒr Automatisierung"
(=automation), and not, as I heavyliy do remeber, "Gesellschaft for
Anwendungssoftware" (=application software).
Holger
_______________________________________________
gfa mailing list
gfa@atari-users.net
http://atariforums.com/mailman/listinfo/gfa
The Origins of GFA-Basic
THE ORIGINS OF GFA BASIC
It began with an Atari 400, a small computer similar to the Commadore 64.
There existed a BASIC for that computer. This BASIC was neither fast nor
comfortable to use, but, with only 16K of RAM, large programs could not be
written anyway. After upgrading the computer to 48K of memory and 88K of disk
space, I wrote some programs in assembly code. Eventually I ended up with a
number of help routines, and a BASIC language with which I could marginally use
with these routines. After trying FORTH, I decided to take a closer look at
BASIC, and slightly modified it. These modifications eventually became so
numerous that I decided to completely replace many of the routines. To remain
compatible, some of the routines were left untouched. There were a lot of
commands I did not like, such as computed GOTOs, and line numbers were a
nuisance.
This new BASIC was published in a computer magazine. Shortly thereafter I
received an offer from GFA Systemtechnik GmbH to write a workable BASIC for the
new computer, the Atari ST.
The Atari ST incorporates a fresh modern processor. Its operating system,
although certainly not the newest or fastest (nor is it very compact, having
been written in C language) is very powerful. And, even though it lacks
multitasking, one can write programs in high level languages that offer
exciting performance.
Shipped with a BASIC language that did not even measure up to the one included
with the Atari 400, the ST was destined to become a language developers dream.
It was possible to now develop a BASIC that did not have to conform to the
standard of any other interpreter.
This new BASIC should have the simplicity of BASIC combined with the
possibility of writing well structured code. The first step was to eliminate
the line numbers. This made the task difficult from the outset because a
solution had to be found to avoid the usual confusion of GOTOs and GOSUBs. It
was important to be able to pass parameters to procedures and to declare local
variables, thus enabling the programmer to use recursive programming
techniques. The BASIC should also make sure that all loops are properly closed
before the program starts execution.
The GOTO statement was one of the last statements added to this BASIC. After
much thought, I even allowed the GOTO command to be used between different
procedures.
In an Interpreter it is possible to use segmented PEEKs and POKEs to simulate
one of the Intel-processors. In a compiled program, this would greatly affect
execution time.
The unsuitable 16 bit integers would not be used either, as this makes it
harder to address all of the memory. Besides, the processor already uses 32
bits internally, thus allowing it to process larger numbers without speed loss.
The editor of this BASIC had to be screen oriented and not use the windows of
GEM. It would be virtually impossible to create non GEM programs from within
the GEM interface. Other reasons exist for not having the editor run under
GEM.
In the case of a program error, it is often possible to save program changes
that were made. Something that cannot always be done from within GEM because
the windows lock up. So it happened that a relatively fast editor, one that
could be used without a mouse, was created.
I wanted to write the BASIC completely in machine language so that it would be
fast and take up only a small portion of memory. Other languages like C use
only a few machine instructions outside of the library, and they always pass
parameters through the stack. The MC68000 has a very powerful instruction set
that can be better utilized with an Assembler.
Taking all this into consideration, Version 1.0 of GFA BASIC came into
existence less than 6 months later.
While I was writing the interpreter, I carefully made sure that the finished
programs could be easily compiled. That is why the MERGE command is missing.
This command may be useful in an interpreter, but is of little value in a
compiler.
While I was working on the compiler, I was confronted with requests to expand
the command set. Some of those requests I was able to incorporate in Version
2.0 of the interpreter. Most new commands, like VOID, BASEPAGE, and OPTION,
were inserted to give the compiler more optimization opportunities, and to
provide the programmer with more control over the compiling process.
Even an extensive computer language cannot fulfill all the wishes of everyone
who uses it. This book will, therefore, show you how to create necessary
routines using GFA BASIC.
This book does not present you with complete applications; it gives routines
that can be incorporated into your own programs.
GFA BASIC is only a BASIC and not a Modula 2, therefore you cannot
create modules in quite the same way. Modula 2 takes a lot more coding and a
multitude of small modules to write an application. Modula 2 can only be used
as a compiler. BASIC includes numerous commands that would have to be created
within libraries in Modula 2.
Part of this book discusses many different operating system routines which
include examples wherever I felt they were needed. Naturally, there are
routines that can be run directly without going to the low-level operating
system routines, but rather with built in commands.
An important part of this book is the last chapter, where a complete GEM
program is shown. It demonstrates how to use all parts of a window. This is
not easy to do in GEM, but it makes it convenient for the user of the program.
For the programmer, GEM always means extra work. There are many programs where
most of the code is written just to manipulate the window.
I hope that you find the routines and tips in this book useful, and I wish you
much success.
Taken from the 'Introduction' section of the book "The GFA BASIC Book"
Written by Frank Ostrowski
Text Translation by Wilford Niepraschk
Published in the U.S.A. by MichTron, Inc.
(C)1987 GFA Systemtechnik
1st English Edition: September 1987
ISBN 0-923213-85-6
Misc Images
Rather than duplicate alot of work that has already been done this document
will not explain each and every system call available.
I highly recommend you have some additional documentation.
GFA specific:
GFA-Basic Book
Concepts in Programming
Programming with GFA-Basic 3.0
GFA-Basic Training Reboot Camp
GFA-Basic Programmer's Reference Guide Volume 1
The GFA-Basic & Assembler User Book
GFA-Basic Toolkit Volume 1
Atari in general:
The Atari Compendium (also available on CD-ROM)
Modern Atari System Software A programmer's Guide
The TRB Reference Series AES Quick Reference
The TRB Reference Series VDI Quick Reference
Atari ST GEM Programmer's Reference (Abacus)
Atari ST Internals (Abacus)
Atari ST Machine Language (Abacus)
Atari ST Tips & Tricks (Abacus)
Atari ST 3D Graphics (Abacus)
ST Disk Drives: Inside and Out (Abacus)
COMPUTE!'s ST Programmer's Guide
COMPUTE!'s Technical Reference Guide Atari ST: AES
COMPUTE!'s Technical Reference Guide Atari ST: TOS
COMPUTE!'s Technical Reference Guide Atari ST: VDI
If you see a typo, find a program listing that does not work, or anything else
wrong then please contact me. If you find this document handy and find yourself
releasing a program, then please give me a mention in your doc file. That's all
I ask. ;^)
Patches for GFA-Basic
I've seen several patches for GFA-Basic, but the best one by far is the one
listed below. I personally use it on a daily basis.
GFA-Basic Interpreter/Compiler-Patcher Version 1.05/1.07 (1994)
Compiler & Library-Patches by Christoph Conrad,
Adalbertsteinweg 113, D-52070 Aachen, Germany - eMail:
Christoph_Conrad@AC3.maus.de
Interpreter-Patches and GEM interface by - Gregor Duchalski,
Baueracker 15a, D-44627 Herne, Germany - eMail:
Gregor_Duchalski@DO.maus.ruhr.de
This patch completely removes all the LINEA calls used in the GFA libs. It also
makes the compiled programs function on multi-tasking operating systems. It
should also be noted that this patch removes the auto mouse hiding/showing that
takes place when graphics commands are used. Once patched you must hide/show
the mouse yourself when using VDI graphics commands.
GFA_PTCH.TXT LIBPATCH.TXT
LicomLIB 5.9.H
Copyright (c)1998 Richard Gordon Faika
All rights reserved.
Hompage:
www.atari-computer.de/rgfaika/
Email:
rgfaika@atari-computer.de
richard-gordon.faika@b.maus.de
This patch replaces many routines in the GFA library file. From what I can tell
from the German docs it adds automatic FPU support among many other things. An
impressive update to the GFA library. The patch seems to require an original
German v3.6TT compiler/linker package.
Patchable areas in GFA-Basic
Within GFABASIC.PRG and GFABASRO.PRG there is a small area where you can
predetermine the appeareance of the program.
Always ensure that you have made a backup of your master disk before attempting
such patches.
Auto Clear Screen
OPEN "U",#1,"GFABASIC.PRG" !or "GFABASRO.PRG"
SEEK #1,31
PRINT #1,"E"; !or "H";
CLOSE #1
With "E" the monitor screen will be erased before the program starts and with
"H" the monitor is left as it is.
Autorun Patch
OPEN "U",#1,"GFABASRO.PRG"
SEEK #1,32
PRINT #1,"TESTPROG.GFA";CHR$(0);
CLOSE #1
When starting GFABASRO.PRG the default TESTPROG.GFA will start if you do not
alter this by using the Install Application option of the GEM Destop.
The program's name and path may not exceed 63 bytes. The zero byte at the end
of the string is very important. If you only give the zero byte, the original
status will be reimplemented.
Variable Default Type
OPEN "U",#1,"GFABASIC.PRG"
SEEK #1,32
FOR i%=0 TO 24
READ a%
OUT #1,a%
NEXT i%
CLOSE #1
' A B C D E F G H I J K L M N O P Q R S T U V X Y Z
DATA 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
It is possible to change the DATA row. Doing this will alter the preset
default-type for the variable, the name of which starts with the above letter.
Only the following values are allowed:
0 = DEFFLT
1 = DEFSTR
2 = DEFINT
3 = DEFBIT
8 = DEFWRD
9 = DEFBYT
Editor Colors
OPEN "U",#1,"GFABASIC.PRG"
SEEK #1,58
FOR i%=0 TO 3
READ a%
PRINT #1,MKI$(a%);
NEXT i%
CLOSE #1
' Normal colors for the Editor
DATA &0777,&0700,&0070,&0000
' Colors inverted for the Editor
' DATA &0000,&0700,&0070,&0777
Known problems with GFA-Basic
Features not implemented due to it's age and lack of support:
FPU 68881/882 (sort of)
CPU 68010/020/030/040/060 support
Things just act plain weird:
~INP(2) will fail under MiNT if the application does not initialize the AES.
The GFA linker in some cases is smart enough to link only what's needed.
If your application makes no AES calls it will not initialize the AES.
Further investigation shows that any command that uses Bconin() fails
to wait for input.
Commands and functions which don't quite work right (A to Z):
$X
$F%
ACOS(), ASIN()
AFTER GOSUB, EVERY GOSUB
APOLY
APPL_TPLAY()
BITBLT
CALL
CASE
CLS
DEFFN
DFREE()
DIM, ERASE
EXIST()
FILESELECT
FRE()
FUNCTION
GET, PUT, SGET, SPUT
GET #, PUT #
GETSIZE()
GOTO
GRAF_MKSTATE()
INLINE
INSTR(), RINSTR()
LPENx, PADx, STICK(), STRIG()
LPRINT
MAT DET, MAT INPUT, MAT QDET, MAT RANG
MAT PRINT
MAT READ
MENU_REGISTER()
MSHRINK()
OBJC_CHANGE()
ON BREAK GOSUB
ON ERROR GOSUB
ON GOSUB
ON MENU BUTTON
ON MENU GOSUB
ON MENU IBOX
ON MENU KEY
ON MENU MESSAGE
ON MENU OBOX
OPTION BASE
POINT()
POLYFILL, POLYLINE, POLYMARK
QSORT, SSORT
RESTORE, _DATA
RESUME label
SETMOUSE
SOUND, WAVE
SPACE$(), STRING$()
SPRITE
STE?, TT?
STR$()
TEXT
VDIBASE
VSETCOLOR
V_OPNWK(), V_OPNVWK()
Compiler issues:
EXIT IF
IF-THEN
INSERT
FOR-NEXT
Start-up/Shut-down modules
This section will try and explain what happens when GFABASIC starts and
terminates. The code you can't really control.
The basic layout of a compiled GFA program is like so:
INIT module
your code
EXIT module
What does the INIT module do exactly:
Calculates how much BSS space it needs and clears it.
Moves the stack pointer to the BSS.
MSHRINK() is called. Skipped if started as an ACC, OS auto shrinks an ACC)
Line-A Init is called. This is harmless, used by the Line-A gfx commands.
APPL_INIT() is called. The appl_id is saved.
V_OPNVWK() is called. The vdi_handle is saved. No clipping rectangle is set.
WORK_OUT() array is created.
Default VDI workstation values are setup.
If any GFA window commands are linked, WINDTAB() structure is initialized.
MALLOC($Mxxx) is called. If $Mxxx=0 all ram is allocated for stings/arrays.
CLEAR is called. All Variables are cleared.
RESTORE is called. First DATA statement is located for READ.
User code starts here...
What does the EXIT module do exactly:
User code ends here with EDIT, QUIT, or SYSTEM...
If any GFA window commands are linked, all open GFA windowd are closed.
V_CLSVWK() is called.
APPL_EXIT() is called.
CLOSE (no parameter) is called. All open files are closed.
pterm() is called. User error code is passed out via SYSTEM/QUIT.
Note:
GFA deos not call MFREE() as it assumes pterm() will auto free the ram.
Number Table
Dec Hex Bin Dec Hex Bin Dec Hex Bin Dec Hex Bin
0 $00 %00000000 64 $40 %01000000 128 $80 %10000000 192 $C0 %11000000
1 $01 %00000001 65 $41 %01000001 129 $81 %10000001 193 $C1 %11000001
2 $02 %00000010 66 $42 %01000010 130 $82 %10000010 194 $C2 %11000010
3 $03 %00000011 67 $43 %01000011 131 $83 %10000011 195 $C3 %11000011
4 $04 %00000100 68 $44 %01000100 132 $84 %10000100 196 $C4 %11000100
5 $05 %00000101 69 $45 %01000101 133 $85 %10000101 197 $C5 %11000101
6 $06 %00000110 70 $46 %01000110 134 $86 %10000110 198 $C6 %11000110
7 $07 %00000111 71 $47 %01000111 135 $87 %10000111 199 $C7 %11000111
8 $08 %00001000 72 $48 %01001000 136 $88 %10001000 200 $C8 %11001000
9 $09 %00001001 73 $49 %01001001 137 $89 %10001001 201 $C9 %11001001
10 $0A %00001010 74 $4A %01001010 138 $8A %10001010 202 $CA %11001010
11 $0B %00001011 75 $4B %01001011 139 $8B %10001011 203 $CB %11001011
12 $0C %00001100 76 $4C %01001100 140 $8C %10001100 204 $CC %11001100
13 $0D %00001101 77 $4D %01001101 141 $8D %10001101 205 $CD %11001101
14 $0E %00001110 78 $4E %01001110 142 $8E %10001110 206 $CE %11001110
15 $0F %00001111 79 $4F %01001111 143 $8F %10001111 207 $CF %11001111
16 $10 %00010000 80 $50 %01010000 144 $90 %10010000 208 $D0 %11010000
17 $11 %00010001 81 $51 %01010001 145 $91 %10010001 209 $D1 %11010001
18 $12 %00010010 82 $52 %01010010 146 $92 %10010010 210 $D2 %11010010
19 $13 %00010011 83 $53 %01010011 147 $93 %10010011 211 $D3 %11010011
20 $14 %00010100 84 $54 %01010100 148 $94 %10010100 212 $D4 %11010100
21 $15 %00010101 85 $55 %01010101 149 $95 %10010101 213 $D5 %11010101
22 $16 %00010110 86 $56 %01010110 150 $96 %10010110 214 $D6 %11010110
23 $17 %00010111 87 $57 %01010111 151 $97 %10010111 215 $D7 %11010111
24 $18 %00011000 88 $58 %01011000 152 $98 %10011000 216 $D8 %11011000
25 $19 %00011001 89 $59 %01011001 153 $99 %10011001 217 $D9 %11011001
26 $1A %00011010 90 $5A %01011010 154 $9A %10011010 218 $DA %11011010
27 $1B %00011011 91 $5B %01011011 155 $9B %10011011 219 $DB %11011011
28 $1C %00011100 92 $5C %01011100 156 $9C %10011100 220 $DC %11011100
29 $1D %00011101 93 $5D %01011101 157 $9D %10011101 221 $DD %11011101
30 $1E %00011110 94 $5E %01011110 158 $9E %10011110 222 $DE %11011110
31 $1F %00011111 95 $5F %01011111 159 $9F %10011111 223 $DF %11011111
32 $20 %00100000 96 $60 %01100000 160 $A0 %10100000 224 $E0 %11100000
33 $21 %00100001 97 $61 %01100001 161 $A1 %10100001 225 $E1 %11100001
34 $22 %00100010 98 $62 %01100010 162 $A2 %10100010 226 $E2 %11100010
35 $23 %00100011 99 $63 %01100011 163 $A3 %10100011 227 $E3 %11100011
36 $24 %00100100 100 $64 %01100100 164 $A4 %10100100 228 $E4 %11100100
37 $25 %00100101 101 $65 %01100101 165 $A5 %10100101 229 $E5 %11100101
38 $26 %00100110 102 $66 %01100110 166 $A6 %10100110 230 $E6 %11100110
39 $27 %00100111 103 $67 %01100111 167 $A7 %10100111 231 $E7 %11100111
40 $28 %00101000 104 $68 %01101000 168 $A8 %10101000 232 $E8 %11101000
41 $29 %00101001 105 $69 %01101001 169 $A9 %10101001 233 $E9 %11101001
42 $2A %00101010 106 $6A %01101010 170 $AA %10101010 234 $EA %11101010
43 $2B %00101011 107 $6B %01101011 171 $AB %10101011 235 $EB %11101011
44 $2C %00101100 108 $6C %01101100 172 $AC %10101100 236 $EC %11101100
45 $2D %00101101 109 $6D %01101101 173 $AD %10101101 237 $ED %11101101
46 $2E %00101110 110 $6E %01101110 174 $AE %10101110 238 $EE %11101110
47 $2F %00101111 111 $6F %01101111 175 $AF %10101111 239 $EF %11101111
48 $30 %00110000 112 $70 %01110000 176 $B0 %10110000 240 $F0 %11110000
49 $31 %00110001 113 $71 %01110001 177 $B1 %10110001 241 $F1 %11110001
50 $32 %00110010 114 $72 %01110010 178 $B2 %10110010 242 $F2 %11110010
51 $33 %00110011 115 $73 %01110011 179 $B3 %10110011 243 $F3 %11110011
52 $34 %00110100 116 $74 %01110100 180 $B4 %10110100 244 $F4 %11110100
53 $35 %00110101 117 $75 %01110101 181 $B5 %10110101 245 $F5 %11110101
54 $36 %00110110 118 $76 %01110110 182 $B6 %10110110 246 $F6 %11110110
55 $37 %00110111 119 $77 %01110111 183 $B7 %10110111 247 $F7 %11110111
56 $38 %00111000 120 $78 %01111000 184 $B8 %10111000 248 $F8 %11111000
57 $39 %00111001 121 $79 %01111001 185 $B9 %10111001 249 $F9 %11111001
58 $3A %00111010 122 $7A %01111010 186 $BA %10111010 250 $FA %11111010
59 $3B %00111011 123 $7B %01111011 187 $BB %10111011 251 $FB %11111011
60 $3C %00111100 124 $7C %01111100 188 $BC %10111100 252 $FC %11111100
61 $3D %00111101 125 $7D %01111101 189 $BD %10111101 253 $FD %11111101
62 $3E %00111110 126 $7E %01111110 190 $BE %10111110 254 $FE %11111110
63 $3F %00111111 127 $7F %01111111 191 $BF %10111111 255 $FF %11111111
Shift Table
logical shift left (lsl) (asl) SHL()
1 * 2
2 * 4
3 * 8
4 * 16
5 * 32
6 * 64
7 * 128
8 * 256
logical shift right (lsr) (asr) SHR()
1 / 2
2 / 4
3 / 8
4 / 16
5 / 32
6 / 64
7 / 128
8 / 256
N.AES Functions
' GFA-Basic bindings for N.AES v1.2
'
FUNCTION appl_control(ap_cid&,ap_cwhat&,VAR ap_cout%)
$F%
GCONTRL(0)=129
GCONTRL(1)=2
GCONTRL(2)=1
GCONTRL(3)=1
GCONTRL(4)=0
GINTIN(0)=ap_cid&
GINTIN(1)=ap_cwhat&
ADDRIN(0)=V:ap_cout%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
'
FUNCTION appl_yield
$F%
GCONTRL(0)=17
GCONTRL(1)=0
GCONTRL(2)=1
GCONTRL(3)=0
GCONTRL(4)=0
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
'
FUNCTION form_popup(tree%,x&,y&)
$F%
GCONTRL(0)=135
GCONTRL(1)=2
GCONTRL(2)=1
GCONTRL(3)=1
GCONTRL(4)=0
GINTIN(0)=x&
GINTIN(1)=y&
ADDRIN(0)=tree%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
'
FUNCTION graf_multirubber(x&,y&,minw&,minh&,rec%,VAR outw&,outh&)
$F%
GCONTRL(0)=69
GCONTRL(1)=4
GCONTRL(2)=3
GCONTRL(3)=1
GCONTRL(4)=0
GINTIN(0)=x&
GINTIN(1)=y&
GINTIN(2)=minw&
GINTIN(3)=minh&
ADDRIN(0)=rec%
GEMSYS
outw&=GINTOUT(1)
outh&=GINTOUT(2)
RETURN GINTOUT(0)
ENDFUNC
'
FUNCTION objc_xfind(obj%,start&,depth&,x&,y&)
$F%
GCONTRL(0)=49
GCONTRL(1)=4
GCONTRL(2)=1
GCONTRL(3)=1
GCONTRL(4)=0
ADDRIN(0)=obj%
GINTIN(0)=start&
GINTIN(1)=depth&
GINTIN(2)=x&
GINTIN(3)=y&
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
'
FUNCTION shel_help(sh_hmode&,sh_hfile%,sh_hkey%)
$F%
GCONTRL(0)=128
GCONTRL(1)=1
GCONTRL(2)=1
GCONTRL(3)=2
GCONTRL(4)=0
GINTIN(0)=sh_hmode&
ADDRIN(0)=sh_hfile%
ADDRIN(1)=sh_hkey%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
'
FUNCTION shel_rdef(lpcmd%,lpdir%)
$F%
GCONTRL(0)=126
GCONTRL(1)=0
GCONTRL(2)=1
GCONTRL(3)=2
GCONTRL(4)=0
ADDRIN(0)=lpcmd%
ADDRIN(1)=lpdir%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
'
FUNCTION shel_wdef(lpcmd%,lpdir%)
$F%
GCONTRL(0)=127
GCONTRL(1)=0
GCONTRL(2)=1
GCONTRL(3)=2
GCONTRL(4)=0
ADDRIN(0)=lpcmd%
ADDRIN(1)=lpdir%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
'
FUNCTION wind_draw(wi_dhandle&,wi_dstartob&)
$F%
GCONTRL(0)=99
GCONTRL(1)=2
GCONTRL(2)=1
GCONTRL(3)=0
GCONTRL(4)=0
GINTIN(0)=wi_dhandle&
GINTIN(1)=wi_dstartob&
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
'
FUNCTION wind_sget(w_handle&,w_field&,buff%)
$F%
GCONTRL(0)=104
GCONTRL(1)=4
GCONTRL(2)=1
GCONTRL(3)=0
GCONTRL(4)=0
GINTIN(0)=w_handle&
GINTIN(1)=w_field&
GINTIN(2)=CARD(SWAP(buff%))
GINTIN(3)=CARD(buff%)
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
'
' eof
N.AES Objects
WHITEBAK N.AES
purpose: Switch on the MagiC special buttons.
C-prototype: #define WHITEBAK 0x0040
Binding: Tree[obnr].If_state |= WHITEBAK; [bit 6 on]
Parameter description:
If_type = G_BUTTON
G_BUTTON with underscore:
(if_state >> 8) & 0x80 = 0. [bit 15 off]
(if_state >> 8) & 0x7f decides the position of the underscore. [bits 8-14]
As Checkbox with underscore:
If_flags & RADIOBUTTON = 0. [bit 4 off]
(if_state >> 8) & 0x80 = 0x80. [bit 15 on]
(if_state >> 8) & 0x7f decides the position of the underscore. [bits 8-14]
If_flags & FL3DMASK decides the colour of the underscore. [bits 9-10]
As Radiobutton with underscore:
If_flags & RADIOBUTTON = RADIOBUTTON. [bit 4 on]
(if_state >> 8) & 0x80 = 0x80. [bit 15 on]
(if_state >> 8) & 0x7f decides the position of the underscore. [bits 8-14]
If_flags & FL3DMASK decides the colour of the underscore. [bits 9-10]
As Checkbox without underscore:
(if_state >> 8) = 0xff. [bits 8-15 on]
If_flags & RADIOBUTTON = 0. [bit 4 off]
As Radiobutton without underscore:
(if_state >> 8) = 0xff. [bits 8-15 on]
If_flags & RADIOBUTTON = RADIOBUTTON. [bit 4 on]
As Frame:
(if_state >> 8) = 0xfe. [bit 9-15 on]
If_state & SHADOWED control font size [bit 5 on]
If_flags & FL3DMASK decides the 3D-behaviour of frame and font. [bits 9-10]
If_type = G_STRING
G_STRING with underscore:
(if_state >> 8) & 0x80 = 0. [bit 15 off]
(if_state >> 8) & 0x7f decides the position of the underscore. [bits 8-14]
G_STRING, completely underlined based on chars:
(if_state >> 8) = 0xfe. [bits 9-15]
If_flags & FL3DMASK decides the 3D-behaviour of line and font. [bits 9-10]
G_STRING, completely underlined based on object width:
(if_state >> 8) = 0xff. [bits 8-15 on]
If_flags & FL3DMASK decides the 3D-behaviour of line and font. [bits 9-10]
If_type = G_TITLE
G_TITLE with underscore:
(if_state >> 8) & 0x80 = 0. [bit 15 off]
(if_state >> 8) & 0x7f decides the position of the underline. [bits 8-14]
3D-behaviour:
FL3DIND Bit switches text 3D attribute.
FL3DBAK Bit switches line/frame 3D attribute.
Underline colour:
None = black.
Background = black.
Indicator = green.
Activator = red.
With all underscore positions:
If the text is shorter, there will be no underscore drawn.
See too: Appl_getinfo, form_keybd
---
eof
Debugging with GFA-Basic and MiNT
Debugging with GFA-Basic and MiNT
by Lonny Pursell
Revision 0.10b
May 4, 2006
Introduction
This document describes a method for debugging when all else fails and all you
have to go on is the crash log MiNT dumps in the console. Sometimes you can
simply add PRINT statements at various points in the program in order to narrow
your search. However sometimes this becomes rather tedious, especially in very
large programs. In some extreme cases I've actually seen programs suddenly stop
crashing simply by adding PRINT statements. Needless to say that is a very
frustrating situation if that happens. The method described here will help you
locate the exact PROCEDURE or FUNCTION in a more precise manner. Hopefully
saving you time which can be put to better uses, like coding more applications.
:o)
Note: The particular example presented here is not an actual crash log from a
compiled GFA-Basic program, however all the same principles apply.
Understanding the crash log
Firstly one needs to understand the information MiNT is trying to provide when
an application crashes. A typical crash log might look like this:
PROCESS "make_ndx" KILLED: MEMORY VIOLATION. (PID 021) Type: free
PC: 0050A128 Addr: 0090BFD4 BP: 0050A000
Note: The example used here is a an application that crashes only when MiNT's
memory protection (MP) is enabled. All values are in hex notation.
The log entry breaks down like this:
Entry Description
PROCESS "make_ndx" name of the program that crashed
KILLED: MEMORY VIOLATION the reason the program was killed
(PID 021) GEMDOS Process ID of the program
Type: free type of memory block accessed
PC: 0050A128 address of Program Counter
Addr: 0090BFD4 address it attempted to access
BP: 0050A000 BASEPAGE address of the program
Type can have one of the following entries:
Type Description
private owned by another application
global remapped to 'hardware' for violation reports
super only accessible in supervisor mode only
readable read only, writing not allowed
free free memory, has no owner
hardware memory not controlled by MiNT
This represents the type of memory block the application attempted to illegally
access. This can be an important clue.
Note: Information taken from file mprot.x on the MiNT CVS server.
Interpreting the crash log
The most interesting pieces of information here are the PC and BP values. With
a little math we can determine the exact offset into the binary where the crash
occurred.
OFFSET = PC - (BP + 256)
This is accomplished by subtracting the BASEPAGE + 256 from the Program Counter.
Adding 256 to the BASEPAGE accounts for the size of the BASEPAGE itself. We are
not interested in the BASEPAGE because it will not be included in the
disassembly.
In the above example we get this:
$0050A128 - ($0050A000 + $100) = $28 !hex
5284136 - (5283840 + 256) = 40 !decimal
We now know that at offset $28 (40) in the binary is where the crash actually
occurred.
I know the offset, now what?
The next step would be to recompile the application with the Symbol Table option
set to on. This allows TTDigger (TTD) to show much more detailed information
when disassembling a program. All the PROCEDURE and FUNCTION names in the
program will be visible in TTD starting with an underscore. Some examples:
GFA-Basic TTD
FUNCTION test _TEST:
FUNCTION dump_tree(addr%) _DUMP_TR:
PROCEDURE init_system _INIT_SY:
PROCEDURE go(x&,y&) _GO:
Only the first 7 characters of PROCEDURE and FUNCTION names will be shown.
Entry points (labels) for PROCEDURE and FUNCTION names are always aligned to
the left edge of the window and followed by a colon.
Note: The 7 character limitation within the Symbol Table is actually part of
the DRI Object File Specification.
Symbol Table warning
The Symbol Table will make the binary larger. It is also recommended you do
not leave this option on all the time. Distributing binaries with the Symbol
Table serves only hackers, and it makes reverse engineering your application
quite a bit easier. So always remember to disable the Symbol Table option when
you are done debugging!
Using TTD
Now start TTD and load your application. Scroll down to the offset which you
calculated earlier ($28). Once you locate the offset, you can see the assembler
instruction that actually caused the program to crash. Now scroll up to the
first label that begins with an underscore "_". This should be the PROCEDURE
or FUNCTION your program was executing when it suddenly came to a grinding halt.
Note: TTD can be set to work in Hex or Decimal mode.
It's possible the offset does not lie in the range of your application. This
can happen if you are loading and executing external modules or overlays. If
this happens you can apply the same techniques to the module or overlay.
However if you are not the author of the module or overlay, you probably won't
have access to the source code and thus cannot resolve the problem yourself.
Another tip that might help
If you suspect your program is crashing outside of a PROCEDURE or FUNCTION you
can add some markers that are easy to spot in TTD.
Examples: dummy$="XXXX"
dummy$=">>>>"
The GFA-Basic Compiler converts 4 character strings directly into code instead
of placing them in the DATA segment of the binary. Thus they will appear in the
TTD listing exactly where you place them in your source code.
Note: Turn on the HEX/ASC option in TTD.
TTD output (further analysis)
Here's the actual code segment from the offending application:
* Created by TT-Digger v7.0
* Mon Apr 24 07:54:20 2006
* TEXT $0004FC bytes, segment starts at $00000000
* DATA $00005E bytes, segment starts at $000004FC
* BSS $00014E bytes, segment starts at $0000055A
* SYMBOLS $000000 bytes
* FLAG $0000
000: movea.l $0004(a7),a0 ; a0 = basepage addr
004: move.l $000C(a0),d0 ; d0 = length of text segment
008: add.l $0014(a0),d0 ; add d0,length of data segment
00C: add.l $001C(a0),d0 ; add d0,length of bss segment
010: addi.l #$00000100,d0 ; add d0,256
016: move.l d0,-(a7) ; push new size on to the stack
018: move.l a0,-(a7) ; push block addr on to the stack
01A: clr -(a7) ; push 0 on to the stack
01C: move #$004A,-(a7) ; push Mshrink opcode on to the stack
020: trap #1 ; Gemdos (make the call)
022: adda.l #$0000000C,a7 ; restore stack to previous state
028: move.l #$FFFFFFFF,-(a7) ; push -1 on to the stack
02E: move #$0048,-(a7) ; push Malloc opcode on to the stack
032: trap #1 ; Gemdos (make the call)
034: addq.l #6,a7 ; restore stack to previous state
Note: This is only a partial listing. The actual listing is much larger, but
its not really needed to illustrate the problem. Comments added for clarity.
Program breakdown:
$000 - $010 computes the actual program size, result in d0
$016 - $022 MSHRINK call -> status%=MSHRINK(addr%,size%)
$028 - $034 MALLOC call -> free_ram%=MALLOC(-1)
Understanding the problem
From the listing we can determine the crash occurs very early on in the programs
start up phase. We can see at offset $28 we have this:
move.l #$FFFFFFFF,-(a7)
This one line of code simply tries to move (LPOKE if you will) the value -1 to
where ever the stack pointer is currently pointing. Why does this one line of
code bring our program to a grinding halt?
The answer in this case requires some basic knowledge of how MiNT starts up an
application. The first thing MiNT does is allocate all available ram (largest
available block). It then creates a BASEPAGE for the application in the first
256 bytes and following that is the actual code of the application. By default
MiNT sets the user stack pointer to the end of the memory block.
This line of code is actually the program preparing for a MALLOC call. It is
attempting to inquire (-1) the largest free memory block.
What happens in this particular case is the program attempts to do the right
thing and give back memory it does not need with MSHRINK. However, before doing
so it fails to move the stack pointer to a safe location inside it's own memory
space. Remember the stack pointer by default is pointing to the end of the
memory block. After the MSHRINK call the stack pointer is literally left
pointing out into free memory! As soon as the MSHRINK succeeds the memory is
no longer owned by the application and under no circumstances will MiNT allow
you to access memory you do not own when MP is enabled. The program is
instantly killed as a result. This is a huge mistake on the part of the
programmer, if not downright sloppy programming.
There you have it, a way to let MiNT help you debug your programs.
Contact
Hopefully the information presented here is useful. To make suggestions or
report a typo please visit:
http://www.bright.net/~gfabasic/
eof
From: Albin Laβ <Albin_Lass@HB2.maus.de>
Organization: MAUS Hansestadt Bremen 2 +49-421-702569
Newsgroups: <maus.computer.sprache.gfabasic>
Date: Wednesday, September 11, 2002 7:11 AM
Subject: Re: floating point conversion
Hi Lonny!
LP> How does GFA internally store these?
Byte: 0 1 2 3 4 5 | 6 7
Bit : 63 16 | 15 0
IMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM SEEEEEEEEEEEEEEE
<--------------- 48 bit Mantissa --------------> <--- 16 bit --->
^ (normalized) ^ Exponent
| | (bias=1023)
| |
+-- MSB = Integer Bit +-- Sign of Mantissa
Integer Bit is allways one, except number is zero (then all Bytes zero).
If Exponent negative (sign of Mantissa is negative), than exp = -exp.
--------------------------------- schnipp ---------------------------------
CLS
DO
INPUT "Number: ";number#
addr%=V:number#
mantissa_h%={addr%}
mantissa_l%=CARD{addr%+4}
bias%=WORD{addr%+6}
PRINT "BYTE: 0 1 2 3 4 5 6 7"
PRINT "BIT : 63 16 15 0"
PRINT "BIN : ";BIN$(mantissa_h%,32);BIN$(mantissa_l%,16)'BIN$(bias%,16)
PRINT "HEX : ";HEX$(mantissa_h%,8);HEX$(mantissa_l%,4);SPACE$(37);HEX$(bias%,4)
b2%=bias%
IF bias%<0
neg!=TRUE
bias%=-bias%
ELSE
neg!=FALSE
ENDIF
exponent%=bias%-1023
dual_value#=ABS(number#)/(2^exponent%)
PRINT "DEZ : ";LEFT$(STR$(dual_value#)+SPACE$(49),49);STR$(b2%);" (";STR$(exponent%);")"
PRINT "CALC: (";neg!;")^0 * ";STR$(dual_value#);" * 2^(";bias%;"-1023)"
PRINT
LOOP
--------------------------------- schnipp ---------------------------------
Ciao, ALbin.
From: Albin Laọ <Albin_Lass@HB2.maus.de>
Organization: MAUS Hansestadt Bremen 2 +49-421-702569
Newsgroups: <maus.computer.sprache.gfabasic>
Date: Friday, September 13, 2002 3:42 AM
Subject: Re: floating point conversion
Hi Lonny!
Sorry for german writing! But, I'm a bad english writer. ;)
LP> I have been looking for such info for ages!
Ich hatte mal vor ca. 10 Jahren (in einem Bƒcherladen) in irgendeinem Buch
(ich glaube es war von Data Becker) geblèttert. Und darin war auch das
Format der GFA-Fliesskommazahlen beschrieben und ein Hinweis darauf, daọ
das irgendeinem *IEEE*-Standard (wie auch die FPU-Datentypen) entsprechen
soll.
Suche also mal nach "IEEE" (die genaue Nummer und URL weiọ ich leider nicht).
LP> Did you figure this out on your own?
Ja. Und zwar durch Analyse eines reassemblierten GFA-Compilats und durch
Vergleich mit den dokumentierten FPU-Datentypen.
Und die Richtigkeit der Analyse hatte ich dann nochmal mit einem Beispiel-
Programm (was ich dir gepostet habe) ƒberprƒft.
Ach, ja. Da fehlen am Ende eigentlich noch einige Zeilen:
result#=(neg!^0*dual_value#)*2^exponent%
PRINT "RES : ";STR$(result#)
Ciao, ALbin.
From: Albin Laọ <Albin_Lass@hb2.maus.de>
Organization: MAUS Hansestadt Bremen 2 (+49-421-702569)
To: <atari@q1.net>
Date: Monday, September 16, 2002 5:33 AM
Subject: floating point conversion
Hi Lonny!
LP> I don't know any German, but lucky for me there is translators. ;-)
Na, dann ... Hauptsache wir verstehen uns. ;)
LP> I have many books on GFA, but never found this info.
Tja, leider weiọ ich nicht mehr, was das fƒr ein Buch das war. :(
Ich glaube es war _nicht nur_ ƒber GFA.
LP> I managed to add these myself after some test runs. ;-)
Hab ich mir auch (fast) schon so gedacht.
Mit einem Calculator wère das wohl auch nichts ... ;)
LP> In this line you reference the 'number#' itself.
Stimmt, ist ein wenig umstèndlich. Einfacherer wère es so: ;)
WORD{addr%+6}=1023
dual_value#=number#
LP> How would you figure out the floating point value of a float just
LP> based on the 8 bytes stored in ram?
Hatte ich ja schon geschrieben: einmal durch Anschauen (im Compilat) wie
die Routinen von GFA z.B. ein Long in ein Float wandelt (oder auch STR$(n#)).
Und durch Vergleich mit den FPU-Datentypen. Die sind nèmlich IEEE-Standard.
Und wenn die GFA-Floats auch IEEE sind, dann sollte das ziemlich èhnlich
sein.
Beschrieben werden die FPU-Datentypen z.B. im Buch "68030 Assembly Language
Reference" (von Steve Williams (Addison-Wesley)) unter dem Kapitel 4.2.1.2
"Floating Point Intructions"/"Binary Floating Point Data Formats".
Falls Du das Buch nicht zur Hand haben solltest: Ich hab's mal in ein
Hypertext (ST-Guide) umgeschrieben: :)
Fileliste der Maus @ OL (Phone: 0441-3844034):
Gruppenprogrammteil Maus.Computer.Software.Hypertext
Nr. System Filename Bytes Dauer Abruf DpM Datum
260 ST TOS MC68030E.ZIP 429034 01:56 7 0.16 03.11.98
Programmier-Tool, Textfile, Freeware
Ausfuehrliche Dokumentation ueber die Motorola-Prozessoren MC68000 bis
MC68030. Mit FPU und MMU. (Hypertext, englisch).
Von Albin Lass @ HB2
LP> The files I have, I have no way to know the float value before hand,
LP> if you follow me.
Nicht so ganz. Du willst wissen, wie die Bitwertigkeit der Mantisse ist?
Bit 47 46 45 44 43 42 41 ...
Wert 1 1/2 1/4 1/8 1/16 1/32 1/64 ...
oder 2^0 2^-1 2^-2 2^-3 2^-4 2^-5 2^-6 ...
LP> Thus, I cannot compute 'dual_value' at all.
Wie? Per Hand? Warum ƒberlèsst Du die Arbeit nicht dem Computer?
Ahh, ich verstehe: Du willst Beweise ... ;)
Dann setze mal Folgendes im Programm ein:
--------------------------------- schnipp ---------------------------------
...
calc_dual(mantissa_h%,mantissa_l%,dual_value#)
...
PROCEDURE calc_dual(m_h%,m_l%,VAR dual#)
CLR dual#,d_exp&
FOR i&=31 DOWNTO 0
IF BTST(m_h%,i&)=TRUE
dual#=dual#+2^d_exp&
ENDIF
DEC d_exp&
NEXT i&
FOR i&=15 DOWNTO 0
IF BTST(m_l%,i&)=TRUE
dual#=dual#+2^d_exp&
ENDIF
DEC d_exp&
NEXT i&
RETURN
--------------------------------- schnapp ---------------------------------
LP> Many thanks for the info,
Bitte schüüünn!
LP> I am much closer than I was.
Na, hoffentlich bist Du _jetzt_ noch ein bischen _mehr_ schlauer geworden. ;)
LP> http://www.q1.net/~atari/
Hmm, ist da nicht auch ein Crack-Code bezƒglich LST->GFA drauf? :)
Ciao, ALbin.
31 8 7 6 0
mmmmmmmmmmmmmmmmmmmmmmmm s eeeeeee
m = mantissa
s = sign bit
e = exponent
Note: Maximum of 5 decimal places: '0.12345'
--------------------------------------------------------------------------------
From: http://alvyn.sourceforge.net/amos_file_formats.html
* 4 bytes: the single-precision floating point value.
o bits 31-8: mantissa (24 bits)
o bit 7: sign bit. Positive if 0, negative if 1
o bits 6-0: exponent
An exponent of 0 means 0.0, regardless of mantissa.
Counting from MSB (23) to LSB (0),
each bit set in the mantissa is 2^(mantissa_bit + exponent - 88)
--------------------------------------------------------------------------------
From: http://www.atari-forum.com/wiki/index.php/STOS.BAS
1 long: number value - 1st 24 bits are the mantissa,
25th bit is the sign,
last 7 bits are the exponent
Note: to convert to a readable format,
each bit of the mantissa = 2 ^ (bit_position + exponent - 88.0).
Add up the values indicated by each bit in the mantissa.
FUNCTION get_float(VAR p%)
LOCAL s!
LOCAL e&,b&
LOCAL d%,m%
LOCAL f
f=FALSE
d%=LONG{p%}
m%=SHR(d%,8) !mantissa
s!=BTST(d%,7) !sign
e&=AND(d%,&H7F) !exponent
IF e&>FALSE !fix?
FOR b&=23 DOWNTO 0
IF BTST(m%,b&)=TRUE
f=f+(2^(b&+e&-88))
ENDIF
NEXT b&
ENDIF
IF s!=TRUE !negative?
f=-f
ENDIF
ADD p%,4
RETURN ROUND(f,5) !clip
ENDFUNC
Assembler Notes
Program startup
move.l 4(a7),d0 ;basepage address (prg)
move.l a0,d0 ;0=prg/<>0 acc (basepage address)
a7 ;prg=stack assigned by os/acc=invalid, no stack!
Accessories are pre-shrunk (MSHRINK) by the OS.
Programs must call MSHRINK themselves.
Initial DTA address = BASEPAGE+128
If you don't move the DTA, the command line will be clobbered.
OS calls
Type Destroyed Output Input Invalid opcodes
------ ------------- -------- -------- ---------------------------
AES none # paramblk paramblk crash (N.Aes pops an alert)
VDI none # paramblk paramblk crash
BIOS d0-d2/a0-a2 d0 stack garbage (MiNT -32)
XBIOS d0-d2/a0-a2 d0 stack opcode
GEMDOS d0-d2/a0-a2 d0 stack -32
Line-A d0-d2/a0-a2 * + paramblk crash
# = Noted in the TOS.HYP
* = Additional registers that are destroyed are noted at each function call.
+ = Depends on the call made.
Note: Never call the AES in supervisor mode.
GFA-Basic Editor/Interpreter Manual
CONTENTS
Chapter 1 - Introduction
About This Manual
Using GFA-Basic 3 For The First Time
The Editor
Fundamentals
The Cursor Keypad
The Numeric Keypad
Further Editing Commands
Further Control Commands
The Menu Bar and Function Keys
Special Commands
Chapter 2 - Variables and Memory Management
Variable Types
Arrays
Matrix Commands
Type Transformation
Pointer Operations
Deleting and Exchanging
Reserved Variables
Special
Memory Management
Chapter 3 - Operators
Arithmetic Operators
Logical Operators
Concatenation Operator
Comparison Operators
Assignment Operator
Operator Hierarchy
Chapter 4 - Numerical Functions
Mathematical Functions
Random Number Generator
Integer Arithmetic
Commands and Functions
Bit Operations
Chapter 5 - String Manipulation
Chapter 6 - Input and Output
Keyboard and Screen Handling
KEYxxx Commands
Data Input and Output
Data Commands
File Management
Directory Handling
Files
Sequential Access
Random Access
Communicating with Peripherals
Byte by Byte Input and Output
Serial (RS232) and MIDI Interfaces
Mouse and Joysticks
Printing
Sound Generation
Chapter 7 - Program Structure
Decision Commands
Multiple Branching
Loops
Procedures and Functions
Error Handling
Interrupt Programming
Other Commands
Program Tracing
Chapter 8 - Graphics
Graphics Definition Commands
General Graphics Commands
Grabbing Sections of the Screen
Chapter 9 - Event, Menu, and Window Management
Event Management
Pull-down Menus
Window Commands
Other Window-related Commands
Chapter 10 - System Routines
BIOS, XBIOS, and GEMDOS
Line-A Calls
VDI Routines
Special VDI Routines and GDOS
Non-BASIC Routine Calls
Other System-related Commands
Chapter 11 - AES Libraries
Object Structure
Text Data Structure (TEDINFO)
Icon Data Structure (ICONBLK)
Color Icon Data Structure (CICONBLK)
Color Icon Structure (CICON)
Bit Image Block Structure (BITBLK)
Application Block Structure (APPLBLK)
Parameter Block Structure (PARMBLK)
Application Services Library
Event Library
Menu Library
Object Library
Form Library
Graphics Library
Scrap Library
File Selector Library
Window Library
Resource Library
Shell Library
Sample Programs
Chapter 12 - Appendix
Compatibility with GFA-BASIC 2
GEMDOS() Table
BIOS() Table
XBIOS() Table
Line-A Variable Table
V_OPNWK() and V_OPNVWK() Input Parameter Table
VDI WORK_OUT() Array Table
VT-52 Escape Code Table
Scan Code Table
ASCII Table
Special ASCII Characters
Fill Pattern Table
Line Style Table
Error Codes
Editor Error Messages
Interpreter Error Codes (compiled code)
BIOS Error Codes (compiled code)
GEMDOS Error Codes (compiled code)
Bomb Error Codes (compiled code)
Publisher
GFA_PTCH.TXT
---------------------------------------------------------------------------
- GFA-BASIC Interpreter/Compiler-Patcher -
- Version 1.07 -
---------------------------------------------------------------------------
- Compiler & Library-Patches by -
- Christoph Conrad, Adalbertsteinweg 113, D-52070 Aachen -
- eMail: Christoph_Conrad@AC3.maus.de -
- -
- Interpreter-Patches and GEM interface by -
- Gregor Duchalski, Baueracker 15a, D-44627 Herne -
- eMail: Gregor_Duchalski@DO.maus.ruhr.de -
- -
- A big thank you for the English translation of GFA_PTCH -
- and this documentation goes to *The System ST Team* -
---------------------------------------------------------------------------
The program enclosed provides a convenient method of making useful patches
to the GFA-BASIC 3.x interpreter and compiler.
At the start, select the Basic interpreter or compiler (GFA_BCOM.PRG).
After that you will be taken to the settings dialog box.
Something in advance: Please take care not to save the patched program(s)
under the same name as the original(s). We accept no responsibility for the
functionality of the patches, anyone who damages his own interpreter and
does not have a backup, only has himself to blame!
----------------------------------------------------------------------------
Patching the compiler
----------------------------------------------------------------------------
Two changes can be made to the compiler or to the library:
- Insertion of an improved INIT section
- A bugfix for the crash under Mag!X
Both patches can be made individually or in one go. The Mag!X patch only
changes the GFA_BCOM.PRG file, the INIT patch also updates the library.
In the patch dialog box, you can enter the new names that should be used to
save the compiler and the library. If necessary, you can also use the
original library again in case the preset name is not correct.
----------------------------------------------------------------------------
Patching the compiler 1: New INIT section
----------------------------------------------------------------------------
You can get precise information about the new INIT section by reading the
text file LIBPATCH.TXT. The listing ERR.LST contains some examples of
how to use the new features.
Important: The LIBPATCH folder _must_ contain the files HIDEM.O, INIT35.O
and INIT36.O!
Clicking on 'Patch' will start the automatic patching procedure. At the
end, you should try to create a new index file (GFA3BLIB.NDX) using the
program MAKE_NDX.PRG. This program (you should have received this with the
original package containing the compiler) will search first in the original
library folder and then in the folder LIBPATCH. If this fails, the file can
still be chosen using the file selector. If this also fails, then the
program will terminate. You should be aware that in this instance you will
have to create an NDX file 'by hand'. If you can avoid this situation, so
much the better.
Hint: If you do not have the MAKE_NDX.PRG program, you can obtain this from
GFA Systemtechnik (good luck with that) or send your original diskette and
a stamped, addressed return mailer to G. Duchalski and the adress mentioned
above.
---------------------------------------------------------------------------
Patching the compiler II: MAG!X bugfix
---------------------------------------------------------------------------
The compiler crashes under Mag!X with the message "Memory block destroyed".
This is the cause:
The compiler uses MShrink (GEMDOS 74) to reduce its memory requirement as
neccessary. Using Malloc (GEMDOS 72) it then checks for the largest
available memory block and allocates this amount less 16 Kbytes.
Unfortuantely, the program assumes fom this that the allocated memory lies
directly after the area previously shrunk. In general this is true. Under
Mag!X, it lies before the allocated memory block (the address that was
returned by MAlloc) which is indeed the so-called MCB, 'Memory Control
Block'.
This contains
- An identifier ('ANDR' or 'KROM' a greeting to one of the programmers
- The length of the allocated block
- The base page address of the program, to which the block belongs
- A pointer to the last MCB.
The GFA compiler overwrites the MCB. After the compiler terminates, Mag!X
checks whether the chain of MCBs is still intact and then reports the error
described.
By the way: This problem also occurs under MultiTOS. However, in this case
it can be removed by simply setting the memory protection flags in the
program header to GLOBAL.
Through the use of the patch, the GFA compiler no longer uses the first
16 bytes lying after the MShrink memory block and therefore dose not
overwrite an MCB. The behaviour of the compiler remains nevertheless
incorrect, so that the area allocated does not unconditionally lie after
that which is still in use by the compiler (although as a rule this is
true).
----------------------------------------------------------------------------
Patching the interpreter
----------------------------------------------------------------------------
This provides either practical configuration patches, as documented
by GFA or the correction of errors.
Interpreters that can be patched:
Version: File length:
3.6TT 104770
104766
104739
104597 (English version)
3.5E 103510
103337 (English version)
3.50 102519
102523
3.07 92894
What will be patched in the interpreter?
- No more LINEA calls:
Also see LIBPATCH.TXT. When moving the mouse in the editor you may get
some residual images, but not while a program is running.
- No more SETCOLOR calls, that change the colors on the TT:
GFA Basic make some errors with the internal setting and querying of the
screen colors, so that in resolutions like TT Medium, some colors are
changed after running the interpreter. This patch prevents this. Also
the command SETCOLOR will no longer have an effect. The better command
VSETCOLOR should be used as a replacement.
Hint: Please take note that additional patches made to the editor colors
in conjunction with the SETCOLOR patch will have no effect either!
- MERGE will no longer abort when ASCII 4 is encountered within the text:
The interpreter normally aborts the merging of files at the
corresponding line when it encounters ASCII 4 (EOT == End of trans-
mission, CONTROL D, left arrow). Under UNIX, ASCII 4 is the EOF
character which was one of the greatest ambitions of GFA Systemtechnik.
This patch removes this disrupting behaviour.
- CALL bug removed:
The CALL command in interpreter version 3.6 D TT with a size of 104770
bytes does not work because of a typing error (movem.l a4/a6,-(sp)
instead of movem.l a4-a6,-(sp)). The patch repairs this command.
- Free system memory:
When starting, the interpreter reserves all available memory for itself
apart from 16 Kbytes. This is especially a problem on non-TT machines
since too little memory is available for accessories and they refuse to
work. This patch allows you to set the amount of memory that will remain
free (e.g. 32Kbytes).
- Activate 'New names':
The 'New names' option from the Basic's system menu will
be activated automatically.
- The DEFLIST preset
- The editor colors
Hint: These do not work when the 'No more SETCOLOR calls' is active at
the same time.
- The default variable type can be entered without Postfix.
This is preset to Float.
- No CLS when strating program
Patching is basically simple: Once you have selected the patches you
require, select the "Patch.." button. The patched version of the
interpreter will then be saved under a new name.
----------------------------------------------------------------------------
Version history
----------------------------------------------------------------------------
Vers. Date
24.07.93 - First version released. And shortly afterwards, I added
the numbering of versions. :-)
0.90ß 26.07.93 - MERGE patch for V 3.50 of the interpreter incorporated.
- The defalut variable type of the interpreter loaded
will be read and displayed.
- Patches for later versions expanded.
0.91ß 27.07.93 - No more 'mouse droppings' with the file selector
- Compiler patch support started.
0.92ß 29.07.93 - DEFFILL patch incorporated, its action was wrongly
documented.
- GFA_BCOM.PRG now longer has an evaluation table
appended. All of the data necessary is now incorporated
directly within the file.
01.08.93 - The compiler was wrongly patched.
0.93 08.08.93 - Library patches integrated.
0.94 13.08.93 - Call to the MAKE_NDX program was incorrect.
- MERGE patch for the 3.5E Interpreter incorporated.
- Instruction reworked.
0.95 19.08.93 - Remaining patches incorporated: Line-A and SETCOLOR
suppression for Version 3.07.
- DEFFILL patch expanded to a value of 8.
- Documents reworked again.
0.96 28.08.93 - 3.6 Interpreter with 104739 Bytes now supported.
- Line-A patch for 3.07 doesn't work.
0.97 27.09.93 - 3.6 Interpreter with 104766 Bytes now supported.
0.98 29.09.93 - Modifications for the MAG!X-Compiler patch begun.
02.10.93 - MAG!X-patch incorporated completely.
04.10.93 - A brief information dialog now appears when the program
is started.
0.99 23.01.94 - New INIT section. The old one contained an error in
conjunction with floating point varaibles.
- The program no longer uses LINEA.
1.00 07.02.94 - The SETCOLOR patch did not work with V3.50 of the
interpreter.
- An additional patch has been added: The size of the
memory which remains free after starting the program can
be changed. The default is 16 Kbytes the least that is
practical when using accessories e.g. (ERGO!help).
- 3D effects under MultiTOS and Mag!X were incorrect.
- If SHIFT, CONTROL or ALTERNATE is pressed when starting
the program, the info dialog no longer appears. The file
selector appears instead.
1.01 10.04.94 - The LINEA patch for the interpreter with 102523 Bytes
was incorrect.
- The memory patch would only work on the ST until the
next RESERVE call occurred. This was then reset to 16
KB.
15.04.94 - A successful patch operation is now confirmed with an
appropriate message.
1.02 15.05.94 - The SETCOLOR patch for V3.5 of the interpreter with
102519 Bytes did not work (Andre Muller).
- Since the editor colors patch does not work at the same
time as SETCOLOR suppression, the corresponding option
will be diabled (David Reitter).
1.03 20.07.94 - A few internal changes, some further security checks
were added and some adaptions for the new English
version.
- The 'Patch...' button will be disabled if no patch
is chosen for the interpreter.
1.04 11.08.94 - Included support for English 3.6 interpreter
(104597 bytes).
1.05 29.08.94 - 'New names' patch included.
1.06 07.09.94 - Included support for English 3.5E interpreter
(103337 bytes), thanx to Bob Samuel.
1.07 05.10.94 -Included support for French 3.6TT interpreter
(104740 bytes).
-ERR.LST and the new FILESELECT replacement can
be found in the LISTINGS directory.
22.10.94 -'Patch...' was not selectable if only one of the
last three patches was chosen.
---------------------------------------------------------------------------
Status and disclaimer
---------------------------------------------------------------------------
GFA_PTCH is freeware and can be freely distributed so long as the contents
of the original archive remains complete. The commercial use of this
program is prohibited. The distribution by PD vendors is allowed provided
that the fee charged does not exceed DM 10.-.
We accept no responsibility for the functionality of the patches, anyone
who damages his hard- or software by using GFA_PTCH and does not have a
backup only has himself to blame!
The newest version of this program can always be found in the Maus DO.
If you have any suggestions for additional patches or have a Basic version
that is not supported, we would be pleased to here from you.
Have fun
Gregor Duchalski & Christoph Conrad
--------------------------------------------------------------------------
LIBPATCH.TXT
************************************************************************
Please note, the following text is not up to my usual(?) standard of
translation. It is both colloquial, and contains a lot of jargon - too
much for my understanding and my dictionary!
Nevertheless, I hope it will be both useful, and usable!
The Saint - July '94
*************************************************************************
///////////////////////////////////////////////////////////////////////////////
/ /
/ 19.08.93 /
/ /
/ Compiler/Library patches for GFABASIC Atari ST/STE/TT/Falcon /
/ /
/ P*ST: /
/ Christoph Conrad /
/ Adalbertsteinweg 113 /
/ 52070 Aachen /
/ /
/ E-Mail direct: /
/ MAUS: Christoph Conrad @ AC3 /
/ /
/ E-Mail Gateways: /
/ FIDO: Christoph Conrad % Maus AC3 2:242/2.6 /
/ ACHTUNG: evt. neu /
/ Christoph Conrad % Maus AC3 2:242/42.333 /
/ USEnet: Christoph_Conrad@ac3.maus.de (keine ueberlangen Mails!) /
/ Zerberus: Christoph_Conrad%ac3@zermaus.zer /
/ Pronet: MAUS:AC3:Christoph_Conrad /
/ Internet: conrad@pool.Informatik.RWTH-Aachen.DE /
/ (selten, bitte keine ueberlangen Mails!) /
/ BTX: Seite *35008024#, im Formular ausfüllen /
/ Christoph_Conrad@AC3.MAUS.DE.UUCP /
/ (kostet 90 Pfennig) /
/ /
/ In case you have discovered something that causes a problem, or you have /
/ suggestions for improvements, write to me by EMail (preferrably) or P*ST. /
/ /
/ When you find an error in Basic, write to me! /
/ /
/ I cannot accept any responsibility or take liability for any damage that /
/ could possibly have been caused to your data or programs either directly or /
/ indirectly that have occurred as a result of using these patches! /
/ /
///////////////////////////////////////////////////////////////////////////////
Contents:
(I) General & specific info for these patches
(II) Various questions and answers
(I) General & specific info for these patches
Moin,
GFABASIC has grown close to all of our hearts. When I first got my ST, it was
the only programmming language that offered a really fast turn around time (edit
a program, test it, edit a....), a hyperspeed compiler/interpreter (in most cases
the compiler also created correctly fixed code!) a usable editor and could
usefully be employed on a 1Mb computer _without_ a hard drive. I suspect that
this was ther reson for the success of GFA BASIC.
In the course of time and particularly (but not only) in conjunction with
graphic improvements has GFABASIC shown some of its shortcomings. These library
patches correct some (serious) problems.
The library patches has already appeared in two versions as GFAL1030 and
improved in GFAL1072. I was then asked by Gregor Duchalski whether I did
not have the desire to contribute some of my own ideas to patch the interpreter
using a convenient GEM interface.
Since my patch program offered a convenient operating environment AND because of
Gregor's involvement and the wishes of the GFABASIC MAUS group, I decided to do
this. This convinced me to develop my own GFA library that can be installed
using GFA_PTCH.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
What does the compiler patch part of GFA_PTCH offer?
- Line-A patches are incorporated automatically!
- Clean Auto folder recognition
- Clean recognition of accessories
- In case the memory requested by $m does not exist, this can be recognized
- $U/$I bug in 3.6 removed!
Important: I definately advise against the $I matter in particular. It is
untidy or in fact lethal. Also, $U can be critical. Wirth this Init part,
$U/$I will run just as "dirty" or "uncertain" as before, apart from the fact
that it does now actually run under 3.6.
ERR.LST demonstartes to you in an exemplary way all of the features. This also
uses $I+ cleany in the case of the demo. Take note of the comments incorporated
in ERR.LST and the hints offered below!
!!! Part of the assembler code is © GFA Systemtechnik
Changes made to either part are for personal use only. Modified copies may not
be re-distributed!
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Since there was a great deal of work involved in developing these patches, If
you find them useful, a gift (of thanks) of >= 10,- would show your appreciation
:-)
Alternatively, since I am a music fan, you can send me a cassette (Chrome
dioxide, Dolby B - prefferrably a TDK SA-X) containing some of your favourites.
All types from Classical vocal (Opera, Operetta etc.), Rock, Folk and Disco
(Bananarama, Sabrina) are welcome. I prefer lesser known groups/bands/
interpretations. I hope to get a flood of cassettes!!! :-)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
What does GFA_PTCH.PRG do ?
== (a) patches the compiler
Attention: Programs created using a patched compiler will _NOT_ run with an
original library!
== (b) Patches the library
In the strictest sense this is not a patch but an exchange of code.
== 9c) Creation of a new index file GFA3BLIB.NDX
MAKE_NDX.PRG must be used _unconditionally_, which creates a new GFA3LIB.NDX.
this ought to be used with GFA_PTCH.
You ought probably to save the old version of GFA3BLIB.NDX even though you
could re-create this at any time using MAKE_NDX.PRG with the old library.
Unfortunately, MAKE_NDX first appeared with version 3.5. Currently I am
unaware (even if you are) whether it could be included with this package
and I have queried this with GFA. If it can't, I will probably write a
functional equivalent.
== (d) Patch the interpreter
You must _unconditionally_ patch the interpreter using GFA_PTCH.PRG. In
case your version of the interpreter has not been seen by us:
Replace the FIRST occurrance of $A00A and $A009 by $4E71. This _ought_ to
cause a crash. As a result of the patch: $E0C0 $A00A $4CDF as well as $0008
$A009 $246E.
This will produce "mouse droppings" when moving the mouse within the
interpreter editor, but not whilst a program is running (the clean nesting
of hidems/showms for GRAF_MOUSE is taken for granted!).
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
In case you have further problems:
- Make a test with the original GFA3BLIB (+ the previous GFA3BLIB.NDX).
Send me
- the INIT.O file for your library
- The exact version number/length of the library & compiler.
This can be done simply by: Run INIT2DMP.PRG from the same folder as
GFA3BLIB which will produce a printable or E-mail-able file INIT.DMP.
!!! Make sure that you use your ORIGINAL library or a copy of it and !!!
!!! not one that has already been patched !!!
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
How do I work with it ?
Please take a look at the ERR.LST file. I hope that will be enough. You
should then read through the question and answers section of this text. The
commands that you ought to avoid (e.g. the Line A patches), and you will
find many of the tips useful.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
BUGS:
Hopefully there are not too many
Still being worked on:
ERR appears when starting the interpreter not always when initialised to
zero.
Before you blame this INIT, please test it first using the orignal GFA3BLIB
(& the previous GFABLIB.NDX).
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Disclaimer:
I have taken all possible precautions to create error-free programs & data.
Nevertheless, it is not totally possible to exclude errors. Therefore, the
authors cannot accept any responsibility or take liability for any damage
that could possibly have been caused to your data or programs either directly
or indirectly that have occurred as a result of using these programs!
*****************************************************************************
(II) Questions & answer section
QUESTIONS & ANSWERS:
+++++++++++++++++++++
QUESTION:
I have taken your advice that Line-A should not be used. Why is this so?
Therefore, how can I make my compiler library (GFA3BLIB) Line-A free?
ANSWER:
Here is an extract from the 10th edition of the Profibook:
[Start of quote]
The architecture of the operating system certainly speaks against the usage
of Line-A routinmes. These are used for display in the low-level VDI screen
driver. Using them prevents the possible usage of another (faster) screen
driver!
Also, Line-A routines are only provided for ST modes (320*200, 640*200,
640*400). Already, with 256 color graphics (special graphic cards or the TT
in 'low' resolution) the provisions of the Line-A interface have been
exhausted (see COLBIT0 to COLBIT3)
[End of quote]
In case that was a sclear as mud: DON'T PANIC!
The deciding factor in all this will be that progams using Line-A routines
will not run correctly with graphic cards! Ergo: Do away with it!
*** Take heed from a correct nesting of hidems/showms (via GRAF_MOUSE AES
78). For each hide of a show, "droppings" will result. With the mouse not
switched on, when it already is, as is the rule when starting GEM programs,
there are no "droppings".
*** AVOID THE FOLLOWING COMMANDS:
CRSCOL CRSLIN MOUSE MOUSEK MOUSEX MOUSEY SETMOUSE RC_COPY
SHOWM HIDEM SPRITE ACHAR ACLIP ALINE APOLY ARECT
ATEXT BITBLT HLINE L~A PSET PTST GET PUT
SGET SPUT FILESELECT FILESELECT #
When using without #file_number:
INPUT INPUT$ LINE INPUT
Replacement commands:
MOUSE/MOUSEK/MOUSEX/MOUSEY -> (AES) GRAF_MKSTATE
SETMOUSE -> (AES) APPL_TPLAY
SHOWM/HIDEM -> (AES) GRAF_MOUSE
FILESELECT -> (AES) FSEL_INPUT
FILESELECT # -> (AES) FSEL_EXINPUT
SPRITE -> (VDI) vro/vrt_cpyfm
ACHAR -> (VDI) TEXT
ACLIP -> (VDI) CLIP
ALINE -> (VDI) LINE
APOLY -> (VDI) POLYFILL
ARECT -> (VDI) PBOX
ATEXT -> (VDI) TEXT
BITBLT -> (VDI) BITBLT q%(),z%(),d%()
HLINE -> (VDI) LINE
PSET -> (VDI) PLOT oder v_pmarker bei grob > 200 Punkten
PTST -> (VDI) POINT
GET/PUT/SGET/SPUT -> (VDI) BITBLT
RC_COPY -> (VDI) BITBLT
>> Without a guarantee of completeness!
+++++++++++++++++++++
QUESTION:
Where can I find information about GEM conformant programming?
ANSWER:
Tim Orens ProGEM. This text from 1985, which you should be able to find in
most mailboxes provides the best in 'Professsional GEM' programming. You
will find more in the book 'Vom Anfänger zum GEM-Profi' by Gebrüder Geiss.
A little confused, but otherwise very good. As reference material, the
'Profibuch' by Jankowski/Reschke/Rabich, is undoubtedly irreplaceable.
++++++++++++++++++++
QUESTION:
GFA already has good commands for using windows. What can these be used
for?
ANSWER:
I advise against using GFA's own window management routines. In previous
versions this is incorrect - today, who knows? Using the AES, it is equally
as 'simple' or 'difficult'.
+++++++++++++++++++++
QUESTION:
Sometimes my program is no longer under my control. With the best will in
the world I cannot find any erros. What is happening and how do I find out?
ANSWER:
Use SysMon and TempleMon. You can find TempleMon in many mailboxes - SysMon
can be obtained directly from the author:-
Karsten Isakovic
Wilmersdorferstr. 82
1000 Berlin 12
At the time of the crash, you will at least be able to establish the last
used system call and possibly the bad parameter.
Another good possibility is to use the TRACE procedurename (seee the
manual). When all of the lines that have been traced are written to a
previously opened file (PRINT #1,TRACE$) you will quickly be able to
localise the cause of the crash.
The Turbo-C/Pure-C debugger can be equally as useful when the program has
been translated into symbols.
There is an extensive unknown error that exists GFA-Basic's own memory
management. This exists in all three versions.
Hint: add a FRE(0) command (in conjunction with any string) liberally to
your code.
Try the following (after re-booting):
' Compiler version with $m
' instead of RESERVE
RESERVE 1000
$m 4711
' RESERVE will cause a quicker crash but is actually unneccessary
' The lines ending (**) will then really cause the interpreter to return a
' value of minus 4 from (FRE() MOD 16) == 0 after the RESERVE
' Because of the backtrailer with rest16$ with the compiler in case
' $m XXXX with (XXXX MOD 16)<>0
rest16%=(FRE(0) MOD 16)-4 ! **
IF rest16%<0 ! **
ADD rest16%,16 ! **
ENDIF ! **
rest16$=STRING$(rest16%,0) ! **
' (FRE() MOD 16) == 0 now fulfilled
str$="AHAH"
DO
@crash(str$)
LOOP
PROCEDURE crash(str$)
str$="OHOH"
RETURN
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Special thanks:
- Harald Ax for DELITE, an outstanding GFA-Shell
- Jankowski/Rabich/Reschke for his "Profibuch", an indispensible treasure.
- Karsten Isakovic for his 'SysMon', as well as
Thomas Tempelmann and Johannes Hill for 'TempleMon'
Both tool are known as 'The Programmers best friends' :-)
- ATARI / Landon Dyer for the 'MadMac'.
- GENESIS for 'Selling England by the pound' as well as 'Foxtrot'
THE CURE for 'Disintegrations'
THE RED HOT CHILI PEPPERS for 'Blood sugar sex magik'
KING'S X © 1992 (with 'Black Flag')
TEMPLE OF THE DOG für ihr Debütalbum
RAGE AGAINST THE MACHINE for their debut album
BODY COUNT & ICE-T for the Plate
- Barbara for her understanding, that gives me life without my
computer =:^}
Have fun,
Byeeeeeeeeeeeeee, Chris
VDIBASE.TXT
This information was provided by Ingo Schmidt (from a book).
Starting address of a memory block which GEM installs to manage the VDI
parameters. This list isn't valid for the Mega-TOS or Blitter-TOS. GFA V3.0
gives confused values here. However, in the standard ROM-TOS the parameter
block for the virtual workstation is at address &H578C. That block also is 308
bytes long and has the same structure as VDIBASE. The VDIBASE is a copy of that
parameter block. So in V3.0 you can use the hardware address instead of
VDIBASE.
Offset Size Description
0 word current text rotation (0, 900, 1800, 2700)
2 word clipping flag (0=on, 1=off)
4 long address of current font header
8 word DDA_INC (?)
10 word multi-fill flag
12 word number of scan lines of current fill pattern
14 long start address of fill pattern
18 word points/absolute mode (?)
20 long SCRTCHP (buffer pointer, current boot sector ??)
24 word SCRPT2 (minus offset to LPEEK(VDIBASE+20) ??)
Gives the start of the eventually executable part of the boot
sector -> from LPEEK(VDIBASE+20)-DPEEK(VDIBASE+24) these are the
last 490 bytes of the boot sector ??
26 word current text style
28 word T_SCLSTS (=0 ??)
30 word current polygon fill color
32 word current fill pattern -> DEFFILL color,DPEEK(VDIBASE+32)-1,style
34 word boundary flag
36 word current fill style
38 word current text alignment (0=left, 1=centered, 2=right)
40 word VDI handle of current workstation (GFA-Basic)
42 word current line start form
44 word current line color
46 word current line end form
48 word current line style
50 word current line width
52 long pointer to next VDI-(GDOS) font
56 word current polymarker color
58 word current polymarker height
60 word current polymarker type
62 word relative polymarker height
64 long pointer to next virtual workstation parameter block
68 word number of available GEM/VDI fonts
70 word index of current GEM/VDI font
72 byte copy of current font header (88 bytes)
160 word ?
162 word current text color
164 word current user line style
166 word plane 1 of user fill pattern [mono] (16 words)
198 word plane 2 of user fill pattern [color] (16 words)
230 word plane 3 of user fill pattern [color] (16 words)
262 word plane 4 of user fill pattern [mono] (16 words)
294 word current vertical text alignment
0=baseline, 1=halfline, 2=ascentline,
3=bottomline, 4=descentline, 5=topline
296 word current graphics mode -> GRAPHMODE DPEEK(VDIBASE+296)-1
298 word current coordinate system
Normalized Device Coordinates (NDC)=0
Raster Coordinates (RC)=2 -> standard
300 word x1, y1, x2, y2 of current clipping box (4 words)
This system variable should be avoided. This table is actually stored outside
the programs memory space. Messing around with this table can lead to
unpredictable results.
ATTRDEF.H
/*
********************************* attrdef.h ***********************************
*
* $Revision: 3.1 $ $Source: /u/lozben/projects/vdi/mtaskvdi/RCS/attrdef.h,v $
* =============================================================================
* $Author: lozben $ $Date: 91/01/04 12:20:40 $ $Locker: $
* =============================================================================
*
* $Log: attrdef.h,v $
* Revision 3.1 91/01/04 12:20:40 lozben
* Typedefed structure atribute to ATTRIBUTE.
*
* Revision 3.0 91/01/03 15:05:57 lozben
* New generation VDI
*
* Revision 2.2 90/04/24 15:51:14 lozben
* Expanded the user defined pattern array from a 4x16 to an 8x16.
*
* Revision 2.1 89/02/21 17:28:19 kbad
* *** TOS 1.4 FINAL RELEASE VERSION ***
*
*******************************************************************************
*/
#ifndef _ATTRDEF_H_
#define _ATTRDEF_H_
/* Structure to hold data for a virtual workstation */
typedef struct attribute {
WORD chup; /* Character Up vector */
WORD clip; /* Clipping Flag */
FONT_HEAD *cur_font; /* Pointer to current font */
WORD dda_inc; /* Fraction to be added to the DDA */
WORD multifill; /* Multi-plane fill flag */
WORD patmsk; /* Current pattern mask */
WORD *patptr; /* Current pattern pointer */
WORD pts_mode; /* TRUE if height set in points mode */
WORD *scrtchp; /* Pointer to text scratch buffer */
WORD scrpt2; /* Offset to large text buffer */
WORD style; /* Current text style */
WORD t_sclsts; /* TRUE if scaling up */
WORD fill_color; /* Current fill color (PEL value) */
WORD fill_index; /* Current fill index */
WORD fill_per; /* TRUE if fill area outlined */
WORD fill_style; /* Current fill style */
WORD h_align; /* Current text horizontal alignment */
WORD handle; /* handle for attribute area */
WORD line_beg; /* Beginning line endstyle */
WORD line_color; /* Current line color (PEL value) */
WORD line_end; /* Ending line endstyle */
WORD line_index; /* Current line style */
WORD line_width; /* Current line width */
FONT_HEAD *loaded_fonts; /* Pointer to first loaded font */
WORD mark_color; /* Current marker color (PEL value) */
WORD mark_height; /* Current marker height */
WORD mark_index; /* Current marker style */
WORD mark_scale; /* Current scale factor for marker data */
struct attribute *next_work; /* Pointer to next virtual workstation */
WORD num_fonts; /* Total number of faces available */
WORD scaled; /* TRUE if font scaled in any way */
FONT_HEAD scratch_head; /* Holder for the doubled font data */
WORD text_color; /* Current text color (PEL value) */
WORD ud_ls; /* User defined linestyle */
WORD ud_patrn[32*16]; /* User defined pattern */
WORD v_align; /* Current text vertical alignment */
WORD wrt_mode; /* Current writing mode */
WORD xfm_mode; /* Transformation mode requested */
WORD xmn_clip; /* Low x point of clipping rectangle */
WORD xmx_clip; /* High x point of clipping rectangle */
WORD ymn_clip; /* Low y point of clipping rectangle */
WORD ymx_clip; /* High y point of clipping rectangle */
} ATTRIBUTE;
#endif
BASEPAGE.H
/*
* $Id: basepage.h,v 1.4 2001/06/13 20:21:41 fna Exp $
*
* This file belongs to FreeMiNT. It's not in the original MiNT 1.12
* distribution. See the file Changes.MH for a detailed log of changes.
*/
/*
* Description: Definition of the basepage structure.
*/
# ifndef _mint_basepage_h
# define _mint_basepage_h
typedef struct basepage BASEPAGE;
struct basepage
{
long p_lowtpa; /* pointer to self (bottom of TPA) */
long p_hitpa; /* pointer to top of TPA + 1 */
long p_tbase; /* base of text segment */
long p_tlen; /* length of text segment */
long p_dbase; /* base of data segment */
long p_dlen; /* length of data segment */
long p_bbase; /* base of BSS segment */
long p_blen; /* length of BSS segment */
char *p_dta; /* pointer to current DTA */
BASEPAGE *p_parent; /* pointer to parent's basepage */
long p_flags; /* memory usage flags */
char *p_env; /* pointer to environment string */
/* Anything after this (except for p_cmdlin) is undocumented,
* reserved, subject to change, etc. -- user programs must NOT use!
*/
char p_devx[6]; /* real handles of the standard devices */
char p_res2; /* reserved */
char p_defdrv; /* default drv */
long p_undef[17]; /* reserved space */
long p_usp; /* a fake USP to make dLibs programs happy */
char p_cmdlin[128]; /* command line image */
};
# endif /* _mint_basepage_h */
ERRNO.H
/*
* $Id: errno.h,v 1.4 2001/06/13 20:21:42 fna Exp $
*
* mint/errno.h -- MiNTLib.
* Copyright (C) 1999 Guido Flohr <guido@freemint.de>
*
* This file is part of the MiNTLib project, and may only be used
* modified and distributed under the terms of the MiNTLib project
* license, COPYMINT. By continuing to use, modify, or distribute
* this file you indicate that you have read the license and
* understand and accept it fully.
*/
#ifndef _MINT_ERRNO_H
# define _MINT_ERRNO_H 1 /* Allow multiple inclusion. */
#ifndef __KERNEL__
/* for src integrity checking until all src is converted */
#error no __KERNEL__
# ifndef _FEATURES_H
# include <features.h>
# endif
__BEGIN_DECLS
/* See below. */
#define __KERNEL_NEG(c) c
#else /* __KERNEL__ */
/* The kernel should actually have code like
if (whew_we_dont_know_that)
return -ENOSYS;
instead of the current
if (whew_we_dont_know_that)
return ENOSYS;
That seems to be a matter of taste.
As a convenience we offer both possibilities here:
*/
# ifdef POSITIVE_ERROR_CODES
# define __KERNEL_NEG(c) (c)
# else /* not POSITIVE_ERROR_CODES */
# define __KERNEL_NEG(c) (-(c))
# endif /* not POSITIVE_ERROR_CODES */
/* If you prefer to type E_OK instead of 0 ... */
# define E_OK 0
#endif /* not __KERNEL__ */
/* The original atarierr.h defined quite a few error codes which were
either useless or non-standard. Important codes such as EISDIR,
ENOTEMPTY were missing, others were simply misunderstood (for example
the usual EINVAL would really be an ENOSYS, EINVAL is not invalid
function number but invalid argument) and especially in MiNT
some error codes got really overloaded, for example ENOENT serves
as ENOENT, ESRCH and ECHILD, or EACCES and EPERM were the same.
The codes in this file try to find the closest equivalent for
all error codes currently in use, marks some error codes as
deprecated and tries to be fit for the future by defining all
error codes that may be needed for future enhancement.
*/
/*
The explanations are mostly taken from the GNU libc manual.
Unfortunately they don't always document the current usage in the
MiNT system but rather how it should be. I've marked all current
misusage with either `KERNEL' or `FIXME'.
We provide way too many synonyms for error codes here. Both in
the kernel and the libc only the `official' name (the one in the
top row that bears the actual define) should be used.
*/
/* Where is ENOERR and E_OK? This file is <errno.h> and not <noerror.h>,
no error is 0, basta. */
/* Is this really needed? Deprecated. */
#define EERROR __KERNEL_NEG(1) /* Generic error. */
/* A system resource that can't be shared is already in use. For example
if you try to delete a file that is the root of a currently mounted
filesystem, you get this error.
This used to be EDRNRDY resp. EDRNRDY. */
#define EBUSY __KERNEL_NEG(2) /* Resource busy. */
#ifdef __LOOSE_ERRROR_CODES
# define EDRNRDY EBUSY
# define EDRVNR EBUSY
#endif
/* Deprecated. */
#define EUKCMD __KERNEL_NEG(3) /* Unknown command. */
#ifdef __LOOSE_ERRROR_CODES
# define EUNCMD EUKCMD
#endif
/* Checksum error detected while reading from a block device such as
a floppy drive. Obviously non-standard but often used. */
#define ECRC __KERNEL_NEG(4) /* CRC error. */
#ifdef __LOOSE_ERRROR_CODES
# define E_CRC ECRC
#endif
/* Bad request. */
#define EBADR __KERNEL_NEG(5) /* Bad request. */
#ifdef __LOOSE_ERRROR_CODES
# define EBADREQ EBADR
# define EBADRQ EBADR
#endif
/* Invalid seek operation (such as on a pipe). */
/* KERNEL: The pipe file system currently returns 0 for seek on a pipe! */
#define ESPIPE __KERNEL_NEG(6) /* Illegal seek. */
#ifdef __LOOSE_ERRROR_CODES
# define ESEEK ESPIPE
# define E_SEEK ESPIPE
#endif
/* Wrong medium type. */
#define EMEDIUMTYPE __KERNEL_NEG(7) /* Wrong medium type. */
#ifdef __LOOSE_ERRROR_CODES
# define EUKMEDIA EMEDIUMTYPE
# define EMEDIA EMEDIUMTYPE
#endif
/* A sector that does not exist was addressed in the call to a bock
device function. */
#define ESECTOR __KERNEL_NEG(8) /* Sector not found. */
#ifdef __LOOSE_ERRROR_CODES
# define ESECNF ESECTOR
#endif
/* No paper. No, not at the conveniences, in the printer. */
#define EPAPER __KERNEL_NEG(9) /* No paper. */
/* Read and write faults. Deprecated, be more specific instead. */
#define EWRITE __KERNEL_NEG(10) /* Write fault. */
#ifdef __LOOSE_ERRROR_CODES
# define EWRITEF EWRITE
#endif
#define EREAD __KERNEL_NEG(11) /* Read fault. */
#ifdef __LOOSE_ERRROR_CODES
# define EREADF EREAD
#endif
/* Another generic error. Who can tell the difference to EERROR? */
#define EGENERIC __KERNEL_NEG(12) /* General mishap. */
/* An attempt was made to modify something on a read-only file
file system. */
#define EROFS __KERNEL_NEG(13) /* Write protect. */
/* A removable medium was exchanged before the operation could finish. */
#define ECHMEDIA __KERNEL_NEG(14) /* Media change. */
#ifdef __LOOSE_ERRROR_CODES
# define E_CHNG ECHMEDIA
#endif
/* The wrong type of device was given to a function that expects a
particular sort of device. */
#define ENODEV __KERNEL_NEG(15) /* No such device. */
#ifdef __LOOSE_ERRROR_CODES
# define EUKDEV ENODEV
# define EUNDEV ENODEV
#endif
/* Bad sectors on block device medium found. Uhm, if the driver found
them, mark them as bad and don't bother the user with that.
Deprecated. */
#define EBADSEC __KERNEL_NEG(16) /* Bad sectors found. */
#ifdef __LOOSE_ERRROR_CODES
# define EBADSF EBADSEC
#endif
/* A device with a removable media (such as a floppy) is empty. */
#define ENOMEDIUM __KERNEL_NEG(17) /* No medium found. */
#ifdef __LOOSE_ERRROR_CODES
# define EIDISK ENOMEDIUM
# define EOTHER ENOMEDIUM
#endif
/* MetaDOS error (deprecated). */
#define EINSERT __KERNEL_NEG(18) /* Insert media. */
/* MetaDOS error (deprecated). */
#define EDRVNRSP __KERNEL_NEG(19) /* Drive not responding. */
/* No process matches the specified process ID.
KERNEL: This is a new error code. Currently ENOENT is returned instead. */
#define ESRCH __KERNEL_NEG(20) /* No such process. */
/* There are no child processes. This error happens on operations
that are supposed to manipulate child processes, when there aren't
any processes to manipulate.
KERNEL: This is a new error code. Currently ENOENT is returned instead. */
#define ECHILD __KERNEL_NEG(21) /* No child processes. */
/* Deadlock avoided; allocating a system resource would have resulted
in a deadlock situation. The system does not guarantee that it
will notice all such situations. This error means you got lucky
and the system noticed; it might just hang.
KERNEL: This is a new error code. The kernel currently never returns
it. But that doesn't mean that there are no deadlock situations in
the kernel. */
#define EDEADLK __KERNEL_NEG(22) /* Resource deadlock would occur. */
#define EDEADLOCK EDEADLK
/* A file that isn't a block special file was given in a situation
that requires one. For example, trying to mount an ordinary file
as a file system in Unix gives this error. New code. */
#define ENOTBLK __KERNEL_NEG(23) /* Block device required. */
/* File is a directory; you cannot open a directory for writing, or
create or remove hard links to it.
KERNEL: This is a new error code. Flink() should be fixed. */
#define EISDIR __KERNEL_NEG(24) /* Is a directory. */
/* Invalid argument. This is used to indicate various kinds of
problems with passing the wrong argument to a library function.
FIXME: This used to be the same as `ENOSYS'. In fact that should
be two distinct error codes. For example, the `fchmod' function
should return `EINVAL' if the file descriptor passed as an
argument corresponds to a pipe or socket, not an ordinary file.
But since `fchmod' is a function that is currently only supported
under MiNT the same error would be reported if the operating
system does not support the call at all. It is common practice
to cache such failures because in the case of `ENOSYS' there
is no chance that succeeding calls will proceed. So how do
you want to distinguish between these cases? */
#define EINVAL __KERNEL_NEG(25) /* Invalid argument. */
/* Inappropriate file type or format. The file was the wrong type
for the operation, or a data file had the wrong format.
On some systems `chmod' returns this error if you try to set the
sticky bit on a non-directory file. */
#define EFTYPE __KERNEL_NEG(26) /* Inappropriate file type or format. */
/* While decoding a multibyte character the function came along an
invalid or an incomplete sequence of bytes or the given wide
character is invalid. */
#define EILSEQ __KERNEL_NEG(27) /* Illegal byte sequence. */
/* Function not implemented. Some functions have commands or options
defined that might not be supported in all implementations, and
this is the kind of error you get if your request them and they are
not supported.
KERNEL: This was usually called EINVFN (invalid function number) and
that's why it was probably mixed up with EINVAL (invalid argument).
FIXME: Grep thru the MiNTLib sources for EINVAL and replace it with
the correct ENOSYS. Same for the kernel. */
#define ENOSYS __KERNEL_NEG(32) /* Function not implemented. */
/* This is a "file doesn't exist" error for ordinary files that are
referenced in contexts where they are expected to already exist.
KERNEL/FIXME: This used to be the same as ESRCH and and ECHILD,
in the kernel it was usually called EFILNF. Fix the wrong usage
of ESRCH and ECHILD and replace EFILNF with ENOENT. */
#define ENOENT __KERNEL_NEG(33) /* No such file or directory. */
/* A file that isn't a directory was specified when a directory is
required. The usage of the synonyme EPATH is deprecated! */
#define ENOTDIR __KERNEL_NEG(34) /* Not a directory. */
#ifdef __LOOSE_ERRROR_CODES
# define EPATH ENOTDIR
#endif
/* The current process has too many files open and can't open any
more. Duplicate descriptors do count toward this limit.
In BSD and GNU, the number of open files is controlled by a
resource limit that can usually be increased. If you get this
error, you might want to increase the `RLIMIT_NOFILE' limit
or make it unlimited.
Under MiNT we currently have to live without such luxury. */
#define EMFILE __KERNEL_NEG(35) /* Too many open files. */
/* Permission denied; the file permissions do not allow the
attempted operation.
KERNEL: This used to be mixed up with EPERM (operation not permitted). */
#define EACCES __KERNEL_NEG(36) /* Permission denied. */
#ifdef __LOOSE_ERRROR_CODES
# define EACCESS EACCES
#endif
/* Bad file descriptor; for example, I/O on a descriptor that has been
closed or reading from a descriptor open only for writing (or vice
versa). */
#define EBADF __KERNEL_NEG(37) /* Bad file descriptor. */
/* Operation not permitted; only the owner of the file (or other
resource) or processes with special privileges can perform the
operation.
This is a new error code (used to be a synonyme for EACCES). As
a general rule you can say, whenever you want to disallow something
take EACCES. Only if you positively know that EPERM should be
used, then take this one.
FIXME: Some kernel functions should return EPERM, for example
Tsettimeofday, Tsetdate, Tsettime, Setdate ... */
#define EPERM __KERNEL_NEG(38) /* Operation not permitted. */
/* No memory available. The system cannot allocate more virtual
memory because its capacity is full. */
#define ENOMEM __KERNEL_NEG(39) /* Cannot allocate memory. */
/* Bad address; an invalid pointer was detected. In the GNU system,
this error never happens; you get a signal instead. In the MiNT
system this error often happens, and you get angry mails and flames
on the usenet. */
#define EFAULT __KERNEL_NEG(40) /* Bad address. */
/* No such device or address. The system tried to use the device
represented by a file you specified, and it couldn't find the
device. This can mean that the device file was installed
incorrectly, or that the physical device is missing or not
correctly attached to the computer.
Under MiNT this can also happen if a pathname starts with a
drive letter followed by a colon (e. g. `x:/dont/exist'). This
was called `invalid drive specification' or `invalid drive id'. */
#define ENXIO __KERNEL_NEG(46) /* No such device or address. */
/* An attempt to make an improper link across file systems was
detected. This happens not only when you use `link' (for
hard links) but also when you rename a file with `rename'. */
#define EXDEV __KERNEL_NEG(48) /* Cross-device link. */
/* No more matching file names, only used by Fsnext(2). Don't mix
that up with ENFILE. */
#define ENMFILES __KERNEL_NEG(49) /* No more matching file names. */
#ifdef __LOOSE_ERRROR_CODES
# define ENMFIL ENMFILES
#endif
/* There are too many distinct file openings in the entire system.
Note that any number of linked channels count as just one file
opening. This error never occurs in the GNU system, and it probably
never occurs in the MiNT system, too. */
#define ENFILE __KERNEL_NEG(50) /* File table overflow. */
/* Locking conflict. Deprecated.
KERNEL: If the LOCK_NB flag was selected EWOULDBLOCK should be used
instead. Otherwise the process should be blocked until the lock
is available? */
#define ELOCKED __KERNEL_NEG(58) /* Locking conflict. */
/* Deprecated, should only happen with Dlock(). */
#define ENSLOCK __KERNEL_NEG(59) /* No such lock. */
/* Bad argument, used to be `range error/context unknown'. Deprecated. */
#define EBADARG __KERNEL_NEG(64) /* Bad argument. */
/* Another spurious error, deprecated. */
#define EINTERNAL __KERNEL_NEG(65) /* Internal error. */
#ifdef __LOOSE_ERRROR_CODES
# define EINTRN EINTERNAL
#endif
/* Invalid executable file format. This condition is detected by the
`exec' functions. */
#define ENOEXEC __KERNEL_NEG(66) /* Invalid executable file format. */
#ifdef __LOOSE_ERRROR_CODES
# define EPLFMT ENOEXEC
#endif
/* Can't grow block, deprecated. At least within the library this should
be handled with ENOMEM. */
#define ESBLOCK __KERNEL_NEG(67) /* Memory block growth failure. */
#ifdef __LOOSE_ERRROR_CODES
# define EGSBF ESBLOCK
#endif
/* Terminated with CTRL-C (Kaos, MagiC, BigDOS). Nonsense. */
#define EBREAK __KERNEL_NEG(68) /* Aborted by user. */
/* This looks like a joke but it isn't. Who has introduced that
in the kernel? */
#define EXCPT __KERNEL_NEG(69) /* Terminated with bombs. */
/* An attempt to execute a file that is currently open for writing, or
write to a file that is currently being executed. Often using a
debugger to run a program is considered having it open for writing
and will cause this error. (The name stands for "text file
busys".) This is not an error in the GNU system; the text is
copied as necessary. In the MiNT system this error currently cannot
occur. */
#define ETXTBSY __KERNEL_NEG(70) /* Text file busy. */
/* File too big; the size of a file would be larger than allowed by
the system.
KERNEL: This is a new code. If this error condition can occur,
then the correct code should be returned. */
#define EFBIG __KERNEL_NEG(71) /* File too big. */
/* Too many levels of symbolic links were encountered in looking up a
file name. This often indicates a cycle of symbolic links.
KERNEL: There was no difference between EMLINK (too many links and
ELOOP (too many symbolic links). The more common meaning of this
error code is preserved, but whenenver EMLINK should be used, this
has to be fixed in the kernel. */
#define ELOOP __KERNEL_NEG(80) /* Too many symbolic links. */
/* Broken pipe; there is no process reading from the other end of a
pipe. Every function that returns this error code also generates
a `SIGPIPE' signal; this signal terminates the program if not
handled or blocked. Thus, your program will never actually see
`EPIPE' unless it has handled or blocked `SIGPIPE'. */
#define EPIPE __KERNEL_NEG(81) /* Broken pipe. */
/* Too many links; the link count of a single file would become too
large. `rename' can cause this error if the file being renamed
already has as many links as it can take.
KERNEL: This is a new error code. See the note for ELOOP. */
#define EMLINK __KERNEL_NEG(82) /* Too many links. */
/* Directory not empty, where an empty directory was expected. Typically
this error occurs when you are trying to delete a directory.
KERNEL: New error code, for the case of non-empty directories
EEXIST was returned. The new behavior could cause compatibility
problems since inproper implementations of recursive rm commands
could rely on the old error code (85) being returned.
Which error is more probable? */
#define ENOTEMPTY __KERNEL_NEG(83) /* Directory not empty. */
/* File exists; an existing file was specified in a context where it
only makes sense to specify a new file. */
#define EEXIST __KERNEL_NEG(85) /* File exists. */
/* Filename too long (longer than `PATH_MAX') or host name too long
(in `gethostname' or `sethostname'). */
#define ENAMETOOLONG __KERNEL_NEG(86) /* Name too long. */
/* Inappropriate I/O control operation, such as trying to set terminal
modes on ordinary files. */
#define ENOTTY __KERNEL_NEG(87) /* Not a tty. */
/* Range error; used by mathematical functions when the result value
is not representable because of overflow or underflow.
The string to number conversion functions (`strtol', `strtoul',
`strtod', etc. can also return this error. */
#define ERANGE __KERNEL_NEG(88) /* Range error. */
/* Domain error; used by mathematical functions when an argument
value does not fall into the domain over which the function is
defined. */
#define EDOM __KERNEL_NEG(89) /* Domain error. */
/* Input/output error; usually used for physical read or write errors. */
#define EIO __KERNEL_NEG(90) /* I/O error */
/* No space left on device; write operation on a file failed because
the disk is full. */
#define ENOSPC __KERNEL_NEG(91) /* No space left on device. */
/* Error number 92-99 reserved for TraPatch. */
/* This means that the per-user limit on new process would be
exceeded by an attempted `fork'. */
#define EPROCLIM __KERNEL_NEG(100) /* Too many processes for user. */
/* This file quota system is confused because there are too many users. */
#define EUSERS __KERNEL_NEG(101) /* Too many users. */
/* The user's disk quota was exceeded. */
#define EDQUOT __KERNEL_NEG(102) /* Quota exceeded. */
/* Stale NFS handle. This indicates an internal confusion in
the NFS system which is due to file system rearrangements on the
server host. Reparing this condition usually requires unmounting
and remounting the NFS file system on the local host. */
#define ESTALE __KERNEL_NEG(103) /* Stale NFS file handle. */
/* An attempt was made to NFS-mount a remote file system with a file
name that already specifies an NFS-mounted file. (This is an
error on some operating systems, but we expect it to work properly
on the GNU system, making this error code impossible). */
#define EREMOTE __KERNEL_NEG(104) /* Object is remote. */
/* ??? */
#define EBADRPC __KERNEL_NEG(105) /* RPC struct is bad. */
#define ERPCMISMATCH __KERNEL_NEG(106) /* RPC version wrong. */
#define EPROGUNAVAIL __KERNEL_NEG(107) /* RPC program not available. */
#define EPROGMISMATCH __KERNEL_NEG(108) /* RPC program version wrong. */
#define EPROCUNAVAIL __KERNEL_NEG(109) /* RPC bad procedure for program. */
/* No locks available. This is used by the file locking facilities;
This error is never generated by the GNU system, but it can result
from an operation to an NFS server running another operating system. */
#define ENOLCK __KERNEL_NEG(110) /* No locks available. */
/* ??? */
#define EAUTH __KERNEL_NEG(111) /* Authentication error. */
#define ENEEDAUTH __KERNEL_NEG(112) /* Need authenticator. */
/* In the GNU system, servers supporting the `term' protocol return
this error for certain operations when the caller is not in the
foreground process group of the terminal. Users do not usually
see this error because functions such as `read' and `write'
translate it into a `SIGTTIN' or `SIGTTOU' signal. */
#define EBACKGROUND __KERNEL_NEG(113) /* Inappropriate operation for background process. */
/* ??? */
#define EBADMSG __KERNEL_NEG(114) /* Not a data message. */
#define EIDRM __KERNEL_NEG(115) /* Identifier removed. */
#define EMULTIHOP __KERNEL_NEG(116) /* Multihop attempted. */
#define ENODATA __KERNEL_NEG(117) /* No data available. */
#define ENOLINK __KERNEL_NEG(118) /* Link has been severed. */
#define ENOMSG __KERNEL_NEG(119) /* No message of desired type. */
#define ENOSR __KERNEL_NEG(120) /* Out of streams resources. */
#define ENOSTR __KERNEL_NEG(121) /* Device not a stream. */
#define EOVERFLOW __KERNEL_NEG(122) /* Value too large for defined data type. */
#define EPROTO __KERNEL_NEG(123) /* Protocol error. */
#define ETIME __KERNEL_NEG(124) /* Timer expired. */
/* Argument list too long; used when the arguments passed to a new
program being executed with one of the `exec' functions occupy
too much memory space. This condition never arises in the
MiNT system. */
#define E2BIG __KERNEL_NEG(125) /* Argument list too long. */
/* The following error codes are defined by the Linux/i386 kernel.
Some of them are probably useful for MiNT, too. */
#define ERESTART __KERNEL_NEG(126) /* Interrupted system call should be
restarted. */
#define ECHRNG __KERNEL_NEG(127) /* Channel number out of range. */
/* Interrupted function call; an asynchronous signal occured and
prevented completion of the call. When this happens, you should
try the call again.
On other systems you can choose to have functions resume after a
signal handled, rather than failing with `EINTR'. */
#define EINTR __KERNEL_NEG(128) /* Interrupted function call. */
/* Falcon XBIOS errors. */
#define ESNDLOCKED __KERNEL_NEG(129) /* Sound system is already locked. */
#define ESNDNOTLOCK __KERNEL_NEG(130) /* Sound system is not locked. */
#define EL2NSYNC __KERNEL_NEG(131) /* Level 2 not synchronized. */
#define EL3HLT __KERNEL_NEG(132) /* Level 3 halted. */
#define EL3RST __KERNEL_NEG(133) /* Level 3 reset. */
#define ELNRNG __KERNEL_NEG(134) /* Link number out of range. */
#define EUNATCH __KERNEL_NEG(135) /* Protocol driver not attached. */
#define ENOCSI __KERNEL_NEG(136) /* No CSI structure available. */
#define EL2HLT __KERNEL_NEG(137) /* Level 2 halted. */
#define EBADE __KERNEL_NEG(138) /* Invalid exchange. */
#define EXFULL __KERNEL_NEG(139) /* Exchange full. */
#define ENOANO __KERNEL_NEG(140) /* No anode. */
#define EBADRQC __KERNEL_NEG(141) /* Invalid request code. */
#define EBADSLT __KERNEL_NEG(142) /* Invalid slot. */
#define EBFONT __KERNEL_NEG(143) /* Bad font file format. */
#define ENONET __KERNEL_NEG(144) /* Machine is not on the network. */
#define ENOPKG __KERNEL_NEG(145) /* Package is not installed. */
#define EADV __KERNEL_NEG(146) /* Advertise error. */
#define ESRMNT __KERNEL_NEG(147) /* Srmount error. */
#define ECOMM __KERNEL_NEG(148) /* Communication error on send. */
#define EDOTDOT __KERNEL_NEG(149) /* RFS specific error. */
#define ELIBACC __KERNEL_NEG(150) /* Cannot access a needed shared library. */
#define ELIBBAD __KERNEL_NEG(151) /* Accessing a corrupted shared library. */
#define ELIBSCN __KERNEL_NEG(152) /* .lib section in a.out corrupted. */
#define ELIBMAX __KERNEL_NEG(153) /* Attempting to link too many shared
libraries. */
#define ELIBEXEC __KERNEL_NEG(154) /* Cannot exec a shared library directly. */
#define ESTRPIPE __KERNEL_NEG(155) /* Streams pipe error. */
#define EUCLEAN __KERNEL_NEG(156) /* Structure needs cleaning. */
#define ENOTNAM __KERNEL_NEG(157) /* Not a XENIX named type file. */
#define ENAVAIL __KERNEL_NEG(158) /* NO XENIX semaphores available. */
#define EREMOTEIO __KERNEL_NEG(159) /* Remote I/O error. */
#ifdef __KERNEL__
/* This is not really an error but a dummy error code used within the kernel
to indicate that a mount point may have been crossed. */
#define EMOUNT __KERNEL_NEG(200)
#endif
/* There used to be a distinction between MiNTNet errors and ordinary
MiNT errors. This macro is provided for backwards compatibility. */
#define _NE_BASE 300
/* A file that isn't a socket was specified when a socket is required. */
#define ENOTSOCK __KERNEL_NEG(300) /* Socket operation on non-socket. */
/* No default destination address was set for the socket. You get
this error when you try to transmit data over a connectionless
socket, without first specifying a destination for the data with
`connect'. */
#define EDESTADDRREQ __KERNEL_NEG(301) /* Destination address required. */
/* The size of a message sent on a socket was larger than the
supported maximum size. */
#define EMSGSIZE __KERNEL_NEG(302) /* Message too long. */
/* The socket type does not support the requested communications
protocol. */
#define EPROTOTYPE __KERNEL_NEG(303) /* Protocol wrong type for socket. */
/* You specified a socket option that doesn't make sense for the
particular protocol being used by the socket. */
#define ENOPROTOOPT __KERNEL_NEG(304) /* Protocol not available. */
/* The socket domain does not support the requested communications
protocol (perhaps because the requested protocol is completely
invalid). */
#define EPROTONOSUPPORT __KERNEL_NEG(305) /* Protocol not supported. */
/* The socket type is not supported. */
#define ESOCKTNOSUPPORT __KERNEL_NEG(306) /* Socket type not supported. */
/* The operation you requested is not supported. Some socket
functions don't make sense for all type of sockets, and others
may not be implemented for all communications prototcols. In the
GNU system, this error can happen for many calls when the object
does not support the particular operation; it is a generic
indication that the server knows nothing to do for that
cal. */
#define EOPNOTSUPP __KERNEL_NEG(307) /* Operation not supported. */
/* The socket communications protocol family you requested is not
supported. */
#define EPFNOSUPPORT __KERNEL_NEG(308) /* Protocol family not supported. */
/* The address family specified for a socket is not supported; it is
inconsistent with the protocol being used on the socket. */
#define EAFNOSUPPORT __KERNEL_NEG(309) /* Address family not supported
by protocol. */
/* The requested socket address is already in use. */
#define EADDRINUSE __KERNEL_NEG(310) /* Address already in use */
/* The requested socket address is not available; for example, you
tried to give a socket a name that doesn't match the local host
name. */
#define EADDRNOTAVAIL __KERNEL_NEG(311) /* Cannot assign requested address. */
/* A socket operation failed because the network was down. */
#define ENETDOWN __KERNEL_NEG(312) /* Network is down. */
/* A socket operation failed because the subnet containing the remote
host was unreachable. */
#define ENETUNREACH __KERNEL_NEG(313) /* Network is unreachable. */
/* A network connection was reset because the remote host crashed. */
#define ENETRESET __KERNEL_NEG(314) /* Network dropped conn. because of
reset. */
/* A network connnection was aborted locally. */
#define ECONNABORTED __KERNEL_NEG(315) /* Software caused connection abort. */
/* A network connection was closed for reasons outside the control of
the local host, such as by the remote machine rebooting or an
unrecoverable protocol violation. */
#define ECONNRESET __KERNEL_NEG(316) /* Connection reset by peer. */
/* You tried to connect a socket that is already connected. */
#define EISCONN __KERNEL_NEG(317) /* Socket is already connected. */
/* The socket is not connected to anything. You get this error when
you try to transmit data over the socket, without first specifying
a destination for the data. For a connectionless socket (for
datagram protocols, such as UDP), you get `EDESTADDRREQ' instead. */
#define ENOTCONN __KERNEL_NEG(318) /* Socket is not connected. */
/* The socket has already been shut down. */
#define ESHUTDOWN __KERNEL_NEG(319) /* Cannot send after shutdown. */
/* A socket operation with a specified timeout received nor response
during the timeout period. */
#define ETIMEDOUT __KERNEL_NEG(320) /* Connection timed out. */
/* A remote host refused to allow the network connection (typically
because it is not running the requested service). */
#define ECONNREFUSED __KERNEL_NEG(321) /* Connection refused. */
/* The remote host for a requested network connection is down. */
#define EHOSTDOWN __KERNEL_NEG(322) /* Host is down. */
/* The remote host for a requested network connection is not
reachable. */
#define EHOSTUNREACH __KERNEL_NEG(323) /* No route to host. */
/* An operation is already in progress on an object that has
non-blocking mode selected. */
#define EALREADY __KERNEL_NEG(324) /* Operation already in progress. */
/* An operation that cannot complete immediately was initiated on an
object that has non-blocking mode selected. Some functions that
must always block (such as `connect') never return `EAGAIN'. Instead
they return `EINPROGRESS' to indicate that the operation has begun and
will take some time. Attempts to manipulate the object before the
call completes return `EALREADY'. You can use the `select' function
to find out when the pending operation has completed. */
#define EINPROGRESS __KERNEL_NEG(325) /* Operation now in progress. */
/* Resource temporarily unavailable; the call might work if you try
again later. The macro `EWOULDBLOCK' is another name for `EAGAIN';
they are always the same in the MiNT system.
This error can happen in a few different situations:
* An operation that would block was attempted on an object that
has non-blocking mode selected. Trying the same operation
again will block until some external condition makes it
possible to read, write or connect (whatever the operation).
You can use `select' to find out when the operation will be
possible.
Portability Note: In many older Unix systems, this condition
was indicated by `EWOULDBLOCK', which was a distinct error
code different from `EAGAIN'. To make your program portable,
you should check for both codes and treat them the same.
In C programs you should not use a case statement for that
because that will trigger a compile-time error for systems
where `EWOULDBLOCK' and `EAGAIN' expand to the same numerical
value. You should either handle treat it with preprocessor
macros (test if they are equal or not) or use an if conditional.
* A temporary resource shortage made an operation impossible.
`fork' can return this error. It indicates that the shortage
is expected to pass, so your program can try the call again
later and it may succeed. It is probably a good idea to
delay for a few seconds before trying it again, to allow time
for other processes to release scarce resources. Such
shortages are usually fairly serious and affect the whole
system, so usually an interactive program should report the
error to the user and return to its command loop. */
#define EAGAIN __KERNEL_NEG(326) /* Operation would block. */
#define EWOULDBLOCK EAGAIN
/* The kernel's buffer for I/O operations are all in use. In GNU,
this error is always synonymous with `ENOMEM'; you may get one or
the other from network operations. */
#define ENOBUFS __KERNEL_NEG(327) /* No buffer space available. */
/* Too many references: cannot splice. */
#define ETOOMANYREFS __KERNEL_NEG(328) /* Too many references. */
#define _NE_MAX ETOOMANYREFS
#ifndef __KERNEL__
__END_DECLS
#endif
#endif /* _MINT_ERRNO_H */
LINEAVAR.H
/*
****************************** lineavar.h **********************************
*
* $Revision: 3.2 $ $Source: /u/lozben/projects/vdi/mtaskvdi/RCS/lineavar.h,v $
* ============================================================================
* $Author: lozben $ $Date: 91/09/10 19:55:56 $ $Locker: $
* ============================================================================
*
* $Log: lineavar.h,v $
* Revision 3.2 91/09/10 19:55:56 lozben
* Added "WORD qCircle[80]" to the linea structure.
*
* Revision 3.1 91/07/29 16:52:14 lozben
* Definition of the line1010 variable structure.
*
******************************************************************************
*/
#ifndef _LINEAVAR_H_
#define _LINEAVAR_H_
typedef struct vdiVars {
WORD _angle;
WORD begAng;
FONT_HEAD *curFont; /* pointer to current font */
WORD delAng;
WORD deltaY;
WORD deltaY1;
WORD deltaY2;
WORD endAng;
WORD filIntersect;
WORD fillMaxY;
WORD fillMinY;
WORD nSteps;
WORD oDeltaY;
WORD sBegstY;
WORD sEndstY;
WORD sFilCol;
WORD sFillPer;
WORD sPatMsk;
WORD *sPatPtr;
WORD _start;
WORD xC;
WORD xRad;
WORD y;
WORD yC;
WORD yRad;
WORD mPosHx; /* Mouse hot spot - x coord */
WORD mPosHy; /* Mouse hot spot - y coord */
WORD mPlanes; /* Ms planes (reserved, but we used it) */
WORD mCdbBg; /* Mouse background color as pel value */
WORD mCdbFg; /* Mouse foreground color as pel value */
WORD maskForm[32]; /* Storage for ms cursor mask and form */
WORD inqTab[45]; /* info returned by vq_extnd VDI call */
WORD devTab[45]; /* info returned by v_opnwk VDI call */
WORD gCurX; /* current mouse cursor X position */
WORD gCurY; /* current mouse cursor Y position */
WORD hideCnt; /* depth at which the ms is hidden */
WORD mouseBt; /* current mouse button status */
WORD reqCol[16][3]; /* internal data for vq_color */
WORD sizTab[15]; /* size in device coordinates */
WORD termCh; /* 16 bit character info */
WORD chcMode; /* the mode of the Choice device */
ATTRIBUTE *curWork; /* pointer to current works attributes */
FONT_HEAD *defFont; /* pointer to default font head */
FONT_HEAD *fontRing[4]; /* ptrs to link list of fnt hdrs */
WORD iniFontCount; /* # of fonts in the FONT_RING lists */
WORD lineCW; /* current line width */
WORD locMode; /* the mode of the Locator device */
WORD numQCLines; /* # of line in the quarter circle */
LONG trap14Sav; /* space to save the return address */
LONG colOrMask; /* some modes this is ored in VS_COLOR */
LONG colAndMask; /* some modes this is anded in VS_COLOR */
LONG trap14BSav; /* space to sav ret adr (for reentrency)*/
WORD reserved0[32]; /* reserved */
WORD strMode; /* the mode of the String device */
WORD valMode; /* the mode of the Valuator device */
BYTE curMsStat; /* Current mouse status */
BYTE reserved1; /* reserved */
WORD disabCnt; /* hide depth of alpha cursor */
/*
* the next 5 bytes are used as a communication
* block to the vblank cursor draw routine.
* They must be contiguous!!!!!!
*/
WORD xyDraw[2]; /* x,y communication block. */
BYTE drawFlag; /* Non-zero means draw ms frm on vblank */
BYTE mouseFlag; /* Non-zero if mouse ints disabled */
LONG trap1Sav; /* space to save return address */
WORD savCXY[2]; /* save area for cursor cell coords. */
WORD saveLen; /* height of saved form */
WORD *saveAddr; /* screen addr of 1st word of plane 0 */
WORD saveStat; /* cursor save status */
LONG saveArea[64]; /* save up to 4 planes. 16 longs/plane */
WORD (*timAddr)(); /* ptr to user installed routine */
WORD (*timChain)(); /* jmps here when done with above */
WORD (*userBut)(); /* user button vector */
WORD (*userCur)(); /* user cursor vector */
WORD (*userMot)(); /* user motion vector */
WORD vCelHt; /* height of character cell */
WORD vCelMx; /* maximum horizontal cell index */
WORD vCelMy; /* maximum vertical cell index */
WORD vCelWr; /* screen width (bytes) * cel_ht */
WORD vColBg; /* character cell text background color */
WORD vColFg; /* character cell text foreground color */
WORD *vCurAd; /* cursor address */
WORD vCurOff; /* byte ofsset to cur from screen base */
WORD vCurCx; /* cursor cell X position */
WORD vCurCy; /* cursor cell Y position */
BYTE vCTInit; /* vCurTim reload value. */
BYTE vCurTim; /* cursor blink rate (# of vblanks) */
WORD *vFntAd; /* address of monospaced font data */
WORD vFntNd; /* last ASCII code in font */
WORD vFntSt; /* first ASCII code in font */
WORD vFntWr; /* width of font form in bytes */
WORD vHzRez; /* horizontal pixel resolution */
WORD *vOffAd; /* address of font offset table */
/*
* bit 0 cursor flash 0:disabled 1:enabled
* bit 1 flash state 0:off 1:on
* not used bit 2 cursor visibility 0:invisible 1:visible
* bit 3 end of line 0:overwrite 1:wrap
* bit 4 reverse video 0:on 1:off
* bit 5 cursor position saved 0:false 1:true
* not used bit 6 critical section 0:false 1:true
*/
BYTE vStat0; /* cursor display mode (look above) */
BYTE vDelay; /* cursor redisplay period */
WORD vVtRez; /* vertical resolution of the screen */
WORD bytesLin; /* copy of vLinWr for concat */
WORD vPlanes; /* number of video planes */
WORD vLinWr; /* number of bytes/video line */
WORD *contrl; /* ptr to the CONTRL array */
WORD *intin; /* ptr to the INTIN array */
WORD *ptsin; /* ptr to the PTSIN array */
WORD *intout; /* ptr to the INTOUT array */
WORD *ptsout; /* ptr to the PTSOUT array */
/*
* The following 4 variables are accessed by the line-drawing
* routines as an array (to allow post-increment addressing).
* THEY MUST BE CONTIGUOUS !!
*/
WORD fgBp1; /* foreground bit plane #1 value */
WORD fgBp2; /* foreground bit plane #2 value */
WORD fgBp3; /* foreground bit plane #3 value */
WORD fgBp4; /* foreground bit plane #4 value */
WORD lstLin; /* 0 => not last line of polyline */
WORD lnMask; /* line style mask. */
WORD wrtMode; /* writing mode. */
WORD x1; /* X1 coordinate */
WORD y1; /* Y1 coordinate */
WORD x2; /* X2 coordinate */
WORD y2; /* Y2 coordinate */
WORD *patPtr; /* ptr to pattern. */
WORD patMsk; /* pattern index. (mask) */
WORD multiFill; /* multiplane fill flag. (0 => 1 plane) */
WORD clip; /* clipping flag. */
WORD xMnClip; /* x minimum clipping value. */
WORD yMnClip; /* y minimum clipping value. */
WORD xMxClip; /* x maximum clipping value. */
WORD yMxClip; /* y maximum clipping value. */
WORD xAccDda; /* accumulator for x DDA */
WORD ddaInc; /* the fraction to be added to the DDA */
WORD tSclsts; /* scale up or down flag. */
WORD monoStatus; /* non-zero - cur font is monospaced */
WORD sourceX; /* X coord of character in font */
WORD sourceY; /* Y coord of character in font */
WORD destX; /* X coord of character on screen */
WORD destY; /* X coord of character on screen */
WORD delX; /* width of character */
WORD delY; /* height of character */
WORD *fBase; /* pointer to font data */
WORD fWidth; /* offset,segment and form with of font */
WORD style; /* special effects */
WORD liteMask; /* special effects */
WORD skewMask; /* special effects */
WORD weight; /* special effects */
WORD rOff; /* Skew offset above baseline */
WORD lOff; /* Skew offset below baseline */
WORD scale; /* replicate pixels */
WORD chUp; /* character rotation vector */
WORD textFg; /* text foreground color */
WORD *scrtchP; /* pointer to base of scratch buffer */
WORD scrPt2; /* large buffer base offset */
WORD textBg; /* text background color */
WORD copyTran; /* cp rstr frm type flag (opaque/trans) */
WORD (*quitFill)(); /* ptr to routine for quitting seedfill */
WORD (*UserDevInit)(); /* ptr to user routine before dev_init */
WORD (*UserEscInit)(); /* ptr to user routine before esc_init */
LONG reserved2[8]; /* reserved */
WORD (**routines)(); /* ptr to primitives vector list */
SCREENDEF *curDev; /* ptr to a surrent device structure */
WORD bltMode; /* 0: soft BiT BLiT 1: hard BiT BLiT */
/*
* Stuff for 8 plane VDI
*/
WORD reserved3; /* reserved */
WORD reqXCol[240][3]; /* extended request color array */
WORD *svBlkPtr; /* points to the proper save block */
LONG fgBPlanes; /* fg bit plns flags (bit 0 is plane 0) */
/*
* The following 4 variables are accessed by the line-drawing routines
* as an array (to allow post-increment addressing).
* THEY MUST BE CONTIGUOUS !!
*/
WORD fgBP5; /* foreground bitPlane #5 value. */
WORD fgBP6; /* foreground bitPlane #6 value. */
WORD fgBP7; /* foreground bitPlane #7 value. */
WORD fgBP8; /* foreground bitPlane #8 value. */
/*
* we don't get rid of the old area for compatibility reasons
*/
WORD _saveLen; /* height of saved form */
WORD *_saveAddr; /* screen addr of 1st word of plane 0 */
WORD _saveStat; /* cursor save status */
LONG _saveArea[256]; /* save up to 8 planes. 16 longs/plane */
WORD qCircle[80]; /* space to build circle coordinates */
/*============================== NEW STUFF =================================*/
WORD bytPerPix; /* number of bytes per pixel (0 if < 1) */
WORD formId; /* scrn form 2 ST, 1 stndrd, 3 pix */
LONG vlColBg; /* escape background color (long value) */
LONG vlColFg; /* escape foreground color (long value) */
LONG palMap[256]; /* either a maping of reg's or true val */
WORD (*primitives[40])(); /* space to copy vectors into */
} VDIVARS;
#endif
LINEAEQU.S
******************************* lineaequ.s *********************************
*
* $Revision: 3.1 $ $Source: /u/lozben/projects/vdi/mtaskvdi/RCS/lineaequ.s,v $
* ============================================================================
* $Author: lozben $ $Date: 91/07/29 14:55:44 $ $Locker: $
* ============================================================================
*
* $Log: lineaequ.s,v $
* Revision 3.1 91/07/29 14:55:44 lozben
* Created this file of needed equates for the new multitasking vdi.
*
******************************************************************************
.include "devequ.s"
*****************************************
* Non-Overlayable Variables *
*****************************************
angle = -910
beg_ang = -908
CUR_FONT = -906
del_ang = -902
deltay = -900
deltay1 = -898
deltay2 = -896
end_ang = -894
fil_intersect = -892
fill_maxy = -890
fill_miny = -888
n_steps = -886
odeltay = -884
s_begsty = -882
s_endsty = -880
s_fil_col = -878
s_fill_per = -876
s_patmsk = -874
s_patptr = -872
start = -868
xc = -866
xrad = -864
yc = -860
yrad = -858
mouse_cdb = -856 ; define the mouse form storage area
m_pos_hx = -856 ; Mouse hot spot - x coord
m_pos_hy = -854 ; Mouse hot spot - y coord
m_planes = -852 ; Mouse planes (reserved, but we used it!)
m_cdb_bg = -850 ; Mouse background color as pel value
m_cdb_fg = -848 ; Mouse foreground color as pel value
mask_form = -846 ; Storage for mouse cursor mask and form
_INQ_TAB = -782
_DEV_TAB = -692
_GCURXY = -602
_GCURX = -602
_GCURY = -600
_HIDE_CNT = -598
_MOUSE_BT = -596
_REQ_COL = -594
_SIZ_TAB = -498
_TERM_CH = -468
_chc_mode = -466
_cur_work = -464 ; pointer to current works attributes
_def_font = -460 ; pointer to default font head
_font_ring = -456
_ini_font_count = -440
_line_cw = -438
_loc_mode = -436
_num_qc_lines = -434
trap14sav = -432 ; space to save the return address
col_or_mask = -428 ; some modes this is ored in VS_COLOR
col_and_mask = -424 ; some modes this is anded in VS_COLOR
trap14bsav = -420 ; space to sav ret adr (for reentrency)
_str_mode = -352
_val_mode = -350
_MOUSE_ST = -348
cur_ms_stat = -348 ; Current mouse status bits
; bits used as follows
;
; 0 LEFT button state
; 1 RIGHT button state
; 2-4 not used
; 5 movement status
; 6 LEFT button changed
; 7 RIGHT button changed
disab_cnt = -346
_XYDRAW = -344
xydraw = -344 ; x,y communication block.
_DRAW_FLAG = -340
draw_flag = -340 ; Non-zero means draw mouse form on vblank
mouse_flag = -339 ; Non-zero if mouse ints disabled
retsav = -338
sav_cxy = -334 ; save area for cursor cell coords
sav_cx = -334 ; save area for cursor cell coords X pos
sav_cy = -332 ; save area for cursor cell coords Y pos
save_block = -330
save_len = -330
save_addr = -328 ; screen address of 1st word of plane 0
save_stat = -324
save_area = -322 ; save up to 4 planes. 16 longwords / plane
tim_addr = -66
tim_chain = -62
user_but = -58 ; user button vector
user_cur = -54 ; user cursor vector
user_mot = -50 ; user motion vector
v_cel_ht = -46
v_cel_mx = -44
v_cel_my = -42
v_cel_wr = -40 ; used in ST blitter code otherwise obsolete
v_col_bg = -38
v_col_fg = -36
v_cur_ad = -34
v_cur_off = -30
v_cur_cx = -28
v_cur_cy = -26
vct_init = -24 ; v_cur_tim reload value.
v_cur_tim = -23
v_fnt_ad = -22
v_fnt_nd = -18
v_fnt_st = -16
v_fnt_wr = -14
v_hz_rez = -12
v_off_ad = -10
v_stat_0 = -6
v_delay = -5
v_vt_rez = -4
_bytes_lin = -2 ; copy of _v_lin_wr for concat.
lineavar = 0
_v_planes = 0 ; number of video planes.
_v_lin_wr = 2 ; number of bytes/video line.
local_pb = 4
_CONTRL = 4 ; ptr to the CONTRL array.
_INTIN = 8 ; ptr to the INTIN array.
_PTSIN = 12 ; ptr to the PTSIN array.
_INTOUT = 16 ; ptr to the INTOUT array.
_PTSOUT = 20 ; ptr to the PTSOUT array.
_FG_BP_1 = 24 ; foreground bit_plane #1 value.
_FG_BP_2 = 26 ; foreground bit_plane #2 value.
_FG_BP_3 = 28 ; foreground bit_plane #3 value.
_FG_BP_4 = 30 ; foreground bit_plane #4 value.
_LSTLIN = 32 ; 0 => not last line of polyline.
_LN_MASK = 34 ; line style mask.
_WRT_MODE = 36 ; writing mode.
_X1 = 38 ; _X1.
_Y1 = 40 ; _Y1.
_X2 = 42 ; _X2.
_Y2 = 44 ; _Y2.
_patptr = 46 ; ptr to pattern.
_patmsk = 50 ; pattern index. (mask)
_multifill = 52 ; multi-plane fill flag. (0 => 1 plane)
_CLIP = 54 ; clipping flag.
_XMN_CLIP = 56 ; x minimum clipping value.
_YMN_CLIP = 58 ; y minimum clipping value.
_XMX_CLIP = 60 ; x maximum clipping value.
_YMX_CLIP = 62 ; y maximum clipping value.
_XACC_DDA = 64 ; accumulator for x DDA
_DDA_INC = 66 ; the fraction to be added to the DDA
_T_SCLSTS = 68 ; scale up or down flag.
_MONO_STATUS = 70 ; non-zero - cur font is monospaced
_SOURCEX = 72
_SOURCEY = 74 ; upper left of character in font file
_DESTX = 76
_DESTY = 78 ; upper left of destination on screen
_DELX = 80
_DELY = 82 ; width and height of character
_FBASE = 84 ; pointer to font data
_FWIDTH = 88 ; offset,segment and form with of font
_STYLE = 90 ; special effects
_LITEMASK = 92 ; special effects
_SKEWMASK = 94 ; special effects
_WEIGHT = 96 ; special effects
_R_OFF = 98
_L_OFF = 100 ; skew above and below baseline
_DOUBLE = 102 ; replicate pixels
_CHUP = 104 ; character rotation vector
_TEXT_FG = 106 ; text foreground color
_scrtchp = 108 ; pointer to base of scratch buffer
_scrpt2 = 112 ; large buffer base offset
_TEXT_BG = 114 ; text background color
_COPYTRAN = 116 ; copy raster form type flag. (opaque/trans)
_quitfill = 118 ; ptr to routine for quitting seedfill.
UserDevInit = 122 ; ptr to user routine before dev_init
UserEscInit = 126 ; ptr to user routine before esc_init
V_ROUTINES = 162 ; pointer to drawing primitives vector list
CUR_DEV = 166 ; pointer to current device structure
_BLT_MODE = 170
_REQ_X_COL = 174 ; extended request color array
sv_blk_ptr = 1614 ; points to the proper save block
_FG_B_PLANES = 1618 ; foreground bit planes flags (bit 0 is plane 0)
_FG_BP_5 = 1622 ; foreground bit_plane #5 value.
_FG_BP_6 = 1624 ; foreground bit_plane #6 value.
_FG_BP_7 = 1626 ; foreground bit_plane #7 value.
_FG_BP_8 = 1628 ; foreground bit_plane #8 value.
_save_block = 1630
_save_len = 1630
_save_addr = 1632 ; screen address of 1st word of plane 0
_save_stat = 1636
_save_area = 1638 ; save up to 8 planes. 16 longwords / plane
q_circle = 2662 ; space to build circle coordinates
******************* NEW EQUATES *******************
byt_per_pix = 2822 ; number of bytes per pixel (0 if < 1)
form_id = 2824 ; scrn form 2 ST, 1 stndrd, 3 pix
vl_col_bg = 2826 ; escape background color
vl_col_fg = 2830 ; escape foreground color
pal_map = 2834 ; either a maping of reg's or true val
V_PRIMITIVES = 3858 ; all the vectored primitives
Publisher
GFA Software Technologies, Inc.
MichTron, Inc.
Antic Software
GFA Software Technologies, Inc.
ATARI ST
GFA
BASIC
Version 3
Editor/Interpreter
/-------------------\
| GFA |
|-------------------|
| SOFTWARE |
| TECHNOLOGIES INC. |
\-------------------/
July 1988
No part of this publication may be copied, transmitted or stored in a retrieval
system or reproduced in any way including but not limited to photography,
photocopy, magnetic or other recording means, without prior written permission
from the publishers, with the exception of material entered and executed for
the reader's own use.
Warranty
All programs in this manual were written expressly to illustrate specific
training points, they are not warranted as being suitable for any particular
application. Every care has been taken in the writing and presentation of this
manual but no responsibility is assumed by the author or publishers for any
errors or omissions contained herein or any consequential loss suffered
therefrom.
ISBN 1 85181 186 9
COPYRIGHT © 1988 GFA Systemtechnik GmbH
Published in the U.S. by:
GFA Software Technologies, Inc.
27 Congress St.
Salem, MA 01970
MichTron, Inc.
GFA BASIC 3.0
Full Access, Structured BASIC Programming Language
For the Atari ST Series
Written By Frank Ostrowski
GFA Systemtechnik
Published in the United States
By MichTron, Inc.
576 South Telegraph
Pontiac MI, 48053
Tel: (313) 334-5700
BBS: (313) 332-5452
GFA BASIC Interpreter Manual
© GFA Systemtechnik 1988
All rights reserved, including those of translation, photographic reproduction,
and storage in a retrieval system.
Published in the U.S.A.
By MichTron, Inc.
576 South Telegraph
Pontiac, MI 48053
Program Author: Frank Ostrowski
Manual Authors: Gottfried Engels, Markus Görgens, and Frank Ostrowski
Book Design: Thomas L. Logan
Cover Design: Paul Deckard
English Translation: Jeff Little
Edited By: George Miller
1st English Edition August 1988
88 89 90 10 9 8 7 6 5 4 3 2 1
ISBN 0-944500-09-9
Further Trademark and Copyright Notices:
DEC, VT, VT100, VT52, VT101, VT102, VT200, VT220 are registered trademarks of
Digital Equipment Corporation.
GEM is a registered trademark of Digital Research Inc.
Atari, 520ST and 1040ST are registered trademarks of ATARI Corp.
MS DOS is a registered trademark of Microsoft.
D.E.G.A.S. is a registered trademark of Batteries Included.
Printed in the United States
Antic Software
GFA-BASIC 3.0
Full Acess, Structured BASIC Programming Language
For the Atari ST/Mega Series
Published in the United States
by Antic Software
GFA BASIC Interpreter Manual
© GFA Systemtechnik 1988
All rights reserved, including those of translation, photographic reproduction,
and storage in a retrieval system.
Published in the U.S.A.
Antic Software
544 Second Street
San Francisco, CA 94107
(415) 957-0886
Program Author: Frank Ostrowski
Manual Authors: Gottfried Engels, Markus Görgens, and Frank Ostrowski
Book Design: Thomas L. Logan
Cover Design: Paul Deckard
English Translation: Jeff Little
Edited By: George Miller
1st English Edition August 1988
88 89 90 10 9 8 7 6 5 4 3 2 1
ISBN 0-944500-09-9
Further Trademark and Copyright Notices:
DEC, VT, VT100, VT52, VT101, VT102, VT200, VT220 are registered trademarks of
Digital Equipment Corporation.
GEM is a registered trademark of Digital Research Inc.
Atari, 520ST and 1040ST are registered trademarks of ATARI Corp.
MS DOS is a registered trademark of Microsoft.
D.E.G.A.S. is a registered trademark of Batteries Included.
Antic and Antic Software are trademarks of Antic Publishing.
Printed in the United States
Chapter 1 - Introduction
With the release of GFA-Basic 3 one is provided with both an extensive
programming and powerful language which is easy to use via its quick and
friendly Editor. The entire framework and design of the language encourages
structured programming and provides the user with the necessary tools.
The Interpreter provides for simple debugging by means of the special commands
provided. The Editor supports structured programming by automatic indentation
of loops and conditions. Additionally, subroutines can be represented in the
program listing by name only, and 'opened' to their full length by pressing a
key.
In the area of conditional commands, various additions have been made to the
commands IF-ELSE-ENDIF, which already existed in earlier versions of GFA-Basic,
e.g. ELSE IF, SELECT-CASE. Both the values of variables and the variables
themselves can be passed to procedures. Furthermore, the loop types FOR-NEXT,
REPEAT-UNTIL, WHILE-WEND, and DO-LOOP available in earlier versions of
GFA-Basic have been extended with DO-UNTIL, DO-WHILE, LOOP-UNTIL, and
LOOP-WHILE.
System level programming is achieved through the ability to call operating
system routines (GEMDOS, BIOS, XBIOS). Many of these routines are also
available in the form of simple instructions. The programming of Interrupts
with EVERY and AFTER is also possible. Assembler and C routines may be
interleaved into programs with instructions like RCALL, C:, CALL, and MONITOR.
The most important VDI routines and all AES functions, e.g. menu and form
management, are available as built-in functions.
GFA-Basic provides genuine Integer arithmetic, which offers high computing
speed, as well as floating-point arithmetic with high computational accuracy
(13 decimal places), while further variable types BYTE, WORD, and bit
operations BCLR(), BSET(), BTST(), BCHG(), SHL(), SHR(), ROL(), ROR(), etc.,
have been included. Graphics programs can easily make use of the Line-A
routines which are implemented as instructions.
About This Manual
The manual begins with a short description of the GFA-Basic 3 programming
language, followed by an explanation of the manual structure and an
introduction to the use of the GFA-Basic Interpreter. It ends with a
description of the points which one must take note of when using programs which
were written in older versions of GFA-Basic.
The next chapter describes the commands for the operation of the Editor. The
remaining chapters of the manual detail the instructions and facilities of
GFA-Basic 3.0. These are arranged according to criteria concerning the
contents, with joint explanations of related terms, e.g. MIN() and MAX(). In
the Appendix an alphabetical overview of the instructions and functions is
given, with references to the appropriate pages for full explanation.
Descriptions of Commands, etc. are laid out as follows:
• The syntax
• Description of the permissible parameter types
• Explanatory text
• Example
In the Syntax description optional parameters are indicated with square
brackets, e.g.
LEFT$(a$[,x])
In GFA-Basic there are Commands and Functions. Commands do not return a value,
e.g.
LINE 100,100,200,200
Functions, on the other hand, do return a value and can display this value with
PRINT, assign it to variables, etc. Here are some examples:
PRINT ASC("65")
PRINT ASC("a")
a=ASC("a")
b=ASC("a")+32
In this manual the fact that a Function returns a value is not noted in the
Syntax section, but is made clear in the explanation. In the Syntax section, in
the case of the function ASC for example, only ASC(a$) is specified and the
fact that this would be assigned to a numeric variable is not stated.
Where many optional parameters may be given, e.g. with the DATA statement, this
is shown by three periods:
DATA x[,y,...]
The description of permitted parameter types follows the Syntax section. For
these types the following abbreviations are used:
avar Arithmetic variable
This a numeric variable, which can be of any form, e.g. floating-point,
integer, boolean, etc.
aexp Arithmetic expression
This is any simple or complex expression which produces a number and can
include variables. Examples of arithmetic expressions are:
a%
3
2+a%+ASC("a")
svar String variable
This is a character string variable ending with $, e.g.:
a$
sexp String expression
This expression can be of arbitrary complexity but must finally result in a
String. Examples of string expressions are:
a$
"Test"
a$+"GFA BASIC"+LEFT$("MANUAL",4)
ivar Integer variable
This can be any integer variable.
iexp Integer expression
This is any simple or complex expression but the result must be an integer.
bexp Boolean (logical) expression
Any expression from which the result is a Boolean number.
It is important for some numerical expressions that particular variable types
must be used. The most important example of this is with memory addresses.
Addresses must be specified with at least a four byte variable and Boolean,
Byte, or Word variables are thus not allowed.
After the description of the parameter types comes the explanation of the
command. Here the meaning of the command and its individual parameters are
explained. The discussion of a command is terminated with one or more examples.
These examples are designed to be entered into the Editor and started with RUN
(shift+F10 or clicking RUN in the menu bar). After each example the effect it
produces is given.
This form of command description is modified only in the section dealing with
the AES library routines. Here the name of the appropriate command is given,
followed by the explanation of its function, then the syntax of the command
with the description of the individual parameters. At the end of the chapter
concerning the libraries several longer example programs are provided. The
reasoning behind this structure is that many commands in the chapter must be
used in correct conjunction with other commands, so that example programs tend
to contain many AES calls and tend to be somewhat more extensive.
The manual concludes with a collection of tables and an alphabetical list of
all commands, with their page numbers.
Note: Where a program line is longer than the width of the page it has been
wrapped round on the page and right justified. This will not happen
when you are typing in the line, it will just extend to the right of
the screen as far as necessary (up to 255 characters).
Using GFA-Basic 3 For The First Time
This section is for those who have not used GFA-Basic before. Those who have
already worked with the older versions can just scan this section or, if
feeling very confident, jump to Chapter 2.
The GFA-Basic 3 Program disk is not copy-protected, so first make a back-up
copy of the orignal disk. You will find a description of how to do this in your
computer manual. Put the copy of the program disk in your disk drive and start
GFA-Basic by clicking on the icon.
After a short while, the Editor screen will appear, which is where you can
write and debug your programs. For now, enter the following program lines,
pressing Return at the end of each line. Do not omit the spaces, which serve to
separate adjacent keywords. The indenting of instructions within loops is done
automatically by the Editor, as is the capitalisation (or lack of it) when
Return is pressed.
DEFFILL 1,2,8
REPEAT
WHILE MOUSEK=1
PBOX MOUSEX,MOUSEY,MOUSEX+30,MOUSEY+30
WEND
UNTIL MOUSEK=2
In the upper right corner of the screen you will find the word 'Run'. Point
with the mouse arrow to this word and press the left mouse button to start the
program.
Now a white screen appears, on which the mouse pointer is visible. If you now
press the left mouse button and move the mouse about, you can draw on the
screen. A rectangle is used as a 'brush'. Pressing the right mouse button
termimates the program and a box appears containing the message 'Program end'.
Point to the word 'Return' in this box and press the left mouse button to
return you to the Editor.
How does this program work? Drawing takes place with the instruction in the
center of the program. It draws filled rectangles, with the four parameters
specifying the corner points. The first instruction of the program (DEFFILL
1,2,8) determines what pattern the rectangle is to be filled with.
Information about the mouse is contained in the built-in variables MOUSEK,
MOUSEX, and MOUSEY.
MOUSEK determines which mouse button is being pressed. MOUSEK=1 means that the
left button was pressed and MOUSEK=2 that the right button was pressed. MOUSEX
and MOUSEY return the x and y positions on the screen of the mouse arrow point.
The remaining commands (REPEAT, WHILE, WEND, UNTIL) are loop instructions. The
loop formed with the commands WHILE MOUSEK=1 and WEND means 'repeat, as long as
the left mouse button is pressed'. The outside loop, made from the instructions
REPEAT and UNTIL MOUSEK=2, means 'repeat, until the right mouse button is
pressed'.
Since there are no further instructions after the UNTIL, the program terminates
after leaving this loop. Move the cursor (with the arrow keys) to the beginning
of the line after the last and enter the following intentionally wrong program
line, in which the 'i' of the command word PRINT is missing:
prnt "test"
When you press the Return key to leave the line and confirm the instruction, a
bell sounds and on the second screen line the message 'Syntax error' appears.
The Editor checks during program entry whether the instructions entered are
syntactically correct. Now, with the cursor on the letter 'r', press the Delete
key three times. The program line should now contain only:
p "test"
If the Return key is now pressed, then you can leave the line, as the letter p
is recognized automatically as an abbreviation for the command PRINT.
The Editor
The GFA-Basic 3.0 Editor is no usual text editor, but was specially designed
for program development. Syntactically wrong instructions are recognised at the
typing-in stage. In addition, commands are indented automatically in loops or
conditional sections and command names expanded from their abbreviations, e.g.
p expands to PRINT.
When writing a program a syntax check is carried out whenever the cursor leaves
the current line. If the line is not syntactically correct, then the message
'Syntax error' appears on the second line of the screen. It will only be
possible to move the cursor from the line by correcting the syntax or putting
an apostrophe at the beginning, thus converting it into a Comment.
Only one instruction per program line is allowed, but a comment may be added to
the end of a line by beginning the comment with an exclamation mark.
Program lines may he up to 255 characters long. When a line exceeds 80
characters in length it is scrolled horizontally to the left. When the cursor
leaves an instruction line a syntax check is done, correct indentation of the
line is carried out and the line is formatted. In addition, redundant spaces
are removed. e.g. '2 + 2' becomes '2+2', and the letters belonging to command
words and variable names are adjusted according to the current DEFLIST setting.
The preset parameter DEFLIST 0 causes all command words to he written in upper
case and all variable names in lower case.
The Cursor Keypad
Cursor control is by means of the block of arrow keys. The key settings are:
Left arrow - cursor moves one character to the left
Right arrow - cursor moves one character to the right
Up arrow - cursor moves up one line
Down arrow - cursor moves down one line
The movements of the cursor are subject to certain restrictions. It can be
moved a maximum of one character beyond the last character in a line, and a
maximum of one line beyond the last line in a program. If the cursor enters a
line which is too short for the current cursor position, the cursor jumps to
the end of that line, otherwise it maintains its current column position (this
is different to the behaviour of the cursor in earlier versions of GFA-Basic).
It also is possible to position the cursor with the mouse. To do this point the
mouse arrow to the desired place and click the left mouse button.
The Insert key inserts a blank line between the line the cursor is on and the
line above. The cursor is set to the beginning of this blank line.
Clr/Home moves the cursor to the upper left corner under the menu bar.
Control-Clr/Home jumps to the beginning of the program listing.
The Undo key will cancel any changes made in an edited line, provided that the
changes have not been confirmed by moving the cursor off that line.
With the Help key, procedures or functions in the program listing can be
shortened to just their name ('folded'). This is done by moving the cursor to
the line with the word PROCEDURE or FUNCTION on it and then pressing Help. A
'>' character is placed at the beginning of the line to indicate that folding
has occurred. The procedure or function can be unfolded in the same way, or by
deleting the '>'. Of course this does not affect the procedure or function in
the program itself, only as listed. This folding up of subroutines enables one
to create short clear listings in which one 'opens' only the subroutine on
which one is working.
A program with folded up procedures can look as follows. Note, that to call a
procedure in GFA-Basic 3 only the procedure name is used.
init
main_menu
'
> PROCEDURE init
> PROCEDURE main_menu
> PROCEDURE menu_list
> PROCEDURE load
> PROCEDURE store
> PROCEDURE do_work
> PROCEDURE fetch_info
> PROCEDURE show_info
> FUNCTION test_info
With an opened procedure the program then appears as:
init
main_menu
'
> PROCEDURE init
> PROCEDURE main_menu
> PROCEDURE menu_list
PROCEDURE load
FILESELECT "\*.RSC","",rsc_file$
IF NOT EXIST(rsc_file$)
ALERT 1,"File does not exist !",1,"abort",r%
ELSE
IF RSRC_LOAD(rsc_file$)=0
ALERT 1,"Fault when loading the file !",1,"abort",r%
END
ENDIF
ENDIF
RETURN
> PROCEDURE store
> PROCEDURE do_work
> PROCEDURE fetch_info
> PROCEDURE show_info
> FUNCTION test_info
The Numeric Keypad
The numeric keypad is normally used to input numbers and some other characters.
However, in addition it can, in combination with the Control key, perform the
following functions:
Control and 4 Cursor one character to the left
Control and 6 Cursor one caharacter to the right
Control and 8 Cursor one line up
Control and 2 Cursor one line down
Control and 7 Jump to start of program (control-home)
Control and 1 Jump to end of program (control-z)
Control and 9 Move one page up (control-up)
Control and 3 Move one page down (control-down)
Control and 0 Equivalent to pressing Insert
Control and . Equivalent to pressing Delete
Control and - Toggle mode of numeric keypad
Control and ( Same as -
The functions are similar to those obtained on a PC when NumLock is not on.
The numeric pad can also be switched to a mode in which the keys can be used
without having to press Control as well. The switch is made by pressing Control
and '-' on the numeric pad, and indicated by a circumflex to the left of the
menu bar. This key combination acts as a toggle switching between modes each
time it is pressed.
Further Editing Commands
The Delete key deletes the character at the cursor position, the remainder or
the line being pulled to the left.
The Backspace key deletes the character to the left of the cursor.
The Tab key moves the cursor eight character positions to the right.
Control+Tab moves the cursor eight character positions to the left.
LeftShift+Tab inserts blank spaces to the next tab position.
RightShift+Tab deletes all blank spaces in one row up to or from cursor.
The Return or Enter keys move the cursor to the beginning of the next line.
The Escape key enters Direct Mode, in which you can type in commands.
Further Control Commands
Control-Delete Deletes the line on which the cursor appears
Control-U Restores a line deleted as above, or below (the line may
be restored several times - like copying)
Control-Y Deletes the line on which the cursor appears
Control-N Inserts a blank line as with the Insert key
Control-Q Call block menu (like function key F4)
Control-B Mark beginning of block (Block start)
Control-K Mark end of block (Block end)
Control-R Page up
Control-C Page down
Control-E Replace text
Shift-Control-E Input text and find/replace it
Control-F Find text
Shift-Control-F Input text and find it
Control-left arrow Cursor jumps to the beginning of the line
Control-right arrow Cursor jumps to the end of the line
Control-up arrow Page up
Control-down arrow Page down
Control-Clr/Home Jump to beginning of the program
Control-P Deletes everthing to the right of the cursor
Control-O Brings back the string deleted with Control-P and inserts
it at the cursor position. Perhaps it is difficult to
remember these combinations; We thought of:
P = Put line end into buffer
O = Output line from buffer
Control-Z Jump to the end of the program
Control-Tab Cursor jumps one tab position to the left
Control-G (goto) Move to Line Number display (top right on Menu bar), then
enter line number
Control-A Enter ASCII code (up to 3 digits are accepted)
Control-S Enter one character (bit #7 will be set)
A special group of Control commands makes the setting of 'Editor Marks'
possible. These marks are only meaningful to the Editor and have no effect on
the actual program. These marks can be set by Control-n, where n is a number on
the main keyboard. The cursor can be made to jump to a given mark by
simultaneously pressing Alternate and the appropriate number.
The key combinations of Alternate and the numbers 7-9 and 0 are preallocated.
They are as follows:
Alternate+7 Makes the cursor jump to the last cursor position before Direct
mode or before a program was last Run.
Alternate+8 The cursor jumps to the line where the last error occured.
Alternate+9 Moves it to the position at which the last search procedure was
started.
Alternate+0 Moves the cursor to the last cursor position at which a change
was made.
The Menu Bar and Function Keys
The items in the menu bar on the second and first screen lines are also
available via the function keys and Shift-function keys respectively.
On the far left of the menu bar is the Atari symbol (/\), clicking this
generates another menu containing the menu titles, Atari symbol and GFA-Basic.
Clicking the Atari symbol causes an Alert box to appear, giving the title and
version number of GFA-Basic 3.xx and the two options Editor and Menu. Clicking
the Editor button returns you to the Editor, or clicking Menu brings you back
to the same menu.
The GFA-Basic Menu Bar contains the following items:
Save
A File Select box appears, by means of which the current program can be stored
by entering a program name and clicking on OK.
Load
A program can be similarly loaded into the Editor by clicking on the program
name and then clicking on OK.
Deflist
Makes possible the adjustment of the appearance of the program listing (see
DEFLIST later on for details, or experiment).
New names
By means of this item a mode can be set in which variable names are queried as
you introduce them into a program. This is useful as GFA-Baisc allows long
variable names, making typing errors possible. If you are editing a program and
do not mean to introduce new variables and you mis-type an existing name, this
feature will warn you.
Editor
Clicking this entry will return you to the editor.
On the right-hand side of the menu bar is a clock and the line number display.
The use of these two items is explained later on.
Under the Atari symbol there is a space for two further indicators, namely an
up-arrow character () to show when Caps Lock is active on the keyboard, and
the circumflex (^) showing when the numeric pad is used for cursor movements,
etc. These two modes can be entered and exited by clicking the mouse on the
space for the indicator (or the indicator itself if present).
Load (F1)
The command load is used to load a GFA-Basic 3 program. This will be in
tokenised format, which enables programs to be loaded and saved quickly, using
less disk space. The extension '.GFA' will be looked for by default.
Earlier versions of GFA-Basic saved their programs using a different
tokenisation process. For these programs to be loaded into version 3 they must
first be saved, using the old GFA-Basic, in ASCII format ('Save,A') and then
loaded into Version 3 with Merge. After that they can be stored in version 3
format with Save, and then Loaded as normal.
Save (Shift+F1)
A File Select box appears, in which the desired program name can be specified.
The extension '.GFA' will be added to the file name if no other is given. If a
file of that name already exists on the disk it will be renamed to '.BAK'.
Merge (F2)
With this command a file in ASCII format can be inserted into the current
program, starting at the line above the cursor position. The default file
extension will be '.LST'. Syntax checking is also carried out during the
Merging process, but instead of interrupting with a Syntax error when an
uninterpretable line is encountered, the line will be prefixed with the
characters '==>', and must be fixed before the program can be Run.
Save,A (Shift+F2)
The current program will be stored in ASCII format. The extension '.LST' will
be added to the filename if no other is specified. If a file with that name
already exists on the disk, it will be renamed to '.BAK'.
Llist (F3)
This command causes the program to be printed out in the manner specified by
so-called Dot Commands within the program. They have no effect other than on
the printout, and are as follows, where 'x' represents a digit:
.LL xx Maximum line length
.PL xx Maximum page length
.FF xxx Form feed character (for printers, which have other
values than &H0C (Decimal 12). (.FF 012 is the default)
.HE head Text to be put on the first line of each page
.FO foot Text to be put on the last line of each page
.LR xx Left margin
.L- Conditional printing: This instruction causes the following
lines not to be printed
.L+ Printing starts again if it was stopped by a previous .L-
.N1 to .N9 Switches on line numbering adjusted to occupy up to nine
character positions
.N0 Switches off line numbering
.PA Forces a form feed
.P- The point commands are NOT listed
.P+ The point commmands ARE listed, as usual
.P+ and .P- influence the whole listing (like .Nx), the last
command gives the effect
.IN xxx Printer initialization, a string that will be printed only
once at the beginning
In the header and footer text the following can also be inserted:
\xxx The ASCII character xxx
\d Date (see MODE)
\t Time
# Page number
Note: To print the symbols \ and #, use \\ and \# respectively.
Memo: The .dot commands are not case sensitive.
A space after the command is optional.
Syntax errors are silently ignored.
There are 22 commands in all.
Comments are not supported in .dot commands.
Example: '.HE header ! test' will output 'header ! test'
Quit (Shift-F3)
After querying this command to make sure you are sure, GFA-Basic is exited
completely and normally you will be returned to the Desktop.
Block (F4)
If no block has been marked, then the message 'Block ???' appears on the second
line in order to indicate that a block command would be unreasonable. If,
however, a block has been marked, then the Block menu appears on the top line
of the screen. Items can then be chosen with the mouse, or by pressing the key
corresponding to the first letter of the command (except for block Delete,
which for safety is called from the keyboard by Control-D).
Copy
Copies the block to the current cursor position. The block remains marked.
Move
Moves the block to the current cursor position. The block is then 'forgotten'
and no further block commands can be used until another is marked out.
Write Stores the block as an ASCII file (to be read via Merge)
Llist Prints the block out
Start Moves the cursor to the beginning of the block
End Moves the cursor to the end of the block
Del Deletes the block (Control-D)
Hide Removes the block markers
Clicking the mouse outside the Block menu or pressing a key removes it, and the
original menu is restored.
Note: The oddly placed clock symbol in the block menu seems to be a typo or
minor bug in the editor. It doesn't do anything.
New (Shift-F4)
The program currently in the Editor is deleted.
BlkEnd (F5)
The line before the cursor is marked as the end of a block. If the start of
block marker is located before this line, the block is shown in a different
color (or with a dotted background if a monochrome monitor is being used). The
end of a block can also be marked by means of Control-K, without recourse to
the Block menu.
BikSta (Shift-F5)
Marks the beginning of a block as above. Control-B from the keyboard has the
same effect.
Find (F6)
A string of text can be input, which then becomes the object of a search
starting from the current cursor postion. If the string is found, the search
can be continued for another occurrence of the string with Control-F or
Control-L. When a string is found, the cursor is put at its position, or, if
not, at the end of the program. If Find is called again, the previous search
string is presented, which may be accepted with Return, deleted with Escape, or
edited with the cursor, delete and backspace keys. The command can also be
called directly by Shift-Control-F or Shift-Control-L.
You can use the Find function to search in the header rows of closed procedures
or functions.
Procedures which have been 'folded' (see above) are not searched.
Replace (Shift-F6)
This command is for replacing one string of text by another. First the user is
asked for the text to be replaced, then the replacement text. If the text to be
replaced is found, the cursor moves to the beginning of that line. The actual
replacement can be effected with Control-E, where upon another search is made
for further occurrences of the string to be replaced. The command can also be
called from the keyboard using Shift-Control-E. The editing facilities for the
strings are available as above.
Again, 'folded' procedures and functions are not searched.
Pg (F7)
Scrolls the screen one page down. Also called via Control-C.
Pg (Shift-F7)
Scrolls the screen one page upwards. Also called via Control-R.
Insert/Overwr (F8)
Switches between insert and overwrite modes.
Txt 16/Text 8 (Shift-F8)
This feature is available only if a monochrome monitor is being used. It refers
to the size of characters displayed on the screen. 16-pixel high characters
(default) allow 23 lines to be displayed at once on the screen. Using 8-pixel
high characters, 48 lines are displayed.
Flip (F9)
This command switches between the Edit and Output screens. Pressing any key or
a mouse button also switches from the Output to the Edit screen.
Direct (Shift-F9)
Switches to Direct Mode, in which commands are responded to immediately, e.g.
PRINT "hello". Some commands, e.g. loop commands, are not however available in
Direct Mode. This mode can also be reached by pressing the Escape key. In
addition, by use of the up and down arrow keys, the last eight commands entered
in Dircct Mode can be recalled, edited, entered, etc. The Undo key recalls the
last command. Direct Mode can only be entered when the syntax of the current
line in the Editor is correct.
Several lines of instructons can be executed from Direct Mode by writing them
as a procedure in Edit mode and then calling it from Direct Mode.
Test (F10)
Issuing this instruction causes all loops, subroutines and conditional
instructions to be checked for consistency without actually running the
program.
Run (Shift-F10)
The program currently in the Editor is started. If this program contains a
structural fault, of the kind that could have been found with Test above, then
an appropriate error message is displayed and the program is not started. A
running program can be interrupted by the 'Break key' combination,
Control-Shift-Alternate.
The Line Number & Clock Displays
The Line number display and the Clock on the right of the menu bar both react
when clicked with the mouse. In the case of the clock, the cursor moves to the
first hour digit, and the time can be set by typing in the new time and ending
with Return. The input can be edited with the Cursor and Backspace keys, or
pressing Escape aborts the process, leaving the time display as it was.
With the Line number display, the cursor moves there, and a number can be typed
in. Pressing Return causes the cursor to jump to that line number. Instead of
clicking on the Line number display, Control-G could be typed to produce the
same effect. Only numbers are accepted as the input and they can be edited with
the Escape, Cursor and Backspace keys as before.
Memo: The Merge funtion will stop loading if ASCII character 4 (Control-D)
is encountered. If you must use this character in your program it's best
to refer to it with CHR$(4). Merge cannot read Unix format ASCII files.
Special Commands
DEFBIT
DEFBYT
DEFWRD
DEFINT
DEFFLT (DEFSNG, DEFDBL)
DEFSTR
DEFLIST
$
.dot commands
==>
DEFWRD
DEFBIT f$
DEFBYT f$
DEFWRD f$
DEFINT f$
DEFFLT f$
DEFSTR f$
f$: string constant
The instruction DEFxxx facilitates variable declaration, where xxx is the
variable type, specified as follows:
These definitions will normally be declared at the beggining of a program, but
may be changed at any time. The post-fixed symbols will always override and
previous global definitions. The default variable type is floating-point.
The above definitions will have no effect on variables which are already in the
program, they only effect those which are still to be typed in.
DEFBIT
DEFBIT "b"
All variables beginning with the letter 'b' or post-fixed with '!' are declared
as Boolean (logical) variables.
DEFBYT
DEFBYT "by"
All variables beginning with the letterd 'by' or post-fixed with '|' ('rule'
character) are declared as 1-byte integers.
DEFWRD
DEFWRD "w"
All variables beginning with the letter 'w' or post-fixed with '&' are declared
as 2-byte signed integers.
DEFINT
DEFINT "i-k,m-p"
All variables beginning with letters 'i to k' and 'm to p', or post-fixed with
'%' are declared as 4-byte integers.
DEFFLT
DEFFLT "x-z"
All variables beginning with letters 'x to z', or post-fixed with '#' are
declared as 8-byte floating-point (the default variable type).
Appearances of DEFSNG or DEFDBL will be replaced automatically in the Editor
with DEFFLT.
DEFSTR
DEFSTR "s,t"
All variables beginning with the letters 's' and 't', or post-fixed with '$'
are declared as character strings.
DEFLIST
DEFLIST n
n: iexp
DEFLIST determines the format of the program listing. The numerical expression
'n' can be a value between 0 and 11 (inclusive). The effect of the instruction
on the listing is as follows:
n Command Variable Comment
0 PRINT abc !
1 Print Abc !
2 PRINT abc# !
3 Print Abc# !
4 PRINT abc //
5 Print Abc //
6 PRINT abc# //
7 Print Abc# //
8 PRINT abc /*
9 Print Abc /*
10 PRINT abc# /*
11 Print Abc# /*
The default mode is DEFLIST 0.
DEFLIST 0
Instructions and functions are represented in capitols. Variables, procedures,
and function names are in lower case.
DEFLIST 1
Instructions, functions, procedures, and variable names are represented with
the first letter in upper case, and the remainder in lower case.
DEFLIST 2
Same as DEFLIST 0, except that variable type post-fix is added.
DEFLIST 3
Same as DEFLIST 1, except that variable type post-fix is added.
DEFLIST 4-7
Same as DEFLIST 0-3, except that the comment marker is '//'.
DEFLIST 8-11
Same as DEFLIST 0-3, except that the comment marker is '/*'.
Memo: The additional comment styles were not documented in my manual.
DEFLIST style breakdown:
Bit Description
0 Capitalize commands and variables
1 Show prefix for default variable type
2 Display '//' instead of '!'
3 Display '/*' instead of '!'
4-7 Ignored
$
$text
The command $, which is treated by the Interpreter lika a REM, is used for the
control of the Compiler.
Example:
$m16384
--> The compiled program will only allocate 16k of memory.
Memo: For a list of compiler commands see section 'The Compiler Options'.
GFA-Basic 2.0 had a different command for compiler control.
The old command was OPTION "text".
This seems to have been replaced by the $text command.
Commands are not case sensitive.
Commands may be seperated with commas or spaces.
Commands can optionally be preceeded with a dollar sign.
Comments are also allowed.
Example: $ m2048,s& S> $B+ !this is a valid compiler command
The Compiler will accept almost anything in such a line. In fact it only
reacts to correct compiler commands. Any incorrect compiler commands will
be silently ignored. There is no easy way to detect incorrect
compiler commands.
Chapter 2 - Variables and Memory Management
Variable Types
GFA-Basic 3 allows the following variable types:
Type Postfix Memory requirements Range
Boolean ! 1 byte (1 bit in arrays) 0 or -1 (FALSE or TRUE)
Byte | 1 byte 0 to 255
Word & 2 bytes -32768 to 32767
Long % 4 bytes -2147483648 to 2147483647
Float # 8 bytes 2.225073858507E-308 to 3.595386269725E+308
String $ 0 to 32767 bytes ASCII value 0 to 255 for each character
Boolean (logical) variables can accept only the values 0 (FALSE) or -1
(TRUE). If a non-zero value is assigned, then this value is taken as -1. This
variable type is designated by the postfix '!', and occupies '1' byte of
memory. In boolean arrays elements require only one bit.
Example:
b!=TRUE
c!=x>y
Byte variables can accept values between 0 and 255. Larger values will
provoke a "Number not byte" error. The postfix for this variable type is the
vertical rule character '|'. As the name implies, this variable type occupies
one byte.
Example:
x|=128
Word variables are signed 2-byte integers. The postfix of this type is
'&'. Numbers in the range from -32768 to 32767 can be represented. Outside
this range, a "Number not word" error occurs.
Example:
x&=32767
Long variables are signed 4-byte integers with the postfix '%'. Numbers
can be represented in the range from -2147483648 to 2147483647.
Example:
x%=2000000000
Float variables are signed 8-byte floating point with the postfix '#'. The
range of representable numbers extends from 2.225073858507E-308 to
3.595386269725E+308. As this is the default type, no postfix is necessary. The
numerical accuracy is approximately 14 decimal places.
Example:
x=123456789e123
String variables are designated by the postfix '$'. They can have a
maximum length of 32767 characters. Strings are administered by means of a
so-called descriptor, six bytes in length. The first 4 bytes contain the
address of the character string, the last 2 bytes contain the length of the
string. If a string contains and odd number of characters a zero filler byte is
added. The address of the descriptor (Backtrailer) is also added.
Example:
a$="qwertyuiop"
The address of all variable types can be determined with the help of the
functions VARPTR() (V:) and ARRPTR() (*).
Memo: For more information on the internal storage of floats see page
'GFA-Basic v3 float format'.
There seems to be a difference between floats used in the Editor versus
compiled. For example:
f=2.5E+310
PRINT f
PRINT STR$(f)
The Editor produces the expected result "2.5E+310" while the
compiled version produces a different result "2.499999997857E+310".
The book 'GFA-Basic Programmer's Reference Guide Volume I' (page 8)
states a variable name can be up to 255 characters long.
The GFA-Basic v2.x manual (page 47) states this about variable names:
Names of variables must begin with a letter and can be any length
(limited, of course by the length of a line). After the first letter in
the name, digits, underscore, and period are allowed. The full name is
always used to distinguish between variables.
Function names appear to follow the same rules as variable names.
Label names however do not follow the same rules. See GOTO for details.
Procedure names appear to follow the same rules as labels.
Notes on boolean!() arrays:
These are not stored in the logical order as one might assume.
Example:
DIM b!(8)
ARRAYFILL b!(),FALSE
b!(0)=TRUE
PRINT BIN$(BYTE{V:b!(0)},8) !results -> "00000001"
ARRAYFILL b!(),FALSE
b!(7)=TRUE
PRINT BIN$(BYTE{V:b!(0)},8) !results -> "10000000"
For speed reasons GFA stores them backwards. Thus accessing a boolean!()
is not particularly useful unless this is the behaviour you expect.
A signed byte is considered to be in the range of -128 to 127.
Arrays
DIM, DIM?()
OPTION BASE
ARRAYFILL
All variable types can be used in arrays, or 'fields'. An array can be
dimensioned with DIM, or the size of an array can be determined with DIM?().
The management of arrays in memory is effected by means of Descriptors. A
descriptor is a structure six bytes in length, the first four bytes of which
contain the address of the array. The next two bytes specify the number of
dimensions. The array field itself begins with sets of four bytes, giving the
number of elements in each dimension (beginning with the last dimension)
followed by the actual contents of the dimensions. With string arrays, instead
of the contents, the descriptors of the character strings follow the four
number-of-elements bytes. For example, after
DIM a%(2,3)
*a%() gives the address of the array descriptor. The number of dimensions of
the array is in the last two bytes of the descriptor, therefore
PRINT DPEEK(*a%()+4)
returns the value 2.
The array itself begins with the number of elements in the second dimension,
where the zeroth element is taken into account (assuming OPTION BASE 0 is
valid), followed by the number of elements in the first dimension. Then
PRINT LPEEK(V:a%(0,0)-8)
returns the value 4.
PRINT LPEEK(V:a%(0,0)-4)
returns the value 3
Following this, the actual contents in the order:
a%(0,0), a%(1,0), a%(2,0), a%(0,1), a%(1,1), a%(2,1), etc.
Memo: For speed considerations when compiling one should read section
'Array Index Checking'.
The library contains minor bugs which cause incorrect error messages.
Error messages that don't work correctly at DIM:
#14 'array dimensioned twice'
#17 'dim index too large'
It will appear to issue random error messages.
DIM
DIM x(d1,[d2,...]) [,y(d1,[d2,...])]
DIM?(x())
x, y: variable name (arbitrary variable type)
d1, d2: iexp
With the instruction DIM numerical and character string arrays can be declared.
The structure of such an array was explained in the introduction of this
section.
The possible number of the dimensions of the array is only limited by:
a) the last dimension must be smaller than 65535
b) the product of the number of the field elements must be smaller than 65535
So DIM a%(100,10,10) is permitted, as the last dimension (10) and the product
of the number of field elements (100*10*10=10000) are both less than 65535.
In an array, only variables of the same type may exist. The type of array takes
precedence over the type of number put into it.
The function DIM?() determines the total number of elements in an array.
Example:
DIM x(10)
x(4)=3
PRINT x(LEN("test"))
PRINT DIM?(x())
'
DIM y%(2,3)
PRINT DIM?(y%())
--> Two arrays are declared. The output on the screen consists of the
numbers 3, 11, and 12.
Memo: DIM should not be used within a FUNCTION. It seems to clobber any
LOCAL variables defined within the FUNCTION.
DIM seems to crash the compiler if one attempts 8 dimensions:
DIM a&(1,2,3,4,5,6,7,8) <- causes the compiler to crash
OPTION BASE
OPTION BASE n
n: iexp (must be 0 or 1)
With the help of the command OPTION BASE it can be decided whether an array is
to contain a zeroth element or not. With OPTION BASE 0 (default) a zero-th
element is allocated, with OPTION BASE 1 it is not, and the array starts with
element number 1.
The contents of fields are not changed by the OPTION BASE instruction, however
the indices may be, as in the following:
Example:
DIM x%(3)
FOR i%=3 DOWNTO 0
x%(i%)=i%
PRINT i%,x%(i%)
NEXT i%
'
OPTION BASE 1
FOR i%=3 DOWNTO 0
PRINT i%,x%(i%)
NEXT i%
--> x%() is declared, by default including the zero-th element, and the
elements are given the values 0-3 and printed. After OPTION BASE 1, there
is no longer a zero-th element, and accessing the element 3 actually
accesses what was element 2, etc.
The program ends with an error message on attempting to access the no longer
valid zero-th element of the array.
Memo: OPTION BASE 1 causes problems with compiled programs. The library
contains a serious bug which renders OPTION BASE 1 unreliable. Stick to
OPTION BASE 0 and everthing is fine.
ARRAYFILL
ARRAYFILL x(),y
x: name of an array (numerical variable type)
y: aexp
The instruction ARRAYFILL sets all elements of the array x() equal to the value
of the numerical expression y.
Example:
DIM x(10)
PRINT x(4)
ARRAYFILL x(),5+1
PRINT x(4)
--> The first number printed is zero, because when an array is dimensioned all
elements are automatically set to zero. After filling the array with 5+1's,
the number 6 is printed on the screen.
Note: It is not possibie to use the ARRAYFILL command with string arrays.
Memo: ARRAYFILL does not generate an error for undimensioned arrays in the
editor or compiled.
Matrix Commands
System Commands
MAT BASE
Generating Commands
MAT CLR
MAT SET
MAT ONE
Read and Write Commands
MAT READ
MAT PRINT (MAT ?)
MAT INPUT
Copy and Transposition Commands
MAT CPY
MAT XCPY
MAT TRANS
Operation Commands
MAT ADD (MAT)
MAT SUB
MAT MUL
MAT NORM
MAT DET
MAT QDET
MAT RANG
MAT INV
Misc Commands
MAT ABS
MAT NEG
Linear operations with vectors and matrices.
All functions described in this chapter relate only to one and/or
two-dimensional fields with floating-point variables.
Memo: Some of the MAT command can be stopped with break.
However, do to a bug, most of them do not react to the break keys.
MAT DET
MAT QDET
MAT INV
MAT RANG
MAT MUL
MAT INPUT
MAT READ
MAT BASE
MAT BASE n
n: iexp (must be 0 or 1)
The MAT BASE command can only sensibly be used when OPTION BASE 0 has been
activated. In this case, MAT BASE 1 can be used to set the offset for the start
of the row and column indexing of one or two-dimensional fields with floating
point variables to 1 for the matrix operations. MAT BASE 0 resets this offset
to 0 after a MAT BASE 1.
The setting made with MAT BASE n affects the following commands:
MAT READ
MAT PRINT
MAT CPY
MAT XCPY
MAT ADD
MAT SUB
MAT MUL
Note: The default is MAT BASE 1.
Example:
OPTION BASE 0
MAT BASE 1
DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
DIM a(3,3)
MAT READ a()
PRINT a(1,1)
--> Outputs the value 1.
MAT CLR
MAT CLR a()
MAT SET a()=x
MAT ONE a()
a: name of field with numeric variables
x: aexp
MAT CLR a() corresponds to ARRAYFILL a(),0, i.e. the command sets all elements
in the field (matrix or vector) a() to a value of 0.
MAT SET a()=x corresponds to an ARRAYFILL a(),x, i.e. the command sets all
elements in the field (matrix or vector) a() to the value of x.
MAT ONE a() generates from a square matrix a() a uniform matrix, i.e. a square
martrix in which elements a(1,1), a(2,2), ..., a(n,n) are all equally 1 and all
other elements equally 0.
Examples:
DATA 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16
DIM a(3,3)
MAT READ a()
PRINT a(1,1)
MAT CLR a()
PRINT a(1,1)
--> Outputs the value 1, then 0.
DIM a(5,7)
FOR i%=1 TO 5
FOR j%=1 TO 7
a(i%,j%)=RAND(10)
NEXT j%
NEXT i%
MEAT SET a(),5.3
FOR i%=1 TO 5
FOR j%=1 TO 7
PRINT a(i%,j%)
NEXT j%
NEXT i%
--> Outputs the value '3.5' 35 times.
DIM a(3,3)
MAT ONE a()
MAT PRINT a()
--> Outputs: 1,0,0
0,1,0
0,0,1
MAT READ
MAT READ a()
MAT PRINT [#i,]a()[,g,n]
MAT INPUT #i,a()
i, g, n: iexp
a: name of field with numeric variables
MAT READ a() reads a previously dimensioned matrix or vector from DATA
rows.
Example:
DATA 1,2,3,4,5,6,7,8,9,10
DIM a(2,5)
MAT READ a()
PRINT a(2,4)
--> Outputs the value 9.
MAT PRINT [#i,]a()[,g,n] outputs a matrix or a vector. Vectors are output on
one row, the elements being separated by commas. With a matrix, each row is
followed by a rowfeed.
The output can optionally be redirected with #i, as with PRINT.
If g and n are specified, the numbers are formatted as with STR$(x,g,n).
Example:
DATA 1,2.33333,3
DATA 7,5.25873,9.376
DATA 3.23,7.2,8.999
DIM a(3,3)
MAT READ a()
MAT PRINT a()
PRINT "-------------------"
MAT PRINT a(),7,5
--> Outputs: 1, 2.33333, 3
7, 5.24873, 9.376
3.23 7.2, 8.999
-------------------
1.000, 2.333, 3.000
7.000, 5.259, 9.376
3.230, 7.200, 8.999
MAT INPUT #1,a() reads a matrix or vector from a file in ASCII format (the
format being the reverse of MAT PRINT, commas and rowfeeds may be varied as
with INPUT #).
Example:
OPEN "o",#1,"Test.DAT"
DIM a(3,3)
MAT ONE a()
MAT PRINT #1,a()
CLOSE #1
MAT CLR a()
OPEN "i",#1,"Test.DAT"
MAT INPUT #1,a()
CLOSE #1
MAT PRINT a()
--> Outputs: 1,0,0
0,1,0
0,0,1
Memo: The statement 'MAT INPUT a()' crashes the compiler!
Perhaps the #channel is not suppose to be optional and the tokenizer
fails to syntax check it correctly? The example above does not even work,
so perhaps MAT INPUT regardless of the parameters is just plain broken?
MAT READ fails in the editor with 'Out of data' but works compiled.
MAT PRINT a() !works
MAT PRINT a(),g,n !fails, always prints 0s
MAT PRINT works ok compiled.
MAT CPY
MAT CPY a([i,j])=b([k,l])[,h,w]
MAT XCPY a([i,j])=b([k,l])[,h,w]
MAT TRANS a()[=b()]
a, b: name of fields with numerical variables
i, j, k, l, h, w: iexp
MAT CPY a([i,j])=b([k,l])[,h,w] copies h rows with w elements each from matrix
b to the row and column offset of matrix a defined by i,j, starting from the
row and column offset of matrix b defined by l,k.
Example:
DIM a(5,5),b(4,4)
MAT SET a()=1
FOR i%=1 TO 4
FOR j%=1 TO 4
b(i%,j%)=SUC(i%)
NEXT j%
NEXT i%
'
MAT PRINT a()
PRINT "---------"
MAT PRINT b()
PRINT "---------"
MAT CPY a(2,2)=b(2,2),3,3
--> Outputs: 1,1,1,1,1
1,1,1,1,1
1,1,1,1,1
1,1,1,1,1
1,1,1,1,1
---------
2,2,2,2
3,3,3,3
4,4,4,4
5,5,5,5
---------
1,1,1,1,1
1,3,3,3,1
1,4,4,4,1
1,5,5,5,1
1,1,1,1,1
Special Cases
MAT CPY a()=b() copies the complete matrix b into matrix a if the matrix are of
the same order.
Only those elements are copied in this process for which identical indices are
given in both the source and the destination matrix.
Example:
DIM a(5,3),b(4,4)
MAT SET a()=1
FOR i%=1 TO 4
FOR j%=1 TO 4
b(i%,j%)=SUCC(i%)
NEXT j%
NEXT i%
'
MAT PRINT a()
PRINT "-------"
MAT PRINT b()
PRINT "-------"
MAT CPY a()=b(),3,3
MAT PRINT a()
--> Outputs: 1,1,1
1,1,1
1,1,1
1,1,1
1,1,1
-------
2,2,2,2
3,3,3,3
4,4,4,4
5,5,5,5
-------
2,2,2
3,3,3
4,4,4
1,1,1
1,1,1
MAT CPY a(i,j)=b() copies matrix b, starting from the row and column offset
defined by MAT BASE, to the row and column offset of matrix a defined by i,j.
Only those elements are copied for which identical indices are given in both
the source and the destination matrix.
Example:
DIM a(5,3),b(4,4)
MAT SET a()=1
FOR i%=1 TO 4
FOR j%=1 TO 4
b(i%,j%)=SUCC(i%)
NEXT j%
NEXT i%
'
MAT PRINT a()
PRINT "-------"
MAT PRINT b()
PRINT "-------"
MAT CPY a(2,2)=b(2,2),3,3
MAT PRINT a()
--> Outputs: 1,1,1
1,1,1
1,1,1
1,1,1
1,1,1
-------
2,2,2,2
3,3,3,3
4,4,4,4
5,5,5,5
-------
1,1,1
1,3,3
1,4,4
1,5,5
1,1,1
MAT CPY a()=b(i,j) copies matrix b, starting from the row and column offset
defined by i,j, to the offset of matrix a defined by MAT BASE. Only those
elements are copied for which identical indices are given in both the source
and the destination matrix.
Example:
DIM a(5,3),b(4,4)
MAT SET a()=1
FOR i%=1 TO 4
FOR j%=1 TO 4
b(i%,j%)=SUCC(i%)
NEXT j%
NEXT i%
'
MAT PRINT a()
PRINT "-------"
MAT PRINT b()
PRINT "-------"
MAT CPY a()=b(2,2),3,3
MAT PRINT a()
--> Outputs: 1,1,1
1,1,1
1,1,1
1,1,1
1,1,1
-------
2,2,2,2
3,3,3,3
4,4,4,4
5,5,5,5
-------
3,3,3
4,4,4
5,5,5
1,1,1
1,1,1
MAT CPY a(i,j)=b(k,l) copies matrix b, starting from the row and column offset
defined by k,l, to the offset i,j of matrix a. Only those elements are copied
for which identical indices are given in both the source and the destination
matrix.
Example:
DIM a(5,3),b(4,4)
MAT SET a()=1
FOR i%=1 TO 4
FOR j%=1 TO 4
b(i%,j%)=SUCC(j%)
NEXT j%
NEXT i%
'
MAT PRINT a()
PRINT "-------"
MAT PRINT b()
PRINT "-------"
MAT CPY a()=b()
MAT PRINT a()
--> Outputs: 1,1,1
1,1,1
1,1,1
1,1,1
1,1,1
-------
2,3,4,5
2,3,4,5
2,3,4,5
2,3,4,5
-------
1,1,1
1,3,4
1,3,4
1,3,4
1,1,1
MAT CPY a()=b() copies h rows with w elements each from the matrix b, starting
from the row and column offset defined by MAT BASE, the row and column offset
of matrix a defined by MAT BASE. Only those elements are copied for which
identical indices are given in both the source and the destination matrix.
Example:
DIM a(5,3),b(4,4)
MAT SET a()=1
FOR i%=1 TO 4
FOR j%=1 TO 4
b(i%,j%)=SUCC(j%)
NEXT j%
NEXT i%
'
MAT PRINT a()
PRINT "-------"
MAT PRINT b()
PRINT "-------"
MAT CPY a(2,2)=b(2,2)
MAT PRINT a()
--> Outputs: 1,1,1
1,1,1
1,1,1
1,1,1
1,1,1
-------
2,3,4,5
2,3,4,5
2,3,4,5
2,3,4,5
-------
2,3,4
2,3,4
2,3,4
2,3,4
1,1,1
MAT XCPY a([i,j])=b([k,l])[,h,w] works basically in the same manner as MAT CPY
a([i,j])=b([k,l])[,h,w], except that matrix b is being transposed while being
copied to matrix a, i.e. the rows and columns of matrix b are swapped while it
is copied to matrix a. Array b remains unchanged, however. Only those elements
are copied for which identical indices are given in both the source and the
destination matrix.
Example:
DIM a(5,3),b(4,4)
MAT SET a()=1
FOR i%=1 TO 4
FOR j%=1 TO 4
b(i%,j%)=SUCC(j%)
NEXT j%
NEXT i%
'
MAT PRINT a()
PRINT "-------"
MAT PRINT b()
PRINT "-------"
MAT XCPY a(2,2)=b(2,2),3,3
MAT PRINT a()
--> Outputs: 1,1,1
1,1,1
1,1,1
1,1,1
1,1,1
-------
2,3,4,5
2,3,4,5
2,3,4,5
2,3,4,5
-------
1,1,1
1,3,3
1,4,4
1,5,5
1,1,1
Further Special Cases
As with MAT CPY a(i,j)=b(k,l),w,h.
If MAT CPY or MAT XCPY are applied to vectors, j and l may be ignored.
Following a DIM a(n),b(m), a() and b() are interpreted as row vectors, i.e. as
matrix of the (1,n) or (1,m) types.
For a and b to be treated as column vectors, they must be dimensioned as matrix
of the (n,1) or (m,1) type, ie. DIM a(n,1),b(n,1).
If both vectors are of the same order (both are row or column vectors), MAT CPY
must be used. Irrespective of the type of vectors a and b, MAT CPY always
treats both vectors syntactically as column vectors, so that the correct syntax
to be used for MAT CPY is always:
MAT CPY a(n,1)=b(m,1)!
Example:
DIM a(10),b(5) !a() and b() are row vectors
MAT SET a()=1
FOR i%=1 TO 5
b(i%)=SUCC(i%)
NEXT i%
PRINT "a(): ";
MAT PRINT a()
PRINT "b(): ";
MAT PRINT b()
PRINT STRING$(45,"-")
MAT CPY a(3,1)=b(1,1) !interprets a() and b() as column vectors
PRINT "MAT CPY a(3,1)=b(1,1): ";
MAT PRINT a()
--> Outputs: a(): 1,1,1,1,1,1,1,1,1,1
b(): 2,3,4,5,6
------------------------------------------
MAT CPY a(3,1)=b(1,1): 1,1,2,3,4,5,6,1,1,1
For MAT XCPY, one of the two vectors a and b must be explicitly dimensioned as
a row vector, the other as a column vector. For example:
DIM a(1,10),b(5,1)
Since MAT XCPY first transposes the second vector before copying it to the
first. For this reason, MAT XCPY can only be used for DIM a(1,n),b(m,1):
a()=row vector, b()=column vector and DIM a(n,1),b(1,m): a()=column vector,
b()=row vector.
Example:
DIM a(1,10).n(5,1)
MAT SET a()=1
FOR i%=1 TO 5
b(i%,1)=SUCC(i%)
NEXT i%
MAT PRINT a()
PRINT
MAT PRINT b()
MAT XCPY a(1,3)=b(1,1)
PRINT
MAT PRINY a()
--> Outputs: 1,1,1,1,1,1,1,1,1,1
2
3
4
5
6
1,1,2,3,4,5,6,1,1,1
Optionally, the parameters h and w can also be used when copying vectors with
MAT CPY or MAT XCPY. However, the following applies: with MAT CPY, only the h
parameter is used for w=>1. No copying takes place with w=0.
With MAT XCPY, only h is used for w=>1 if b is a column vector to be copied
into a row vector after transposition. No copying takes place when w=0. On the
other hand, only w is used for h=>1 if b is a row vector which is to be copied
to a column vector after transposition. In this case, no copying takes place if
h=0.
MAT TRANS a()=b() copies the transposed from matrix b to matrix a if a and b
are dimensioned accordingly, i.e. the number of rows from a must correspond to
the number of columns in b, and the number of columns from a to the number of
rows of n: for example, DIM a(n,m),b(m,n).
Example:
DIM a(3,4),b(4,3)
MAT SET b()=4
MAT SET a()=1
MAT PRINT a()
PRINT STRING$(10,"-")
MAT PRINT b()
PRINT STRING$(10,"-")
MAT TRANS a()=b()
MAT PRINT a()
--> Outputs: 1,1,1,1
1,1,1,1
1,1,1,1
-------
4,4,4
4,4,4
4,4,4
4,4,4
-------
4,4,4,4
4,4,4,4
4,4,4,4
In the case of a square matrix, i.e. one with equal numbers of rows and
columns, MAT TRANS a() may be used. This command swaps the rows and columns of
matrix a and writes the matrix thus changed back to a.
The original matrix is lost in the process but can be restored with another MAT
TRANS a().
Example:
DIM a(5,5)
FOR i%=1 TO 5
FOR j%=1 TO 5
a(i%,j%)=j%
NEXT j%
NEXT i%
MAT PRINT a()
PRINT STRING$(10,"-")
MAT TRANS a()
MAT PRINT a()
--> Outputs: 1,2,3,4,5
1,2,3,4,5
1,2,3,4,5
1,2,3,4,5
1,2,3,4,5
---------
1,1,1,1,1
2,2,2,2,2
3,3,3,3,3
4,4,4,4,4
5,5,5,5,5
MAT ADD
MAT ADD a()=b()+c()
MAT ADD a(),b()
MAT ADD a(),x
MAT SUB a()=b()-c()
MAT SUB a(),b()
MAT SUB a(),x
MAT MUL a()=b()*c()
MAT MUL x=a()*b()
MAT MUL x=a()*b()*c()
MAT MUL a(),x
MAT NORM a(),0
MAT NORM a(),1
MAT DET x=a([i,j])[,n]
MAT QDET x=a([i,j])[,n]
MAT RANG x=a([i,j])[,n]
MAT INV a()=b()
a, b, c: names of numerical floating point fields
x: aexp (scalar value)
i, j, n: aexp
MAT ADD a()=b()+c() is only defined for matrix (vectors) of the same order,
e.g. DIM a(n,m),b(m,m),c(n,m) or DIM a(n),b(n),c(n). Array c is added to matrix
b, element by element, and the result is written to matrix a.
Example:
DIM a(3,5),b(3,5),c(3,5)
MAT SET b()=3
MAT SET c()=4
MAT PRINT b()
PRINT STRING$(10,"-")
MAT PRINT c()
PRINT STRING$(10,"-")
MAT ADD a()=b()+c()
MAT PRINT a()
--> Outputs: 3,3,3,3,3
3,3,3,3,3
3,3,3,3,3
---------
4,4,4,4,4
4,4,4,4,4
4,4,4,4,4
---------
7,7,7,7,7
7,7,7,7,7
7,7,7,7,7
MAT ADD a(),b() is only defined for matrix (vectors) of the same order, e.g.
DIM a(n,m),b(n,m) or DIM a(n),b(n). Array b is added to matrix a, element by
element, and the result is written to matrix a. The original matrix a is lost
in the process.
Example:
DIM a(3,5),b(3,5)
MAT SET a()=1
MAT SET b()=3
MAT PRINT a()
PRINT STRING$(10,"-")
MAT PRINT b()
PRINT STRING$(10,"-")
MAT ADD a(),b()
MAT PRINT a()
--> Outputs: 1,1,1,1,1
1,1,1,1,1
1,1,1,1,1
---------
3,3,3,3,3
3,3,3,3,3
3,3,3,3,3
---------
4,4,4,4,4
4,4,4,4,4
4,4,4,4,4
MAT ADD a(),x is defined for all matrix (vectors). Here, the scalar x is added
to matrix a, element by element, and the result is written to matrix a. The
original matrix a is lost in the process.
Example:
DIM a(3,5)
MAT SET a()=1
MAT PRINT a()
PRINT STRING$(10,"-")
MAT ADD A(),5
MAT PRINT a()
--> Outputs: 1,1,1,1,1
1,1,1,1,1
1,1,1,1,1
---------
6,6,6,6,6
6,6,6,6,6
6,6,6,6,6
MAT SUB a()=b()-c() is only defined for matrix (vectors) of the same order,
e.g. DIM a(n,m),b(n,m),c(n,m) or DIM a(n),b(n),c(n). Array c is subtracted from
matrix b, element by element, and the result is written to matrix a.
Example:
DIM a(3,5),b(3,5),c(3,5)
MAT SET b()=5
MAT SET c()=3
MAT PRINT b()
PRINT STRING$(10,"-")
MAT PRINT c()
PRINT STRING$(10,"-")
MAT SUB a()=b()-c()
MAT PRINT a()
--> Outputs: 5,5,5,5,5
5,5,5,5,5
5,5,5,5,5
---------
3,3,3,3,3
3,3,3,3,3
3,3,3,3,3
---------
2,2,2,7,2
2,2,2,2,2
2,2,2,2,2
MAT SUB a(),b() is only defined for matrix (vectors) of the same order, e.g.
DIM a(n,m),b(n,m) or DIM a(n),b(n). Array b is subtracted from matrix a,
element by element, and the result written to matrix a. The original matrix a
is lost in the process.
Example:
DIM a(3,5),b(3,5)
MAT SET a()=3
MAT SET b()=1
MAT PRINT a()
PRINT STRING$(10,"-")
MAT PRINT b()
PRINT STRING$(10,"-")
MAT SUB a(),b()
MAT PRINT a()
--> Outputs: 3,3,3,3,3
3,3,3,3,3
3,3,3,3,3
---------
1,1,1,1,1
1,1,1,1,1
1,1,1,1,1
---------
2,2,2,2,2
2,2,2,2,2
2,2,2,2,2
MAT SUB a(),x is defined for all matrix (vectors). Here, the scalar x is
subtracted from matrix x, element by element, and the result is written to
matrix a. The original matrix a is lost in the process.
Example:
DIM a(3,5)
MAT SET a()=6
MAT PRINT a()
PRINT STRING$(10,"-")
MAT SUB A(),5
MAT PRINT a()
--> Outputs: 6,6,6,6,6
6,6,6,6,6
6,6,6,6,6
---------
1,1,1,1,1
1,1,1,1,1
1,1,1,1,1
MAT MUL a()=b()*c() is defined for matrix of an "appropriate" order. Arrays b
and c are multiplied with each other. The result of this multiplication is
written to matrix a. In order for the result to be defined, the matrix on the
left (matrix b in this case) must have the same number of columns as the matrix
on the right (c in this case) has rows. Array a, in this case, must have as
many rows as b and as many columns as c, for example:
DIM a(2,2),b(2,3),c(3,2)
Arrays are multiplied as "row by column", i.e. element a(i,j) is obtained by
multiplying the elements in the ith row of matrix b with the elements in the
jth column of matrix c, element by element, and then adding up the individual
products.
Example:
DIM a(2,2),b(2,3),c(3,2)
MAT SET b()=1
DATA 1,2,-3,4,5,-1
MAT READ c()
MAT PRINT b(),5,1
PRINT STRING$(18,"-")
MAT PRINT c(),5,1
PRINT STRING$(18,"-")
MAT MUL a()=b()*c()
MAT PRINT a(),5,1
--> Outputs: 1.0, 1.0, 1.0
1.0, 1.0, 1.0
------------------
1.0, 2.0
-3.0, 4.0
5.0, -1.0
------------------
3.0, 5.0
3.0, 5.0
With vectors instead of matrix, MAT MUL a()=b()*c() results in the dyadic (or
external) product of two vectors.
Example:
DIM a(3,3),b(3),c(3)
DATA 1,2,-3,4,5,-1
MAT READ b()
MAT READ c()
MAT PRINT b(),5,1
PRINT STRING$(18,"-")
MAT PRINT c(),5,1
PRINT STRING$(18,"-")
MAT MUL a()=b()*c()
MAT PRINT a(),5,1
--> Outputs: 1.0, 2.0, -3.0
------------------
4.0, 5.0, -1.0
------------------
4.0, 5.0, -1.0
5.0, 10.0, -2.0
-12.0, -15.0, 3.0
MAT MUL x=a()*b() is only defined for vectors with an equal number of elements.
The result x is the scalar product (the so-called interior product) of vectors
a and b. The scalar product of two vectors is defined as the sum of n products
a(i)*b(i),i=1,...,n.
Example:
DIM b(3),c(3)
DATA 1,2,-3,4,5,-1
MAT READ b()
MAT READ c()
MAT PRINT b(),5,1
PRINT STRING$(18,"-")
MAT PRINT c(),5,1
PRINT STRING$(18,"-")
MAT MUL x=b()*c()
PRINT x
--> Outputs: 1.0, 2.0, -3.0
------------------
4.0, 5.0, -1.0
------------------
17.0
MAT MUL x=a()*b()*c() is defined for qualified Vectors a and c as well as
qualified Matrix b().
Example:
DIM a(2).b(2,3),c(3)
DATA 1,2,-3,4,5
MAT READ a()
MAT READ c()
MAT SET b()=1
MAT PRINT a(),5,1
PRINT STRING$(18,"-")
MAT PRINT b(),5,1
PRINT STRING$(18,"-")
MAT PRINT c(),5,1
PRINT STRING$(18,"-")
MAT MUL x=a()*b()*c()
PRINT x
--> Outputs: 1.0, 2.0
------------------
1.0, 1.0, 1.0
1.0, 1.0, 1.0
1.0, 1.0, 1.0
------------------
-3.0, 4.0, 5.0
------------------
18.0
MAT NORM a(),0 or MAT NORM a(),1 are defined for matrix and vectors. MAT NORM
a(),0 normalises a matrix (a vector) by rows, MAT NORM a(),1 by columns. This
means that after a normalisation by rows (by columns) the sum of the squares of
all elements in each row (column) is identical at 1.
Example:
DIM a(10,10),b(10,10),v(10)
DATA 1,2,3,4,5,6,7,8,9,-1
DATA 3.2,4,-5,2.4,5.1,6.2,7.2,8.1,6,-5
DATA -2,-5,-6,-1.2,-1.5,-6.7,4.5,8.1,3.4,10
DATA 5,-2.3,4,5.6,12.2,18.2,14.1,16,-21,-13
DATA 4.1,5.2,16.7,18.4,19.1,20.2,13.6,14.8,19.4,18.6
DATA 15.2,-1.8,13.6,-4.9,5.4,19.8,16.4,-20.9,21.4,13.8
DATA -3.6,6,-8.2,-9.1,4,-2.5,2,3.4,6.7,8.4
DATA 4.7,8.3,9.4,10.5,11,19,15.4,18.9,-20,12.6
DATA 5.3,-4.7,6.1,6.5,6.9,-9.2,-10.8,4.3,5.6,9.1
DATA 21.4,19.5,28.4,19.3,24.6,14.9,71.3,23.5,14.5,-12.3
'
CLS
MAT READ a()
MAT CPY b()=a() !Source matrix stored
PRINT "Source matrix"
PRINT
MAT PRINT a(),7,2
~INP(2)
CLS
MAT NORM a(),0
PRINT
PRINT "Row:"
PRINT
MAT PRINT a(),7,2
~INP(2)
'
PRINT
PRINT "Test:"
PRINT
FOR i%=1 TO 10
MAT XCPY v()=a(i%,1)
MAT MUL x=v()*v()
PRINT x'
NEXT i%
PRINT
~INP(2)
'
CLS
MAT CPY a()=b()
MAT NORM a(),1
PRINT "Column:"
PRINT
MAT PRINT a(),7,2
~INP(2)
'
PRINT
PRINT "Test:"
PRINT
FOR i%=1 TO 10
MAT CPY v()=a(1,i%) !Copy column a() in the vector v()
MAT MUL x=v()*v()
PRINT x'
NEXT i%
~INP(2)
--> Outputs:
Source matrix
1.00, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00, 9.00, -1.00
3.20, 4.00, -5.00, 2.40, 5.10, 6.20, 7.20, 8.10, 6.00, -5.00
-2.00, -5.00, -6.00, -1.20, -1.50, -6.70, 4 50, 8.10, 3.40, 10.00
5.00, -2.30, 4.00, 5.60, 12.20, 18.20, 14.10, 16.00, -21.00, -13.00
4.10, 5.20, 16.70, 18.40, 19.10, 20.20, 13.60, 14.80, 19.40, 18.60
15.20, -1.80, 13.60, -4.90, 5.40, 19.80, 16.40, -20.90, 21.40, 13.80
-3.60, 6.00, -8.20, -9.10, 4.00, -2.50, 2.00, 3.40, 6.70, 8.40
4.70, 8.30, 9.40, 10.50, 11.00, 19.00, 15.40, 18.90, -20.00, 12.60
5.30, -4.70, 6.10, 6.50, 6.90, -9.20, -10.80, 4.30, 5.60, 9.10
21.40, 19.50, 28.40, 19.30, 24.60, 14.90, 71.30, 23.50, 14.50, -12.30
Row:
0.06, 0.12, 0.18, 0.24, 0.30, 0.35, 0.41, 0.47, 0.53, -0.06
0.18, 0.23, -0.29, 0.14, 0.29, 0.36, 0.42, 0.47, 0.35, -0.29
-0.11, -0.28, -0.34, -0.07, -0.09, -0.38, 0.26, 0.46, 0.19, 0.57
0.12, -0.06, 0.10, 0.14, 0.30, 0.45, 0.35, 0.40, -0.52, -0.32
0.08, 0.10, 0.33, 0.36, 0.38, 0.40, 0.27, 0.29, 0.38, 0.37
0.32, -0.04, 0.29, -0.10, 0.11, 0.42, 0.35, -0.44, 0.45, 0.29
-0.19, 0.32, -0.44, -0.48, 0.21, -0.13, 0.11, 0.18, 0.36, 0.45
0.11, 0.19, 0.21, 0.24, 0.25, 0.43, 0.35, 0.43, -0.46, 0.29
0.23, -0.21, 0.27, 0.29, 0.31, -0.41, -0.48, 0.19, 0.25, 0.40
0.23, 0.21, 0.30, 0.21, 0.26, 0.16, 0.76, 0.25, 0.15, -0.13
Test:
1 1 1 1 1 1 1 1 1 1
Columns:
0.04, 0.08, 0.08, 0.12, 0.13, 0.14, 0.09, 0.18, 0.20, -0.03
0.11, 0.16, -0.13, 0.07, 0.14, 0.14, 0.09, 0.18, 0.13, -0.14
-0.07, -0.21, -0.15, -0.04, -0.04, -0.15, 0.06, 0.18, 0.07, 0.28
0.18, -0.09, 0.10, 0.17, 0.33, 0.41, 0.18, 0.35, -0.46, -0.36
0.14, 0.21, 0.42, 0.57, 0.51, 0.46, 0.17, 0.33, 0.42, 0.52
0.53, -0.07, 0.35, -0.15, 0.15, 0.45, 0.21, -0.46, 0.47, 0.38
-0.13, 0.25, -0.21, -0.28, 0.11, -0.06, 0.03, 0.08, 0.15, 0.23
0.17, 0.34, 0.24, 0.33, 0.30, 0.43, 0.20, 0.42, -0.44, 0.35
0.19, -0.19, 0.15, 0.20, 0.19, -0.21, -0.14, 0.10, 0.12, 0.25
0.75, 0.80, 0.72, 0.60, 0.66, 0.34, 0.90, 0.52, 0.32, -0.34
Test:
1 1 1 1 1 1 1 1 1 1
MAT DET x=a([i,j])[,n] calculates the determinants of a square matrix of the
(n,n) type. The row and column offsets are preset to a(0,0) or a(1,1),
depending on MAT BASE 0 or MAT BASE 1, assuming that OPTION BASE 1 is enabled.
It is also possible, however, to calculate the determinant of a square part
matrix. To do this, the row and column offsets of a() must be specified as i
and j, and the number of elements in the part matrix as n. A part matrix of the
(n,n) type is then created internally starting from the "position" ith row, jth
column.
Example:
DIM a(10,10),b(4,4)
DATA 1,2,3,4,5,6,7,8,9,-1
DATA 3.2,4,-5,2.4,5.1,6.2,7.2,8.1,6,-5
DATA -2,-5,-6,-1.2,-1.5,-6.7,4.5,8.1,3.4,10
DATA 5,-2.3,4,5.6,12.2,18.2,14.1,16,-21,-13,3.8
DATA 4.1,5.2,16.7,18.4,19.1,20.2,13.6,14.8,19.4,18.6
DATA 15.2,-1.8,13.6,-4.9,5.4,19.8,16.4,-20.9,21.4,13.8
DATA -3.6,6,-8.2,-9.1,4,-2.5,2,3.4,6.7,8.4,10.9
DATA 4.7,8.3,9.4,10.5,11,19,15.4,18.9,-20,12.6
DATA 5.3,-4.7,6.1,6.5,6.9,-9.2,-10.8,4.3,5.6,9.1
DATA 21.4,19.5,28.4,19.3,24.6,14.9,71.3,23.5,14.5,-12.3
'
CLS
MAT READ a()
PRINT "Source matrix"
PRINT
MAT PRINT a(),7,2
PRINT
PRINT "Determinant: ";
MAT DET x=a()
PRINT x;
MAT DET y=a(1,4),4
PRINT
PRINT "Determinant from a(1,4),4: ";
PRINT y
PRINT
PRINT "Test: "
PRINT
MAT CPY b()=a(1,4),4,4 !copy to b()
MAT PRINT b(),7,2
MAT DET z=b() !Determinant from b()
PRINT
PRINT z
--> Outputs:
Source Matrix
1.00, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00, 9.00, -1.00
3.20, 4.00, -5.00, 2.40, 5.10, 6.20, 7.20, 8.10, 6.00, -5.00
-2.00, -5.00, -6.00, -1.20, -1.50, -6.70, 4.50, 8.10, 3.40, 10.00
5.00, -2.30, 4.00, 5.60, 12.20, 18.20, 14.10, 16.00, -21.00, -13.00
3.80, 4.10, 5.20, 16.70, 18.40, 19.10, 20.20, 13.60, 14.80, 19.40
18.60, 15.20, -1.80, 13.60, -4.90, 5.40, 19.80, 16.40, -20.90, 21.40
13.80, -3.60, 6.00, -8.20, -9.10, 4.00, -2.50, 2.00, 3.40, 6.70
8.40, 10.90, 4.70, 8.30, 9.40, 10.50, 11.00, 19.00, 15.40, 18.90
-20.00, 12.60, 5.30, -4.70, 6.10, 6.50, 6.90, -9.20, -10.80, 4.30
5.60, 9.10, 21.40, 19.50, 28.40, 19.30, 24.60, 14.90, 71.30, 23.50
Determinant: -2549840202186
Determinant from a(1,4),4: -57.61200000001
Test:
4.00, 5.00, 6.00, 7.00
2.40, 5.10, 6.20, 7.20
-1.20, -1.50, -6.70, 4.50
5.60, 12.20, 18.20, 14.10
-57.61200000001
MAT QDET x=a([i,j])[,n] works in the same manner as MAT DET x=a([i,j])[,n],
except that it has been optimised for speed rather than accuracy. Both will
normally produce identical results. With "critical" matrix, whose determinant
is close to 0, you should always use MAT DET, though.
Example:
DIM a(10,10)
DATA 1,2,3,4,5,6,7,8,9,-1
DATA 3.2,4,-5,2.4,5.1,6.2,7.2,8.1,6,-5
DATA -2,-5,-6,-1.2,-1.5,-6.7,4.5,8.1,3.4,10
DATA 5,-2.3,4,5.6,12.2,18.2,14.1,16,-21,-13,3.8
DATA 4.1,5.2,16.7,18.4,19.1,20.2,13.6,14.8,19.4,18.6
DATA 15.2,-1.8,13.6,-4.9,5.4,19.8,16.4,-20.9,21.4,13.8
DATA -3.6,6,-8.2,-9.1,4,-2.5,2,3.4,6.7,8.4,10.9
DATA 4.7,8.3,9.4,10.5,11,19,15.4,18.9,-20,12.6
DATA 5.3,-4.7,6.1,6.5,6.9,-9.2,-10.8,4.3,5.6,9.1
DATA 21.4,19.5,28.4,19.3,24.6,14.9,71.3,23.5,14.5,-12.3
'
CLS
MAT READ a()
PRINT "Source matrix"
PRINT
MAT PRINT a(),7,2
PRINT
PRINT "Determinant with MAT DET: ";
MAT DET x=a()
PRINT x;
PRINT
PRINT "Determinant with MAT QDET: ";
MAT DET y=a()
PRINT y;
PRINT
PRINT "Deviation: ";x-y
--> Outputs:
Source Matrix
1.00, 2.00, 3.00, 4.00, 5.00, 6.00, 7.00, 8.00, 9.00, -1.00
3.20, 4.00, -5.00, 2.40, 5.10, 6.20, 7.20, 8.10, 6.00, -5.00
-2.00, -5.00, -6.00, -1.20, -1.50, -6.70, 4.50, 8.10, 3.40, 10.00
5.00, -2.30, 4.00, 5.60, 12.20, 18.20, 14.10, 16.00, -21.00, -13.00
3.80, 4.10, 5.20, 16.70, 18.40, 19.10, 20.20, 13.60, 14.80, 19.40
18.60, 15.20, -1.80, 13.60, -4.90, 5.40, 19.80, 16.40, -20.90, 21.40
13.80, -3.60, 6.00, -8.20, -9.10, 4.00, -2.50, 2.00, 3.40, 6.70
8.40, 10.90, 4.70, 8.30, 9.40, 10.50, 11.00, 19.00, 15.40, 18.90
-20.00, 12.60, 5.30, -4.70, 6.10, 6.50, 6.90, -9.20, -10.80, 4.30
5.60, 9.10, 21.40, 19.50, 28.40, 19.30, 24.60, 14.90, 71.30, 23.50
Determinant with MAT DET: -2549840202186
Determinant with MAT QDET: -2549840202186
Deviation: 0
MAT RANG x=a([i,j])[,n] outputs the rank of a square matrix. As with MAT DET or
MAT QDET, you can select any row and column offset. The number of elements in
the part matrix must be specified with n. This creates a part matrix of the
(n,n) type internally, starting from the position ith row, jth column.
Example:
DIM a(5,5)
DATA 1,2,3,4,5
DATA 3.2,4,-5,2.4,5.1
DATA -2,4,-5,2.4,5.1
DATA 5,-2.3,4,5.6,12.2
DATA 4.1,5.2,16.7,18.4,19.1
'
CLS
MAT READ a()
PRINT "Source matrix"
PRINT
MAT PRINT a(),7,2
PRINT
PRINT "Rang from a(): ";
MAT RANG x=a()
PRINT x;
PRINT
PRINT "Rang from a(1,2),3: ";
MAT RANG y=a(1,2),3
PRINT y;
PRINT
--> Outputs:
Source matrix
1.00, 2.00, 3.00, 4.00, 5.00
3.20, 4.00, -5.00, 2.40, 5.10
-2.00, 4.00, -5.00, 2.40, 5.10
5.00, -2.30, 4.00, 5.60, 12.20
4.10, 5.20, 16.70, 18.40, 19.10
Rang from a(): 5
Rang from a(1,2),3: 2
MAT INV b()=a() is used to determine the inverses of a square matrix. The
inverse of matrix a() is written to matrix b(), hence b() must be of the same
type as a().
Example:
DIM a(5,5),b(5,5),c(5,5)
DATA 1,2,3,4,5
DATA 3.2,4,-5,2.4,5.1
DATA -2,4,-5,2.4,5.1
DATA 5,-2.3,4,5.6,12.2
DATA 4.1,5.2,16.7,18.4,19.1
'
CLS
MAT READ a()
PRINT "Source matrix a(): "
PRINT
MAT PRINT a(),7,2
'
MAT INV b()=a()
PRINT
PRINT "Inverse from a(): "
PRINT
MAT PRINT b(),7,2
PRINT
PRINT "Test b()*a()>Unity matrix ?"
PRINT
MAT MUL c()=b()*a()
MAT PRINT c(),7,2
--> Outputs:
Source matrix a():
1.00, 2.00, 3.00, 4.00, 5.00
3.20, 4.00, -5.00, 2.40, 5.10
-2.00, 4.00, -5.00, 2.40, 5.10
5.00, -2.30, 4.00, 5.60, 12.20
4.10, 5.20, 16.70, 18.40, 19.10
Inverse from a():
0.00, 0.19, -0.19, -0.00, -0.00
0.97, 0.02, -0.09, -0.10, -0.17
0.71, -0.10, -0.10, -0.01, -0.12
-1.65, 0.17, 0.11, -0.06, 0.39
0.71, -0.12, 0.04, 0.09, -0.17
Test b()*a()>Unity matrix ?
1.00, 0.00, 0.00, 0.00, 0.00
0.00, 1.00, 0.00, 0.00, -0.00
0.00, -0.00, 1.00, 0.00, -0.00
-0.00, -0.00, -0.00, 1.00, 0.00
-0.00, 0.00, 0.00, 0.00, 1.00
Memo: MAT DET x=a(i,j),n !causes the compiler to crash
MAT DET x=a(i,j),2+6 !is also fatal
MAT DET x=a(i,j),4 !seems to compile ok
MAT DET x=a(i,j),n& !seems to compile ok
MAT QDET and MAT RANG seem to have the same problems.
MAT ABS
MAT ABS a()
MAT NEG a()
a: names of numerical floating point fields
MAT ABS a() will perform an ABS() function on all elements of a().
Example:
DIM a(3,3)
MAT SET a()=-1
MAT PRINT a()
PRINT STRING$(8,"-")
MAT ABS a()
MAT PRINT a()
--> -1,-1,-1
-1,-1,-1
-1,-1,-1
--------
1,1,1
1,1,1
1,1,1
MAT NEG a() multiplies all elements of a one or two dimensional floating point
array a() with -1.
Example:
DIM a(3,3)
MAT ONE a()
MAT PRINT a()
PRINT STRING$(6,"-")
MAT NEG a()
MAT PRINT a()
--> 1,0,0
0,1,0
0,0,1
------
-1,0,0
0,-1,0
0,0,-1
TYPE()
ASC(), CHR$()
STR$(), BIN$(), OCT$(), HEX$()
VAL(), VAL?()
CVI(), CVL(), CVS(), CVF(), CVD()
MKI$(), MKL$(), MKS$(), MKF$(), MKD$()
CINT(), CFLOAT()
TYPE
TYPE(x)
x: iexp
With the function TYPE() the type of a variable can be determined. The function
operates on the pointer to the variable, and returns a value corresponding to
the variable type as follows:
Float 0
String 1
Long 2
Boolean 3
Float array 4
String array 5
Long array 6
Boolean array 7
Word 8
Byte 9
Word array 12
Byte array 13
Note: An invalid pointer returns the vaiue -1.
Example:
a$="test"
x%=4
DIM y(3)
PRINT TYPE(*a$),TYPE(*x%),TYPE(*y())
--> The numbers 1, 2, and 4 appear on the screen. (*a$, etc, represent the
pointer to a variable.)
ASC
ASC(a$)
CHR$(x)
a$: sexp
x: aexp
ASC() and CHR$() are complementary functions.
The function ASC() returns the ASCII code of the first character in the subject
string. If the string is of zero length (""), zero is returned.
CHR$() gives a character, from a specified ASCII code. Only the lowest 8 bits
of x (the low-byte) are relevant, as ASCII codes only go up to 255.
Example:
PRINT ASC("TEST")
code|=ASC(CHR$(65)) !CHR$(65) is A
PRINT code|,CHR$(189)
--> The numbers 84 and 65 and the copyright sign appear on the screen.
STR$
STR$(x[,y][,z])
BIN$(x[,y])
OCT$(x[,y])
HEX$(x[,y])
x, y, z: aexp
The functions STR$(), BIN$(), OCT$(), and HEX$() convert a numerical expression
into a character string.
The length of the required output string can be specified by a second
parameter. If necessary, it is padded at the front by blanks (STR$()) or zeros
(BIN$(), OCT$(), HEX$()). If the length specified is too short, only that
number of characters will be returned.
STR$() produces a string (base 10) from the number 'x', with 'y' specifying the
required length.
A further variant of STR$() is provided with the third parameter 'z'. The
number is formatted and rounded with 'y' characters and 'z' decimal places.
BIN$() converts an integer to Binary (base 2) representation. The optional
parameter 'y' specifies the number of character positions (1 to 32) to be used.
OCT$() converts an integer to Octal (base 8) representation. The optional
parameter 'y' specifies the number of character positions (1 to 11) to be used.
HEX$() converts an integer to Hexadecimal (base 16) representation. The
optional parameter 'y' specifies the number of character positions (1 to 8) to
be used.
Examples:
a=123.4567
PRINT STR$(a,6,2)
PRINT STR$(PI,5,3)
PRINT STR$(PI,2,2)
--> Prints the numbers 123.46, 3.142, and 14 on the screen.
x=32+15
a$=OCT$(16+7,4)
PRINT HEX$(x),a$,BIN$(1+4+16+64,8)
--> Prints 2F, 0027, and 01010101 on the screen.
Memo: STR$() with 3 parameters is limited to 2000 characters for
parameter 'y' in the editor and 400 characters compiled.
VAL
VAL(a$)
VAL?(a$)
a$: sexp
VAL() turns a character string into a number. If VAL() encounters a character
that cannot be interpreted as part of a number, the conversion stops at that
point with the characters successfully converted returned as the result. If no
number is found at the beginning of the string, zero is returned.
By adding the prefix &H (Hex), &X (Bin), or &O (Oct) numbers in Hexadecimal,
Binary, and Octal notation can be recognized.
The prefixes '$' and '%' may also be used to identify Hexadecimal and Binary
notation respectively.
With VAL?() one can determine the number of characters convertible with VAL(),
returning zero if none can be converted.
Examples:
a$=STR$(12345)
PRINT VAL(a$),VAL("-.123abc123"),VAL?("3.00 km")
--> The numbers 12345,-0.123 and 4 are printed on the screen.
PRINT VAL("&H"+"AF")
--> '175' is displayed.
PRINT VAL("$AA")
PRINT VAL("%10101010")
--> '170' is displayed twice.
Memo: VAL() assumes hex if the type is left out in gfa format strings.
VAL() also ignores leading spaces. VAL?() counts leading spaces.
Example:
PRINT VAL("&HFF") !prints 255
PRINT VAL("&FF") !also prints 255
PRINT VAL(" 255") !also prints 255
PRINT VAL(" 2 0") !prints 2
'
PRINT VAL?(" 22") !prints 4
PRINT VAL?(TRIM$(" 22")) !prints 2
CVI
CVI(a$) CVL(a$) CVS(a$) CVF(a$) CVD(a$)
MKI$(x) MKL$(x) MKS$(x) MKF$(x) MKD$(x)
a$: sexp
x: aexp
The functions CVI(), CVL(), CVS(), CVF(), and CVD() convert character strings
into numbers, but, as opposed to VAL() and STR$(), it is the internal
representation which is set.
The individual CVx() functions have the following effects:
CVI() Changes a 2-byte character string into an Word.
CVL() Changes a 4-byte character string into a Long
CVS() Changes a 4-byte character string containing a valid ST-Basic
compatible number into GFA-Basic 3 floating point format.
CVF() Changes a 6-byte character string containing a valid GFA-Basic 1.0
or GFA-Basic 2.0 compatible number into GFA-Basic 3 floating point
format.
CVD() Changes an 8-byte character string into GFA-Basic 3 floating point
format.
MKI$(), MKL$(), MKS$(), MKF$(), and MKD$() are the inverse of the CVx()
functions above, thus:
MKI$(x%)=CHR$(SHR(x%,8))+CHR$(x%)
MKL$(x%)=CHR$(SHR(x%,24))+CHR$(SHR(x%,16))+CHR$(SHR(x%,8))+CHR$(x%)
(SHR() is the shift-right function. Note that the high-byte comes first.)
Uses might be reading the number formats of other programs or in saving space
when storing numbers in random access files.
Example:
a$=MKL$(1000)
PRINT CVL(a$),LEN(a$)
b$=MKD$(100.1)
PRINT CVD(b$),LEN(b$)
--> Prints the numbers 1000, 4, 100.1, and 8 on the screen.
Memo: For more information on the internal storage of floats see pages
'GFA-Basic v3 float format' and 'ST-Basic float format'.
CINT
CINT(x)
CFLOAT(y)
x: aexp
y: iexp
The function CINT() changes a floating point number 'x' into a rounded integer
value.
CFLOAT() changes and integer 'y' into a floating point number. This function is
not normally required and is specified only for the sake of completeness. With
compiled programs, however, it has a use.
Example:
a=1.2345
a%=10000
b%=CINT(a)
b=CFLOAT(a%)
PRINT b%,b
--> Prints 1 and 10000 on the screen.
Pointer Operations
PEEK(), DPEEK(), LPEEK()
POKE, DPOKE, LPOKE
SPOKE, SDPOKE, SLPOKE
BYTE{}, WORD{} (INT{}), LONG{} ({}), FLOAT{}
CARD{}, SINGLE{}, DOUBLE{}
CHAR{}
VARPTR(), V:
ARRPTR(), * (as function/as command)
ABSOLUTE
PEEK
PEEK(x) DPEEK(x) LPEEK(x)
POKE x,y DPOKE x,y LPOKE x,y
SPOKE x,y SDPOKE x,y SLPOKE x,y
x, y: iexp
With the functions xPEEK() one can read from specified memory locations.
With the functions xPOKE one can write to specified memory locations.
The individual variants are:
PEEK(x) Reads a byte from the address x.
DPEEK(x) Reads two bytes (word) staring at address x.
LPEEK(x) Reads four bytes (long) staring at address x.
POKE x,y Writes the value y as a byte to the address x.
DPOKE x,y Writes the value y as a 2-byte word to the address x.
LPOKE x,y Writes the value y as a 4-byte long to the address x.
It is important that when using DPEEK() and LPEEK(), only even
addresses are given.
The xPEEK() functions always work in supervisor mode.
xPOKE instructions have variants which work in the supervisor mode. So
protected addresses, e.g. 0 to 2047, can be modified. The appropriate
instructions are SPOKE, SDPOKE and SLPOKE. Caution is advised, paricularly in
the supervisor mode, since modifications to protected addresses can have
serious consequences.
Example:
LPOKE XBIOS(14,1)+6,0
--> Sets the head and tail pointers to the keyboard buffer to the buffer start,
effectively erasing the buffer.
or alternately:
REPEAT
UNTIL INKEY$=""
--> Deletes the keyboard buffer, character by character.
WORD
BYTE{x}
WORD{x} (INT{x})
LONG{x} ({x})
FLOAT{X}
CARD{x}
SINGLE{x}
DOUBLE{x}
CHAR{x}
x: iexp
By means of these commands one can read certain variable types starting from a
given address, or write them to an address.
As a function, e.g. y=BYTE{x}, one can read, starting from the address x, and
as an instruction, e.g. BYTE{x}=y, one can write, again starting from address
x.
It is important when using WORD{}, CARD{}, LONG{}, FLOAT{}, SINGLE{}, and
DOUBLE{} that only even numbered addresses are specified, since
otherwise an address error occurs and three bombs are displayed.
Type Meaning
BYTE{} Reads/writes a byte.
CARD{} Reads/writes a 2-byte unsigned integer (0-65535).
WORD{} Reads/writes a 2-byte signed integer.
Instead of WORD{} you may use INT{} which has the same effect.
LONG{} Reads/writes a 4-byte integer.
Instead of LONG{x} you may use {x} which has the same effect.
FLOAT{} Reads/writes an 8-byte variable in GFA-Basic 3 floating-point
format.
SINGLE{} Reads/writes a 4-byte floating-point variable in IEEE
single-precision format.
DOUBLE{} Reads/writes an 8-byte floating-point variable in IEEE
double-precision format.
CHAR{} Reads a string of bytes until a null byte (zero) is encountered, or
writes the specified string of bytes and appends a null byte.
Paricularly important for communication with C routines and GEMDOS().
With x%=LONG{adr%} the variable x% is assigned the long-word value found at the
address adr%, and with LONG{adr%}=x% the value of x% is written as a long-word
to the address adr%.
With SINGLE{} and DOUBLE{} it is possible to read or write in IEEE format, used
by some 'C' compilers. So, with GFA-Basic, a number in the Single or Double
format can be converted and displayed in hexadecimal:
a$=SPACE$(4)
SINGLE{V:a$}=1.2345
PRINT HEX$(CVL(a$),8)
or
a$=SPACE$(8)
DOUBLE{V:a$}=1.2345
PRINT HEX$(LONG{V:a$},8)
PRINT HEX$(LONG{V:a$+4},8)
Some functions mentioned above approximately correspond: LONG{} for instance
corresponds to LPEEK(). However, LONG{} is quicker than LPEEK(), although it
will not work in the Supervisor mode. Attempting to access protected
memory locations (0 to 2047) with LONG{} will result in a bus error, with two
bombs displayed.
Examples:
adr%=XBIOS(2)
t%=TIMER
FOR i%=1 TO 4000
VOID LONG{adr%}
NEXT i%
PRINT (TIMER-t%)/200
'
t%=TIMER
FOR i%=1 TO 4000
VOID LPEEK(adr%)
NEXT i%
PRINT (TIMER-t%)/200
'
PRINT x
FLOAT{*x}=PI
PRINT x
--> The first part of the example shows that LONG{} works more quickly than
LPEEK(), and the second part demonstrates writing a floating-point number
indirectly to a variable.
BYTE{XBIOS(2)+100*160}=&HFF
CARD{XBIOS(2)+102*160}=&HFFFF
LONG{XBIOS(2)+104*160}=&HFFFFFFFF
'
a$="test"+CHR$(0)
PRINT CHAR{V:a$};
'
b$=SPACE$(5)
CHAR{V:b$}="word"
PRINT b$,ASC(RIGHT$(b$))
--> First, some values are written directly to the screen memory and appear as
lines. Then a$ is assigned conventionally, with a zero byte added, where
upon it is read with CHAR{} and printed. Then the word 'word' is written
into the space made for it by assigning b$ as five spaces. The reassigned
b$ is then printed, together with the ASCII code of its last character, to
prove that a null byte was indeed added to 'word'. The output is thus
'test', 'word', and '0'.
Memo:
t$=CHAR{addr%} does not check the resulting string size when compiled.
Always test your code in the interpreter!
VARPTR
VARPTR(x) V:x
ARRPTR(y) *y
x, y: variable name of any type
VARPTR(x) or V:x returns the address of variables or strings or particular
elements of arrays. VARPTR() and V: have the same effect.
ARRPTR(y) or *y returns the addresses of variables, but for strings or arrays
the address of the Descriptor is returned. ARRPTR() and * have the same effect.
Example:
DIM x%(10)
a$="test"
PRINT VARPTR(x%(0)),V:x%(1),ARRPTR(x%())
PRINT ARRPTR(a$),*a$,VARPTR(a$)
--> The third line prints the addresses of the first two elements of x%(),
together with the address of the Array Descriptor. The fourth line prints
the address of the String Descriptor twice, followed by the address of the
first byte of a$.
*x (indirect array passing)
x: svar or an array name followed by ()
The multiply sign also serves as a pointer symbol. In this case *x gives the
address of the variable x in memory. With character strings *x$ gives the
address of the String Descriptor (as with ARRPTR(x$)).
*x is synonymous with ARRPTR(x). This usage has special meaning with the
indirect passing of arrays and variables to subroutines. In addition one can
use, in Version 3, the instruction VAR.
* as a command:
*flt=0
*flt=""
*lng%=0
*lng%=""
Examples:
' Version 2 | ' Version 3
' | '
' indirect array passing | '
DIM a(3) | DIM a(3)
change(*a()) | change(a())
PRINT a(2) | PRINT a(2)
' | '
PROCEDURE change(ptr%) | PROCEDURE change(VAR x())
SWAP *ptr%,x() | ARRAYFILL x(),1
ARRAYFILL x() | RETURN
SWAP *ptr%,x() |
RETURN |
--> The contents of the array a() are changed, without its name being used in
the procedure 'change'. The number 1 is printed on the screen (see also
SWAP).
t%=0
GOSUB num(*t%)
PRINT t%
t$="set"
GOSUB str(*t$)
PRINT t$
PROCEDURE num(p%)
*p%=22
RETURN
PROCEDURE str(p%)
*p%="changed"
RETURN
--> Displays the number '22' and the word 'changed'.
Memo: Be careful using pointers to strings since GFA-Basic can move
them and so the pointer becomes invalid.
* as a command was never documented in the manual.
Poor example:
p%=V:buffer$
BMOVE XBIOS(2),p%,32000
p% can become invalid later on in the program
Good example:
BMOVE XBIOS(2),V:buffer$,32000
this method forces the address to be fetched on demand
String Descriptor
/-------------------------- <array_address%><number_of_dimensions&> (6 bytes)
| |
|
\-- <backtrailer%><block_size%><1st_dimension%><string_address%><string_length&>
|
/-----------------------------------------/ |
|
<string_data...><null_filler_if_odd_length|><string_backtrailer%>
Numeric Descriptor
/-------------------------- <array_address%><number_of_dimensions&> (6 bytes)
| |
|
\-- <backtrailer%><block_size%><1st_dimension%><array_data...>
REM DIM av%(2) !even with this line commented out, this works
addr%=*av%() !creates a null descriptor if the array does not exist
PRINT addr% !one would expect an 'array not dimensioned' error
ABSOLUTE
ABSOLUTE x,y
ABSOLUTE x=y
x: a variable of arbitrary type
y: iexp
With the instruction ABSOLUTE the address y is given to the variable x.
Exampe:
ABSOLUTE x,*y
x=13
y=7
PRINT x,y,*x,*y
--> Here the variable x is assigned to the address of variable y, so that at
the end both variables have the same value (7) and same address.
Memo: This command does not work with array type variables.
For string variables: ABSOLUTE a$,*b$ !works
ABSOLUTE a$,V:b$ !crash
ABSOLUTE a$,value !crash
Deleting and Exchanging
CLEAR
CLR
ERASE
SWAP
INSERT, DELETE
QSORT, SSORT
CLEAR
CLEAR
CLR x[,y,...]
ERASE z1()[,x2(),...]
x, y: svar or avar
z1, x2: name of arbitrary array
With CLEAR all variables and arrays are emptied. The instruction cannot be used
within FOR-NEXT loops or subroutines. When a program is RUN it is implemented
automatically, otherwise it is really only applicable for dealing with serious
faults before using RESUME proc appropriately. All open channels will be close
as well.
The instruction CLR deletes the variables specified in the list following it.
Arrays cannot be deleted with CLR however.
ERASE deletes complete arrays, which can then be redimensioned if required. In
contrast to Version 2, several arrays can be deleted at once, for example ERASE
x(),y().
Example:
x=2
y=3
CLEAR
PRINT x,y
'
x=2
y=3
CLR x
PRINT x,y
'
DIM x(10)
PRINT FRE(0)
ERASE x()
PRINT FRE(0)
--> The above program prints three zeros and a '3' on the screen. After that
the amout of free memory is displayed both before and after the erasure of
x(), showing that the memory occupied by the array is released by ERASE.
Memo: The command ERASE should be avoided as it can lead to many hard to
find errors.
CLEAR closes all open channels, as if 'CLOSE' was executed.
This happens in the editor and compiled programs.
This information was missing from the manual.
Also clears the event flags for all 'ON x GOSUB' commands.
This only happens in the editor.
SWAP
SWAP a,b
SWAP e(),f()
SWAP *c,d()
a, b: avar or svar
c: pointer to an array descriptor
d, e, f: names of arrays
In its most simple variant the instruction SWAP serves to exchange two
variables of the same type (SWAP a,b), In addition, it can be used for
exchanging two arrays. The process is fast, since in fact only the associated
Descriptors are exchanged, having the effect of also exchanging the
dimensioning of the two arrays. Arrays do not need to be dimensioned for this.
The third variant, where one of the descriptors is addressed directly, is
mainly useful for the indirect passing of arrays to subroutines (see second
example).
Note: The instruction SWAP should be clearly differentiated from the
function SWAP(), which is discussed in the section on bit operations.
Examples:
x=1
y=2
PRINT x,y
SWAP x,y
PRINT x,y
--> Thc numbers 1, 2, and then 2 and 1 are displayed.
DIM x(3)
change(*x())
PRINT x(2)
'
PROCEDURE change(adr%)
SWAP *adr%,a()
ARRAYFILL a(),1
SWAP *adr%,a()
RETURN
--> The array x() is filled with 1's in the procedure CHANGE without reference
to the name x(), so the subroutine is of general use. The Descriptor
address is handed over to the subroutine and by means of SWAP, the array is
addressed under the name a().
In Version 3 the array name itself can be passed:
DIM x(3)
change(x())
PRINT x(2)
'
PROCEDURE change(VAR a())
ARRAYFILL a(),1
RETURN
QSORT
QSORT a([s]) [,n[,j%()]]
QSORT s$([s]) [OFFSET o] [WITH i()] [,n[,j%()]]
SSORT a([s]) [,n[,j%()]]
SSORT s$([s]) [OFFSET o] [WITH i()] [,n[,j%()]]
a(): arbitrary array, or string array
i(): integer-array (|, & or %) with at least 256 entries
j%(): 4-byte integer array
s$(): string array
n: iexp
o: iexp
s: +, -, or no sign
You can xSORT string fields with an OFFSET only from version 3.02 on wards.
The OFFSET determines how many characters off the beginning shall not be
considered; e.g.
DIM a$(256)
FILES "*.*" TO "LISTE"
OPEN "I",#1,"LISTE"
RECALL #1,a$(),-1,x%
CLOSE #1
QSORT a$() OFFSET 13,x%
OPEN "O",#1,"CON:"
STORE #1,a$(),x%
CLOSE #1
This program gives the directory as a file "LISTE", with RECALL the array a$()
gets the contents, then the directory is sorted and STOREd to "CON:". By giving
the OFFSET 13 it is not sorted by name but by the length of the files. " " and
"*" and "12345678.123" is skipped.
The instructions SSORT and OSORT allow the elements of an array to be sorted
according to their size. SSORT utilizes the Shellsort and OSORT the Ouicksort.
In the brackets of the array name a plus or minus sign may be inserted, meaning
that the sort is to be done in ascending or descending order respectively. If
neither is specified, the sort by default will be done in ascending order, as
with "+".
The parameter "n" specifies that only the first "n" elements of the array are
to be sorted. If OPTION BASE 0 is active (the default) these are the elements
from 0 to n-1; if OPTION BASE 1 is active then elements from 1 to n are sorted.
If n=-1 then the whole array will be sorted.
When a further integer array is specified as the third parameter, that array
will be sorted along with the first array. Each exchange of elements in the
first array is also carried out in the second. This facility can be used, for
example, if one array contains a sort code, e.g. a post code, and another array
contains related information.
During the sorting of string arrays a sorting criterion can be specified in
form of an array with at least 256 elements by means of WITH. Without
indication of WITH the normal ASCII order is used as a sorting criterion (see
second example).
Examples:
DIM x%(20)
PRINT "Unsorted: ";
FOR i%=0 TO 10
x%(i%)=RAND(9)+1
PRINT x%(i%);" ";
NEXT i%
PRINT
'
QSORT x%(),11
DIM index%(210)
PRINT "Descending sort: ";
FOR i%=0 TO 10
PRINT x%(i%);" ";
index%(i%)=i%
NEXT i%
PRINT
'
SSORT x%(-),11,index%()
PRINT "Ascending sort: ";
FOR i%=0 TO 10
PRINT x%(i%);" ";
NEXT i%
PRINT
PRINT "Sort WITH array: ";
FOR i%=0 TO 10
PRINT index%(i%);" ";
NEXT i%
--> Gives an unsorted field and two sorted series from random numbers. In a
fourth row the values of a second field that was sorted alongside the first
one displayed.
Memo: These commands use self modifying code internally and may not work
correctly on CPUs with caches, such as an 060.
INSERT
INSERT x(i)=y
DELETE x(i)
x: name of an array
i: iexp
y: aexp or sexp, according to variable type of the array
With the instruction INSERT an array element can be inserted. With the
instruction DELETE an array element can be deleted.
INSERT inserts the value of the expression y in the array x() at the position
i. All elements of the array which have an index larger than i are shifted up
one position. Thus if an element stood at position 3 before, then it will be
found at position 4 after the INSERT instruction. The last element of the array
is deleted.
DELETE removes the i-th element of the array x(). All array elements which have
an index larger than i are shifted down one position. The last element of the
array is made zero (or a null string with character string arrays).
These instructions are highly suitable for the management of lists, in which
elements are constantly being inserted or deleted.
Examples:
DIM x%(5)
FOR i%=1 TO 5
x%(i%)=i%
NEXT i%
INSERT x%(3)=33
FOR i%=0 TO 5
PRINT x%(i%)
NEXT i%
--> The numbers 0, 1, 2, 33, 3, and 4 are printed on the screen.
DIM x%(5)
FOR i%=1 TO 5
x%(i%)=i%
NEXT i%
DELETE x%(3)
FOR i%=0 TO 5
PRINT x%(i%)
NEXT i%
--> The numbers 0, 1, 4, 5, and 0 are printed on the screen.
Memo: This works in the editor but not compiled: INSERT a%(j&)=a%(j&+1)
Boolean arrays are not supported by these commands.
Reserved Variables
FALSE,TRUE
PI
DATE$, TIME$
DATE$=, TIME$=
SETTIME
TIMER
_C, _X, _Y
PI
FALSE
TRUE
PI
The logical constant FALSE returns the value 0.
The logical constant TRUE returns the value -1.
The constant PI returns the value of the transcendental number pi
(3.14159265359).
Example:
PRINT FALSE
IF TRUE
PRINT PI
ENDIF
--> Prints the numbers 0 and 3.14159265359 on the screen.
Memo: Be very careful porting source code from other languages.
Often TRUE returns 1 in other languages.
SETTIME
DATE$
TIME$
SETTIME time$,date$
DATE$=date$
TIME$=time$
TIMER
time$, date$: string variable
DATE$ returns the system date in the format:
DD.MM.YYYY (Day, Month, Year)
or
MM/DD/YYYY (US format, see MODE)
Note: Only years between 1980 and 2079 are allowed.
TIME$ returns the system time in the format:
HH:MM:SS (Hours, Minutes, Seconds)
Note: The time is updated every two seconds.
With the instuction SETTIME both the date and time can be set. The strings must
have the same format as for TIME$ and DATE$. If SETTIME is given strings in the
wrong format, then the current values are not changed.
The date and time can also be set individually with DATE$= and TIME$=.
TIMER returns the elapsed time in 1/200 of a second since the system was
powered up.
Examples:
PRINT DATE$,TIME$
SETTIME "20:15:30","27.2.1988"
PRINT DATE$,TIME$
--> The system date and time are printed, reset, and printed again.
t%=TIMER
FOR i%=1 to 2500
NEXT i%
PRINT (TIMER-t%/200)
--> The time in seconds required for the FOR-NEXT loop is displayed.
Memo: t%=TIMER is the same as t%=LPEEK(&H4BA). Returns system timer B.
I suppose its possible the TIMER could roll over eventually, one idea is
to use this method: diff%=ABS(TIMER-tsave%)
TIME$ is returned in 24 hour format, same as GEMDOS().
Tgetdate()+, Tgettime()+, Tsetdate()+, Tsettime()+, Settime()+
_C
_C
_X
_Y
_C returns the number of color registers.
_X returns the current window width in pixels.
_Y returns the current window height in pixels.
Memo: _C = WORK_OUT(13) which is safe to use.
_X and _Y are initialized via Line-A variables and then changed by some
window commands if used.
_X -> V_REZ_HZ (Line-A variables)
_Y -> V_REZ_VT
Avoid, _X and _Y as they change based on the window commands used.
_X and _Y return width and height unlike the WORK_OUT() values which are
the maximum coordinates allowed. Thus: _X = WORK_OUT(0)+1
ST low resolution example:
_X=320 _Y=200
WORK_OUT(0)=319 WORK_OUT(1)=199
Line-A Variable Table+
Special
LET
VOID, ~
LET
LET x=y
x: avar or svar
y: aexp or sexp
With LET, values can be assigned to variables whose names are keywords.
By means of LET one can transfer the value of an expression to a variable. The
expression and the variable must either be both numerical or both character
strings. Normally LET is not necessary: it served in older BASIC's to allow the
use of keywords as variable names. However, GFA-Basic usually recognizes
automatically when a keyword is used in this way and allows it.
Example:
LET print=3
PRINT print
--> The number '3' is displayed on the screen.
VOID
VOID fx
~fi
fx: aexp
fi: iexp
VOID invokes a function but ignores the returned value.
Programming langnages normally differentiate between commands and functions.
Both cause some activity to be carried out, but with functions this activity
'returns' a value, which may be used as an element of an expression, displayed
with PRINT or assigned to a variable etc.
Often, however, the programmer is not interested in the returned value, but
only in the activity carried out. For example, the function INP(2) returns the
ASCII code of a pressed key. If the program is only supposed to wait for a key,
any key, to be pressed, then the code of the key is irrelevant.
With GFA-Basic, in such a case VOID can be used to implement the function,
'forgetting' about the returned value. The alternative form (with a tilde '~'
instead of VOID calculates an integer value before forgetting it, making it
faster than VOID, which calculates a floating-point value.
Example:
VOID INP(2)
or
~INP(2)
--> Waits for a key to be pressed. Which key it was, however, will be unknown
to the program, as the returned code is lost.
Memo: Void cannot be used with string functions:
VOID INPUT$(28,#1) !syntax error
This trick works:
~LEN(INPUT$(28,#1))
Memory Management
FRE()
BMOVE
BASEPAGE, HIMEM
RESERVE
INLINE
MALLOC(), MSHRINK(), MFREE()
Memo: For inforamation related to the compiler and memory management see
section 'Reserving Memory Space'.
FRE
FRE([x])
x: aexp
This function computes the amount of free available memory. The parameter x is
ignored, but if it is present a 'Garbage Collection' is carried out first
(non-current versions of strings are deleted and the memory occupied by them
freed). FRE() results in the free memory being calculated without the Garbage
Collection.
Example:
free%=FRE(0)
max%=free%/3/4
DIM x%(max%)
PRINT free%,max%
--> An array is dimensioned so that it occupies for instance a third of the
free memory space. An integer array occupies 4 bytes per element, thus the
extra division by 4.
Memo: A compiled program should regularly force a 'Garbage Collection' to
insure that the program does not run out of string space. There is a bug
related to the Garbage Collection. If the string ram drops to low
(within 16 bytes of running out of ram) a crash can occur.
Example:
IF FRE()<32768 !less than 32k of free ram inside our program?
~FRE(0) !force garbage collection and free unused strings
ENDIF
BMOVE
BMOVE source,destination,length
source, destination, length: iexp
BMOVE copies a block of memory from one area to another. 'source' is the
address of the first byte of the block to be copied, 'destination' is the
address of the first byte of the area to which the block is to be copied, and
'length' is the length of the block.
The instruction works noticeably faster with even parameters than with odd. It
also works if the source and destination areas overlap.
Example:
DIM screen2%(64000/4)
adr%=VARPTR(screen2%(0))
FOR i%=0 TO 300 STEP 100
PBOX 0,i%,639,i%+50
NEXT i%
PRINT "hi there!"
' XBIOS(2) = the start-of-screen address
BMOVE XBIOS(2),adr%,32000
BMOVE XBIOS(2),adr%+32000,32000
REPEAT
IF MOUSEY<>my%
BMOVE adr%+my%*80,XBIOS(2),32000
my%=MOUSEY
ENDIF
UNTIL MOUSEK=2
--> Vertical movement of the mouse scroll the screen up and down.
BASEPAGE
BASEPAGE
HIMEM
In the variable BASEPAGE is the address of the Basepage of the GFA-Basic
Interpreter, BASEPAGE is a 256-byte long storage area as follows:
Bytes Contents
0- 3 Address of the start of TPA (Transient Program Area)
4- 7 Address of the end of TPA plus 1
8- 11 Address of Text segment of the program
12- 15 Length of the Text segment
16- 19 Address of the Data segment
20- 23 Length of the Data segment
24- 27 Address of the BSS (Block Storage Segment)
28- 31 Length of the BSS
32- 35 Address of the DTA (Disk Transfer Address)
36- 39 Address of the Basepage of the calling program
40- 43 Reserved
44- 47 Address of the Environment Strings
48-127 Reserved
128-255 Command line (first byte specifies length of command text)
The variable HIMEM gives the address of the first free memory location not
used by GFA-Basic. This is normally 16384 bytes below the screen area.
Example:
a%=LONG{BASEPAGE+&H2C}
DO
a$=CHAR{a%}
EXIT IF LEN(a$)=0
PRINT a$
ADD a%,SUCC(LEN(a$)) ! SUCC() = next higher integer
LOOP
--> Here the complete BASIC Environment is displayed.
Memo: BASEPAGE as defined by MiNT -> BASEPAGE.H
HIMEM should be avoided. If you need additional ram see MALLOC().
BASEPAGE+32 will change if one calls FSETDTA().
comp_!=BYTE{BASEPAGE+256}<>96 !false=interpreted/true=compiled
96 = interpreted (bra.s)
65 = compiled (lea)
dacc_!=LONG{BASEPAGE+36}=FALSE !false=prg/true=acc
0 = acc
>0 = prg
BASEPAGE+
RESERVE
RESERVE [n]
n: iexp
The size of the storage area used by GFA-Basic can be specified. If n is
positive, then n bytes are reserved for the Interpreter and the remainder is
released. If n is negative, then the whole of the free memory less n bytes is
reserved.
If no parameter is specified, the state when the Interpreter was started is
restored.
Note: Memory can be reserved only in blocks of 256 bytes.
The instruction can be used, for instance, in order to release a storage area
for data or Resource files. If the storage area for GFA-Basic is reduced with
RESERVE, then one should not forget to enlarge it again later since otherwise
the available space becomes smaller with each execution of the program.
Example:
RESERVE 2560
EXEC 0,"\PROGRAM.PRG","",""
RESERVE
--> 2560 bytes are reserved for the Interpreter, and PROGRAM.PRG (if available)
is loaded and started. After exiting from PROGRAM.PRG the reserved space is
restored.
Memo: Should not be used in compiled programs. Use $mx instead.
RESERVE with no parameter appears to be broken. Very unstable under
multi-tasking operating systems, such as MiNT.
INLINE
INLINE addr,length
addr: 4-byte integer variable, (not an array variable)
length: integer constant, less than 32700
This instruction reserves an area of memory within a program.
No comment is possible on the same line as this instruction, since memory is
internally reserved where otherwise the comment would be.
The reserved area always begins at an even address and it is initially filled
with zeros. When implementing INLINE this address is written to the integer
variable addr. When the program is loaded or saved, the reserved memory area is
also.
Positioning the cursor on the program line which contains the INLINE
instruction and pressing the Help key causes a menu line with the entries Load,
Save, Dump, and Clear to appear on the top line of the editor.
Load is used to load a machine code program or data into the reserved area.
Save saves the contents of the reserved area to disk.
Dump causes a hexadecimal printout on the printer of the reserved area.
Clear fills the reserved area with zeros.
If the INLINE instruction is deleted, so also is the reserved area.
The default file extension is '.INL'.
In to this storage area, for instance, could be put pictures, tables or machine
code programs.
Example:
See the example for C: in the system routines section.
Memo: length&=WORD{addr%-4} (this works in the interpreter only)
The editor will not accept values over 32746, entering any value over
this can cause strange behavior and/or a crash. Enter the value very
carefully, once the editor issues the 'line to long' error message, it's
too late!
The editor will also accept -negative values and crash the moment you
press the return key!
The editor will aslo accept 0 as a size which does not appear to be
fatal. However, one has to wonder what use this would have?
Loading a file that is too large for the inline does not produce a
warning of any kind. It will be truncated at the size of the inline.
However it will complain 'end of file reached' if the file size is
smaller than the inline size.
It's not neccessary to strip the 28 byte header from assembler routines.
The magic number $601A at the start of such a routine is actually a
'bra.s start_addr+28' instruction. The header is effectively skipped,
however removing the header will save you 28 bytes and one less
instruction per call.
When a program is compiled the INLINEs end up perfectly stacked one after
another in the order they are encountered. Example: If you have 3 INLINEs
exactly 10 bytes each, the 3rd INLINE can be located by adding 20 to the
address of the first INLINE. In theory you could reserve 64000 bytes
simply by defining 2 INLINEs 32000 bytes each one after the other. This
however is only valid when compiled.
ASM only appears if started from GFA Assembler. See GFA Assembler manual.
Note: The oddly placed clock character appears to be a typo. It does not
do anything.
MALLOC
MALLOC(x)
MSHRINK(y,z)
MFREE(y)
x, y, z: iexp
The function MALLOC() (GEMDOS 72) is used to reserve (allocate) areas of
memory.
If the parameter x is equal to -1, then the function returns the length of the
largest contiguous free area. If x is a positive number, then this means that x
bytes are to be reserved. In this case MALLOC() returns the start address of
the reserved area. If a fault occurred with the reservation attempt, then the
value 0 is returned.
If larger areas are to be allocated, then first some of GFA-Basic's memory must
be freed with RESERVE.
Allocated storage areas must always be released before the end of the program,
although this is accomplished automatically when leaving the Interpreter.
MSHRINK() (GEMDOS 74) will reduce the size of a storage area previously
allocated with MALLOC(). The parameter y specifies the address of the reserved
storage area (which was returned by MALLOC()). The second parameter z gives the
required (shrunk) size.
The function MSHRINK() returns 0 if the reduction was made without difficulty,
-40 if an incorrect address was given as y, or -67, if the new desired size was
larger than the current size. It is important with MFREE() and MSHRINK() that
an incorrect address is never given.
MFREE() (GEMDOS 73) releases the storage location reserved with MALLOC(). The
parameter y specifies the start address of the memory area to be released
(which was returned by MALLOC()). If the release occurred without problems, the
value 0 is returned, otherwise a negative number is returned.
Example:
RESERVE 1000
PRINT MALLOC(-1)
adr%=MALLOC(60000)
PRINT adr%
IF adr%>0
x%=MSHRINK(adr%,30000)
y%=MFREE(adr%)
ENDIF
RESERVE
--> GFA-Basic's usable memory is reduced to 1000 bytes, and then the size of
the largest free memory area is printed. Then an attempt is made with
MALLOC() to reserve 60000 bytes. If the reservation was successful, i.e.
adr% is not zero, MSHRINK() is used to reduce the size of the reserved area
to 30000 bytes, finally MFREE() releases the memory again.
Memo: A desk accessory should allocate all the ram it needs prior to
entering it's main event loop. On older TOS versions the current running
application will actually own the ram allocated by the accessory. This
will be the desktop itself if you follow this rule, but since the desktop
cannot be exited it's not a problem.
MSHRINK() appears to be completely broken when compiled. Use GEMDOS(74)
instead.
MALLOC() under MiNT with or without memory protection rounds all values
up to a page size. Page size -> 8192 bytes
> FUNCTION mshrink(addr%,size%)
$F%
RETURN GEMDOS(74,W:FALSE,L:addr%,L:size%)
ENDFUNC
Malloc()+, Mxalloc()+, Mshrink()+, Mfree()+
Chapter 3 - Operators
Operators in a programming language serve to link and compare elements in
numeric and logical expressions.
In this chapter the operators available in GFA BASIC V3 are introduced in the
following five sections.
In the first section the numerical operators +, -, *, /, ^, DIV, \, and MOD are
discussed. They link two numerical expressions and produce a number, which can
then be assigned to variables with the equals sign (=). The operators + and -
have a secondary function as unary operators, giving a sign to a number (+1, -2
etc.).
The second section deals with the logical operators AND, OR, XOR, NOT, IMP, and
EQV. They link two logical expressions and produce a logical result (TRUE or
FALSE). The operator NOT has a special role in that it works on only one
logical expression and reverses its logical value (TRUE becomes FALSE and vice
versa).
The third section deals with the concatenation (joining) of string expressions
using the plus sign (+).
The next section describes the comparison operators, which compare two
numerical or two string expressions and produce a logical result (TRUE or
FALSE).
The last section details the order in which operators are processed if several
occur in one expression, and the use of the bracket symbols ( and ), by means
of which the order of processing can be governed.
Arithmetic Operators
+ - * /
^
DIV \
MOD
+n -n
n: number
These arithmetic operators link two numerical expressions and produce a number.
This number can then be used as part of another expression, assigned to a
variable, printed out with PRINT, etc. The operators + and - are also used as
signs to indicate whether numbers are positive or negative (-1, +2, etc.).
x+y Produces the sum of the numbers x and y (addition)
x-y Produces the difference of the numbers x and y (subtraction)
x*y Produces the product of the numbers x and y (multiplication)
x/y Produces the quotient of x divided by y (division)
x^y Produces x raised to the power y (exponentiation)
x DIV y Results in a fast integer division of x by y
x\y The backslash '\' character is an alternative form of DIV
x MOD y Produces the remainder of the division of x by y.
+ provides the value n with a positive sign, unless it was negative, in which
case it is left as it was.
- provides the value n with a negative sign. If is was positive, it is treated
as negative and vise versa.
The following relations are equivalent:
x DIV y = TRUNC(x/y)
x MOD y = x-y*TRUNC(x/y)
(TRUNC() is the Truncate function.)
Example:
13 DIV 4 produces 3
13 MOD 4 produces 1
Memo: Additional reading related to the compiler, see sections
'Integer Division' and 'Integer Multiplication'.
Logical Operators
AND, OR, XOR
NOT, IMP, EQV
These logical operators work at the bit level for 32-bit integer values.
Logical operators link two logical expressions and produce a logical result
(TRUE or FALSE). The operator NOT is an exception, in that it negates the value
of a given expression.
The numerical value for FALSE is 0, and for TRUE is -1.
For those interested in why these values should be chosen, the reason is that
TRUE is considered to be all ones in a 32-bit integer, and FALSE to be all
zeros. Thus:
11111111111111111111111111111111 = TRUE
and
00000000000000000000000000000000 = FALSE
Those familiar with two's complement arithmetic will recognize that the former
is the two's complement notation for -1.
All logical operators can also be applied to numerical expressions. In this
case the logical operations are implemented bit by bit. The effects of logical
operators will be described with so-called truth tables. In these tables the
logical values of the linked expressions are given in the first columns, and
the result in the last column.
NOT
NOT x
x: iexp
The operator NOT negates a given logical expression. It is the only logical
operator, which has a single argument. Each individual bit of the argument is
modified.
x | NOT x
--|------
T | F
F | T
Examples:
PRINT NOT FALSE
PRINT NOT TRUE
PRINT NOT 0
--> The numbers -1, 0, and -1 appear on the screen.
x=1
PRINT BIN$(x,2)
PRINT BIN$(NOT x,2)
--> 01 and 10 appear on the screen.
x%=17
PRINT BIN$(x%,8),x%
PRINT BIN$(NOT x%,8),NOT x%
--> Displays 00010001, 17, 11101110, and -18 on the screen.
AND
x AND y
x, y: iexp
The logical operator AND (conjunction) checks whether two logical expressions x
and y are both true. Only in this case it produces the value TRUE (-1). If one
or both logical expressions are wrong, then AND produces a logical FALSE. With
AND each pair of the 32 bits is tested independently.
x | y | x AND y
--|---|--------
T | T | T
T | F | F
F | T | F
F | F | F
Examples:
PRINT TRUE AND -1
PRINT FALSE AND TRUE
--> On the screen the numbers -1 and 0 appear.
x=3
y=10
PRINT BIN$(x,4)
PRINT BIN$(y,4)
PRINT BIN$(x AND y,4),x AND y
--> Displays 0011, 1010, 0010, and 2 on the screen.
OR
x OR y
x, y: iexp
The command OR (disjunction) checks whether at least one of two logical
expressions x and y is TRUE. Only if x and y are both FALSE will the result
FALSE be produced. Unlike XOR, (see below) a TRUE result from OR means that one
or both arguments are TRUE. OR also works at the bit level with numbers.
x | y | x OR y
---|---|-------
T | T | T
T | F | T
F | T | T
F | F | F
Examples:
PRINT TRUE OR -1
PRINT FALSE OR TRUE
PRINT 0 OR FALSE
--> The numbers -1, -1, and 0 are displayed.
x=3
y=10
PRINT BIN$(x,4)
PRINT BIN$(y,4)
PRINT BIN$(x OR y,4),x OR y
--> Displays 0011, 1010, 1011, and the number 11 appear on the screen.
XOR
x XOR y
x, y: iexp
The XOR operator produces the value TRUE if one, but not both, of the arguments
is TRUE. If they are both TRUE, or both FALSE, the result is FALSE.
Unlike OR, where TRUE OR TRUE = TRUE, TRUE XOR TRUE = FALSE. (XOR is the
Boolean Exclusive Disjunction operation.)
Again, XOR works individually on each of the 32 bits of numeric arguments.
x | y | x XOR y
--|---|--------
T | T | F
T | F | T
F | T | T
F | F | F
Examples:
PRINT FALSE XOR -1
PRINT -1 XOR 1
PRINT 0 XOR FALSE
--> The numbers -1, -2, and 0 are printed on the screen.
x=3
y=10
PRINT BIN$(x,4)
PRINT BIN$(y,4)
PRINT BIN$(x XOR y,4),x XOR y
--> Displays 0011, 1010, 1001, and 9 on the screen.
IMP
x IMP y
x, y: iexp
The operator IMP (Implication) corresponds to a logical consequence. The result
is only FALSE if a FALSE expression follows a TRUE one. IMP also works at the
bit level. Unlike AND, OR, XOR, and EQV, the sequence of the arguments is
important.
x | y | x IMP y
--|---|--------
T | T | T
T | F | F
F | T | T
F | F | T
Examples:
PRINT TRUE IMP -1
PRINT 0 IMP FALSE
PRINT TRUE IMP 0
--> The numbers -1, -1 and, 0 appear on the screen.
x=3
y=10
PRINT BIN$(x,4)
PRINT BIN$(y,4)
PRINT BIN$(x IMP y,4)
--> Displays 0011, 1010, and 1110 on the screen.
EQV
x EQV y
x, y: iexp
The operator EQV (Equivalence) produces a TRUE result only if the arguments are
both TRUE or both FALSE. EQV works at the bit level and sets the bits which are
same in both arguments. This is exactly the opposite of XOR, so x EQV y is the
same as NOT (x XOR y).
x | y | x EQV y
--|---|--------
T | T | T
T | F | F
F | T | F
F | F | T
Example:
PRINT TRUE EQV FALSE
PRINT FALSE EQV FALSE
--> On the screen the numbers 0 and -1 appear.
x=3
y=10
PRINT BIN$(x,4)
PRINT BIN$(y,4)
PRINT BIN$(x EQV y,4)
--> Displays 0011, 1011, and 0110 on the screen.
Concatenation Operator
a$+b$
a$, b$: sexp
The operator '+' also serves to link character strings together. The result is
a character string, composed of a$ and b$.
Example:
a$="GFA-"
PRINT a$+"BASIC"
--> The text 'GFA-BASIC' appears on the screen.
Comparison Operators
=
<
>
==
<= (=<)
>= (=>)
<> (><)
With these numerical, logical, and string expressions can be compared with each
other. The result of this comparison is always one of the logical values TRUE
(-1) or FALSE (0). The operator '==' is an exception: string expressions cannot
be compared with it.
=
x=y
x, y: exp
The operator '=' compares two numerical or string expressions for equality. If
the two expressions are equal, then the result is logically TRUE, otherwise it
is FALSE.
Example:
x=6
IF 2=x/3
PRINT "Ok"
ENDIF
PRINT 2=x/3
--> 'Ok' and -1 appear on the screen.
==
x==y
x, y: aexp
The operator '==' compares two numerical expressions for approximate equality.
With this operator only eight and one half decimal places (28 bits of the
mantissas of floating-point numbers) are compared. '==' is useful for comparing
floating-point numbers, where inaccuracies due to rounding can occur.
Examples:
PRINT 1.0000000001=1
PRINT 1.0000000001==1
--> The numbers 0 and -1 are displayed.
a=SINQ(77) !SINQ() (degrees) is a quick, less accurate SIN() function
b=SIN(RAD(77)) !RAD() converts from degrees to radians
PRINT a=b
PRINT a==b
--> The numbers 0 (logically FALSE) and -1 (TRUE) appear.
<
x<y
x>y
x<=y
x>=y
x, y: exp
These operators serve to compare the size of numerical and string expressions.
With numerical expressions the values are compared, and with string expressions
the comparison depends on the ASCII codes of the characters. The string "ABC"
is treated as the number sequence 65, 66,and 67.
In the comparison "ABC">"AAA", the first characters are compared, which both
have the ASCII code 65. Then the next character is compared. There "B" has a
higher code value than "A", and "B" is then taken as the 'larger'.
Here the comparison of the two strings is broken off, and the statement "ABC"
is larger than "AAA" is deemed logically TRUE.
A special case of the comparison crops up if the two strings end before an
inequality is discovered. An example would be: "AA">"A". This statement is
rated logically TRUE, as is "A"+CHR$(0)>"A".
Now to the individual operators:
x>y TRUE if x is greater than y.
x<y TRUE if x is less than y.
x>=y TRUE if x is greater than, or equal to y.
x<=y TRUE if x is less than, or equal to y.
The following are equivalent ways of writing the same expressions:
x<=y or x=<y
x>=y or x=>y
Example:
PRINT "AAA">"aaa"
PRINT -1<=4-5
--> The numbers -1 and -1 are printed.
<>
x<>y
x, y: exp
This operator checks whether two numerical or string expressions are unequal.
If this is the case, then the statement x<>y is logically TRUE. If x and y are
the same, then the result of x<>y is logically FALSE.
The expressions x<>y and x><y are equivalent.
Example:
PRINT "test"<>"test"
PRINT -1<>4-5
--> 0 and 1 appear on the screen.
Assignment Operator
x=y
x: var
y: exp
The equals sign '=' can be used not only as a comparison operator, but also to
assign a value to a numeric or string variable. The value of the expression y
on the right of the equals sign is determined and assigned to the variable on
the left.
Numerical expressions can only be assigned to numerical variables, and
character string expressions can only be assigned to string variables.
Optionally, the command LET may be used, which also permits the assignment of
values to variables which have the same names as keywords.
Example:
x=LEN("TEST")+3
a$=GF+CHR$(65)
PRINT x,a$
--> On the screen 7 and 'GFA' appear.
Hexadecimal, Binary, and Octal notation can also be used.
Notation Prefix
Hexadecimal &H
Binary &X
Octal &O
Example:
LET test&=&H80 !hex notation
LET test&=&X10000000 !bin notation
LET test&=&O200 !oct notation
--> test& is assigned the value '128' in Hex, Bin, and Oct notation
Operator Hierarchy
If several operators are used in an expression, they are processed in a certain
order, which depends on the operator's place in the so-called operator
hierarchy. The operators at the top of this hierarchy are processsed first. The
hierarchy is as follows:
() Brackets
+ Character string addition
= < > => <= <> Character string comparison
+ - Signing
^ Exponentiation
* / Multiplication, division
DIV MOD Integral and modulo division
+ - Addition, subtraction
= == < <= >= > <> Numeric and logical comparison
AND OR XOR IMP EQV Logical operators
NOT Negation
By means of the brackets it is possible to force lower-precedence operators to
be processed before those higher up the hierarchy.
Example:
PRINT 2+4*3
PRINT (2+4)*3
PRINT 2+(4*3)
PRINT 3*2^2
--> The numbers 14, 18, 14, and 12 appear on the screen.
Chapter 4 - Numerical Functions
There are numerical functions for the following tasks: the functions ABS() and
SGN() return the absolute value and the sign of a numerical expression. ODD()
and EVEN() check whether a number is odd or even. INT(), TRUNC(), FIX(), and
FRAC() deal with separate manipulation of the parts of a number to the left and
to the right of the decimal point. ROUND() rounds an expression. MAX() and
MIN() return the largest or the smallest of several numerical expressions and
SQR() the square root of an expression. The trigonometrical functions are
SIN(), COS(), TAN(), ASIN(), ACOS(), and ATN(). SINQ() and COSQ() are faster,
less accurate alternatives for SIN() and COS(). EXP() and LOG() compute powers
and logarithms. LOG10() computes logarithms to base 10. DEG() and RAD()
transform values from radians to degrees and vice versa. RND(), RANDOM(),
RAND(), and RANDOMIZE deal with the generation of random numbers.
Mathematical Functions
ABS(), SGN()
EVEN(), ODD()
INT(), TRUNC(), FIX(), FRAC()
ROUND()
MIN(), MAX()
SQR()
EXP(), LOG(), LOG10()
SIN(), COS(), TAN()
ASIN(), ACOS(), ATN()
SINQ(), COSQ()
DEG(), RAD()
FACT(), VARIAT(), COMBIN()
SCALE()
ABS
ABS(x)
SGN(x)
x: aexp
The function ABS() returns the absolute value of a numerical expression. The
returned value is the same as the given value, except that its sign is ignored.
The sign of the returned value is always made positive.
With the function SGN() one can determine the sign of a numerical expression
thus:
x SGN(x)
Negative -1
Equal to 0 0
Positive 1
Example:
x=-2
y=ABS(x)
PRINT SGN(x),ABS(5-3),SGN(ABS(x*3))
--> Displays the numbers -1, 2, and 1.
EVEN
EVEN(x)
ODD(x)
x: aexp
This function checks whether the numerical expression x is even. EVEN() results
in TRUE for an even x and FALSE for an odd x. Zero (0) is treated as an even
number.
x EVEN(x)
Even -1 (TRUE)
Odd 0 (FALSE)
Zero -1 (TRUE)
This function checks whether the numerical expression x is odd. ODD() returns
the value -1 (TRUE), if x is odd and 0 (FALSE) if x is even. Zero (0) is
treated as an even number.
x ODD(x)
Even 0 (FALSE)
Odd -1 (TRUE)
Zero 0 (FALSE)
Example:
x=2
PRINT ODD(x),EVEN(-2),ODD(3*5),EVEN(-3*x)
--> The numbers 0, -1, -1, and -1 are displayed.
Memo: These functions convert all types to float format regardless.
For integers only this will work:
FUNCTION odd(int%)
$F%
RETURN BTST(int%,0)
ENDFUNC
INT()
INT(x)
TRUNC(x)
FIX(x)
FRAC(x)
x: aexp
These functions allow independent manipulation of the parts of a numerical
expression to the left and right of the decimal point: INT(), TRUNC(), and
FIX() (TRUNC() and FIX() are identical) return a whole number.
The function TRUNC() simply cuts off the digits to the right of the decimal
point.
INT() returns the largest whole number which is less than or equal to x. There
is no difference between TRUNC() (or FIX()) and INT() for positive x-values,
however, with a negative, non-integer x a difference arises. So TRUNC(-1.2)
removes the decimal places and returns -1 as the result. INT(-1.2), on the
other hand, returns the next smaller whole number, namely -2.
FRAC() returns only the fractional part of x, in other words just the decimal
places, with the same sign as x had. FRAC() is complementary to TRUNC() and
not to INT(). It is always true that x=TRUNC(x)+FRAC(x), but INT(x)+FRAC(x) is
not equal to x for negative values.
Example:
x=-1.4
y=TRUNC(1.3)
PRINT y,INT(x),FIX(3*x),FRAC(x-3)
--> The numbers 1, -2, -4 and -0.4 are displayed.
ROUND
ROUND(x[,n])
x: aexp
n: iexp
The function ROUND(x) returns x rounded to the nearest whole number. The
variant ROUND(x,n) rounds the expression x to n decimal places. If n is zero,
the effect is the same as for ROUND(x). If n is negative, the rounding is done
before the decimal point, so ROUND(155,-1) results in the number 160,
(Note: CINT() also rounds with an Integer result.)
Examples:
y=ROUND(-1.2)
PRINT y,ROUND(1.7)
--> Displays -1 and 2 on the screen.
FOR i%=-5 TO 5
PRINT i%,ROUND(PI*100,i%)
NEXT i%
--> Displays the loop variable and the associated formatted expression on the
screen: PI is multiplied by 100 and then displayed rounded to i% decimal
places. Where i% is negative, the rounding is done to the left of the
decimal point.
MIN
MIN(x[,y,z,...]) MIN(x$[,y$,z$,...])
MAX(x[,y,z,...]) MAX(x$[,y$,z$,...])
x, y, z: aexp
x$, y$, z$: sexp
The function MIN() returns the smallest of the numerical expressions x, y, z,
..., specified in the parameter list.
The function MAX() returns the largest of the numerical expressions x, y, z,
..., specified in the parameter list.
MIN() and MAX() can also be applied to string expressions.
Example:
x=3
y=MAX(3,5.5-4)
PRINT MIN(x,y),MAX(-1,x*2)
--> Displays the numbers 3 and 6.
SQR
SQR(x)
x: aexp
Produces the square root of the numerical expression x. If the expression x is
negative, an error message is invoked.
Examples:
x=9
y=SQR(x)
PRINT y,SQR(4*4)
--> The numbers 3 and 4 appear on the screen.
PRINT SQR(SQR(16))
PRINT SQR(-2)
--> The number 2 appears, followed by an error message.
EXP
EXP(x)
LOG(x)
LOG10(x)
x: aexp
EXP() computes e to the power x (Euler's number e=2.1782818284...), and LOG()
forms the inverse function, that is the natural logarithm of x. Similarly,
LOG10() returns the logarithm of x to the base 10. The numerical expression x
must be larger than zero with the logarithm function, otherwise an error
message results.
Example:
x=2
y=EXP(2)
PRINT y,LOG10(2*5),LOG(x)
--> On the screen 7.389056098931, 1, and 0.6931471805599 appear.
Memo: For FPU use, see function TT?.
SIN
SIN(x)
COS(x)
TAN(x)
ASIN(x)
ACOS(x)
ATN(x)
DEG(x)
RAD(degrees)
SINQ(degrees)
COSQ(degrees)
x, degrees: aexp
These are the trigonometrical functions. The numerical expression x is assumed
to specify radians. They compute the following:
SIN() Sine
COS() Cosine
TAN() Tangent
ASIN() Arc-sine
ACOS() Arc-cosine
ATN() Arc-tangent
To convert between radians and degrees one uses the functions DEG() (radians to
degrees) or the inverse, RAD(). DEG(x) and RAD(x) are thus equivalent to
(x*180/PI) and (x*PI/180) respectively.
The functions SINQ() and COSQ() return Sine and Cosine values, interpolated in
steps of one sixteenth of a degree from an internal table. For graphics work on
the screen this accuracy is not distinguishable from the values computed with
SIN() or COS(), however SINQ() and COSQ() work up to 10 times as fast. Unlike
SIN() and COS(), degrees are expected as the arguments for SINQ() and COSQ().
SINQ(degrees) corresponds to SIN(RAD(degrees)) and COSQ(degrees) corresponds to
COS(RAD(degrees)).
Examples:
x=90
y=COSQ(x*PI/180)
z=270*PI/180
PRINT y,SIN(z),TAN(45),ATN(1/2)
--> The numbers 1, -1, 1.619775190544, and 0.4636476090008 appear.
alpha%=30
PRINT SINQ(alpha%)
--> The number 0.5 is displayed.
Memo: For FPU use, see function TT?.
ASIN() and ACOS() do not seem to handle errors correctly when compiled.
Example: PRINT ASIN(-50) !results in a crash
FACT
FACT(n)
VARIAT(n,k)
COMBIN(n,k)
n, k: iexp
Commands from the field of combinatorics.
FACT(n) returns the factorial of a natural number n (n!). A factorial is the
product of the first n natural numbers, where 0!=1.
VARIAT(n,k) returns the number of variations of n elements to the k-th order
without repetition. The number of variations of n elements to the k-th order
without repition is defined as:
VARIAT(n,k)=n!/(n-k)!
When k > n an error is reported.
COMBIN(n,k) returns the number of combinations of n elements to the k-th order
without repetition. The number of combinations of n elements to the k-th order
without repition is defined as:
COMBIN(n,k)=n!/((n-k)!*k!)
When k > n an error is reported.
Example:
x=FACT(6)
y=VARIAT(6,2)
z=COMBIN(6,2)
PRINT x,y,z
~INP(2)
--> The values 720, 30, and 15 appear on the screen. A key is then waited for.
SCALE
SCALE(i,j,k)
i, j, k: iexp
Divides an integer into the product of two other integers.
SCALE(i,j,k) multiplies the integer numbers i and j, producing an integer
result. The result is then divided by the integer number k and the quotient is
returned. This is somewhat faster than i*j/k.
The return value is an integer so any decimal places will be lost.
One possible application for this function is for scaling of graphics.
Example:
i&=64
j&=8
k&=16
PRINT (i&*j&)/k&
PRINT SCALE(i&,j&,k&)
--> The values 32 and 32 appear on the screen.
Random Number Generator
RND()
RAND()
RANDOM()
RANDOMIZE
This group of commands deals with the generation of random numbers.
RANDOM
RND[(x)]
RAND(y)
RANDOM(x)
RANDOMIZE [y]
x: aexp
y: iexp
This group of commands deal with the generation of random numbrs:
RND() produces a random number between 0 and 1 (including 0, excluding 1). The
optional parameter (x) has no meaning.
RAND(y) produces a 16-bit random integer in the range 0 to y-1. Where y is an
integer with a maximum value of 65535 (&HFFFF). If y exceeds 65535, then its
low-order word is taken as the argument.
RANDOM(x) produces a random integer be tween 0 and x (including 0, excluding
x). The numerical expression x need not be integer if not all numbers are
required to have the same probability.
RANDOMIZE y initialises the random number generator with the value y. If the
random number generator is initialised several times with the same y, the same
sequence of random numbers will be produced. Without the use of RANDOMIZE at
the beginning of a program, different sequences will be generated each time the
program is run, which may be undesirable in some cases. For initialising the
random number generator one can also use RANDOMIZE (without parameters) or
RANDOMIZE 0, which initializes the random number generator with a random
number.
Examples:
x=RND
PRINT x,RND(2)
--> Two random numbers between 0 and 1 appear on the screen.
x=RANDOM(2)
y=RAND(4)
PRINT x,y,RAND(x),RANDOM(3*x)
--> Four integer random numbers are displayed.
RANDOMIZE 3
x=RND
RANDOMIZE 3
PRINT x,RND
--> The same 'random number' is printed twice.
Random()+
Integer Arithmetic
INC, DEC
ADD, SUB, MUL, DIV
PRED(), SUCC()
ADD(), SUB(), MUL(), DIV()
MOD()
These instructions are shorter forms of the following frequently used
statements:
Instruction Corresponds to
DEC x x=x-1
INC x x=x+1
ADD x,y x=x+y
SUB x,y x=x-y
MUL x,y x=x*y
DIV x,y x=x/y
The statements on the left require less time for their execution than those on
the right, particularly in the case of integer variables. It is important to
note that INC, DEC, ADD, SUB, MUL, and DIV do not carry out an overflow check
with integer variables (types |, &, and %). If overflow occurs, only the
appropriate number of low-order bits (8 for byte, 16 for word, etc.) are used
for the result. Thus for byte-sized variables, if x|=16 and y|=17, MUL x|,y|
gives the result 16 in x|. The extra '256' in the 9th bit is ignored.
Memo: For compiler options see section 'Integer Rounding'.
For compiler optimizations see sections 'Simple Additions', 'Multiplication',
'Division', and 'More Complicated Calculations'.
For information about how the compiler handles integer overflow see
section 'Integer Overflow'.
DEC
DEC i
INC i
i: avar
The instruction DEC decrements the value of the specified variable, in other
words it subtracts one (1) from it's value.
The instruction INC increments the value of the specified variable, in other
words it adds one (1) to it's value.
These instruction can work with floating-point variables, but are substantially
faster with integers.
Examples:
x%=4
y%=7
DEC x%
INC y%
PRINT x%,y%
--> The numbers 3 and 8 appear.
a|=255
INC a|
INC a|
PRINT a|
--> Results in '1' being displayed, as there is no overflow check.
ADD
ADD x,y
SUB x,y
MUL x,y
DIV x,y
x: avar
y: aexp
The instruction ADD increases the variable x by the value of y. With this
instruction x must be a numeric variable, and y must be a numerical expression.
The instruction SUB decreases the variable x by the value of y. With this
instruction x must be a numeric variable, and y must be a numerical expression.
The instruction MUL multiplies x by the value of y and assigns the result to x.
With this instruction x must be a numeric variable, and y must be a numerical
expression.
The instruction DIV divides x by the value of y and assigns the result to x.
With this instruction x must be a numeric variable, and y must be a numerical
expression.
These instructions can work with floating-point variables, but are
substantially faster with integers.
Note: DIViding a variable by zero (0) results in an error.
Example:
x%=1
y%=2
z%=3
ADD x%,y% !now x% is equal to 3
SUB z%,(x%-1)/2 !the numerical expression (x%-1)/2 restults in 1
PRINT x%,z%
--> The numbers 3 and 2 are displayed.
PRED
PRED(i)
SUCC(i)
i: iexp
PRED() and SUCC() determine the next higher or next lower number.
PRED() returns the next lower number than the argument. So PRED() returns the
PREDecessor of a numerical expression. Note that this instruction operates on
integer expressions, so any decimal places are ignored. This gives rise to the
effect that, for instance, PRED(2.1) returns the result of 1, and not 2.
SUCC() returns the next higher number than the argument. So SUCC() returns the
SUCCessor of a numerical expression. Note that this instruction operates on
integer expressions, so any decimal places are ignored.
This function will also operate on string expressions, see the section on
String Manipulation.
Example:
i%=6
j&=PRED(i%)
PRINT j%,SUCC(2),PRED(3*i%)
--> On the screen, the numbers 5, 3, and 17 appear.
ADD()
ADD(x,y)
SUB(x,y)
MUL(x,y)
DIV(x,y)
MOD(x,y)
x, y: iexp
ADD(), SUB(), MUL(), DIV(), and MOD() offer quicker integer arithmetic with
Polish notation.
These functions can replace more usual expressions thus:
Instruction Corresponds to
ADD(x,y) x+y
SUB(x,y) x-y
MUL(x,y) x*y
DIV(x,y) x/y or x DIV y
MOD(x,y) x MOD y
Since these function uses integer arithmetic, any decimal places are ignored.
These function can be nested at will. This method of notation is known as
'Polish'.
After the following program segment is run...
x%=5
y%=4
ADD y%,3
z%=SUB(x%,3)
... x% will have the value 5, y% the value 7, and z% the value 2.
Examples:
DEFINT "a-z"
x=4
y=ADD(x,x) !y becomes equal to 8
z=SUB(x,2)
PRINT y,z,ADD(x,MUL(y,2))
--> The numbers 8, 2, and 20 appear on the screen.
DEFINT "a-z"
x=2
y=MUL(x,3) !y becomes equal to 6
PRINT 7,DIV(8,x),MOD(11,4) !MOD(11,4) is equal to 3
--> The numbers 6, 4, and 3 appear on the screen.
DEFINT "a-z"
x=5
y=ADD(SUB(x,2),MUL(3,4))
PRINT y,DIV(8,MOD(14,4))
--> Displays the numbers 15 and 4.
Bit Operations
BCLR(), BSET(), BTST(), BCHG()
SHL|(), SHL&(), SHL()
SHR|(), SHR&(), SHR()
ROL|(), ROL&(), ROL()
ROR|(), ROR&(), ROR()
AND(), OR(), XOR(), IMP(), EQV()
SWAP()
BYTE(), CARD(), WORD()
These Bit Operations affect numerical expressions at the bit level. The
commands BCLR(), BSET(), BTST(), and BCHG() are direct implementations of the
68000 instructions. Note, however, that they are used as functions, not
commands.
They reset, set, test, and negate individual bits. SHLx(), SHRx(), ROLx(), and
RORx() shift or rotate. AND(), OR(), XOR(), IMP(), and EQV() are logical
functions. In the following explanations the convention is used that bit 0 is
the least significant bit. With 4-byte integers bit 31 is the most significant
bit and is also the sign bit (if the sign bit is set, i.e. =1, then a negative
number is represented in two's complement form, otherwise it is a positive
number).
SWAP() exchanges the high- and low-order words of a 4-byte value. BYTE() reads
the lower 8 bits and CARD() the lower 16 bits of an expression. WORD() extends
a word to form a long word, i.e. bit 15 is copied into positions 16 to 31.
Memo: BSET (BCLR) internally uses and returns a signed 32-bit value. If you
bit change e.g. a word variable BSET(m&,15), the return value is a long
integer with all bits 15-31 set, i.e. <0. For this reason b&=BSET(m&,15)
generates an error, since the result is not a word. The result must be
masked to 16 bits first, using e.g. AND &FFFF or WORD().
BCLR
BCLR(x,y)
BSET(x,y)
BCHG(x,y)
BTST(x,y)
x, y: iexp
These functions permit the resetting, setting, negating, and testing of bits.
The bit numbers are counted starting from 0 on the 'right' and are internally
ANDed with 31, so that they are always taken as being between 0 and 31.
The function BCLR() sets the y-th bit of the numerical expression x to 0.
The function BSET() sets the y-th bit of the numerical expression x to 1.
The function BCHG() sets bit y of numerical expression x to 1 if it was 0, or
sets it to 0 if it was 1.
The function BTST() returns -1 (TRUE) if bit y of numerical expression x is
equal to 1 and 0 (FALSE) if it is equal to 0.
Examples:
x=BSET(0,3)
PRINTx,BSET(0,5)
--> The numbers 8 (2^3) and 32 (2^5) appear on the screen.
REPEAT
t|=INP(2)
PRINT CHR$(t|),CHR$(BCLR(t|,5))
UNTIL CHR$(t|)="x"
--> If CapsLock is off, this program prints the letter corresponding to the key
pressed, in both lower and upper case. (With lower case letters, bit 5 is
always set; resetting this bit forces the transformation to upper case).
s$="TESTcase"
FOR i%=1 TO LEN(s$)
PRINT CHR$(BCHG(ASC(MID$(s$,i%)),5));
NEXT i%
--> Displays testCASE on the screen. Each lower case letter is changed to upper
case, and vice versa. (this will not work with umlauted characters).
Memo: This generates the error message 'number not a word':
r&=-1
r&=BCLR(r&,15) !seems logical yet it fails
r&=AND(r&,&H7FFF) !use this instead
Why does it fail? The variable is seen as a LONG regardless.
SHR
SHL|(x,y) SHL&(x,y) SHL(x y)
SHR|(x,y) SHR&(x,y) SHR(x,y)
ROL|(x,y) ROL&(x,y) ROL(x,y)
ROR|(x,y) ROR&(x,y) ROR(x,y)
x, y: iexp
These instructions SHift or ROtate the numerical expression x by y bits. If the
variable type is not specified this will occur over long word length (4 bytes).
If word length is specified (with &), the operation takes place over 2 bytes,
and with byte length (|) over one byte.
The third letter of the function name specifies the direction for the shift,
'L' standing for left, and 'R' for right.
With word-length operations (with &) bit 15 is copied to bits 16 to 31, thus
preserving the sign. With byte-length operations bits 8 to 31 are set to 0.
The following tables show the effect of the shift instructions:
x% SHL|(x%,1) BIN$(x%,16) BIN$(SHL|(x%,1),16)
18 36 00000000 00010010 00000000 00100100
642 4 00000010 10000010 00000000 00000100
x% SHL&(x%,1) BIN$(x%,16) BIN$(SHL&(x%,1),16)
18 36 00000000 00010010 00000000 00100100
130 260 00000000 10000010 00000001 00000100
x% SHR&(x%,2) BIN$(x%,16) BIN$(SHR&(x%,2),16)
24 6 00000000 00011000 00000000 00000110
4162 1040 00010000 01000010 00000100 00010000
Note: The bit representations have been grouped as two sets of 8 bits for
the sake of clarity. BIN$() does not do this.
The next examples concern rotation. Here, bits which leave one end of the
argument are pushed in again at the other end. For instance, if only the
highest bit of a byte is set, and the byte is then shifted one bit to the left
(ROL|(128,1)), the set bit which disappears off the left end is re-introduced
on the right as bit 0. With a shift to the left, (say SHL|(128,1)) the set bit
would have been lost, with bit 0 being made zero.
Examples of rotation are:
x| ROL|(x|,1) BIN$(x|,1) BIN$(ROL|(x|,1),8)
6 12 00000110 00001100
130 5 10000010 00000101
x| ROR|(x|,3) BIN$(x|,8) BIN$(ROR|(x|,3),8)
66 72 01000010 01001000
2 64 00000010 01000000
Example:
x|=128+1 !bits 7 and 0 set
y%=ROR|(x|,1) !y becomes 192
PRINT SHL(y%,4),y%*2^4
PRINT SHL(ROR|(128+1,1),4)
--> The number 3072 is printed three times. The function SHL(a,b) is equivalent
to a*2^b, if no bit is lost off the left end of the four-byte number a. The
bit-shift formulation, however, is clearly quicker.
AND()
AND(x,y)
OR(x,y)
XOR(x,y)
IMP(x,y)
EQV(x,y)
x, y: iexp
These functions operate logically on two numerical expressions.
The function AND() returns a result in which only those bits are set which are
set in both x and y.
The result of OR() contains bits set in the places in which bits are set in
either x or y or both.
XOR() sets only those bits which are set in x or y but not both (or, to put it
another way: XOR() sets those bits which are different in x and y).
IMP() resets a bit to zero if the appropriate bit in x is set and in y is
reset, otherwise the bit is set.
EQV() sets a bit of the result if the appropriate bits in x and y are both set,
or both reset.
See the section on Logical Operators for the truth table for this function.
Examples:
x=3
y=2
z=AND(x,y)
PRINT z,OR(2,7),XOR(x,1+4+8)
--> On the screen, the numbers 2, 7, and 14 appear.
PRINT BIN$(15,4),15
PRINT BIN$(6,4),6
PRINT BIN$(IMP(15,6),4),"IMP(15,6)"
PRINT BIN$(EQV(15,6),4),"EQV(15,6)"
--> Displays: 1111 15
0110 6
0110 IMP(15,6)
0110 EQV(15,6)
SWAP()
SWAP(x)
x: iexp
The function SWAP() re-formulates (if necessary) the numerical expression x as
a long word (4 bytes) and exchanges its upper and lower words (2 bytes in each
case). This could be useful when passing longword parameters to an operating
system routine which requires the words in reverse order.
Note: This function has nothing to do with the instruction of the same
name, which swaps values of variables.
Example:
x=1044480
PRINT BIN$(x,32)
y=SWAP(x)
PRINT BIN$(y,32)
--> The following appears on the screen: 00000000000011111111000000000000
11110000000000000000000000001111
An example of SWAP() in use might be: ~WIND_SET(0,13,SWAP(t%),t%,0,0)
BYTE()
BYTE(x)
CARD(x)
WORD(x)
x: iexp
BYTE() returns the lower 8 bits of the numerical expression x.
The functions CARD() returns the lower 16 bits of the numerical expression x.
The function WORD() extends a word to long word length (32 bits) by copying bit
15 to bit positions 16 to 31, thus preserving the sign.
Examples:
PRINT BYTE(255),BYTE(1+255)
PRINT HEX$(CARD(&H1234ABCD))
--> 255, 0, and ABCD are printed.
x%=&HFFFF
PRINT BIN$(x%,32)
x%=WORD(x%)
PRINT BIN$(x%,32)
--> The screen displays: 00000000000000001111111111111111
11111111111111111111111111111111
Chapter 5 - String Manipulation
LEFT$(), RIGHT$()
MID$ (as a command), MID$() (as a function)
PRED(), SUCC()
LEN()
TRIM$()
INSTR(), RINSTR()
STRING$(), SPACE$(), SPC()
UPPER$()
LSET, RSET
These functions allow the manipulation of strings by selectively altering and
concatenating (+) their contents. The functions LEFT$() and RIGHT$() return the
left or right part of a character string. MID$(), used as a function, returns a
section from the middle of a string, or, used as a command, allows the
replacement of part of one string with all or part of another. PRED() and
SUCC() return the character with the ASCII code one lower or one higher than
the first character of the specified string. While LEN() determines the length
of a character string. INSTR() and RINSTR() search a particular string for the
occurrence of another string. STRING$(), SPACE$(), and SPC() generate strings
composed of several identical strings, and UPPER$() transforms all lower case
letters in a string to upper case. Left and right justified insertion of one
string into another is accomplished with LSET and RSET.
Memo: For compiler optimizations see section 'Character Strings'.
See FRE() for problems related to string memory handling.
RIGHT$
LEFT$(a$[,x])
RIGHT$(a$[,x])
a$: sexp
x: iexp
LEFT$() returns the first x characters from the character string a$. If x is
larger than the number of characters in a$, then the whole of a$ is returned.
If x is not specified, the first character of a$ is returned.
RIGHT$() returns the last x characters from the character string a$. If x is
larger than the number of characters in a$, then the whole of a$ is returned.
If x is not specified, the last character of a$ is returned.
Examples:
a$="Right-minded people use GFA BASIC"
b$=LEFT$("GFA Systemtechnik",4)
PRINT b$;RIGHT$(a$,5)
--> 'GFA BASIC' is printed on the screen.
a$="Oh, don,t"
b$=LEFT$(a$)+RIGHT$("look")
PRINT b$
--> 'Ok' appears on the screen.
MID$
MID$(a$,x[,y])=b$ (as a command)
a$: svar
b$: sexp
x, y: iexp
MID$() used as an instruction makes possible the replacement of part of a
string variable a$ with the string expression b$. So with MID$(a$,x,y)=b$,
characters from b$ will overwrite those in a$, starting at the x-th character
position of a$. The optional parameter y determines how many characters of b$
are used. If y is omitted, then as many characters as possible of a$ are
replaced with those from b$. The length of a$ is unchanged, so that no
characters will be written beyond the end of a$.
Example:
a$="GFA SYSTEMTECHNIK"
MID$(a$,5)="BASIC "
'
b$="Testword"
MID$(b$,6,10)="are you serious?"
PRINT a$, b$
--> 'GFA BASIC TECHNIK' and 'Testware' are printed.
MID$()
MID$(a$,x[,y]) (as a function)
a$: sexp
x, y: iexp
The function MID$() returns y characters starting at position x of the string
a$. If x is larger than the length of a$ then a null string ("") is returned.
If y is omitted, the function returns the whole of the string from position x
onwards.
Example:
a$="This is the GFA BASIC manual"
b$=MID$(a$,13,9)+MID$("version 3",8)
PRINT b$
--> On the screen, the text 'GFA BASIC 3' appears.
PRED()
PRED(a$)
SUCC(a$)
a$: sexp
PRED() returns the character with the ASCII code one less than that of the
first character of the specified string. (In other words, its PREDecessor in
the ASCII table.)
SUCC() returns the character with the ASCII code one greater than of the the
first character of the string specified. (In other words, its SUCCessor in the
ASCII table.)
These function are also effective with numbers, see the section on Integer
Arithmetic.
PRED(a$) corresponds to the expression CHR$(ASC(a$)-1).
SUCC(a$) corresponds to the expression CHR$(ASC(a$)+1).
Example:
character$="blue moon"
predecessor$=PRED(character$)
successor$=SUCC(character$)
PRINT predecessor$;SUCC(predecessor$);successor$
--> 'abc' is displayed on the screen.
LEN
LEN(a$)
TRIM$(a$)
a$: sexp
LEN() returns the number of characters contained in a$.
TRIM$() removes spaces from the left and right ends of strings.
Examples:
a$="test"
x=LEN(a$)+1
PRINT x,LEN("word")
--> Displays the number 5 and 4.
b$=" test "
PRINT LEN(b$)
PRINT TRIM$(b$)
PRINT LEN(TRIM$(b$))
--> Displays 9, the word 'test' (without spaces), and 4.
INSTR
INSTR(a$,b$)
INSTR(a$,b$[,x])
INSTR([x,]a$,b$)
a$, b$: sexp
x: iexp
The function INSTR() searches the character string a$ for an occurrence of the
string b$. If x is specified, then the search begins at character position x in
a$, otherwise the whole string is searched.
If b$ is found within a$, the character position at which it begins is
returned, or, if it is not found the function returns zero (0). This value may
be assigned to a variable or used to determine whether a particular string was
present in a$. If a$ and b$ are both null strings (""), one (1) is returned.
The search goes from left to right.
Example:
a$="GFA-Systemtechnik"
x=INSTR(a$,"System")
PRINT x,INSTR("GFA-BASIC","BASIC",6)
--> The numbers 5 and 0 appear on the screen.
REPEAT
a$=123456"
b$=INKEY$
UNTIL INSTR(a$,b$)
--> Waits until one of the specified keys has been pressed.
Memo: INSTR() has a bug which only appears if parameter 'x' is used.
Use the following code listing instead:
FUNCTION instr(a$,b$,i&)
$F%
LOCAL v&
v&=INSTR(a$,b$,i&)
IF v&<i& !bug?
v&=0
ENDIF
RETURN v&
ENDFUNC
RINSTR
RINSTR(a$,b$)
RINSTR(a$,b$[,x])
RINSTR([x,]a$,b$)
a$, b$: sexp
x: iexp
The function RINSTR() searches the character string a$ for an occurrence of the
string b$. If x is specified, then the search begins at character position x in
a$, otherwise the whole string is searched.
If b$ is found within a$, the character position at which it begins is
returned, or, if it is not found the function returns zero (0). This value may
be assigned to a variable or used to determine whether a particular string was
present in a$. If a$ and b$ are both null strings (""), one (1) is returned.
The search goes from right to left.
Example:
PRINT RINSTR("a:\FOLDER\*.GFA","\")
--> The string '\' is sought in the string 'a:\FOLDER\*.GFA', starting
from the end. Its first occurrence is found at position 10.
Memo: RINSTR() has a bug which only appears if parameter 'x' is used.
Use the following code listing instead:
FUNCTION rinstr(a$,b$,i&)
$F%
LOCAL v&
v&=RINSTR(a$,b$,i&)
IF i&=LEN(b$) !bug?
v&=-(LEFT$(a$,i&)=b$)
ELSE IF i&<LEN(b$) !bug?
v&=0
ENDIF
RETURN v&
ENDFUNC
STRING$
STRING$(x,a$)
STRING$(x,code)
SPACE$(x)
SPC(x)
x, code: iexp
a$: sexp
The function STRING$() returns a string which reproduces the expression 'a$'
(or ASCII character whose number is 'code') x times, where x has a maximum
value of 32767.
SPACE$() returns a string consisting of x spaces.
SPC() inserts x spaces in a PRINT statement without the need to create a string
variable or to explicitly specify the spaces by " ".
Example:
a$="GFA "
b$=SPACE$(5)
PRINT b$;STRING$(3,a$);SPC(4);STRING$(5,65)
--> ' GFA GFA GFA AAAAA' appears on the screen.
Memo: STRING$() compiled issues the wrong error code (#15).
Interpreter issues #10 as it should be.
SPACE$() and STRING$(count,code) do weird things with out of range
string sizes in compiled applications. No error is generated and the
string LEN() ends up -negative.
UPPER$
UPPER$(A$)
a$: sexp
All lower case letters in a$ are converted to upper case.
This also happens to characters containing umlauts.
Example:
a$=" test"
b$=UPPER$(a$)+UPPER$("ware")
PRINT UPPER$("Gfa basic 3");b$
--> On the screen 'GFA BASIC 3 TESTWARE' appears.
Memo: Umlaut conversion table is as follows:
Before: üéäàåçæöñãõøœij
After: üÉÄÀÅÇÆöÑÃÕØŒIJ
RSET
LSET a$=b$
RSET a$=b$
a$: svar
b$: sexp
LSET and RSET will set the string expression b$ into a$, justified either to
the left or to the right. If b$ is shorter than a$ (the normal situation)
spaces will be inserted to make up the original length of a$. Note that the
actual content of a$ is irrelevant: only its length is significant.
Example:
a$="xxxxx"
FOR i%=1 TO 128
LSET a$=STR$(i%) ! left-justified format
PRINT a$;
NEXT i%
PRINT
'
FOR i%=1 TO 128
RSET a$=STR$( i%) !right-justified format
PRINT a$;
NEXT i%
~INP(2)
--> Displays left- and right-justified formatted columns of numbers, then waits
for a key to be pressed.
a$=STR$(i%,5,0) could also be used in place of RSET a$=STR$(i%)
This first section begins with an examination of the command INKEY$, which
takes a single character from the keyboard. Next, the family of INPUT commands
is examined, along with the related commands LINE INPUT, FORM INPUT, and FORM
INPUT AS. The discussion of output capabilities begins with the most simple
instruction, PRINT, and goes on to extended versions such as PRINT AT and PRINT
USING. CRSCOL, CRSLIN, and POS() are used to report on the current cursor
position, and TAB(), HTAB, and VTAB are used to control it. At the end of this
section, the KEYxxx commands are considered, these being a family of commands
for the interrogation of the keyboard, and its configuration while a program is
running.
Memo: Internally GFABASIC uses a 4kb disk caching scheme. How does this work?
All reads/writes are round to 4096 bytes. If you read one byte from a
file, it will actually read 4096 bytes and any futher reads up to the
end of the 4kb buffer will be read from ram. The same applies to writes,
a 4kb buffer is created and it only purges the cache when its full. This
speeds up disk reads and writes, especially with floppy disks.
This disk caching scheme only applies to disk files. It is not used on
devices like MIDI and serial ports, or the console even if one uses
OPEN on these devices.
A warning about files OPEN for output:
You must make sure you CLOSE these files before your program exits or
data could be lost. CLOSE will force any cached data to be written,
before closing the file. If you let the operating system close these
files at pterm(), any cached data will be lost and these files will be
truncated.
Keyboard and Screen Handling
INKEY$
INPUT, LINE INPUT, FORM INPUT
PRINT (?), PRINT AT(), PRINT USING
WRITE
LOCATE
MODE
DEFNUM
CRSCOL, CRSLIN
POS(), TAB()
HTAB, VTAB
INKEY$
INKEY$
INKEY$ reads a character from the keyboard. This function will, however, not
detect depressions of the Shift, Alternate, or Control keys alone. INKEY$ does
not wait for a key to be pressed, but scans the keyboard to check whether a key
has been pressed since the last scan. If it has, the command accepts that
pressed key, otherwise a null string ("") is returned. When the key pressed has
no ASCII code, for example a Function key or the HELP or UNDO keys, then INKEY$
returns the scan code of the pressed key as a two-character long string
containing CHR$(0) as its first character, and the identification code of the
special key as the second character.
The following example demonstrates how the values returned by INKEY$ can be
examined:
DO
t$=INKEY$
IF t$<>""
IF LEN(t$)=1
PRINT "Character: ";t$,"ASCII code: ";ASC(t$)
ELSE
PRINT "CHR$(0)+Scan code: ";CVI(t$)
ENDIF
ENDIF
LOOP
--> Displays the ASCII or Scan code of each key pressed.
Note: CVI() turns a 2-byte string into an integer. As the first byte of the
string is zero, in this case it returns the value of the second byte.
INPUT ["text",] x [,y,...]
INPUT ["text";] x [,y,...]
x, y: avar or svar
The command INPUT can be used in several ways. It accepts the input of
variables or variable lists with or without a text message being displayed on
the screen. For INPUT, the cursor will normally retain its last screen
position; however, by means of PRINT AT() followed by a semicolon, or by using
LOCATE, VTAB, or HTAB, the cursor can be put at a desired screen position.
A text string may follow the INPUT command, separated from the following
variables by a comma or a semicolon. If a semicolon is used, then a question
mark and a space are printed on the screen and the cursor placed at the
succeeding character position. When a comma is used, the question mark and
space are omitted, and the cursor is placed directly after the last character
of the text string.
If no text is to be displayed, then the question mark and space are printed,
and the cursor is put directly after the space (as if a null string ("") had
been used as text, followed by a semicolon).
When only one variable is to be input, the user types in a number or a
character string and terminates it by pressing either the Return or the Enter
key. When several values are to be entered (if there was a list of variables
after the INPUT statement in the program line), each individual variable can be
terminated by pressing Return or Enter, or they may be typed in separated by
commas and all confirmed together with a single press of the Return or Enter
key.
If a string is to be entered which may contain commas, the instruction LINE
INPUT must be used.
If a numeric variable was expected by the INPUT statement, and a non-numeric
string typed in instead, a bell signal sounds, and the input must be repeated.
Prior to the Return or Enter key being pressed the input can be edited by means
of the Backspace, Delete, and Left and Right arrow keys. Pressing the INSERT
key switches between, insert and overwrite modes during editing. The maximum
length of the input is 255 characters.
Special symbols can be entered in three different ways:
- By holding down the Alternate key and typing in the ASCII code of the
desired character using the numeric pad. When the Alternate key is
released, the appropriate character is displayed. For instance, with 64
as the ASCII code, the characeter '@' appears. This also works with
INKEY$, INP(2), GEM Dialog Boxes etc., if it is not switched off by the
command KEYPAD.
- By typing Control-S followed by another character, for example Control-S
C for the Pi character. (Press the Control and S key at the same time,
then press C.) This feature only works with the INPUT statement or in
Edit mode, when a program is actually being typed in.
- By typing Control-A followed by the ASCII code of the desired character,
e.g.: Control-A 64 for the '@' character.
Example:
INPUT a$
INPUT "",b$
INPUT "Enter two numbers :";x,y
PRINT a$,b$,x,y
--> Reads in two strings and two numeric variables. The first input command
generates a ?, the second appears with no text and the third issues the
message 'Enter two numbers: ?'.
LINE INPUT ["text",] a$ [,b$,...]
LINE INPUT ["text";] a$ [,b$,...]
a$, b$: svar
LINE INPUT is a variant of the INPUT command. Unlike INPUT, it allows commas to
be accepted as part of the input. The preceding description of the input of
variables or a variable list, and the facilities for correction of the input
prior to the pressing of Return or Enter also apply to LINE INPUT. LINE INPUT,
however, may only be used with string variables.
Example:
LINE INPUT a$
INPUT b$
PRINT a$,b$
--> When the program is Run, and the text 'com,ma' inputted twice, a$ is taken
as 'com,ma' whilst b$ contains 'com', as the 'ma' is taken as a separate
input and ignored. See also LINE INPUT #.
Memo: The maximum length of the input is 255 characters.
FORM INPUT n,a$
FORM INPUT n AS a$
n: iexp
a$: svar
FORM INPUT and FORM INPUT AS are both used to input string variables. The value
of n specifies the number of characters to be entered, up to a maximum of 255.
Additionally, FORM INPUT AS displays the current value of a$, which can then be
edited, or taken as a 'default' input by pressing Return or Enter immediately.
The editing facilities are the same as those for the INPUT command.
Example:
FORM INPUT 10,a$
b$="test"
FORM INPUT 5 AS b$
PRINT a$,b$
--> This asks for two strings to be entered. On the entry of the second string,
the word 'test' is displayed as a preselected value of b$. This may then be
edited, or accepted by pressing Return.
Memo: A value of 0 for n is valid and causes the input to auto end.
PRINT
PRINT [expression]
PRINT AT(column,line) [expression]
WRITE [expression]
LOCATE column,line
expression: arbitrary combination of sexp or aexp
column, line: iexp
The instruction PRINT, without parameters, causes a blank line to be printed.
If the cursor happens to be on the last line, the entire screen is scrolled up
one line. PRINT followed by an expression causes the expression to be printed
at the current cursor position. Text strings must be enclosed in quotes. If the
expression to be printed consists of several elements (constants, variables, or
expressions), the individual parts must separated by a semicolon, comma, or
apostrophe, with the following effects:
• A comma causes the cursor to move to one position past the next column number
which is divisible by 16. In other words, the columns 1, 17, 33, etc. are
used. If this takes the cursor beyond the end of the line, the cursor moves
to column 1 of the next line.
• A semicolon causes the output of the corresponding elements, one after the
other without any spaces being added.
• An apostrophe inserts one space between the appropriate elements.
PRINT AT() makes it possible for the expression to be displayed on a specified
line, starting at a specified column. Depending on the current screen
resolution, up to 80 columns and 25 lines are available.
Note: Column and line numbers begin at 1, and not 0.
If a window is open, the column and line numbers are relative to the top
left-hand corner of the window.
If the output expression (the message) is not terminated with a semicolon, the
cursor is placed at the beginning of the next line. If it was already at the
bottom of the screen, then the screen is scrolled up by one line.
If print control characters (ASCII characters from 0 to 31) are specified, then
these are processed by the VT-52 Emulator (see Appendix).
The WRITE command can be used to send output to the screen. The command is
followed by the numerical or string expressions to be sent, separated by
commas. The output includes the commas and, with string expressions,
the quotation marks are also included. A semicolon may be placed after the last
item to be output, in which case the usual Carriage Return/Line Feed will be
suppressed.
LOCATE places the cursor at the specified column and line, i.e. in the
same order as PRINT AT(). It will not, however, actually display
anything. See VTAB and HTAB.
Examples:
a$="GFA Systemtechnik"
PRINT LEFT$(a$,4)+"BASIC"'1+2;
PRINT ".0","GFA ";UPPER$(MID$(a$,5))
--> Displays 'GFA BASIC 3.0' and 'GFA SYSTEMTECHNIK'.
PRINT AT(5,8);"Fifth column, eighth line"
--> Prints the message starting at the position x=5, y=8.
LOCATE 5,8
PRINT "Eighth line, fifth column"
--> Positions the cursor at the fifth column of the eighth line and
displays the message, again x=5 and y=8.
WRITE 1+1,"Hello",3*4
--> The output is: '2,"Hello",12'.
Memo: The manual originally documented LOCATE with the parameters
reversed. However it actually works like so: LOCATE x,y
Internally PRINT is really a BIOS call to bconout(DEV_CON).
LOCATE is really a BIOS call to bconout(VT-52 ESC+Y)
PRINT AT() is convert to a call to LOCATE.
Bconout()+, Cconws()+, v_curtext()+, vs_curaddress()+
PRINT USING
PRINT USING format$,expression [;]
PRINT AT(column,line);USING format$,expression [;]
format$: sexp
expression: as many aexp or sexp as wanted, separated by commas
column, line: iexp
PRINT USING and its variant PRINT AT() USING serve to format data output on the
screen. These commands work in the same general way as PRINT or PRINT AT().
However, the data in the expression to be displayed are ormatted according to
the contents of format$.
The following symbols may be used to format a numerical expression:
# Reserves a character position for a number (digit).
. A period specifies the position of the decimal point within several '#'
symbols
, A comma in the appropriate place between '#' signs causes the insertion
of a comma, e.g. as a 'thousands' separator in 10,000.
- The minus sign reserves a character position for a minus sign, in case
the number to be printed is negative. For a positive number a space will
be printed instead. (GFA-Basic normally prints nothing preceding a
positive number.)
+ Reserves a space for the plus sign of a positive number. If the number
is positive, the '+' sign will be printed, but if it is negative a minus
sign will appear as usual. (See '-' above.)
* Replacement for # above, with the difference that leading zeros are
replaced by asterisks, instead of blanks.
$ Causes one dollar '$' character to be printed before a number, provided
it is put directly before the first '#' symbol.
^ Specifies the length of the exponent (including the 'E+') when a number
is to be printed in exponential format (e.g. E+123). If the number of
digits before the decimal point is specified using several '#' symbols,
then the exponent is adjusted to take account of this. For a negative
exponent, the possibility of a '-' must be allowed for by '-' above.
In contrast to GFA-Basic Version 2, the principle 'Formatting First' is adhered
to. That is, in the case of overflows only the digits with character positions
reserved for them will be displayed. Thus, great care must be taken to ensure
that the string to be printed can actually be accommodated within the format
specified.
For formatting strings the following symbols are available:
& Causes the output of the entire character string.
! The output is limited to the first character of the string.
\...\ Specifies the number of characters of the string to be printed.
(The counting includes the two '\' symbols).
_ Causes the output of the character following the underline ('_')
character. A sequence of characters can be output by placing it
between two '_' characters.
Examples:
PRINT USING "#.####",PI
PRINT AT(4,4);USING "PI_._._.#.###",PI;
--> Displays '3.1416' and 'PI... 3.142'.
FOR i%=1 TO 14
PRINT USING "###.##^^^^ ",2^i%;
NEXT i%
--> Displays: 1.00E+00 2.00E+00 4.00E+00 8.00E+00 16.00E+00
32.00E+00 64.00E+00 128.00E+00 256.00E+00 512.00E+00
1.02E+03 2.05E+03 4.10E+03 8.19E+03 16.38E+03
The functions of commas and periods can be exchanged using the MODE command.
MODE
MODE n
n: iexp
With MODE the representations of the decimal point and the 'thousands comma' as
interpreted by PRlNT USING (and also by STR$() with 3 parameters) can be
reversed. This allows the use of the continental method of representing
numbers.
In addition, MODE selects the format of the date representation used by DATE$,
SETTIME, DATE$=, and FILES. The parameter n can be between 0 and 3. The
following may then be used:
Mode USING DATE$
0 #,###.## DD.MM.YYYY (default)
1 #,###.## MM/DD/YYYY US
2 #.###,## DD.MM.YYYY
3 #.###,## MM/DD/YYYY
Memo: MODE does no range check at all on the parameter.
DEFNUM
DEFNUM n
n: iexp
DEFNUM affects the output of numbers by the PRINT command and its variants.
All numbers following the DEFNUM instruction are outputted to occupy n
character positions, not counting the decimal point. Rounding takes place based
on the value of the (n+1)-th digit. The internal computational accuracy is not
affected.
Example:
PRINT 100/6
DEFNUM 5
PRINT 100/6
--> The numbers 16.66666666667 and 16.667 appear on the screen.
Memo: Only values =>3 are accepted, lower numbers are ignored.
The upper limit appears to be 14.
The default is 13.
DEFNUM 14 seems to work and outputs the result minus the rounding.
CRSCOL
CRSCOL
CRSLIN
POS(x)
TAB(n)
HTAB column
VTAB line
n, column, line: iexp
x: aexp
This group of commands serve to return the location of the cursor, or to place
the cursor at a particular position.
CRSCOL returns the current column (X) position of the cursor.
CRSLIN returns the current line (Y) position of the cursor.
POS() returns the number of characters displayed on the screen (ANDed with 255
to give a maximum of 255) since the last Carriage Return. The expression x is
ignored. The value returned by POS() may, however, not agree with CRSCOL e.g.
if a string 120 characters long is displayed, POS(0) in this case will return
the value 120, where as CRSCOL will return 41, the column number of the next
character to be printed counting from the left edge. With the output of control
characters POS() has even less to do with the current cursor column reported by
CRSCOL, since POS() will keep track of non-printed characters, e.g.
ESCape=CHR$(27). POS() will, however, ignore Line Feeds=CHR$(10), be reduced by
one by the printing of a Backspace=CHR$(8), or be reset to zero by a Carriage
Return=CHR$(13).
TAB(n) prints spaces until POS() reaches n. If POS() already exceeds n, then a
Carriage Return/Line Feed is executed first. The value of n is limited to a
maximum of 255 by ANDing it internally with 255.
The instruction HTAB positions the cursor to the specified column (X).
The instruction VTAB positions the cursor to the specified line (Y).
Note: The cursor columns and lines are counted from 1, and not 0.
Examples:
PRINT AT(3,12);"Test";
PRINT CRSCOL'CRSLIN
PRINT TAB(37);"Test";
PRINT POS(0)
INP(2)
--> On the screen, 'Test7 12' appears and, underneath it, 'Test41'. (POS()
returns 41, and not 42, as it is counted from zero rather than 1 as with
CRSCOL).
PRINT AT(4,3);"Word 1"
HTAB 4
VTAB 2
PRINT "Word 2"
--> 'Word 1' appears starting at line 3, column 1, and 'Word 2' at line 2,
column 4.
Memo: CRSCOL/CRSLIN are actually Line-A variables.
Internally HTAB/VTAB call CRSCOL/CRSLIN.
CRSCOL/CRSLIN -> V_CUR_XY (Line-A variables)
Line-A Variable Table+, vq_curaddress()+, vs_curaddress()+
KEYxxx Commands
KEYPAD
KEYTEST
KEYGET
KEYLOOK
KEYPRESS
KEYDEF
This group of functions makes it possible to read the status of the keyboard
shift keys while a program is running as well as assigning freely definable
character strings (max. 31 characters each) to the Function Keys, which will
also be available when using the GFA BASIC Editor.
KEYPAD
KEYPAD n
n: iexp
The numerical expression n is evaluated bit by bit and has the following
meaning:
Bit Meaning 0 1
0 NumLock On Off
1 NumLock Not switchable Switchable
2 CTRL-KEYPAD Normal Cursor
3 ALT-KEYPAD Normal ASCII
4 KEYDEF without ALT Off On
5 KEYDEF with ALT Off On
With bit 0 set the keypad will act as a 'PC' keypad with NumLock off, i.e. it
responds with cursor movements.
With bit 1 set the 'PC' NumLock mode can be toggled with Control and '-',
otherwise it cannot. Control and '(' also toggles NumLock mode. When NumLock
is on a circumflex (^) appears under the Atari logo in the Menu bar.
With bit 2 set, NumLock is effectively switched off while the Control key is
held down. Thus Control-4 (on the keypad) produces cursor movements.
With bit 3 set ASCII values for characters can be typed in with the ALTernate
key held down. When ALT is released, the character appears.
With bit 4 set, the character strings assigned with KEYDEF to the keys F1 to
F10 and Shift-F1 to Shift-F10 are output when the key is pressed.
With bit 5 set the ALTernate key must also be held down.
When turned on, the Atari ST is effectively configured to KEYPAD 0. With
GFA-Basic in operation, the default keypad mode is decimal 46, i.e. bits 1, 2,
3, and 5 are set (&X101110).
KEYTEST
KEYTEST n
KEYGET n
KEYLOOK n
n: ivar
KEYTEST is similar to INKEY$ and reads a character from the keyboard. If no key
was pressed since the last input (apart from Alternate, Control, Shift, and
Caps Lock) the returned value is zero, otherwise its value corresponds to the
key in the table shown below for KEYGET.
KEYGET waits for a key to be pressed and then returns a long word value
corresponding to the key. This 32-bit long word is constructed as follows:
Bits 0- 7: ASCII code
Bits 8-15: Zero
Bits 16-23: Scan code
Bits 24-31: Status of Shift, Control, Alternate, and CapsLock as follows:
Bit Key
0 Right shift
1 Left shift
2 Control
3 Alternate
4 Caps lock
KEYLOOK allows a character to be read from the keyboard buffer, without
changing the buffers contents, as with KEYGET or INKEY$.
If n is a byte or word variable then an integer conversion takes place
automatically.
Examples:
PRINT "Please press ESCape"
REPEAT !The program runs through the loop
UNTIL INKEY$=CHR$(27) !until the ESCape key is pressed.
'
PRINT "Please press ESCaPe again"
REPEAT !Again runs through the loop but
KEYTEST n| !this time checks the keyboard here for
UNTIL n|=27 !character number 27.
--> Waits twice for the ESCape key to be pressed. Note that in the second
example bits 0 to 7 are masked off automatically by using a byte-sized
(8-bit) variable.
PRINT "Please press a key"
key_1|=INP(2) !Waits for a key-press.
PRINT "Press another key please"
KEYGET key_2| !Waits again.
PRINT "INP(2): ";key_1| !The ASCII codes of the depressed
PRINT "KEYGET: ";key_2| !keys are printed.
--> Waits twice for keys to be pressed, and displays their ASCII codes.
REPEAT
KEYLOOK n%
UNTIL n%
INPUT "Type in something ";a$
--> Waits in a loop until a key is pressed, then begins the input of a$ without
losing the initial character.
DO
KEYGET a%
PRINT HEX$(a%,8),BIN$(a%,32),
OUT 5,a%
PRINT
LOOP
--> Waits for a key to be pressed and displays the value returned by KEYGET in
both hexadecimal and binary.
Note: OUT 5,a% allows the characters associated with control codes 0-32 to
be displayed.
Cnecin()+ Iorec()+
KEYPRESS
KEYPRESS n
n: iexp
The command KEYPRESS simulates the pressing of a key. That is, the character
with the ASCII code contained in the lowest-order 8 bits of n is added to the
keyboard buffer. Additionally, the state of the Control, Shift, and Alternate
keys may be passed in the highest-order byte, as defined by KEYGET. If the
ASCII code given is zero, a scan code may be passed in bits 16 to 23, e.g.
KEYPRESS &H3B0000 presses F1.
Examples:
FOR i&=65 TO 90 !Simulates the pressing
KEYPRESS i& !of the keys A-Z ....
NEXT i&
KEYPRESS 13 !.... followed by a Carriage Return
INPUT a$ !Characters are taken up to the first Carriage Return
PRINT a$
--> The letters from A to Z are printed.
KEYDEF 1,"Hello"+CHR$(13)
KEYPRESS &H83B0000
PAUSE 1
LINE INPUT a$
PRINT a$
-->A string to be produced by pressing ALT-F1 is defined, then a press of this
key is simulated, followed by a slight pause to give the associated
interrupt routine time to process it. The word "Hello" is then taken as the
inputted a$.
Iorec()+
KEYDEF
KEYDEF n,s$
n: iexp
s$: sexp
The command KEYDEF makes it possible to assign an arbitrary character string
(with a maximum length of 31 characters) to the Function Keys. The arithmetic
expression n (with a value from 1 to 20 inclusive) determines the key. A value
of n from 1 to 10 refers to the keys F1 to F10, and from 11 to 20, to the keys
Shift-F1 to Shift-F10. The defined string is available both during the running
of a program and from the GFA-Basic Editor.
However, in the Editor the ALTernate key must also be pressed, as otherwise the
GFA-Basic commands would not be available.
Example:
KEYPAD 16 !Sets ALT key as not required
DO
KEYDEF 1,"F1" !String for F1 key
KEYDEF 11,"Shift+F1" !String for Shift-F1 key
INPUT x$
LOOP
--> Instead of having to type in a string as the input, pressing F1
automatically supplies the string 'F1' and pressing Shift-F1 supplies the
string 'Shift+F1'.
Memo: This command relies on an interrupt and should be avoided.
If n is over 20 the command exits with no error message.
If s$ is over 31 characters it gets clipped off.
This section first describes the storing and recalling of constants with DATA,
READ, and RESTORE. Then file management is dealt with starting with the
indexing commands DIR$(), CHDIR, DIR, FILES, MKDIR, and RMDIR, and explaining
the structure of the hierarchical filing system. Next comes the opening,
closing, renaming etc. of files with EXIST(), KILL, NAME, OPEN, and CLOSE
followed by the facilities for storage of areas of memory with BLOAD, BSAVE,
BGET, and BPUT. Then sequential input and output with INPUT$(), INPUT # and
PRINT # are covered, together with indexed sequential accessing of files (SEEK,
RELSEEK), as well as random accessing (FIELD, GET #, PUT #, SEEK, RELSEEK). The
section on peripheral devices describes byte by byte input and output with
INP(), OUT and their 'query' counterparts INP?() and OUT?(), and input from the
serial and MIDI interfaces (INPAUX$, INPMID$).
Finally, the commands are given for the handling of the mouse and joysticks
(MOUSE, MOUSEX, MOUSEY, MOUSEK, HIDEM, SHOWM, STICK(), STRIG()), and printer
output (LPRINT, LPOS(), HARDCOPY).
Data Commands
DATA const [,const1,const2,...]
READ var [,var1,var2,...]
RESTORE [label]
_DATA
_DATA=
const, const1, const2: numerical or string constants
var, var1, var2: avar or svar
label: user-defined label
DATA statements are used to store numeric or string constants which can then be
accessed with READ. Numeric values can be specified in hexadecimal, octal, or
binary form, but string constants must be enclosed in inverted commas if they
contain commas, as commas are normally used to separate items in the DATA
statement.
Internally associated with DATA and READ is the so-called data pointer, which
always points to the next item to be READ. When a program is RUN, this is the
first item in the first DATA statement. The RESTORE instruction allows the data
pointer to be moved so as to point to any DATA statement, provided the DATA
statement is preceded by a label. If no label is specified by RESTORE, the data
pointer is moved to the first DATA statement in the program.
The label can consist of numbers, letters, underline characters ('_') or
periods, and, unlike variable names, can begin with a number. The label
occupies a line by itself and must end with a colon, although the colon is not
used when the label is referred to elsewhere in the program.
_DATA returns the position of the DATA pointer. _DATA is 0 if the next READ
would result in an "out of data" error.
_DATA= permits the setting of the DATA pointer to a value which has been
previously determined with _DATA.
Examples:
FOR i=1 TO 3
READ a
PRINT a'
NEXT i
'
RESTORE roman_numbers
READ a$,b$,c$,d$
PRINT
PRINT a$'b$'c$'d$
'
DATA 1,2,3,4
DATA a,b,c,d
'
roman_numbers:
DATA I,II,III,IV
--> In the loop the numeric values 1, 2, and 3 are read in and printed on the
screen. After that, by means of RESTORE, the data pointer is moved to the
line containing the roman numerals as data. They are also read in and
printed.
DATA 10,&A,$A,&HA,&O12,&X1010,%1010
FOR i%=1 to 7
READ a%
PRINT a%
NEXT i%
--> The number 10 is read in seven times. Like INPUT, VAL() etc., READ can
interpret Hexadecimal numbers if they are prefixed with '$' or '&H', and
Binary numbers if they are prefixed with '%' or '&X'.
DIM dp%(100)
DATA 1,2,3,4,5,6,7,8,9
DATA 13,24,328,3242,1,0
'
i%=0
DO WHILE _DATA
dp%(i%)=_DATA
INC i%
READ a
LOOP
'
DEC i%
'
FOR j%=i% DOWNTO 0
_DATA=dp%(j%)
READ a
PRINT a
NEXT j%
~INP(2)
--> Displays: 0 1 3242 328 24 13 9 8 7 6 5 4 3 2 1
A key is then waited for.
Memo: If a string contains a comma or double quotes or spaces on either
end, the entire string must be enclosed in double quotes. Certain
characters cannot be placed in DATA statements. They are ASCII 4, 10,
and 13. Example: DATA " spaces, "quotes", and commas in the string "
Adding quotes does not increase the size of the compiled binary.
_DATA seems to work in the Editor/Interpreter, but I had problems with it
in compiled programs.
The _DATA pointer truely is a pointer, as it actually returns the address
of the item in the DATA statement itself. Thus, this can be done in the
Editor:
DATA test,this
BYTE{_DATA}=ASC("T")
READ t$
PRINT t$
The word "Test" will appear.
This will actually change your source code if executed in the Editor!
When compiled, the commas between data items become nulls which would
allow the use of CHAR{} to fetch data items. Thus, this can be done in a
compiled program:
DATA Hello world,hi
PRINT CHAR{_DATA}
The words "Hello world" will appear.
Comments cannot be placed behind DATA statements.
If the label used with RESTORE is undefined, the compiler will not issue
an error message. Instead the data pointer will be set incorrectly to
the first data statement in the program.
File Management
In the following section, instructions related to file organisation are
explained.
First, however, it is important to know the structure of a file specification
and the rules of the hierarchical filing system. A file specification consists
of three parts: the drive specification, the file name and the filename
extension. The drive specification contains the disk drive identification in
the range A to P, followed by a colon. The file name is up to 8 characters in
length, with, optionally, an extension comprising a period and up to 3
characters. Groups of files may be gathered into directories (also called
folders), which may themselves be gathered into different sub-directories (or
folders) and so on. The lowest level of grouping (which contains all the files
on the disk in their respective directories and sub-directories) is known as
the root directory. Starting from this root directory, directories may be
accessed, followed by sub-directories, etc. Therefore, for a file to be
accessed, the following information must be given:
- Drive specification
- Name of directory if any, sub-directory if any, etc.
- The actual name of the file and its extension, if any
These parts are separated by reverse diagonal strokes "\" (backslashes). Names
for directories have the same format as filenames. The access path for a file
is a combination of these elements.
Example:
A:\TEXT.DOC\MANUAL\CHAPTER1.DOC
This means that the file to be accessed, named CHAPTER1, has the extension .DOC
and is in a sub-directory called MANUAL, which it self is in a sub-directory
called TEXT.DOC. TEXT.DOC is in the root directory of disk drive A:.
Two special symbols are available to make file selection easier, which can be
used within file names and their extensions. These are the question mark ('?')
and the asterisk ('*'). The question mark acts like a 'wildcard' and will be
accepted as any character whose ASCII value is greater than 32. The asterisk is
similar, except that it can be taken as any sequence of characters in the file
specification.
The command DIR will be explained in a moment, but for now, from the Direct
Mode of GFA BASIC (reached by pressing ESCape), you can type in 'DIR', which
will cause all the files on drive A: to be displayed.
Typing 'DIR *.GFA' lists those files which have the extension '.GFA'.
Typing 'DIR ?AB?.*A' lists those files which have four-letter file names with
the middle two letters 'AB', and an extension ending in 'A'.
Typing 'DIR *.*' lists all files.
The TOS File System+
Directory Handling
DFREE()
CHDRIVE
DIR$()
CHDIR
DIR, FILES
FGETDTA(), FSETDTA()
FSFIRST(), FSNEXT()
MKDIR, RMDIR
DFREE
DFREE(n)
CHDRIVE n
CHDRIVE n$
DIR$(n)
CHDIR name$
n: iexp
n$, name$: sexp
DFREE() (disk free) returns the amount of space free for storage on drive n in
bytes. This can take a few seconds, or longer with a partitioned hard disk
drive. See CHDRIVE below for the meaning of the parameter n.
CHDRIVE (Change Drive) sets the default disk drive. This is the drive which is
used by DIR etc. if no other drive is specified. Any drive can be made the
default drive with CHDRIVE followed by the drive number from 0 to 16. Drive 0
corresponds to the current default drive, drive 1 corresponds to A:, drive 2 to
B:, etc. The argument of CHDRIVE may also be a string, in which case the first
character (from A to P) identifies the drive.
DIR$(n) returns as a string the current access path for drive n, as set with
CHDIR below. See CHDRIVE above for the meaning of the parameter n.
CHDIR sets the current directory. Since the default drive cannot be changed
with CHDIR, the specified directory must be on the current default drive or a
specified drive.
So, after CHDIR "B:\TEST", the directory TEST on drive B: becomes the current
directory, which may be accessed without the need to specify the path
'B:\TEST'. With CHDIR "\", one can return to the root directory from any
sub-directory. The directory required is always looked for as a sub-directory
of the current directory. Thus if, after making B:TEST the current directory as
above, one issued the command CHDIR "TEST2", the effective path from the root
directory would be B:\TEST\TEST2.
There are two special folder names: '.' aud '..', which are shorthand ways of
referring to the 'current' directory path and the 'parent' directory path
respectively. The parent path is that which leads up to, but does not include,
the current directory. For instance, with the path 'B:\TEST\TEST2' above, the
parent path is 'B:\TEST'. Thus to change the current directory to another on
the same level, perhaps TEST2A, it is only necessary to type CHDIR "..\TEST2A".
Examples:
CHDRIVE 1
PRINT DFREE(0)
PRINT DIR$(2)
CHDRIVE "C:\"
--> Disk drive A: is selected as the current default drive, and its free
storage capacity is printed. Then the current access path for drive B: is
printed, and finally drive C: is made the current default drive.
CHDIR "\"
CHDIR "TEXT.DOC\MANUAL"
CHDIR "APPENDIX"
--> CHDIR "\" sets the current directory to be the root directory of the
current drive. In the second line MANUAL, which is a sub-directory of the
sub-directory TEXT.DOC, is made the current directory. In the third line a
further sub-directory APPENDIX is made the current directory, so that the
access path is now \TEXT.DOC\MANUAL\APPENDIX.
Memo: DFREE() will fail on large capacity drives, internally it uses word
values. Call GEMDOS(54) directly to get a more accurate value. Due the
limits of a long% drive larger than 2gb are still a problem.
DIR$() does not report invalid drive identifiers.
Dfree()+, Dsetdrv()+, Dgetpath()+, Dsetpath()+
DIR
DIR p$ [TO name$]
FILES p$ [TO name$]
p$, name$: sexp
The instructions DIR and FILES allow directories to be printed out, or sent to
a specified device or file with 'TO name$'. If no device is specified, the
output goes to the screen. The desired access path and file mask (e.g. *.*) is
specified in the expression p$. FILES is very similar to DIR, with the
difference that it also provides information on the length, time and date of
the listed files, and will also list folder names, identified by a '*' prefix,
if they fulfill the conditions of the file mask.
If p$ ends in '\', with no file mask, the mask '*.*' will be added
automatically by default.
With the optional extra 'TO name$' the directory information can be sent to a
peripheral device or to a file. In this case name$ must contain the device
identifier (e.g. "LST:") or a file specification (e.g. "A:\CONTENTS.LST").
Examples:
DIR "A:\BOOKS\*.DOC"
--> All files with the extension .DOC in the folder BOOKS on drive A: are
listed on the screen.
DIR "A:\BOOKS\MANUAL\*.DOC" TO "B:\MANUAL\CONTENTS.ASC"
--> The list of files ending in .DOC in the folder MANUAL, which itself is
found in the folder BOOKS, is sent to the file CONTENTS.ASC in the folder
MANUAL on drive B:.
DIR "A:\*.*" TO "PRN:"
--> All the files on drive A: are listed on the printer.
FILES "A:\*.DOC" TO "LST:"
--> All the files on drive A: which have the extension .DOC are listed on the
printer.
Memo: Missing from the original manual. Pressing Right-Shift will pause the
display.
Internally channel #87 is used if the 'TO' parameter is specified.
This could cause a conflict if channel #87 is already in use.
FGETDTA
FGETDTA()
FSETDTA(addr)
addr: iexp
The DTA (disk transfer address) can be read with the function FGETDTA() or set
with the instruction FSETDTA(). The default address of the DTA is BASEPAGE+128
when a program frist starts up. The DTA address will be reset back to
BASEPAGE+128 if the commands DIR or FILES are used. EXIST() does not reset the
DTA address.
The DTA has the following structure:
Offset Bytes Meaning
0 21 Reserved for GEMDOS()
21 1 File attributes (see below)
22 2 Time
24 2 Date
26 4 File length
30 14 File name terminated with null byte, without blanks
Memo: The DTA structure is exactly 44 bytes.
A call to FSETDTA() will change entry BASEPAGE+32.
Original manual stated: The DTA address is changed when a File Select
Box is used. This not true.
The commands FSFIRST() and FSNEXT() use the DTA address.
Fgetdta()+, Fsetdta()+, DTA+
FSFIRST
FSFIRST(p$,attr)
FSNEXT()
p$: sexp
attr: iexp
The function FSFIRST() searches for the first file on a disk to fulfill the
criteria specified in p$ (e.g. "C:\*.GFA"). If such a file is found, the file
name, together with other information, is written into the DTA (see FGETDTA()
and FSETDTA()). The parameter attr contains the file attributes which the file
to be found may have; for instance, it is possible to seareh for hidden files
(bit 1) or folders (bit 4).
The function FSNEXT() searches for the next file which fulfills the conditions
of FSFIRST().
The meaning of the attribute bits:
Bit Meaning (if the bit is =1)
0 The file is write protected
1 The file is hidden (excluded from DIR search)
2 The file is a System file (excluded from DIR search)
3 Disk label
4 Folder (sub-directory)
5 Archive bit
Example:
~FSETDTA(BASEPAGE+128) !Set the DTA
e%=FSFIRST("\*.GFA",-1) !Set search criteria (-1 = all bits set)
DO UNTIL e%
IF BYTE{BASEPAGE+149} AND 16 !If it is a folder
PRINT "*";CHAR{BASEPAGE+158}, !indicate by a star
ELSE !otherwise
PRINT 'CHAR{BASEPAGE+158}, !a space before the file name
ENDIF
e%=FSNEXT() !Continue search
LOOP
--> Displays all files with the extension .GFA from the current directory on
the screen, as well as all folder names with that extension, indicated with
the prefix '*'.
Memo: This will fail:
e%=FSFIRST(p$,attr&)
DO UNTIL e%
f$=CHAR{BASEPAGE+128+30}
IF EXIST(f$)
' EXIST() calls FSFIRST() internally and breaks the search criteria!
ENDIF
e%=FSNEXT()
LOOP
Fsfirst()+, Fsnext()+
MKDIR
MKDIR name$
RMDIR name$
name$: sexp
The instruction MKDIR (make directory) puts a new directory (folder) on the
disk. The expression name$ contains the associated access path.
The instruction RMDIR (remove directory) deletes a directory, provided,
however, that it is empty (i.e. contains no files or sub-directories). The
expression name$ contains the associated access path.
Example:
MKDIR "A:\PROGS"
RMDIR "A:\PROGS"
--> The directory "PROGS" is created on drive A:, then deleted.
Dcreate()+, Ddelete()+
Files
EXIST()
OPEN, CLOSE
LOF(), LOC(), EOF()
TOUCH
NAME (RENAME)
KILL
BLOAD, BSAVE
BGET, BPUT
EXIST
EXIST(name$)
name$: sexp
By means of EXIST() one can determine whether a given file exists on a disk.
The parameter name$ conatins the access path and the file name. The funcition
returns the value TRUE (-1), if the file exists, or FALSE (0) if not.
Example:
OPEN "O", #1,"TEST.TXT"
PRINT #1,"EXAMPLE"
CLOSE #1
PRINT EXIST("TEST.TXT")
PRINT EXIST("TEST.DOC")
--> The file TEST.TXT is opened, some sample text is put in it, and the file is
closed again. The value -1 (TRUE) is the printed, followed by 0 (FALSE), as
the file TEST.DOC does not exist.
Also see: FSFIRST(), FSNEXT().
Memo: The EXIST() function seems to cause problems in desk accessories.
EXIST() seems to cause a system crash if you attempt to change the
resolution after it has been called at least once in a program. The
EXIST() function ruins the command line. Either fetch the command line
before using EXIST() or don't use EXIST(), instead call GEMDOS()
directly. Commands such as FILES, DIR, and FILESELECT also clobber the
command line.
OPEN
OPEN mode$,#n,name$[,len]
mode$, name$: sexp
n, len: iexp
OPEN opens a data channel to a file or to a peripheral device. The expression
mode$ sets one of the following access modes:
mode$ Description
O output A file is opened to receive data. If neccessary the file
will be created, or, if the file already exists its contents
will be deleted.
I input A file is opened for reading.
A append An existing file is opened, and the data pointer set to the
end of the file. Data output to the file will then be added
at that point.
U update An existing file is opened for reading and writing.
R random access A Random Access file is opened for reading and writing.
This file type is described fully later.
The numerical expression n contains the channel number and can take a value
from 0 to 99. This channel number must be specified when working with the file.
The '#' sign before the channel number can be omitted, as the Editor will
supply it anyway. The expression name$ contains the access path and the file
name of the required file.
Instead of a file name, a peripheral device can be specified. The numerical
expression len is only used with the Random Access mode and defines the length
of a data record. The maximum record length is 32767 bytes, and the maximum
number of fields approximately 5000.
The following device names can be used:
name$ Device Internal use
LST: list Printer (parallel) BIOS 0
AUX: auxiliary Serial (RS232) BIOS 1
CON: console Keyboard/Screen BIOS 2 or VDI
MID: musical instr. digital interface MIDI port BIOS 3
IKB: intelligent keyboad Keyboard processor BIOS 4
VID: video Monitor BIOS 5 or VDI
PRN: printer Printer GEMDOS -3
STD: console (stdin/stdout) Keyboard/Screen GEMDOS 1
LPT: same as PRN:
COM: same as AUX:
Example:
OPEN "O", #1,"TEST.TXT" !send data to a file
or
OPEN "O", #1,"PRN:" !send data to the printer
Memo: From BUGFIXED.TXT from my master disk:
There is a new device called 'STD:'. This is the same as 'stdin' and
'stdout' respectively in C-programs. A shell can be used to redirect the
output of a GFA-BASIC program.
GFABASIC TEST >DUMMY
This line starts GFA-BASIC and the program TEST.GFA. Any output via
'STD:' is redirected to the file DUMMY.
IMPORTANT: Control-C will cause termination of the program if pressed
while reading/writing file DUMMY. The default for input/output is the
keyboard/console.
Device numbers =>6 are not supported by the OPEN command.
To access such devices, use Operating System calls instead.
Device PRN: does not work correctly on the Falcon030.
Internally GFA uses GEMDOS handle -3, which should of been handle 3.
Fopen()+, Fcreate()+
CLOSE
LOF(#n)
LOC(#n)
EOF(#n)
CLOSE [#n]
TOUCH [#]n
n: iexp
The numerical expression n refers to the channel number previously specified
with OPEN.
LOF() (length of file) returns the length of a file in bytes.
LOC() (location) returns the current position of the data pointer measured in
bytes from the beginning of the file. (where LOC() returns zero). See also
SEEK.
EOF() (end of file) determines whether the data pointer points to the end of a
file (or the whole file has been read). If the data pointer does point to the
end of the file, TRUE (-1) is returned, otherwise FALSE (0).
CLOSE closes a data channel to a file or peripheral device previously opened
with OPEN. The numerical expression n contains the number of the channel to be
closed. If the channel number is omitted, all open files are closed.
TOUCH updates the date and time stamps of a file, giving it the current system
date and time.
Examples:
OPEN "o",#1,"TEST.TXT"
FOR i%=1 to 20
PRINT #1,STR$(i%)
NEXT i%
CLOSE #1
FILES "TEST.TXT"
DELAY 20 ! Wait 20 seconds
OPEN "u",#1,"TEST.TXT"
TOUCH #1
CLOSE #1
FILES "TEST.TXT"
--> In the example the file TEST.TXT is opened, written to, and closed. Then
the file information is displayed, including the time and date. Twenty
seconds later the file is opened again, the date and time updated, then
closed. The file information is displayed again.
OPEN "i",#1,"TEST.TXT"
PRINT "file length: ";LOF(#1)
PRINT
PRINT "data","position of the data pointer"
DO UNTIL EOF(#1)
INPUT #1,a$
PRINT "";a$,LOC(#1)
LOOP
CLOSE #1
--> The example opens the file from the previous example for reading. First
the length of the file is displayed by means of LOF(). Then the contents of
the file are displayed along with the associated data pointer position
until the termination condition of the loop is met when EOF() is TRUE.
Memo: TOUCH does not issue an error if the #channel is wrong.
TOUCH doesn't work in the editor or compiled, just does nothing.
CLOSE #n does not issue an error if the #channel is wrong.
EOF(), LOC(), and LOF() don't issue errors if the #channel is wrong.
Fclose()+, Fdatime()+
NAME
NAME old$ AS new$
RENAME old$ AS new$
KILL name$
old$, new$, name$: sexp
NAME gives the file specified in old$ the new name specified in new$. The
contents of the file is not changed. Of course, old$ and new$ must refer to the
same disk drive in their file specifications. NAME and RENAME are synonymous.
KILL deletes the file specified in the expression "name$".
Example:
OPEN "o",#1,"TEST.TXT"
PRINT #1, "example"
CLOSE #1
'
NAME "TEST.TXT" AS "EXAMPLE.TST"
DIR
KILL "EXAMPLE.TST"
DIR
--> The file TEST.TXT is opened and some sample data written to it. It is then
renamed as EXAMPLE.TST and the directory displayed to show its presence.
EXAMPLE.TST is then deleted and the directory displayed again, this time to
show its absence.
Frename()+, Fdelete()+
BLOAD
BLOAD name$[,addr]
BSAVE name$,addr,count
BGET #n,addr,count
BPUT #n,addr,count
name$: sexp
n, addr, count: aexp
With BSAVE an area of memory can be stored on disk (or RAM-disk, hard disk
drive etc.), and loaded again e.g. with BLOAD. The numerical expression addr
specifies the address of the first byte of the area to be saved, or, with
BLOAD, the address where the data from disk is to be put. If no address is
specified with BLOAD, the address that was specified with BSAVE when the area
was saved will be used. BSAVE must also specify the number of bytes to be
saved. The parameter name$ is the file specification of the file to which the
area is to be saved, or from which it is to be loaded. See the beginning of
"File Management" for details of the specification. BSAVE and BLOAD always use
a whole file.
BGET reads from channel 'n', the number of bytes 'count', and places the data
at address 'addr'. BPUT writes to channel 'n', the number of bytes 'count',
starting at address 'addr'. BGET and BPUT access a file via its channel number
n, so it is possible to use BGET and BPUT to save or load parts of a file.
Examples:
DEFFILL 1,2,4
PBOX 100,100,200,200
BSAVE "RECTANG.PIC",XBIOS(2),32000 !XBIOS(2) gives screen address
CLS
PRINT AT(4,20);"Picture stored. Press a key"
~INP(2)
CLS
BLOAD "RECTANG.PIC"
--> Draws a rectangle and stores the screen under the name "RECTANG.PIC". An
appropriate message is displayed, and, after a key has been pressed, the
file is re-loaded, again to the screen memory area.
DEFFILL 1,2,4
PBOX 0,0,639,199
DEFFILL 1,2,2
PBOX 0,200,639,399
DEFTEXT 1,0,0,32
TEXT 10,115,"the upper half"
TEXT 10,315,"the lower half"
'
OPEN "o", #1,"SCREEN.PIC"
BPUT #1,XBIOS(2),32000
CLOSE #1
PAUSE 25
CLS
'
OPEN "i",#1,"SCREEN.PIC"
BGET #1,XBIOS(2)+16000,16000
BGET #1,XBIOS(2),16000
CLOSE #1
--> The upper half of the screen is filled with one pattern, the lower half
with another, and appropriate messages are put in each half. Then the
entire screen is saved into the file SCREEN.PIC. After a pause, the first
half of the file is loaded into the bottom half of the screen, and the
second half of the file is loaded into the top half of the screen.
Fread()+, Fwrite()+
Memo: BSAVE does not actually save the address of the memory block into
the file. BLOAD attempts to load the block at the last address used in
the last BSAVE command that was executed with in the same program if no
address is speficied. Internally GFA uses channel #89 to perform
BSAVE/BLOAD. Conflicts can occur if you use this channel and leave it
open and then call BSAVE or BLOAD. The result is an error #22.
BLOAD is not allowed on devices. The result is an error #-1.
Sequential Access
INP(#), INP&(#), INP%(#)
OUT #, OUT& #, OUT% #
INPUT$()
INPUT #
LINE INPUT #
PRINT #
PRINT # USING
WRITE #
STORE, RECALL
SEEK, RELSEEK
INP
INP(#n)
INP&(#n)
INP%(#n)
OUT #n,a[,b,c,...]
OUT& #n,a[,b,c,...]
OUT% #n,a[,b,c,...]
n: iexp
INP(#n) reads a byte from a file which has been previously opened with OPEN.
The numerical expression n is the channel number under which the file was
OPENed.
INP&(#n) reads a word (two-byte value) from a file.
INP%(#n) reads a long (four-byte value) from a file. Thus a%=INP%(#1) can
replace a%=CVL(INPUT$(4,#1)).
OUT #n sends a byte to a file which was been previously opened with OPEN. The
numerical expression n is the channel number under which the file was OPENed.
Only the low-order 8 bits of a, b, c, ... are output, thus limiting their
values to 255.
OUT& #n sends a word (two-byte value) to a file.
OUT% #n sends a long (four-byte value) to a file.
INP() and OUT without the '#' can also be used for communication with the
screen, keyboard, etc. (e.g. INP(2) reads a character from the keyboard). See
the section called "Communicating with Peripherals".
Example:
OPEN "o",#1,"TEST.TXT"
OUT #1,128
CLOSE #1
'
OPEN "i",#1,"TEST.TXT"
a=INP(#1)
CLOSE #1
PRINT a
--> In the first part of the example a file is opened for output and a byte is
written to it. In the second part this byte is read back in as the variable
'a' which when printed is revealed to have the value 128.
Memo: INP(#n), INP&(#n), and INP%(#n) incorrectly return error code 0 if
the #channel number is incorrect.
Fread()+, Fwrite()+
INPUT$(count[,#n])
n, count: iexp
INPUT$() reads 'count' characters from the keyboard and assigns them to a
string. Optionally, if the channel number n (0 to 99) is specified, the
characters are read in as bytes from a file or peripheral device. In both cases
the numerical expression 'count' determines the number of characters read.
Example:
OPEN "o",#1,"VERSION.DAT"
PRINT #1,"GFA BASIC, Version 3.0"
CLOSE #1
'
OPEN "i",#1,"VERSION.DAT"
v$=INPUT$(9,#1)
CLOSE #1
PRINT v$
PRINT "Please type in the Version number: ";
PRINT INPUT$(3)
--> In the first part of the example the file 'VERSION.DAT' is opened and a
message printed to it. The second part reads the first 9 characters of this
file into the variable v$ and displays v$ on the screen. Then a message
appears, and 3 characters are taken from the keyboard and printed.
Memo: INPUT$(count,#n) incorrectly returns error code 0 if the #channel
number is wrong.
Fread()+
INPUT #n,var1 [,var2,var3,...]
LINE INPUT #n,a1$ [,a2$,a2$,...]
n: iexp
var1, var2, var3, a1$, a2$, a3$: avar or svar
Parameter n is the channel number which was previously opened with OPEN.
INPUT #n makes it possible to take data from a file or a peripheral device.
Individual variables or variable lists (where the variables are separated by
commas) can be input. This instruction corresponds to INPUT, except that it
deals with files.
LINE INPUT # corresponds to LINE INPUT except that it deals with files.
Example:
OPEN "o",#1,"TEXT.DOC"
WRITE #1,"Goodbye","Hello","Hello, Hello, Hello"
CLOSE #1
'
OPEN "i",#1,"TEXT.DOC"
INPUT #1,a$,b$
LINE INPUT #1,c$
CLOSE #1
PRINT a$
PRINT b$
PRINT c$
--> Three strings are written to the file TEXT.DOC. The first two are read back
in with INPUT #, the third with LINE INPUT #, as it contains commas. The
three strings are printed.
Fread()+
PRINT #
PRINT #n,expression
PRINT #n,USING form$,expression
WRITE #n,expression
n: iexp
form$: sexp
expression: aexp or sexp or a combination
PRINT #n outputs data to a specified channel. Parameter n (0 to 99) denotes the
required channel. Otherwise the instruction operates like PRINT. PRINT #n AT,
however, is not possible.
PRINT #n USING allows formatted output to a data channel. The parmater n (0 to
99) denotes the required channel. Otherwise the instruction operates like PRINT
USING.
The instruction WRITE # serves primarily for the space-saving storage of data
in sequential files in a format suitable for later reading with INPUT #. The
expressions are separated by commas and character strings must be enclosed in
quotation marks. The parmater n (0 to 99) denotes the required channel.
Otherwise the instruction operates like WRITE.
Examples:
OPEN "o",#1,"TEXT.DOC"
PRINT #1,"test"
CLOSE #1
'
OPEN "i",#1,"TEXT.DOC"
INPUT #1,a$
CLOSE #1
PRINT a$
--> The string 'test' is printed to the file TEXT.DOC, which is then closed and
re-opened for input. INPUT # takes the string from the file as a$, which is
then printed on the screen.
OPEN "o",#1,"TEST.DAT"
WRITE #1,"Version ",3,".0"
CLOSE #1
'
OPEN "i", #1,"TEST.DAT"
INPUT #1,v1$,v2$,v3$
CLOSE #1
PRINT v1$+v2$+v3$
--> Data separated by commas is put into the file TEST.DAT and afterwards read
back in again with INPUT # and displayed on the screen.
Fwrite()+
STORE
STORE #i,x$() [,n [TO m]]
RECALL #i,x$(),n [TO m] ,x
i, n, m: iexp
x$(): string array
x: variable, at least 32-bit (long)
The instruction STORE is used for sending the contents of an array to a file or
data channel (with the elements separated by CR/LFs). The optional parameter m
specifies how many elements of the array are to be sent to the previously
OPENed channel i; if m is omitted, the whole array is transferred.
The instruction RECALL allows the quick inputting of m lines from a text file
to the array x$(). If m=-1 all available lines are read. If m is too large for
the dimension of the array, then the number of lines read in is limited
automatically. If the end of file is reached during reading then the inputting
is broken off without an error occurring. In each case, after the reading has
been completed, the variable x will contain the number of strings actually
read.
In addition to mentioning the number of strings to be read/written you can give
the range of the strings to be stored, e.g, STORE #1,a$(),10 TO 20.
--> That stores eleven strings from a$(), starting with number 10 up to 20,
counting always starts with zero.
Note: STORE functions with files and peripheral devices, but RECALL only
functions with files, since a SEEK (see following) is used internally.
Examples:
DIM A$(1000)
FOR i%=0 TO 499
a$(i%)=STR$(RND) ! anything
NEXT i%
'
OPEN "o",#1,"TESTFILE.TXT"
STORE #1,a$(),500
CLOSE #1
'
DIM b$(2000)
OPEN "i",#1,"TESTFILE.TXT"
RECALL #1,b$(),-1,x
CLOSE #1
PRINT x
--> The number of text lines read is displayed (500).
PRINT "Line counter: "
DIM a$(1000)
DO
FILESELECT "\*.*","",f$
EXIT IF f$=""
lc%=0
OPEN "i",#1,f$
DO
RECALL #1, a$(),-1,x%
ADD lc%,x%
LOOP WHILE x%
CLOSE #1
PRINT f$'"contains"'lc%'"lines."
LOOP
--> This program counts the lines in text files.
Memo: RECALL will crash if any line in the file exceeds about 9100 bytes in
length when compiled.
RECALL searches for ASCII 10 and not ASCII 13 as one might assume.
Thus it will read unix text files, but not Apple text files.
Fread()+, Fwrite()+
SEEK
SEEK #n,pos
RELSEEK #n,num
n, num, pos: iexp
The commands SEEK and RELSEEK permit the re-positioning of the data pointer
with an accessed file, allowing the realisation of indexed sequential file
access. The numerical expression n contains the channel number used when the
file was OPENed. Both commands can be used only with files, not with peripheral
devices. The data pointer specifies which byte of a file was read or written
last. Except for access mode 'A' (used to append data to the end of an existing
file) the data pointer has the value 0 when opening a file. Reading or writing
commences with first byte, to which the data pointer subsequently points.
The SEEK command positions the data pointer to a specified byte number in a
file. The pointer can, however be moved a specified number of bytes forwards or
backwards with RELSEEK (relative seek): the pointer is moved the number of
bytes specified in num. RELSEEK is generally faster than SEEK.
SEEK may use positive values of pos up to the relevant file length. RELSEEK
accepts positive or negative values of num, an error occurring when an attempt
is made to position the data pointer past the end or before the beginning of a
file. SEEK #n,0 takes the pointer to the start of a file.
Example:
OPEN "o",#1,"X.X"
PRINT #1,STRING$(20,"*")
SEEK #1,10
PRINT #1,"#";
RELSEEK #1,-5
OUT #1,48,49
CLOSE #1
'
OPEN "i",#1,"X.X"
LINE INPUT #1,a$
CLOSE #1
PRINT a$
--> Displays: ******01**#*********
Memo: FSEEK does not issue and error when compiled if the #channel is
wrong.
SEEK can except negative values. The offset then specifies the number of
bytes from the end of the file. Seems to be an undocumented feature.
Fseek()+
Random Access
FIELD
GET #, PUT #
RECORD #
In the following section the handling of a Random Access file is described.
Two terms are particularly important: Data record and data field. A data field
is a single item of information, for instance a name or telephone number. A
data record consists of a number of data fields, and is analogous to one card
in a card index. The length of a record (in bytes) must equal the sum of the
lengths of the individual fields.
The difference between a random access file and a sequential file lies in the
method of data access. With a sequential file the entire file must be loaded in
order to be able to access a particular data record, whereas with a random
access file the record may be obtained directly. This is particularly useful
with very large files, although this advantage is offset by greater consumption
of space on the disk, because a random access file uses a fixed record length,
resulting in waste if some records are shorter than others.
Memo: FIELD and related commands when compiled, in most cases issue the
wrong error code. If you see error #111, it's really some other error.
FIELD #
FIELD #n,num AS svar$ [,num AS svar$,num AS svar$,...]
FIELD #n,num AT(x) [,num AT(x),num AT(x),...]
n, num, x: iexp
svar$: svar (not an array variable)
The command FIELD # AS is used to divide data records into fields. The
numerical expression n is the number of the data channel (0 to 99) of a file
previously opened with OPEN. The integer expression num determines the field
length. The variable svar$ contains data for one field of a data record. If
the data record is to be divided into several fields, the parts 'num AS svar$'
must be separated by commas. The sum of the individual field lengths must equal
the data reeord length, otherwise an appropriate error message is displayed.
Thus in order to keep the field lengths to those specified in the FIELD command
it is convenient to use the commands LSET and RSET or MID$.
By using AT() instead of AS numeric variables can be written to a random access
file. In this case num must contain the length of the variable (1 for
byte-type, 2 for word-type etc.) and the brackets must contain a pointer to the
variable (see *, VARPTR()). Actually an arbitrary area of memory can be
transferred by specifying the number of bytes (num) and the address of the
first byte (x). Note that there is no space after the 'AT'.
For example:
FIELD #1,4 AT(*a%),2 AT(*b&),8 AT(*c#)
Arbitrary combinations of AS and AT() are possible, e.g.:
FIELD #2,4 AS a$,2 AT(*b&),8 AT(*c#),6 AS d$
Unlike in Version 2, several successive FIELD commands can be used, on
sucessive lines, referring to the same channel number. The effect is the same
as that of one long FIELD command. The maximum record length is 32767 bytes,
and the maximum number of fields approximately 5000.
RECORD
GET #n [,r]
PUT #n [,r]
RECORD #n,r
n, r: iexp
GET reads a data record from a random access file. Similarly, PUT stores a data
record in such a file. The parameter n (0 to 99) is the channel number under
which the file was OPENed, and the optional parameter r contains a value
between 1 and the number of data records in the file, specifying the number of
the data record to be read or stored. If r is omitted, the next record will be
read or stored.
RECORD sets the number of the record to be read or stored next with GET or PUT.
(e.g. after RECORD #1,15 record number 15 will be read by GET #1.)
Note: Only one record at a time can be added to a file. A FOR-NEXT loop
etc. must be used for multiple record storage.
Examples:
OPEN "r",#1,"PERSONAL.INF",62
FIELD #1,24 AS name$,2 AT(*house&)
FIELD #1,24 AS road$,12 AS town$
FOR i%=1 TO 3
INPUT "Name : ";n$
INPUT "House number: ";house&
INPUT "Road : ";r$
INPUT "Town : ";t$
LSET name$=n$
LSET road$=r$
LSET town$=t$
PUT #1,i%
CLS
NEXT i%
CLOSE #1
--> First a random access file (mode 'r') with a record length of 62 bytes is
opened. With FIELD a data record is specified as consisting of 4 fields of
24, 2, 24, and 12 bytes respectively (adding up to 62, the record length
specified in the OPEN statement).
Then the program asks for three names and addresses. Each time the name,
house number, etc. are inserted left justified into the appropriate
variables and the whole data record is written to the file.
In older versions of GFA BASIC instead of '2 AT(*house&)' it was necessary to
use '2 AS house$' and then 'LSET house$=MKI$(house&)' etc.
OPEN "r",#1,"PERSONAL.INF",62
FIELD #1,24 AS name$,2 AT(*house&)
FIELD #1,24 AS road$,12 AS town$
FOR i%=1 TO 3
GET #1,i%
PRINT "Record number: ";i%
PRINT
PRINT "Name : ";name$
PRINT "House number: ";house&
PRINT "Road : ";road$
PRINT "Town : ";town$
PRINT
PRINT
NEXT i%
CLOSE #1
--> Here the file PERSONAL.INF is opened in Random Access mode and the three
records are read in and printed out.
Memo: GET # and PUT # compiled issue the wrong error message if the field
length changes. Should issue error #54 and not error #8.
Fread()+, Fwrite()+
Communicating with Peripherals
INP(), INP&(), INP%()
INP?()
OUT, OUT&, OUT%
OUT?()
INP()
INP(n)
INP&(n)
INP%(n)
INP?(n)
OUT n,a[,b,c,...]
OUT& n,a[,b,c,...]
OUT% n,a[,b,c,...]
OUT?(n)
n, a, b: iexp
INP() reads a byte from a peripheral device. The numerical expression n can
accept values from 0 to 5 (see the following table). The command OUT sends a
byte to a peripheral device.
INP&() reads a word (two-byte value) from a peripheral device. OUT& sends a
word to a peripheral device.
INP%() reads a long (four-byte value) from a peripheral device. OUT% sends a
long to a peripheral device.
Unlike GFA-Basic Version 2, one can now send several bytes with one OUT
statement.
INP?() and OUT?() determine the input or output status of a peripheral device.
A non-zero value is returned if the device is ready to send/receive, and zero
(logical FALSE) if it is not.
INP() and OUT with the '#' can also be used for sequential file access, (e.g.
INP(#2) or OUT #2,a reads from or writes to an already open file). See the
section called "Sequential Access".
Device table is as follows: (See OPEN for more details)
n Device Meaning
0 LST: (list) Printer
1 AUX: (auxiliary) Serial (RS232)
2 CON: (console) Keyboard/Screen
3 MID: (MIDI) MIDI interface
4 IKB: (intelligent kbd.) Keyboard processor
5 VID: (video) Screen
Examples:
PRINT AT(4,4);"Press a key please"
~INP(2)
--> A message is displayed and the program then waits for a byte from device 2
(the keyboard).
OUT 2,27,69,10,10,10
PRINT "Hello"
--> This command clears the screen (by means of the VT-52 control sequence
ESCape+E, corresponding to the ASCII codes 27 and 69), then issues three
Line Feed characters (ASCII code 10). Thus, 'Hello' is printed on the
fourth line.
Memo: For some strange reason ~INP(2) will fail under MiNT if the
AES/VDI are not linked at compile time. In fact any command that uses
bconin() internally most likely won't work. Symptoms are this:
1) Won't wait for input and returns instantly.
2) Always returns the value 26.
Undocumented INP() feature allows -negative device numbers.
Negative device numbers perform an inquire function like INP?().
The results for INP?(0) and INP(-0) however are different since you
can't have negative zero. So that device can't be inquired with INP(-0).
INP(2) (console) returns scancode+128 for any key that has no ASCII
value.
Device numbers =>6 will cause GFA to overwrite internal data!
To access such devices, use operating system calls instead.
Clobbers the internal POS() table and could effects TAB() as well.
Works with device numbers 6 to 9.
INP()
INP?(), OUT?()
Does not work with device numbers 6 to 9.
INP&(), INP%()
OUT, OUT&, OUT%
Handy options:
OUT 4,18 !freeze the mouse, disable mouse packet reporting
OUT 4,8 !unfreeze the mouse, enable mouse packet reporting
Bconin()+, Bconout()+, Bconstat()+, Bcostat()+
Serial (RS232) and MIDI Interfaces
INPAUX$
INPMID$
By means of INPAUX$ and INPMID$ data can be read in very quickly from the
serial and MIDI interfaces.
Example:
DO
PRINT INPAUX$;
LOOP UNTIL MOUSEK
--> Reads in all the data from the input buffer of the serial interface. This
method of data input is much faster than inputting byte by byte.
inp_aux$=""
WHILE INP?(1)
inp_aux$=inp_aux$+CHR$(INP(1))
WEND
--> This alternative method is clearly slower.
Bconin()+
Mouse and Joysticks
MOUSEX, MOUSEY, MOUSEK
MOUSE
SETMOUSE
HIDEM, SHOWM
STICK, STICK(), STRIG()
PADX(), PADY(), PADT()
LPENX, LPENY
MOUSE
MOUSEX
MOUSEY
MOUSEK
MOUSE mx,my,mk
mx, my, mk: avar
MOUSEX, MOUSEY, and MOUSEK return the X and Y coordinates of the mouse pointer,
and information on the state of the mouse buttons. MOUSE allows the gathering
of that information with one statement, giving the current mouse coordinates to
mx and my and the mouse button status to mk. MOUSEK (or mk) will return values
betwwen 0 and 3, with the following meaning:
Note: These commands respect the current CLIP OFFSET.
mk Button(s) pressed
0 None
1 Left
2 Right
3 Both left and right
Example:
REPEAT
IF MOUSEK=1
PLOT MOUSEX,MOUSEY
ENDIF
UNTIL MOUSEK=2
'
REPEAT
MOUSE x%,y%,k%
IF k%=2
PLOT x%,y%
ENDIF
UNTIL k%=1
--> In the first REPEAT-UNTIL loop a point is plotted on the screen at the
mouse pointer position if the left mouse button is pressed. When the right
button is pressed the second REPEAT-UNTIL loop is entered. In the second
loop, plotting takes place provided the right mouse button is held down.
When the left button is pressed, the loop and the program both terminate.
Memo: These are actually Line-A variables.
MOUSE -> GCURX, GCURY, MOUSE_BT (Line-A variables)
MOUSEX -> GCURX
MOUSEY -> GCURY
MOUSEK -> MOUSE_BT
Line-A Variable Table+, graf_mkstate()+
SETMOUSE
SETMOUSE mx,my[,mk]
mx, my, mk: iexp
The command SETMOUSE permits the positioning of the mouse cursor under program
control. The optional parameter mk can simulate the mouse buttons being pressed
or released. This unfortunately is only valid for the VDI, not, (or seldom)
with the AES.
Example:
FOR i%=0 to 300
HIDEM
SETMOUSE i%,i%
PLOT MOUSEX,MOUSEY
SHOWM
PAUSE 2
NEXT i%
--> Moves the mouse pointer diagonally down the screen, plotting points at its
current position as it goes.
Memo: This command should be considered a Line-A call.
Use with caution or not at all.
SETMOUSE -> CUR_X/CUR_Y, GCURX/GCURY, MOUSE_BT (Line-A variables)
USER_MOT, USER_BUT, DEV_TAB
The editor seems to swap the left and right button values:
As documented by Atari: (the compiler works as documented)
Bit Value Meaning Bit status
--- ----- ------- --------------
01 1 Left On=down/Off=up
10 2 Right On=down/Off=up
11 3 Both On=down/Off=up
Line-A Variable Table+
appl_tplay()+, vsm_locator()+, vex_motv()+, vex_butv()+
HIDEM
HIDEM
SHOWM
The commands HIDEM (hide mouse) and SHOWM (show mouse) cause the mouse pointer
to be made invisible or visible respectively. Use of the ALERT command or other
AES routines causes the mouse pointer to be switched on, and, if not required,
it must be subsequently re-hidden with HIDEM.
During output to the screen with PRINT or the VDI or Line-A routines the mouse
pointer is automatically switched off, but afterwards returned to its previous
state.
Example:
REPEAT
IF MOUSEK=1
SHOWM
ENDIF
IF MOUSEK=2
HIDEM
ENDIF
UNTIL MOUSEK=3
--> The mouse pointer is activated by pressing the left button, and
de-activated by pressing the right button. Pressing both simultaneously
ends the program, when the 'Program End' alert box leaves the pointer
visible.
Memo These are actually Line-A calls.
graf_mouse()+, v_hide_c()+, v_show_c()+
Line-A Hide Mouse+, Line-A Show Mouse+
STICK
STICK m
STICK(p)
STRIG(p)
m, p: iexp
The Atari ST is provided with two interfaces (ports) for the attachment of
mouse and joysticks. Port 0 can return mouse or joystick information, but port
1 can only return joystick data.
STICK 0 causes port 0 to return mouse information, and STICK 1 causes it to
return joystick information. Port 1 always reads a joystick. Normally it is not
necessary to use STICK, since mouse queries (MOUSE, MOUSEK, etc.) and joystick
queries (STICK(), etc.) cause STICK 0 and STICK 1 to be executed automatically.
However, before using AES functions (ALERT, etc.) the mouse should be activated
if necessary with STICK 0.
The function STICK(p) returns the position of a joystick. For p=0 the joystick
at port 0 is read, and for p=1, the joystick at port 1. The values returned
correspond to the position of the stick as follows:
5 1 9
\ | /
4-- 0 --8
/ | \
6 2 10
The function STRIG(p) returns the state of the fire button on the joystick
attached to port p as a logical value: TRUE (-1) if it is pressed, or FALSE (0)
if not.
Note: The values for 'p' on the STE can be in the range 0 to 5. 0 and 1
act the same as normally found on the ST but 2-5 are exclusively for the
STE, and DO NOT check for the mouse at the same time. This effectively
speeds up the joystick polling.
Examples:
STICK 1 ! Activates joystick if attached to port 0
REPEAT
direction%=STICK(0)
fire!=STRIG(0)
SELECT direction%
CASE 4
PRINT "Left"
CASE 8
PRINT "Right"
CASE 2
PRINT "Down"
CASE 1
PRINT "Up
ENDSELECT
UNTIL fire!
WHILE STRIG(0)
WEND ! Waits for fire button to be released
--> With movement of the joystick, appropriate messages are printed until the
fire button is pressed. After waiting for it to be released, the program
ends.
Note the difference between the REPEAT and WHILE constructs:
REPEAT
' program segment
UNTIL condition
WHILE condition
' program segment
WEND
With REPEAT, the program segment will certainly be executed at least once,
whereas with WHILE the program segment might not be executed at all if the
condition is false.
Memo: STE STICK() and STRIG() options are incorrectly detected on some
machines based on the '_SND' cookie.
STICK(p)/STRIG(p) Hardware
----------------- --------------
0 mouse/joystick
1 joystick
2 ste only
3 ste only
4 ste only
5 ste only
PADT
PADX(i)
PADY(i)
PADT(i)
i: iexp
These functions are available for reading the STE's paddle controllers.
Parameter 'i' can be 0 or 1 for the two supported paddles.
PADX(i) returns the x-position of the paddle.
PADY(i) returns the y-position of the paddle.
PADT(i) returns the status of the paddle buttons.
FALSE (0) -> not pressed
TRUE (-1) -> pressed
Memo: Incorrectly detected on some machines based on the '_SND' cookie.
PADT() contains a bug in the library.
LPENX
LPENX
LPENY
These functions are available for reading the STE's lightpen socket.
LPENX returns the x-position of the lightpen.
resolution: 0-319 regardless of the mode
LEPNY returns the y-position of the lightpen.
resolution: 1:1 for all modes
Memo: Incorrectly detected on some machines based on the '_SND' cookie.
Probably only works correctly in ST modes. Internally it uses the
shifter value to calculate LPENX.
Printing
LPRINT
LPOS()
HARDCOPY
HARDCOPY
LPRINT expression
LPOS(x)
HARDCOPY
expression: aexp or sexp, arbitrarily mixed
x: avar (dummy argument)
LPRINT is identical to the PRINT command and its variants (LPRINT USING, etc.),
except that output goes to the printer instead of the screen, and it is not
possible to use the PRINT AT equivalent, as this would involve re-positioning
the print head. Similarly to POS(), LPOS() returns the number of characters
printed since the last Carriage Return.
HARDCOPY causes a copy of the screen to be output to a suitable printer, in the
same way as by pressing the ALTernate-Help keys. There is a driver for
non-Epson compatible 9 pin printers which, unlike HARDCOPY does not use
XBIOS(20). It is activated by SDPOKE &H4EE,0.
Some hard copy drivers don't react on routine XBIOS(20). Frank Ostrowski made
last-minute changes to the HARDCOPY command. Now there is a SPOKE &H4EE,0 and a
VSYNC that should help even the worst cases.
Examples:
LPRINT
LPRINT "test"
PRINT LPOS(x)
--> The word "test" comes out on the printer (if it is attached, switched on,
and On-line) and the current print head position appears on the screen.
FOR i%=20 TO 180 STEP 10
CIRCLE 320,200,i%
NEXT i%
HARDCOPY
--> Concentric circles are drawn on the screen, then a copy of the screen is
made on the printer.
Memo: LPRINT does not work on an Atari Falcon030.
Scrdmp()+, v_hardcopy()+
Sound Generation
SOUND
WAVE
DMACONTROL, DMASOUND
MW_OUT
SOUND
SOUND [chan,vol,note,octave,del]
SOUND [chan,vol,#per,del]
WAVE [voice,env,form,freq,del]
chan, vol, note, octave, del, per, voice, env, form, freq: iexp
SOUND and WAVE serve to control the three-channel tone generator of the Atari
ST, the three channels having nothing to do with the data channels used to
communicate with peripheral devices and files. The parameters have the
following meanings:
chan Channel number (1 to 3)
vol Volume (0 to 15)
note Note (1 to 12) determines the note as follows:
Note: 01 02 03 04 05 06 07 08 09 10 11 12
Tone: C C# D D# E F F# G G# A A# B
octave Octave (1 to 8)
del Delay in 1/50ths second before the next GFA-Basic command is
executed.
per Period of the wave form multiplied by 125000. Thus for a given
frequency, per=ROUND(125000/frequency). In the alternative form of
the SOUND command, #per can be used to replace the note and octave
parameter, e.g. SOUND 1,15,10,4,250 and SOUND 1,15,#284,250 both
produce a tone of 440Hz. (Range 0 to 4095)
voice Channel combination: with WAVE, any channel or combination of
channels may be activated simultaneously. The value of 'voice' is
256 multiplied by the period (0 to 31) of the noise generator, plus
the sum of the following:
Bit Value Description (low byte)
0 1 Channel 1 tone enable
1 2 Channel 2 tone enable
2 4 Channel 3 tone enable noise enable
3 8 Channel 1 noise enable |noise enable
4 16 Channel 2 noise enable ||noise enable
5 32 Channel 3 noice enable |||tone enable
6 64 Port A: 0=input/1=output ||||tone enable
7 128 Port B: 0=input/1=output |||||tone enable
||||||
This is a word constructed as follows: ---PPPPPBA321321
|||||
(0-31) noise period
env Specifies the channels for which the envelope shaper (see
'form') is to be active. Its value is the sum of the following:
Bit Value Description
0 1 Channel 1 channel 3
1 2 Channel 2 |channel 2
2 4 Channel 3 ||channel 1
|||
This is a byte constructed as follows: -----321 (Range: 0-3)
form Specifies the envelope shape (0 to 15) thus:
Bit Value Description Shape
00xx 0-3 same as 9 \_____________
01xx 4-7 same as 15 /|____________
1000 8 Falling saw tooth \|\|\|\|\|\|\|
1001 9 Falling linearly \_____________
1010 10 Triangle, beginning with fall \/\/\/\/\/\/\/
1011 11 Falling linearly, then to max \|¯¯¯¯¯¯¯¯¯¯¯¯
1100 12 Rising saw tooth /|/|/|/|/|/|/|
1101 13 Rising linearly and holding /¯¯¯¯¯¯¯¯¯¯¯¯¯
1110 14 Triangle, beginning with rise /\/\/\/\/\/\/\
1111 15 Linear rising, then to zero /|____________
This is a byte constructed as follows: ----CAAH
||||
|||hold
||alternate
|atack
continue
freq Frequency of the wave form. (Range is 0-65535.)
Controls the release of the envelope generator.
Tone generation is begun by the SOUND or WAVE command and ended by another
SOUND or WAVE command (SOUND 1,0,0,0,0 produces silence). As the operating
system uses the sound chip to produce a keyboard click, this also terminates an
on-going sound output situation. The keyboard click can be disabled by:
SPOKE &H484,BCLR(PEEK(&H484),0)
...and enabled by:
SPOKE &H484,BSET(PEEK(&H484),0)
These two statements have the effect of setting bit 0 of memory location &H484
to zero or one respectively.
The period of the envelope is determined by the parameter 'del'.
With both SOUND and WAVE, the parameters are remembered, so that for subsequent
use with similar parameters, it is only necessary to specify parameters up to
the one that is to change: after WAVE 7,7,0,10000,100, it is only necessary to
type WAVE 1 to change the first parameter, leaving the others the same.
Example:
SOUND 1,15,1,4,20
SOUND 2,15,4,4,20
SOUND 3,15,8,4,20
WAVE 7,7,0,65535,300
--> A tone is produced with each channel and modulated by means of WAVE.
Memo: These commands use movep.w internally and could be fatal on a
machine fitted with a 68060 cpu. No proper range checking on any of
these parameters.
SOUND or WAVE with no parameters, stops all sound.
SOUND command undocumented behavior:
Channel: 0 is the same as channel 1.
Volume: 16 allows envelope control like WAVE. (bit 4 = 1)
Dosound()+, Giaccess()+
DMASOUND
DMACONTROL ctrl
DAMSOUND beg,end,rate[,ctrl]
beg, end, rate, ctrl: iexp
These commands allow sampled DMA sound to be played on the STE.
The DMACONTROL command controls the method used to play back the sound as
follows:
Method Bits ctrl
Stop sound %00 0
Play once %01 1
- %10 -
Play in loop %11 3
The DMASOUND command causes the sound to be played. The parameters are as
follows:
beg - Sample starting address
end - Sample ending address
rate - Sample rate:
0 = 6.25 kHz
1 = 12.5 kHz
2 = 25 kHz
3 = 50 kHz
ctrl - See command DMACONTROL above.
Example:
' Try each of the DMASOUND lines for different effect.
n%=360*32
DIM a|(n%)
' DMASOUND V:a|(0),V:a|(n%),0,3
' DMASOUND V:a|(0),V:a|(n%),1,3
' DMASOUND V:a|(0),V:a|(n%),2,3
DMASOUND V:a|(0),V:a|(n%),3,3
FOR i%=0 TO n%
a|(i%)=128+SINQ(i%*i%/7200)*127
NEXT i%
REPEAT
UNTIL MOUSEK
DMACONTROL 0
Memo: The DMASOUND command can be used to play mono sound samples if bit 7
is set to 'on' in the rate parameter. Example: rate&=BSET(rate&,7)
DMA sound data format: signed (-128 to 127) 8-bit PCM
Mono: sample must be of even length
Stereo: word (15--left--8/7--right--0)
DMASOUND defaults to 'play in loop' due to a bug if ctrl& is omitted.
MW_OUT
MW_OUT mask,data
mask, data: iexp
This command controls the STE Internal Micro Wire Interface, and is used for
controlling sound.
MW_OUT &H7FF,x
x=&X10 011 ddd ddd Set Master Volume
000 000 -80 dB
010 100 -40 dB
101 xxx 0 dB
The value of the last 5 Bits is equivalent to Half of the volume in dB.
x=&X10 101 xdd ddd Set Front Left Channel
x=&X10 100 xdd ddd Set Front Right Channel
x=&X10 111 xdd ddd Set Rear Left Channel (reserved)
x=&X10 110 xdd ddd Set Rear Right Channel (reserved)
00 000 -40 dB
01 010 -20 dB
10 1xx 0 dB
The last 4 Bits*2 = dB
x=&X10 010 xxd ddd Set Treble
x=&X10 001 xxd ddd Set Bass
0 000 -12 dB
0 110 0 dB (flat)
1 100 +12 dB
x=&X10 000 xxx xdd Set Mix (input select)
00 -12 dB
01 Mix GI sound (normal ST)
10 Reserved
11 Reserved
Example:
MW_OUT &H7FF,&X10000000010 !Switches the ST's sound off.
Memo: This command seems to be fatal (locks up) from the editor if used
on non-STE hardware. Internally it does not check the hardware at all.
The library version does check the hardware.
Chapter 7 - Program Structure
In this chapter the commands used for controlling the execution of a program
are discussed, starting with 'Decision Commands', by means of which the
execution of certain program sections is carried out only if certain criteria
are met. In the case of IF, THEN, ELSE, ENDIF, and ELSE IF, the criterion is a
logical one: BASIC checks if a logical expression is true or false, in addition
to these are the multiple decision commands SELECT, CASE, DEFAULT, ENDSELECT,
and CONT. These not only check for true or false, but can accept arbitrary
values which can be reacted to selectively.
The next section covers the loop commands, which make the repeated execution of
specified sections of a program possible. GFA-Basic 3 is provided with a very
large number of such loop types: FOR-TO-STEP-NEXT, REPEAT-UNTIL, DO-LOOP or
ENDLOOP, DO-WHILE, DO-UNTIL, LOOP-WHILE, LOOP-UNTIL, and EXIT IF.
For structured programming the use of sub-routines is of great importance.
With the commands PROCEDURE, GOSUB (or @), and RETURN (or ENDSUB) new
'commands' can be created in the form of subroutines.
Functions may also be defined by the user. With the commands DEFFN and FN
functions are created like formulas. More flexibility is possible with the
commands FUNCTION, ENDFUNC, and RETURN, which allow the formation of complete
subroutines that return a value.
Also in this section is a detailed description of the way in which variables
are dealt with by subroutines. Local variables may be declared with LOCAL, with
the effect that they are only valid in that subroutine. Variables of the same
name in other parts of the program are unaffected. Variables can be passed to
subroutines as values, or, with the VAR command, the variable itself can be
passed (called by reference), and its value changed without the need to refer
to it directy by name in the subroutine.
The section on conditional branches also explains the commands which deal with
the following two special events: the simultaneous pressing of the 'break keys'
Control-Shift-Alternate, which normally stop a program; and the error situation
which occurs when, for example, an attempt is made to divide by zero, or to
take the square root of a negative number etc. Both of these events can be made
to trigger the execution of a user-defined routine, instead of stopping the
program.
It is possible in GFA-Basic 3 to call a subroutine when a specified amount of
time has elapsed, using the commands EVERY and AFTER. This is explained in this
chapter.
Towards the end of the chapter the absolute branch GOTO, the commands PAUSE and
DELAY, which temporarily suspend program execution, as well as different
methods of ending the program (QUIT, SYSTEM, END, EDIT, NEW, and STOP) are
presented. The last section covers the commands for monitoring the execution of
a program (TRON, TROFF, TRON proc, TRACE$, DUMP, ERR$(), and ERROR).
Decision Commands
IF, THEN
ELSE IF
ELSE
ENDIF
IF
IF condition [THEN]
(instructions)
ELSE
(instructions)
ENDIF
condition: bexp
These commands enable one to specify that a section of a program will only be
executed if a logical condition is met. The following example demonstrates
this:
IF a=1 THEN
PRINT "a is equal to 1"
b=2
ENDIF
In this case a=1 is the logical condition. The instructions in the lines
between IF and ENDIF are processed only if this logical condition is
met. If it is untrue, then the program continues with the commands after the
ENDIF and the command THEN is not considered. It should be noted that it is
sufficient to use the form:
IF a=1 instead of IF a=1 THEN
The following construction is somewhat more complex:
IF a=1
PRINT "a is equal to 1"
ELSE
PRINT "a is not equal to 1,"
PRINT "it is equal to ";a
ENDIF
In this case shown above, the instructions between IF and ELSE are processed if
the logical condition after the IF is true. The program then continues
execution after the ENDIF. However, if the condition after IF is not fulfilled,
then the instructions between ELSE and ENDIF become effective. Again, program
execution is continued after the ENDIF.
Note: Any numerical expression, which is not equal to 0, i.e. is FALSE, is
considered to be true. The logical value for TRUE is -1 but any non-zero
value is considered to be equivalent.
Example:
x=1
IF x
PRINT "x is true"
ENDIF
INPUT y
IF x=9 OR ODD(y)
PRINT "y is an odd number"
ELSE
PRINT "y is an even number"
ENDIF
--> First the message 'x is true' is displayed and then a numeric input is
requested. Since x cannot be 9, the text appears 'y is an odd number', if
you have entered an odd number, otherwise 'y is an even' is displayed.
Memo: This fails compiled:
IF FALSE !the entire IF-ENDIF structure ends up missing!
ENDIF
Seems ok in the interpreter.
ELSE IF
ELSE IF condition
condition: bexp
The command ELSE IF enables nested IF's to be more clearly expressed in a
program. The following examples show a simple menu selection made on a single
key-press. If l, s, or e is pressed then, respectively, a load, save or, input
routine is called. In all other cases the message 'unknown command' is printed.
The normal nested version is as follows:
DO
t$=CHR$(INP(2))
'
IF t$="l"
PRINT "Load text"
ELSE
IF t$="s"
PRINT "Save text"
ELSE
IF t$="e"
PRINT "Enter text"
ELSE
PRINT "unknown command"
ENDIF
ENDIF
ENDIF
'
LOOP
The use of ELSE IF produces a shorter listing with smaller program indents:
DO
t$=CHR$(INP(2))
'
IF t$="l"
PRINT "Load text"
ELSE IF t$="s"
PRINT "Save text"
ELSE IF t$="e"
PRINT "Enter text"
ELSE
PRINT "unknown command"
ENDIF
'
LOOP
The program works in the following way:
If the condition after IF is fulfilled (t$="l"), then the instructions between
IF and the next ELSE IF are processed - PRINT "Load text" - and then the
program jumps to the command ENDIF. If the condition for the first IF is not
true then the other IF's are encountered.
In the second case, if the condition after the ELSE IF command is met, then all
instructions up to the next ELSE, ELSE IF or ENDIF (if no ELSE exists) are
proeessed and the program jumps to the instruction after ENDIF. If neither the
condition after the IF or the condition after ELSE IF is true, then the
commands between ELSE and ENDIF are implemented (if an ELSE exists).
Multiple Branching
ON GOSUB
SELECT (SWITCH), CASE, CONT, DEFAULT (OTHERWISE), ENDSELECT (ENDSWITCH)
ON GOSUB
ON x GOSUB proc1,proc2, ...
x: iexp
proc1, proc2: procedure name witbout parameter
This command branches the program to a procedure, which is in the list
specified after GOSUB. The x is a numerical (normally integer) expression,
whose decimal part (if any) is ignored. If x is smaller than 1 or larger than
the number of the procedure names after the GOSUB, then no subroutine is
called. After calling the subroutine the program execution is continued
immediately after the ON x GOSUB. With this command no parameters can be passed
to the procedure.
Example:
x=3
ON x GOSUB proc1,proc2,proc3
x=1
ON x+1 GOSUB proc1,proc2,proc3,proc4
--> First the procedure proc3 is called, then the procedure proc2.
Memo: If the procedure used with ON GOSUB is undefined the compiler will
not issue and error message. Instead the compiler writes a bad binary
where ON GOSUB is translated into JSR 0.l!
SELECT
SELECT x
CASE y [TO z] or CASE y [,z, ...]
(instructions)
CONT
CASE TO y
(instructions)
CASE y TO
(instructions)
DEFAULT
(instructions)
ENDSELECT
x, y, z: iexp or string-constant with a maximum length of 4 characters
The command SELECT makes branching possible using the CASE command, on the
basis of the value of the numerical expression x. The following examples give
an explanation of the program structure that results:
x=0
SELECT x+2
CASE 1
PRINT "x is equal to 1"
CASE 2 TO 4
PRINT "x is equal to 2, 3, or 4"
CASE 5,6
PRINT "x is equal to 5 or 6"
DEFAULT
PRINT "x is not equal to 1, 2, 3, 4, 5, or 6"
ENDSELECT
--> The message 'x is equal to 2, 3, or 4' is displayed.
First the numerical expression after SELECT is evaluated, which is the branch
condition, in this case 2. Then the various CASE instructions are gone through
and checked as to whether the current value of the branch condition is to be
found.
In this example the argument '1' follows the first CASE command. Since the
branch condition is 2, the program jumps to the next CASE.
After the second CASE are the arguments '2 TO 4'. As the value of x falls
within this range the condition is fulfilled and the message printed on the
screen. After that, program execution continues after the command ENDSELECT.
After the third CASE command is a further variant of the possible arguments for
the SELECT command. There the desired values are separated, in a list, by
commas.
If none of the current branch criterion after the various CASE commands is met,
then the instructions between DEFAULT and ENDSELECT are executed (assuming a
DEFAULT is present). In addition, instead of DEFAULT, OTHERWISE can be used
(giving compatibility with other BASICs) but the GFA interpreter replaces it
with DEFAULT automatically.
Also, after CASE commands, not only numeric values but also strings may be used
as the argument. These may have a maximum length of four characters. If only
one character is specified then its ASCII value is used as the branch
criterion. If two characters are specified, then this value is calculated as
follows:
ASCII value of first character + 255 * ASCII value the second character.
...and so on for the third and fourth characters.
Note: The maximum length of CASE is 4 characters, i.e. CASE "ABCD".
Example:
exit!=FALSE
REPEAT
key%=INP(2)
SELECT key%
CASE "a" TO "z"
PRINT "the lower-case letter "+CHR$(key%)+" was entered"
CASE "A" TO "Z"
PRINT "the upper-case letter "+CHR$(key%) +" was entered"
CASE 27
exit!=TRUE !program ends when <Esc> key is pressed
DEFAULT
PRINT "an inadmissible key was pressed!"
ENDSELECT
UNTIL exit!
--> Within a loop the keyboard is queried and the program jumps according to
which key was pressed and the appropriate message is displayed. Pressing
the Esc key is used as an abort criterion for the loop.
The next example illustrates the meaning of the CONT command, which is
effective if it comes before a CASE or DEFAULT command. This CONT command must
not be confused with the command of the same name used for resuming execution
of an interrupted program run.
Example:
x=1
SELECT x
CASE 1
PRINT "x is equal to 1"
CONT
CASE 2
PRINT "x is equal to 2"
CASE 1,3
PRINT "x is equal to 3"
DEFAULT
PRINT "x is not equal to 1, 2, or 3"
ENDSELECT
--> Displays 'x is equal to 1' and then 'x is equal to 2'.
The CONT command provides a method of jumping over a CASE or DEFAULT command.
In this example the value x is equal to the argument after the first CASE, i.e.
x=1. Therefore the message "x is equal to 1" is printed. Then comes the CONT
command, which jumps over the line CASE 2 and, although the branch condition is
not fulfilled, the CONT command causes the instruction PRINT "x being equal to
2" to be implemented. The normal processing continues with processing jumping
to the ENDSELECT command.
Example:
SELECT INP(2)
CASE "a" TO "g"
PRINT "a to g"
DEFAULT
PRINT "default"
ENDSELECT
--> If you press one of the a, b, c, d, e, f, or g keys the text 'a to g' is
displayed, with any other key (except the shift keys) the message 'default'
is printed.
With the CASE command a number of different possibilities can be combined, it
is not necessary for them to be written separately:
SELECT a$
CASE "a" TO "z"
CONT
CASE "A" TO "Z"
CONT
CASE "ae","oe","ue","ss","Ae","Oe","Ue"
PRINT "OK"
ENDSELECT
and similarly with ranges:
SELECT a$
CASE "a" TO "z","A" TO "Z","ae","oe","ue",...
...
...
Memo: For compiler options see sections 'SELECT-CASE Parameter' and
'SELECT-CASE Optimisation'.
The editor will accept this CASE """" however moving the cursor over the
line will cause strange behavior.
CONT must proceed a CASE or DEFAULT command or it will not work at all.
Even a comment between them will cause it to fail.
The editor will allow this:
SELECT x
PRINT !code placed here won't be executed (dead code)
CASE 1
CASE 2
ENDSELECT
SELECT x
DEFAULT !default is always executed
PRINT "hello"
ENDSELECT
Loops
FOR, TO, STEP, DOWNTO, NEXT (ENDFOR)
REPEAT, UNTIL (ENDREPEAT)
WHILE, WEND (ENDWHILE)
DO, LOOP (ENDDO)
DO WHILE, DO UNTIL
LOOP WHILE, LOOP UNTIL
EXIT IF
GFA-Basic 3 is provided with an unusually large selection of loop types.
Normally one differentiates between 'entry testing' and 'exit testing' loops.
'Entry testing' loops are those, such as WHILE-WEND, in which the abort
condition for the loop is checked before entry into the loop. While with 'exit
testing loops', such as FOR-NEXT, this condition is examined at the end of the
loop, consequently such are gone through at least once. A special loop type,
DO-LOOP, is also available in GFA-Basic. This type acts as a continuous loop
without an abort condition. In GFA-Basic this command can be very flexibly
used. Both after DO and after LOOP the extensions WHILE and UNTIL can be used
so that the loops begin or end with a logical condition. In all of the loop
types mentioned here, as many as abort conditions as required may be used in
the loop body using the EXIT IF command.
Memo: For compiler optimizations see section 'Loop Commands'
FOR
FOR c=b TO e [STEP s]
(instructions)
NEXT i
FOR c=b DOWNTO e
(instructions)
NEXT i
c: avar
b, e, s: aexp
The FOR-NEXT command (also called a counting loop) is used for repeated
processing a group of instructions between the commands FOR and NEXT. For this
purpose the count variable c is incremented (or decremented), beginning with
the initial value b, as far as the end value 'e'.
The instructions in the loop body are gone through, until NEXT is reached.
There the count variable c is increased by the value s given after STEP. If no
STEP value is given, then an increment of one is assumed. Next c is checked to
see whether it has exceeded the value e. If this is the case, the loop is
exited and the program continued with the command after the NEXT. If not, the
program loops back again to the first instruction, this process is repeated,
until c is larger than e. A consequence of this exit method is that c, after
the loop is left, is equal to e+s, i.e. the first value which exceeds the abort
criterion. Also, the contents of a FOR-NEXT loop will always be gone through at
least once.
Note: In place of a STEP value of -1 the command DOWNTO can be used instead
of TO. However, with DOWNTO the use of STEP is not possible.
In general, for the count variable c one should use integer variables, because
thereby the loop can be processed more quickly than with floating-point
variables. This is naturally not possible with non-integer STEP increments. In
place of the command NEXT followed by the count variable, the command ENDFOR i%
can be used, but the Interpreter automatically replaces it with NEXT i%.
Examples:
FOR c=1 TO 10
PRINT c'
NEXT c
FOR c=-1 DOWNTO -10
PRINT c'
NEXT c
--> Displays on the screen, the numbers:
1 2 3 4 5 6 7 8 9 10 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10
a$="T*e*s*t*w*o*r*d"
FOR j=1 TO LEN(a$) STEP 2
PRINT MID$(a$,j,1);
NEXT j
--> Displays the word 'Testword' on the screen.
Memo: For compiler options see section 'FOR-NEXT Loop Checking'.
A FOR-NEXT loop going backwards with a byte| counter using STEP will
completely fail when compiled. Such a loop will work in the interpreter
however. Somehow the loop ends up missing entirely when compiled!
FOR i|=200 TO 100 STEP -1 !does not work compiled
PRINT i|;",";
NEXT i|
FOR i|=200 DOWNTO 100 !this works compiled
PRINT i|;",";
NEXT i|
REPEAT
REPEAT
(instructions)
UNTIL condition
condition: bexp
The REPEAT-UNTIL command provides an 'exit tested' loop in which a number of
instructions are repeated until a logical condition is true.
When the command REPEAT is reached in a program, the group of instructions up
to the UNTIL are processed. Then it checks whether the logical condition after
UNTIL is true (-1). If this is the case, then the instructions after the UNTIL
are implemented. However, if the condition is false (0), then the program
execution jumps to the REPEAT. The instructions between REPEAT and UNTIL are
processed at least once, as long as the loop is not left by an EXIT IF or GOTO
command. ENDREPEAT can be used in place of UNTIL, which the Interpreter
automatically replaces by UNTIL.
Examples:
REPEAT
UNTIL MOUSEK
--> Waits for a mouse key to be depressed.
i=1
REPEAT
INC i
j=SQR(i)
UNTIL i>10 AND FRAC(j)=0
PRINT i
--> Displays the number '16' on the screen.
WHILE
WHILE condition
(instructions)
WEND
condition: bexp
The commands WHILE and WEND can include a group of commands, which are
processed as long as the logical condition is met. If GFA-Basic meets a WHILE
command, then the logical condition following it is checked. If it is true,
then the instructions between WHILE and WEND are implemented. When the WEND is
reached the program jumps to the WHILE and the cycle begins again, until
condition is false. ENDWHILE can be written instead of WEND, which the
Interpreter automatically replaces with WEND.
Example:
WHILE INKEY$=""
PLOT MOUSEX,MOUSEY
WEND
--> Enables drawing with the mouse, until a key is pressed. If a character is
already in the keyboard buffer, then no point is set.
DO
DO
(instructions)
LOOP
The commands DO LOOP produce a continuous loop. The program processes the
instructions between DO and LOOP and returns upon meeting LOOP to the command
DO. The loop can only be left by means of EXIT IF, GOTO, or other such commands
to abandon its execution. In place of LOOP, ENDDO can be written, which the
Interpreter replaces with LOOP.
Example:
DEFFILL 1,2,4
DO
MOUSE mx,my,mk
IF mk
PBOX mx,my,mx+25,my+25
ENDIF
LOOP
--> Draws filled rectangles at the current mouse pointer position when a mouse
key is pressed.
DO WHILE
DO WHILE condition
DO UNTIL condition
LOOP WHILE condition
LOOP UNTIL condition
condition: bexp
The commands DO and LOOP can be extended using UNTIL and WHILE. The loop
command DO WHILE causes the instructions in the loop to be executed only as
long as condition is true. If the loop begins with DO UNTIL, then it is entered
only if the condition is not true. LOOP WHILE causes the program to jump back
to the DO command as long as condition is true. LOOP UNTIL requires that the
condition must be false for the program to loop back. Below, the conditions at
DO are testing for true and at LOOP are testing for false.
DO WHILE condition WHILE condition
' corresponds to '
LOOP WEND
DO REPEAT
' corresponds to '
LOOP UNTIL condition UNTIL condition
The command variants DO, DO WHILE, and DO UNTIL can be combined at will with
LOOP, LOOP WHILE, and LOOP UNTIL, so forming altogether nine types of loops.
Examples:
DO
LOOP UNTIL MOUSEK
--> Waits for a mouse button to be pressed.
DO UNTIL MOUSEK=2
DO WHILE MOUSEK=1
LINE 0,0,MOUSEX,MOUSEY
LOOP
LOOP UNTIL INKEY$="a"
--> Draws lines when left mouse button is held down. If the right mouse button
is pressed or the 'a' key is struck the program ends.
DO UNTIL EOF(#1)
INPUT #1,a$
LOOP
--> Reads character strings from channel 1 sequentially, until the file end is
reached.
WHILE NOT EOF(#1)
INPUT #1,a$
WEND
--> Using WHILE-WEND is slower, since, additionally, NOT is required.
EXIT IF
EXIT IF condition
condition: bexp
By means of EXIT IF loops can be jumped out of, if the Boolian (logical)
condition is fulfilled. The actual loop type is arbitrarily selectable. EXIT IF
can be used within IF-ENDIF and SELECT-ENDSELECT.
Example:
DO
EXIT IF MOUSEK
LOOP
REPEAT
EXIT IF INKEY$="x"
UNTIL FALSE
--> The program terminates, if first a mouse button is pressed and then the 'x'
key is pressed.
Memo: This fails compiled:
DO
EXIT IF FALSE !generates 2 linker errors (?)
LOOP
Seems ok in the interpreter.
Procedures and Functions
GOSUB (@, proc)
PROCEDURE (SUB), RETURN (ENDSUB, ENDPROC)
VAR
LOCAL
FUNCTION, RETURN x, ENDFUNC
DEFFN, FN (@func)
In GFA-Basic 3 subroutines, as in most modern programming languages, are given
names. These subroutines can have parameters handed over to them and can then
work on these parameters. There are two forms of parameters available, one
where a value is passed to the subroutine and the second where the variable
itself is passed. In the second case the variable can be changed by the
procedure without the necessity of referring to the variable by name. These two
forms are known as "call by value" and "call by reference".
Likewise the use of local variables is possible, i.e. no consideration has to
be taken on possible name clashes when calling procedures or functions. By
means of DEFFN single-line functions can be defined and addressed using the FN
function name. Multi-line functions are also possible. These are a special form
of procedure and return a result (with RETURN).
Memo: For compiler options see section 'Subroutines'.
Parameters passed to built in GFA commands are register based.
Parameters passed to user subroutines are stack based.
Using no parameters and passing parameters in globals is techincally
faster but will make your code very hard to read.
PROCEDURE
proc[(par1,par2,...)]
PROCEDURE proc[(var1,var2,...)]
(instructions)
RETURN
proc: procedure name
par1,par2: sexp,aexp
var1,var2: svar,avar
Between the commands PROCEDURE and RETURN are the instructions of a subroutine.
After PROCEDURE the name of the subroutine and possibly the list of the
variables to be received are placed. Calling a PROCEDURE takes place by giving
its name at the beginning of the line, along with a list of appropriate
parameters, which are placed in parentheses. For the sake of clarity, the
option of placing @ or GOSUB in front of the procedure name is available. This
also avoids the possibility of confusing procedure names with GFA-Basic
commands, e.g. @rem, GOSUB stop. Parameters can be constants, variables, and
expressions. Not only the values, but also variables can be passed (see VAR).
The command RETURN is used to end a procedure. When it is reached during the
program execution, the program resumes execution from the instruction after the
GOSUB. In place of the command PROCEDURE one can write SUB and instead of
RETURN, ENDPROC, or ENDSUB can be used which the Interpreter replaces itself.
Example:
GOSUB slow_print("** Manual for **")
@slow_print("* GFA BASIC 3 *")
slow_print("GFA SYSTEMTECHNIK")
'
PROCEDURE slow_print(t$)
LOCAL i%
FOR i%=1 TO LEN(t$)
PRINT MID$(t$,i%,1);
PAUSE 3
NEXT i%
PRINT
RETURN
--> Slowly prints the message character by character.
a=8
@cube_root(a)
PRINT a
'
PROCEDURE cube_root(VAR x)
x=x^(1/3)
RETURN
--> Computes the cube root of 8 displaying 2 on the screen.
VAR
PROCEDURE proc(var,VAR var1[,var2,...])
FUNCTION func(var,VAR var1[,var2,...])
var1, var2: any variable type
VAR-parameters allow variables themselves to be passed and not just their
contents. They make it possible, not only to pass values into a procedure or
function but also, to pass variables which can then be changed within the
procedure or function. If the command VAR is found in the parameter list of a
procedure or function, all of the variables that follow will be treated as
VAR-parameters.
With VAR-parameters, unlike with global variables there is no danger of
unintended side-effects. Using VAR-parameters complete arrays can be passed.
VAR-parameters are not allowed within the calling line to a procedure or
function, only within its definition.
Note: VAR-parameters must always appear as the last elements of a
parameter list.
The use of VAR-parameters is generally quicker than the use of ordinary
parameters or pointers.
Examples:
sum(13,12,a)
sum(7,9,b)
PRINT a,b
PROCEDURE sum(x,y,VAR z)
z=x+y
RETURN
--> Two pairs of numbers are added, the values being passed to the variables a
and b. Then the numbers 25 and 16 are printed on the screen.
DIM a(9)
FOR i%=0 TO 9
a(i%)=RND
NEXT i%
mean(0,9,a(),m)
PRINT "mean = ";m
PROCEDURE mean(from%,to%,VAR array(),mean)
mean=0
FOR i%=from% TO to%
ADD mean,array(i%)
NEXT i%
DIV mean,to%-from%+1
RETURN
--> The arithmetic array filled with random numbers is calculated and printed
out.
Note: In Version 2 it was possible to achieve the effect of passing local
variables by passing their pointers. Using this method in Version 3 may
result in the error message 'Pointer (*x) error'. It is therefore
strongly recommended that VAR-parameters are used to pass local
variables.
LOCAL
LOCAL var1[,var2,var3,...]
var1, var2, var3: avar, svar
It is possible using the command LOCAL to limit the area of application of
variables. The variables specified after LOCAL are only valid in the procedure
in which the LOCAL command is used. Also any variables in all subroutines
called by this procedure will be local. Thus it is possible for variables
specified after LOCAL to have the same name as variables in the main program,
i.e. global variables. These global variables cannot be addressed then in the
subroutine but are available after leaving the procedure and remain unchanged.
Note: The parameter list given to a procedure or function are always local.
Example:
x=2
GOSUB test
PRINT x,y
'
PROCEDURE test
LOCAL x,y
x=3
y=4
RETURN
--> The numbers 2 and 0 are displayed on the screen.
Memo: For compiler optimizations see section 'Local and Global Variables'.
FUNCTION
@func[(par1,par2,...)]
FUNCTION func [(var1,var2,...)]
(instructions)
RETURN exp
ENDFUNC
func: function name
par1, par2: sexp, aexp
var1, var2: svar, avar
exp: sexp, aexp
The commands FUNCTION and ENDFUNC form a subroutine, in a similar manner to
PROCEDURE. The name of the subroutine and, optionally, the list of variables
are given after FUNCTION command. Calling the subroutine takes place by the use
of @ or FN and the function name, followed by a parameter list if necessary.
The parameters can be constants, variables or expressions. Not only the values,
but also the variables can be handed over by the parameter (see VAR).
If the command RETURN is reached during program execution, then the value given
after it or the value of the variable named is returned. However, in a function
RETURN can be used several times, with IF or the like. A function cannot be
terminated without a RETURN command by ENDFUNC. In a function name ending with
the $ character the functions will produce a string result.
Example:
fl%=@fac_loop(15)
fr%=@fac_recurs(10)
'
PRINT "loop: fac(15) = ";fl%
PRINT "recursion: fac(10) = ";fr%
'
FUNCTION fac_loop(f%)
w=1
FOR j%=1 TO f%
MUL w,j%
NEXT j%
RETURN w
ENDFUNC
'
FUNCTION fac_recurs(f%)
IF f%<2
RETURN 1
ELSE
RETURN f%*@fac_recurs(PRED(f%))
ENDIF
ENDFUNC
--> The factorials of 15 and 10 are, respectively, computed within a loop and
recursively.
Memo: For compiler options see sections 'Return Value of a Function' and
'ENDFUNC Generation'.
How to code a safe multi-line FUNCTION that cannot fail.
FUNCTION example(p) !poor method
IF p=>0 AND p<=7
RETURN 8
ELSE IF p=>8 AND p<=15
RETURN 16
ENDIF
ENDFUNC !expect unpredictable results if you reach this point
FUNCTION example(p) !better method
LOCAL r
IF p=>0 AND p<=7
r=8
ELSE IF p=>8 AND p<=15
r=6
ENDIF
RETURN r !this method insures that RETURN is never missed
ENDFUNC
DEFFN
DEFFN func[(x1,x2,...)]=expression
FN func[(y1,y2,...)]
func: function name
x1, x2: var
expression, y1, y2: exp
The command DEFFN allows the definition of single-line functions. These
functions can appear at any point in the program.
The term 'expression' can be any numeric or string expression which can include
any of the parameters x1, x2, etc listed in the definition. These parameters
are local variables to the function, and if they are also globally defined, no
reference can be made to them in the expression as the local variables will be
used instead. When the function is called these variables will contain the
values listed within the brackets of the function call.
Note: The function can be called using either 'FN func' or '@func'.
Functions can be nested at will, to any depth. However, recursion is not
possible and if attempted, the break-key combination will not work.
Examples:
DEFFN test(y,a$)=x-y+LEN(a$)
x=2
PRINT @test(4,"abcdef")
--> The number 4, i.e. 2-4+6 is displayed on the screen.
DEFFN first_last$(a$)=LEFT$(a$)+RIGHT$(a$)
b$=@first_last$("TEST")
PRINT b$
--> The text "TT" is displayed on the screen.
DEFFN fourth_power(x)=x^4
DEFFN fourth_root(x)=x^(1/4)
PRINT @fourth_root(@fourth_power(1024))
--> The number 1024 is displayed on the screen.
Note: Return value is always a float, thus slower.
Memo: If placed directly after a PROCEDURE or FUNCTION definition
which has no parameters, a bug in the compiler occurs. In the editor
it seems ok.
Symptoms: Program works fine in the editor but when compiled acts really
strange. Doing things you know it should not be doing. The
problem will persist even if the DEFFN is not called!
Further investigation shows that the compiler compiles the functions
right where it encounters them. Thus, if the DEFFN is defined inside
another routine, it jumps over it with a BRAnch always statement.
This makes for some really messing looking code in the dis-assembler!
Regardless of where you place them the compiler generates needless
BRAnch statements anyway, making the binary larger.
If one if going to use this command, do not define them inside other
routines. Best place to put them is between the main body of code and
the first subroutine or at the very end of the listing after the last
subroutine.
' works in the editor, fails compiled
' insert a line of code above the DEFFN, then it works compiled
@test
EDIT
PROCEDURE test !no parameters
DEFFN dummy=0
PRINT "test"
RETURN
I recommend this command be avoided. The multi-line FUNCTION command is
much more flexible and you can control what type of variable is passed
back via compiler commands. Use the FUNCTION command instead.
Error Handling
ON BREAK, ON BREAK CONT, ON BREAK GOSUB
ON ERROR, ON ERROR GOSUB
RESUME, RESUME NEXT, RESUME label
ERROR, ERR, ERR$()
FATAL
In this section two different types of events are considered. Non GFA-Basic
specific events such as checking for mouse clicks, selecting pull-down menus.
ets, are dealt with in other chapters (Menu and Window Programming and AES
Libraries).
The first of these two events to be discussed is the simultaneous pressing of
the Control, Shift, and Alternate keys. The second type of event is the
occurrence of an error during program execution.
ON BREAK
ON BREAK
ON BREAK CONT
ON BREAK GOSUB proc
proc: procedure name
These three commands control the response to the simultaneous pressing of the
Control, Shift (left shift-key only), and Altemate keys. Normally, pressing
this key combination causes the termination of a program but, it can also be
used to call a particular procedure. To do this, the procedure to be called is
defined by means of the instruction ON BREAK GOSUB proc.
When an ON BREAK CONT is present in a program, the Control, Shift, and
Alternate key combination is deactivated. An ON BREAK reactivates this key
combination once again.
Example:
ON BREAK GOSUB test
PRINT "Press CONTROL, SHIFT, (the left one) and ALTERNATE"
DO
LOOP
'
PROCEDURE test
PRINT "that was it"
ON BREAK
RETURN
--> The request to press the key combination is displayed. When they are
pressed, the procedure 'test' switches the normal BREAK routine on again.
Memo: Return code will be -128 if the program is stopped (compiled).
For compiler related options see sections 'Interrupt Routines' and
'Checking the BREAK keys, EVERY and AFTER'.
If the procedure used with ON BREAK GOSUB is undefined the compiler will
not issue and error message. Instead the compiler writes a bad binary
where ON BREAK GOSUB is translated into JSR 0.l!
The editor does not report a missing procedure with ON BREAK GOSUB.
ON ERROR
ON ERROR
ON ERROR GOSUB proc
RESUME [NEXT]
RESUME [label]
proc: procedure name
label: label name
The occurrence of a fault (a TOS or GFA-Basic specific fault) normally causes
the output of an error message and an abnormal termination. With ON ERROR GOSUB
there is the possibility of branching to a specified procedure, following the
detection of an error. In the procedure one can then determine the appropriate
reaction to the error.
With the command ON ERROR one switches back to the normal error-trapping, so as
to display the appropriate error message and bring about an abnormal
termination. Under these conditions, therefore, when an error arises, an ON
ERROR command is implemented automatically. In order to be able to react to a
number of errors which occur one after the other, the ON ERROR GOSUB proc
command must be contained within the error-trapping routine.
The RESUME command allows one to react in different ways when errors have
arisen and it is only used in an error-trapping procedure. When used on its own
as 'RESUME', this command causes the error to be repeated. RESUME NEXT
continues execution with the command which follows the command causing the
error. RESUME label causes the program to continue from the point 'label'. The
label for RESUME may be located either in a procedure or in the main program.
If a fatal error occurred (see FATAL), then only RESUME label can be used and
not RESUME NEXT or RESUME without a label.
Example:
ON ERROR GOSUB error_trapping
ERROR 5
PRINT "and again..."
ERROR 5
PRINT "is not reached"
'
PROCEDURE error_trapping
PRINT "Ok, error intercepted"
RESUME NEXT
RETURN
--> The texts 'Ok, error intercepted' is displayed and then 'and again...'.
Then the error message 'Square root only for positive numbers', is brought
about by ERROR 5. The label for RESUME may be located either in a procedure
or in the main program.
Memo: If the label used with RESUME is undefined the compiler will not
issue and error message. Instead the compiler writes a bad binary where
RESUME is translated into JMP 0.l!
If the procedure used with ON ERROR GOSUB is undefined the compiler will
not issue and error message. Instead the compiler writes a bad binary
where ON ERROR GOSUB is translated into JSR 0.l!
The editor does not report a missing procedure with ON ERROR GOSUB.
Division by zero = error code 0
When passed out via pterm() (END) it cannot be detected.
The label for RESUME cannot be located inside a FUNCTION.
ERROR
ERROR x
ERR
ERR$(x)
FATAL
x: aexp
With ERROR x, the occurrence of error number x can be simulated. (For the table
of error messages, see Appendix.) This command is particularly useful for
example, when testing an error processing routine.
The number of the error that has arisen is returned in the variable ERR and, by
means of this, one can determine the appropriate reaction to the occurrence of
a specific error.
The function ERR$(x) returns, as a string, the GFA-Basic error message with the
number x.
The variable FATAL is true if an error in the program generates an unknown
address. This can happen, for example, when the error arose from the processing
of an operating system routine. When this happens, a RESUME or RESUME NEXT can
no longer be correctly executed.
Examples:
ON ERROR GOSUB error_trapping
INPUT "Which error do you want: ",e
ERROR e
'
PROCEDURE error_trapping
PRINT "That was error no.: ";ERR
IF FATAL
PRINT "It was a fatal error"
ENDIF
RETURN
--> The user is asked to select an error by means of its error number and it is
displayed on the screen. The program then asks for the next error number.
~FORM_ALERT(1,ERR$(100))
--> The error message with the identification 100 is displayed, i.e. the
copyright message, as an alert box.
Memo: For compiler options see sections 'Error Messages' and
'Error Numbers Instead of Bombs'.
ERR is intialized to 0 only when the editor is first started.
However, ERR is not reset to 0 at each 'Run'.
This should be considered a bug in the editor.
ERR$() will accept any value. The actual range should be -128 to 127.
Interrupt Programming
EVERY ticks GOSUB proc
EVERY STOP
EVERY CONT
AFTER ticks GOSUB proc
AFTER STOP
AFTER CONT
ticks: iexp
proc: procedure name
By means of the commands EVERY and AFTER, procedures can be called after the
expiration of a certain amount of time 'ticks'. The command EVERY causes the
procedure 'proc' to be called every 'ticks' clock units. AFTER causes this
procedure to be called once only on the expiration of 'ticks' clock units.
The clock unit (tick) is defined as one two-hundredth of a second so ticks=200
sets an elapsed time of one second. However, a branch to the specified
procedure can only be called on every fourth clock unit, resulting in an
effective time resolution of one fiftieth of a second.
By means of EVERY STOP, the calling of a procedure can be prevented on
expiration of the time period. With EVERY CONT, the calling of the procedure is
again is allowed. The commands AFTER STOP and AFTER CONT work similarly, being
implemented internally by means of the etv_timer vector ($400).
It is only after the complete processing of a command that a check is made to
ascertain whether such a procedure is to be implemented. Thus commands which
are executed slowly, such as INP(2), QSORT, file operations, or the like, can
obstruct these routines.
Examples:
EVERY 4 GOSUB lines
lines!=TRUE
GRAPHMODE 3
DEFFILL 1
PLOT MOUSEX,MOUSEY
REPEAT
IF MOUSEK=1
EVERY STOP
ELSE
EVERY CONT
ENDIF
DRAW TO MOUSEX,MOUSEY
UNTIL MOUSEK=2
'
PROCEDURE lines
INC y%
LINE 320,y%,639,y%
IF y%=399
y%=0
ENDIF
RETURN
--> Draws lines in the right half of the screen from top to bottom and, at the
same time, permits the user to draw using the mouse. Pressing the left
mouse button switches the moving lines in or out. The program can be
terminated by means of the right mouse button.
PRINT "Text follows in 3 seconds, "
PRINT "if you do not press a key"
AFTER 600 GOSUB text
REPEAT
UNTIL INKEY$<>"" OR exit!
AFTER STOP
'
PROCEDURE text
PRINT
PRINT "here is the text"
exit!=TRUE
RETURN
--> If no key is pressed in the three seconds after the program starts, then
the message appears. If a key is pressed, then this terminates the program.
Memo: For compiler related options see sections 'Interrupt Routines' and
'Checking the BREAK keys, EVERY and AFTER'.
EVERY and AFTER rely on system timer B.
If the procedure used with EVERY and AFTER is undefined the compiler will
not issue and error message. Instead the compiler writes a bad binary
where EVERY and AFTER are translated into JSR 0.l!
The editor does not report missing procedures with EVERY/AFTER.
Other Commands
REM (/, //, /*), !, '
GOTO, label:
DELAY, PAUSE
END, EDIT, STOP
NEW
LOAD
SAVE, PSAVE
LIST, LLIST
CHAIN, RUN
QUIT, SYSTEM
REM
REM x
' x
<command> !x
x: arbitrary text
A line which begins with a REM or ' command, can contain any text which is
placed after these. The text, known as a REMark or comment, is not part of the
program proper or subject to the syntax control of the editor and during
program execution are not considered. They are usually used to make clearer how
the program works. In addition, comments can be added to the end of a command
line, other than one with DATA or INLINE commands. This is done by ending the
executable portion of the program by means of an exclamation mark '!'.
Note: The forward slash '/' can also be used, however the editor will
replace "/ comment" with "' comment".
Example:
REM comment
' PRINT "comment"
PRINT "REM" ! comment
--> The word 'REM' appears on the sereen. Everthing else is ignored.
GOTO
GOTO label
label: label name
By means of a 'label', specific locations in the program can be defined and a
program started from this point with the instruction 'GOTO label'. Program
execution is commenced from the label position. The label can consist of
letters, numbers, underlines, and periods. However, unlike with variable names,
it may also begin with a number. It must, however, end with a colon. The colon
should be left off when refering to a label in a GOTO command.
The use of GOTO is not allowed for jumping out of procedures, functions, or
FOR-NEXT loops into the main part of the program. The use of this command also
leads to unclear program structures which are not easy to follow and, it is
generally considered, GOTO's should be avoided wherever possible.
Example:
PRINT "place 1"
GOTO jump_point
PRINT "place 2"
jump_point:
PRINT "place 3"
--> The texts "place 1" and "place 3" appear on the screen.
Memo: If the label used with GOTO is undefined the compiler will not
issue and error message. Instead the compiler writes a bad binary where
GOTO is translated into JMP 0.l!
This example shows what is and what is not valid when using the GOTO command:
FOR j=0 TO 31
IF i=15
' GOTO label3 !no good
ENDIF
NEXT j
FOR i=0 TO 31
IF i=15
' GOTO main1 !no good
GOTO label3 !ok jump within the same loop
ENDIF
label3:
NEXT i
' GOTO label1 !no good
' GOTO label2 !no good
' GOTO label3 !no good
main1:
'
PROCEDURE proc1
GOTO label1 !ok jump into aonther procedure from a procedure
' GOTO label2 !no good
' GOTO main1 !no good
RETURN
PROCEDURE proc2
GOTO label1 !ok jump within the same procedure
label1:
RETURN
FUNCTION func1
GOTO label2 !ok jump into another function from a function
' GOTO label1 !no good
' GOTO main1 !no good
RETURN 0
ENDFUNC
FUNCTION func2
GOTO label2 !ok jump within the same function
label2:
RETURN 0
ENDFUNC
DELAY
PAUSE x
DELAY x
x: aexp
The command PAUSE suspends program execution for x/50 seconds. DELAY has a
similar effect but the argument x is specified in seconds with a theoretical
resolution in milliseconds. DELAY uses the GEM routine EVNT_TIMER() and is,
therefore, recommended for use in GEM programs.
Example:
PRINT "start"
PAUSE 100
PRINT "a pause"
DELAY 2
PRINT "end"
--> The text 'start' appears then, two seconds later the further message 'a
pause' is displayed. This is followed after a further two seconds by 'end'.
Memo: PAUSE -> Internally uses TIMER. Uses system timer B.
DELAY -> Internally uses EVNT_TIMER().
evnt_timer()+
EDIT
END
EDIT
STOP
These commands terminate the execution of a program. The command END terminates
the program's execution and displays a box with the text 'Program end' on the
screen. On clicking on the 'Return' button, GFA-Basic 3 returns to the Editor.
EDIT terminates program execution and returns control to the Editor
immediately.
STOP causes an Alert box to appear with the choice of STOP and CONT. When the
choice CONT is made, program execution continues. When the choice is STOP,
GFA-Basic goes into Direct mode. At this stage, one can test and change the
values of variables and, by means of CONT, continue program execution.
Example:
x=3
STOP
PRINT x
--> Select the button 'STOP' when the appropriate Alert box appears. Now enter,
in direct mode, the following commands:
PRINT x
--> The number 3 appears, next enter:
x=4
CONT
--> The last command of the program (PRINT x) is now processed and the number 4
appears, demonstrating that the value specified in Direct mode has been
assigned to the variable x.
Memo: These commands don't always generate code when compiled.
This is some odd bug in the compiler.
The same problem can happen inside a FUNCTION.
Depending on its placement they sometimes fails, examples:
PROCEDURE test
' add a code generating line here, then it works
EDIT !if it follows a proc def it fails
RETURN
NEW
NEW
This command deletes the program currently in memory. In Direct mode, for
safety's sake, the wishes of the user are queried. When in the Editor this
command can be executed by means of Shift-F4 or a mouse click and, again a
safety query is made.
Memo: The command NEW is translated to END when compiled.
LOAD
LOAD f$
f$: sexp
The command LOAD loads a GFA-Basic program. The expression f$ must contain the
file name along with the full access path for the file. When no extension is
specified for the file, the default extension '.GFA' is used.
Example:
LOAD "A:\TEST.GFA"
--> The program loads TEST.GFA from the root directory of drive A.
SAVE
SAVE f$
PSAVE f$
f$: sexp
The command SAVE stores a program on disk, under the specified name, f$. By
means of the command PSAVE, the specified file can be saved with list
protection and cannot subsequently be listed after re-loading with LOAD as it
is run immediately. In both cases, when no extension is specified for the file,
the default extension '.GFA' is used.
Example:
SAVE "A:\TEST.GFA"
--> Saves the current program under the file name TEST.GFA on drive A.
LIST
LIST [f$]
LLIST [f$]
f$: sexp
The command LIST displays the current program on the screen. Optionally, an
access path can be specified, by which the program can be stored in ASCII
format. Program sections that are to be inserted in to other programs by means
of 'MERGE', must be saved with LIST or SAVE,A from the Editor Menu, in ASCII
format.
When no extension is specified for the saving of a file, '.LST' is used as the
default extension.
By means of the command LLIST, the current program can be output to the
printer. The printer listing can be interrupted only by the switching off the
printer. Once switched off, the printer will probably continue to print for
some seconds before the program resumes or control is returned to the Editor.
(See LLIST and the .dot commands in the section covering the Editor.) In
addition, it is also possible to send text to a printer (see OPEN).
Examples:
LIST "A:\TEST,LST"
--> The current program is stored under the name "TEST.LST" in ASCII format on
drive A.
.ll 70
.pl 66
LLIST
--> The current program is output to the printer with a line length of 70
characters and a page length of 66 lines.
CHAIN
CHAIN f$
f$: sexp
The command CHAIN loads a GFA-Basic program into memory and starts execution
immediately when the program is loaded. When no extension is specified, the
extension '.GFA' is assumed.
Example:
CHAIN "A:\EXAMPLE.GFA"
--> The program EXAMPLE.GFA is loaded from disk and is immediately RUN.
Memo: This command works a bit differently compiled.
See section 'Interpreter - Compiler Differences'.
RUN
RUN [f$]
f$: sexp
The command RUN starts the current program. Additionally, if a complete file
name with access path is specified, then the appropriate program is loaded and
started, replacing any program currently in memory.
Example:
RUN "A:\PART2.GFA"
--> The program PART2.GFA is loaded from drive A and RUN.
QUIT
SYSTEM [n]
QUIT [n]
n: iexp
The commands SYSTEM and QUIT are equivalent in their effect, as they both
terminate program execution and leave GFA-Basic. Unlike in Version 2, SYSTEM
and QUIT return a 2 byte integer value to the calling routine (normally the
Desktop). This integer has a value of zero if the Interpreter was terminated
correctly and left the calling program to hand over to the Desktop.
The convention applied in this case is that zero signals an error free run. A
positive 16 bit number signals the occurrence of an internal error or a warning
and a negative 16 bit number mostly points to the appropriate operating system
error message. However this is not adhered to by all programs.
Example:
RESERVE 100
PRINT EXEC(0,"GFABASIC.PRG","","")
--> This short program starts by reducing the work space for BASIC to 100
bytes, it then loads and runs a second copy of the GFA-Basic program. If
the program below is run, the operation of the second copy of GFA-Basic is
terminated and returns the value 23 to the original GFA-Basic. This value
will then be printed.
PRINT "This is the second level GFA BASIC"
QUIT 23
Memo: Trying to pass error code 0 out is a bit of a problem since
the documentation for Pterm() states that 0 = Ok. GFA really should
not have defined 0 as an error code.
Pterm()+
Program Tracing
TRON, TROFF
TRON #
TRON proc
TRACE$
DUMP
Memo: Missing from the original manual. Pressing Right-Shift will pause the
display. The Caps Lock key will toggle slow motion (On=Slow).
The tracing commands are not usable in compiled applications.
TRON
TRON
TRON #n
TROFF
n: iexp
The command TRON (TRace ON) causes each command to be listed on the screen as
they are executed. This list can be diverted to a printer or the serial
interface by specifying the relevant channel number. The command TROFF turns
the TRace OFF again.
Example:
PRINT "Start:"
TRON
FOR i%=1 TO 5
PRINT i%
NEXT i%
TROFF
PRINT "End"
--> The word 'Start:' appears on the screen, then the numbers from 1 to 5 are
displayed, along with the commands which lead to their display. After that
the word 'End' is displayed.
OPEN "o",#1,"\tron.lst"
TRON #1
FOR i%=1 TO 10
PRINT i%
NEXT i%
TROFF
CLOSE #1
'
OPEN "O",#2,"prn:"
TRON #2
FOR i%=10 TO 630 STEP 10
LINE i%,0,i%,100
NEXT i%
TROFF
CLOSE #2
--> The numbers from 1 to 10 are displayed, along with the relevant commands
and a row of vertical lines at a distance of 10 pixels. This output is
directed to disk or printer.
Memo:
TRON is not usable in compiled applications.
TRACE$
TRON proc
TRACE$
proc: procedure name
With help of the instruction 'TRON proc', a procedure can be specified which is
called before the execution of each individual command. The variable TRACE$
then contains the command which is to be processed next. The command TRON proc
makes for very efficient error tracing when used in conjunction with TRACE$. In
addition, as well the next command to be processed being displayed, specified
variables can be output to screen or printer, allowing changes in the variables
to be followed during the course of the program run.
It is important that the TRON procedure should not affect the program itself
while running, so while in use, no PRINT commands should be made to the screen
(TEXT, ATEXT, ...) and the use of VDI routines should be avoided because of
GDOS's use of DEFTEXT, Line-A, etc.
Example:
TRON tr_proc
GRAPHMODE 3
DO UNTIL MOUSEK
x1%=100+RAND(200)
y1%=100+RAND(100)
x2%=200+RAND(200)
y2%=200+RAND(100)
PBOX xl%,y1%,x2%,y2%
LOOP
'
PROCEDURE tr_proc
IF BIOS(11,-1) AND 4 ! Control key
adr%=XBIOS(2)
BMOVE adr%+1280,adr%,4*1280
PRINT AT(1,5);SPACE$(80);
PRINT AT(1,5);LEFT$(TRACE$,79);
PAUSE 20
ENDIF
RETURN
--> This program draws randomly-distributed rectangles on the screen. Pressing
the Control key causes the command just processed to appear on the screen.
The program is terminated by the pressing of a mouse button.
Memo:
The editor does not report a missing procedure with TRON proc.
TRON is not usable in compiled applications.
DUMP
DUMP [a$[TO b$]]
a$, b$: sexp
With the help of the DUMP command, the contents of variables can be displayed
during a program run; or labels, procedures, and functions listed. In addition
the string expression a$ can accept the following:
Examples:
DUMP
--> Returns all values of variables and the dimensioning of arrays.
DUMP "a"
--> As above but only operates on variables or arrays which begin with 'a'.
DUMP ":"
--> Lists all labels and specifies the Editor line number where each label is
used. The variation (:b) lists only those labels which begin with 'b'.
DUMP "@"
--> Lists all procedures and functions and specifies the Editor line number
where each is found.
proc_name @ 100 (procedure)
func_name FN 200 (function returning a numerical value)
func_name $ FN 300 (function returning a string)
Labels, procedures, and functions which are no longer defined, are specified
without Editor line numbers. If the program listing was saved with the SAVE,A
option and then newly reloaded, these undefined names no longer appear. However
labels, procedures, and function names which are still usable but not defined,
are displayed without Editor line numbers.
The Editor line number specified after the name can be jumped to in the Editor
by means of Control+G.
When the contents of a string is output, a maximum of 60 characters is
displayed. If the character string is longer than this, then the last character
displayed is '>'. If a control character, i.e. ASCII value < 32, is to be
displayed, this is replaced by a period.
The outputs mentioned above can also be directed to a file and, in this case,
the file name must be specified in b$.
If no extension is specified a default extension of '.DMP' is used.
Chapter 8 - Graphics
Three different graphic modes are available on the Atari ST: one black and
white mode and two color modes. The actual screen coordinates available for the
graphic commands and the colors representable with them depend on the current
resolution. An overview of the available graphic modes is given below:
Mode Resolution Color Palette Memory
ST Low 320x200 16 512/4096 32000
ST Medium 640x200 4 512/4096 32000
ST High 640x400 2 back/white 32000
TT Low 320x240 256 4096 153600
TT Medium 640x480 16 4096 153600
TT High 1280x960 2 black/white 153600
Note: With the release of the STe the palette was expanded from 512 to
4096 colors. ST high on the TT is actually duo-chrome, meaning any two
colors can be used instead of the usual black and white.
In the first section, the commands for the selection of colors (SETCOLOR,
COLOR) are covered. After that, the commands for the selection and generation
of different types of mouse pointers, display symbols, fill patterns, frames,
and line types (DEFMOUSE, DEFMARK, DEFFILL, BOUNDARY, DEFLINE) are explained.
The next section describes the CLIP commands, which are used to trim graphic
displays, and the general graphic commands for drawing different geometrical
basic forms (PLOT, LINE, BOX, CIRCLE, and ELLIPSE). The various options for
producing polygons (POLYLINE, POLYMARK, and POLYFILL) are described along with
the graphic text command TEXT. The section ends with a description of the
instruction FILL.
In the last part of this chapter, the treatment of screen sections with SGET,
SPUT, GET, and PUT is described.
Memo: The start-up code initializes the following:
TEXT vst_alignment(0,1) left justified/base line
GRAPHMODE vswr_mode(1) MD_REPLACE
BOUNDARY vsf_perimeter(1) PERIMETER_ON
Graphics Definition Commands
SETCOLOR, VSETCOLOR
COLOR
DEFMOUSE
DEFMARK
DEFFILL
BOUNDARY
DEFLINE
DEFTEXT
GRAPHMODE
SETCOLOR
COLOR color
SETCOLOR register,red,green,blue
SETCOLOR register,composite
VSETCOLOR color,red,green,blue
VSETCOLOR color,composite
register, red, green, blue, composite, color: iexp
The command COLOR determines the line color. Values between 0 and 255,
dependant on the current resolution, are valid.
The first variant of SETCOLOR determines the proportion of the colors red,
green, and blue in a particular color register. The intensity of the color
element is specified on a scale from 0 (low) to 7 (high) and the number of
available color registers depends on the current resolution. In the second
variant of SETCOLOR, the color setting is defined by a single parameter whose
value is computed by the following formula:
composite = red * 256 + green * 16 + blue * 1
and, as with the other setting, the values for red, green, and blue are
specified on a scale from 0 to 7.
The setting of color elements in the color registers is, naturally, only
applicable when in the color modes. However, in the monochrome mode, when a
composite value other than 0 or 1 is specified, even numbers have the same
effect as 0 and odd numbers the same effect as 1.
Example:
SETCOLOR 0,0
--> On a mono monitor, the display appears as white on a black background.
Through an apparently unexpected mix-up in the design of the operating system,
the color registers used by SETCOLOR do not correspond directly to the numbers
used by COLOR. To overcome this the command VSETCOLOR is available.
The values of red, green, and blue are numbers in the range 0 to 15. The term
composite is calculated in the same manner as SETCOLOR, i.e.:
composite = red * 256 + green * 16 + blue * 1
VSETCOLOR 1,2,3,4 is the same as VSETCOLOR 1,&H234
The syntax of the VSETCOLOR command is virtually identical to that of SETCOLOR,
the sole difference being in the parameters 'register' and 'color'. They are
related as shown:
For Low Resolution:
SETCOLOR 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
VSETCOLOR 00 02 03 06 04 07 05 08 09 10 11 14 12 15 13 01
For Medium Resolution:
SETCOLOR 00 01 02 03
VSETCOLOR 00 02 03 01
For High Resolution:
SETCOLOR 0,even corresponds to VSETCOLOR 0,0
SETCOLOR 0,odd corresponds to VSETCOLOR 0,&HFFF
Example:
' In Low resolution
FOR i%=0 TO 15
DEFFILL i%
PBOX i%+20,0,319,199
NEXT i%
DO
a%=INP(2)
EXIT IF a%=27
VSETCOLOR a% AND 15,RAND(-1)
LOOP
--> This program draws overlapping color boxes, the result being 16 vertical
bars (the left hand one is the same color as the border, i.e. color 0). By
ANDing the key code with 15, a color register number can be chosen and this
register is then set to a random value. The program is left by using the
Escape key.
Memo: 'VSETCOLOR i,rgb' contains a bug such that the red and blue values
end up swapped. This happens in the editor and compiled.
vsl_color()+, vs_color()+, EsetColor()+, Setcolor()+
DEFMOUSE
DEFMOUSE symbol
DEFMOUSE bitpattern$
symbol: iexp
bitpattern$: sexp
The first DEFMOUSE variant determines the current mouse pointer, selected from
the eight pre-defind types. The value of 'symbol' defines the type of the
pointer in the following way:
0 --> Arrow
1 --> Text cursor
2 --> Busy bee
3 --> Pointing hand
4 --> Open hand
5 --> Thin cross-hair
6 --> Thick cross-hair
7 --> Outlined cross-hair
8 --> Arrows all directions NAES
9 --> Arrows left and right NAES
10 --> Arrows up and down NAES
The second variant of the DEFMOUSE command allows the user to define a mouse
pointer. The action point, the mask color, the pointer color, the bit design
pattern for the appearance of the mask, and the appearance of the mouse pointer
are specified by means of a character string. The action point, is that point
of the mouse pointer whose coordinates are defined as the mouse position. If
the mouse position is interrogated, it is the coordinates of the action point
which are returned.
All these values must be entered as word size values and the command MKI$() can
be used for this purpose. Thus, bitpattern$ is assembled as follows:
bitpattern$ = MKI$(x-coordinate action point)
+ MKI$(y-coordinate action point)
+ MKI$(1) !1=bit-planes (required)
+ MKI$(mask color) !normally 0
+ MKI$(cursor color) !nromally 1
+ mask$ !bit pattern of the mask
+ cursor$ !bit pattern of the cursor
mask$ and cursor$ consist of 16 words each, each word being the bit pattern of
a line.
Example:
DEFMOUSE 2
DELAY 1
m$=MKI$(0)+MKI$(0)+MKI$(1)+MKI$(0)+MKI$(1)
FOR i%=1 TO 16
m$=m$+MKI$(65535)
NEXT i%
FOR i%=1 TO 16
m$=m$+MKI$(1)
NEXT i%
PBOX 200,150,400,250
DEFMOUSE m$
REPEAT
UNTIL MOUSEK
--> First, a bee appears as a mouse pointer. Then after one second, the mouse
pointer turns into a line. When the mouse is placed on the black background
at the center of the screen, the mouse changes to a rectangle, the mask
having been defined as this rectangle. The final loop is then left by
pressing a mouse button.
Memo: Values larger than 7 for 'symbol' do not work.
To use values over 7 one must call GRAF_MOUSE() instead.
DEFMOUSE m -> AES call to GRAF_MOUSE()
DEFMOUSE m$ -> VDI call to vsc_form()
The string should be exactly 74 bytes.
No error handling on the string length at all.
graf_mouse()+, vsc_form()+
DEFMARK
DEFMARK [color],[type],[size]
color, type, size: iexp
DEFMARK determines the color, type, and size of the marks, at the corner points
of a polygon, which are diplayed by the command POLYMARK. According to the
actual screen resolution, values between 0 and 255 can be assigned to the
numerical expression 'color' (see the start of this chapter). The 'type'
parameter gives the following corner marks:
1 --> Period
2 --> Plus sign
3 --> Star
4 --> Rectangle
5 --> Cross
6 --> Diamond
Values larger than 6 result in the use of the star as the corner mark. Values
for the 'size' of the shape are specified in pixels. Thus a value of 8 will
produce a mark that is 8 x 8 pixels in size. When only the second parameter or
third parameter of the command are required, one can omit the parameter in
question and enter only the parameter-seperating commas. Thus,
DEFMARK ,,4
means that the first two parameters keep their current value and the size of
the marks is set to 4.
Example:
DIM x%(1),y%(1)
x%(0)=50
y%(0)=50
x%(1)=150
y%(1)=150
DEFMARK 1,4,2
POLYMARK 2,x%(),y%()
DEFMARK ,3,4
POLYMARK 2,x%(),y%() OFFSET 100,0
--> This draws two pairs of points with different corner marks.
vsm_color()+, vsm_type()+, vsm_height()+
DEFFILL
DEFFILL [color],[style],[pattern]
DEFFILL [color],bitpattern$
color, style, pattern: iexp
bitpattern$: sexp
This command determines the fill pattern for the commands PBOX, PCIRCLE,
PELLIPSE, POLYFILL, and FILL. It sets the color, style, and pattern of the
filling and enables one to define one's own patterns. The pattern color can be
assigned values from 0 to 255, depending on the currnet screen resolution (see
the beginning of this chapter). The following results are obtained from
assignment of values to style:
0 --> Empty
1 --> Solid
2 --> Dots
3 --> Hatched
4 --> User defined (default Atari symbol)
Patterns can be selected from 24 dot-based patterns or 12 line-based patterns
by means of the 'pattern' parameter (see Appendix: Fill Pattern Table).
Parameters can be omitted from this definition, as long as the
parameter-seperating commas are included. Thus,
DEFILL ,2,4
selects the fill-pattern 2,4 and leaves the fill color as previously defined.
In the second variation of the command DEFFILL, using the 32 byte parameter
'bitpattern$', a 16 x 16 pixel pattern can be defined. This information must be
presented in word format and can be assembled by means of the MKI$() command.
The medium resolution fill pattern is represented by two bit-planes which are
combined to define the actual colors produced. The 16 words for the second
bit-plane optionally follow the 16 words of the first.
The first bits from each of these bit-planes are combined, this two bit number
(in the range 0 to 3) represents the color of the pixel at the top left corner
of the block. The second pair of bits represents the color of the second pixel,
to the right of the first, and so on.
For low resolution, four bit-planes are needed to represent a color fill
pattern (one plane could be used but this would giva a single color pattern),
therefore the bit pattern must be 64 words (128 bytes) in length.
The first bit-plane represents the least significant bit of the color. If
however the second of these planes is left off, this will result in a single
color fill pattern, the color being that chosen in the parameter 'color'.
Example:
DEFFILL 1,2,4
PBOX 10,10,40,40
BOX 50,50,100,100
FILL 70,70
FOR i=1 TO 16
f$=f$+MKI$(RAND(65535))
NEXT i
BOX 100,100,150,150
DEFFILL 1,f$
FILL 120,120
--> Draws two boxes filled with a standard pattern and a third filled with a
random pattern.
DO
FOR j%=0 TO 15
f$=""
s%=BCHG(s%,j%)
FOR i%=1 TO 16
f$=f$+MKI$(s%)
NEXT i%
DEFFILL 1,f$
PBOX 0,0,639,399
NEXT j%
LOOP
--> Parallel vertical bars are displayed and increase in size until they fill
the screen. This is done by defining and altering a fill pattern and
displaying a rectangle filled with this pattern.
FOR i%=1 TO 64 !64 for low, 32 for medium, and 16 for high resolution
READ a%
a$=a$+MKI$(a%)
NEXT i%
DEFFILL ,a$
PBOX 20,20,300,200
' First Bit-plane:
DATA -1,-1,-1,-1,-1,-1,-1,-1,0,0,0,0,0,0,0,0
' Second Bit-plane:
DATA -1,-1,-1,-1,0,0,0,0,-1,-1,-1,-1,0,0,0,0
' Third Bit-plane:
DATA -1,-1,0,0,-1,-1,0,0,-1,-1,0,0,-1,-1,0,0
' Fourth Bit-plane:
DATA -1,0,-1,0,-1,0,-1,0,-1,0,-1,0,-1,0,-1,0
--> This routine creates a filled pattern which, on a mono monitor, has two
broad black and white strips. In medium resolution, four strips of half the
width are produced in the four possible colors. In the case of the low
resolution mode, 16 strips of one line height result, in all 16 colors.
This pattern is then used to fill a box by PBOX.
Memo: No error handling on the string length at all.
Planes LEN() in bytes Words
------- ----------------- -----
1 32 (16*16*1)/8 16
2 64 (16*16*2)/8 32
4 128 (16*16*4)/8 64
8 256 (16*16*8)/8 128
15 1024 16*16*4 512 (exceeds INTIN() array limits)
16 1024 .. ..
24 1024 .. ..
32 1024 .. ..
If the mode is High or True color, pass a pattern with 32-bit pixels.
The format is always 'xrgb', one long per pixel.
vsf_color()+, vsf_style()+, vsf_interior()+, vsf_udpat()+
BOUNDARY
BOUNDARY n
n: iexp
The command BOUNDARY uses the Function vsf_perimeter() to switch off (or on)
the border normally drawn round a filled shape (with PBOX, PCIRCLE, etc). When
n is not zero, a border is drawn around the filled area, when it is zero, no
border is drawn.
Example:
DEFFILL 1,2,2
BOUNDARY 1 !switch on border
PBOX 50,50,100,100
BOUNDARY 0 !swith off border
PBOX 150,50,200,100
--> Draws two filled rectangles, one with and one without a border.
vsf_perimeter()+
DEFLINE
DEFLINE [style],[thickness],[begin_s],[end_s]
style, thickness, begin_s, end_s: iexp
The command DEFLINE determines the appearance of lines drawn with the commands
LINE, BOX, RBOX, CIRCLE, ELLIPSE, and POLYLINE. The first parameter 'style'
determines the line style, with a choice between pre-defined and user-defined
styles. The following styles are available:
1 --> Solid line
2 --> Long-dashed line
3 --> Dotted line
4 --> Dot-dashed (Chain-linked) line
5 --> Dashed line
6 --> Dash dot dot...
7 --> User defined line
User-defined patterns can be created from a 16-bit value in which each bit
corresonds to a set point in the monochrome mode. This is a special case and
must be a -negative 16-bit value.
The second parameter 'thickness' sets the width of the line in pixels and this
parameter must only have odd values. If even the line thickness is rounded down
to the next smallest odd number. The start and end symbols of a line are
defined my means of begin_s and end_s. The available options are:
0 --> Square
1 --> Arrow
2 --> Round
Parameters can be omitted in the definition providing the parameter-seperating
commas are entered. Thus,
DEFLINE ,,1,1
specifies an arrow as a symbol for the line beginning and end, leaving the
style and width unchanged (see Appendix: Line Style Table).
Example:
FOR i=1 TO 6
DEFLINE i
LINE 50,i*50,200,i*50
NEXT i
DEFLINE 1,1,1,2
FOR i=2 to 12 STEP 2
DEFLINE ,i
LINE 250,i*25,400,i*25
NEXT i
DEFLINE -&X101010101010101,1,0,0
LINE 500,10,500,390
VOID INP(2)
--> Lines in the six pre-defined styles are drawn followed by lines of
different thickness. The line in the user-defined pattern is dotted.
Finally, the program waits for a key to be pressed.
vsl_type()+, vsl_width()+, vsl_ends()+, vsl_udsty()+
DEFTEXT
DEFTEXT [color],[attr],[angle],[height],[fontnr]
color, attr, angle, height, fontnr: iexp
This command determines the appearance of a character string that is to be
displayed with TEXT. The parameter 'color', depending on the current
resolution, may contain a value between 0 and 255. The second parameter 'attr'
sets the text attributes which can be created by combinations of the values
given below:
Bit Value Effect Example
- 0 --> Normal Normal
0 1 --> Bold Bold
1 2 --> Light Light
2 4 --> Italic Italic
3 8 --> Underlined Underlined
4 16 --> Outlined Outlined
The parameter 'angle' determines the direction of the text characters, the
value being specified in 1/10 degree steps in a clockwise direction.
900
|
|
|
1800 -- Text origin -- 0
|
|
|
2700
Note: However, only the following values are permitted by GEM:
0 --> From left to right (default)
900 --> From bottom to top
1800 --> From right to left, upside down
2700 --> From top to bottom
If a value other than one of the above is givn, the nearest multiple of 900 is
used.
The parameter 'height' specifies the text height of a capitol letter in pixels,
and with the normal character set only the following character heights are
actually readable:
4 --> Icon
6 --> Subscript
13 --> Normal character height
32 --> Expanded character height
Finally, the parameter 'fontnr' specifies the number of the desired character
set. This font must have previously been installed (see also GDOS:
VST_LOAD_FONTS(), VQT_NAME(), ...).
Example:
FOR i|=0 TO 5
DEFTEXT 1,2^i|,0,13
TEXT 100,i|*16+100,"This is the text attribute "+STR$(i|)
NEXT i|
--> Displays the example text with different attributes.
vst_color()+, vst_effects()+, vst_rotation()+, vst_height()+, vst_font()+
GRAPHMODE
GRAPHMODE n
n: iexp
The command GRAPHMODE determines the way in which graphics is output to the
screen with relation to what is already there and is important when pictures
are to be drawn on top of one another. Four possible modes can be represented
by the numerical expression n:
1 --> Replace
2 --> Transparent
3 --> Xor
4 --> Reverse transparent (inverted and transparent)
When n has the value 1, the new drawing is simply drawn over the existing
screen contents obliterating it completely.
When n is equal to 2, the new drawing is ORed with the existing one, which
means that the old picture can still be seen behind the new one.
With n equal to 3, the new drawing is XORed with the existing one. This means
that, at each pixel where a graphic point was already present, that graphic dot
is deleted, and for all other points, the image is drawn normally. The
importance of this mode is that the process is reversible. By XORing the new
drawing with itself the original screen is restored. Thus, by using this mode,
animation is possible by repeated drawing and 'undrawing' of a figure as it is
moved around the screen.
In the case where n = 4, the new drawing is inverted and then ORed with the
existing one. In this way, a display similar to mode 2 is produced (n=2), but
the new picture is shown in reverse video.
Example:
FOR i%=1 TO 4
GRAPHMODE i%
DEFFILL 1,3,8
PBOX 150*i%-100,10,150*i*,100
DEFFILL 1,2,10
PBOX 150*i%-140,50,150*i%-40,150
NEXT i%
--> Four filled rectangles are drawn, and a further four are drawn partly
overlapping the previous ones. Each pair is combined using a different
GRAPHMODE setting.
vswr_mode()+
General Graphics Commands
CLIP, CLIP OFF, CLIP OFFSET
PLOT
LINE
DRAW, DRAW TO
DRAW(), SETDRAW
BOX, PBOX
RBOX, PRBOX
CIRCLE, PCIRCLE
ELLIPSE, PELLIPSE
POLYLINE, POLYMARK, POLYFILL
POINT()
FILL
CLS
TEXT
SPRITE
CURVE
First of all in this section, the use of the CLIP commands in graphic displays
is considered.
The general graphic commands PLOT, LINE, BOX, RBOX, CIRCLE, and ELLIPSE are
considered next. These draw points, lines, rectangles, rectangles with rounded
corners, circles, and ellipses, and by means of PBOX, PRBOX, PCIRCLE, and
PELLIPSE, they can be filled with colors or patterns.
POLYLINE draws a polygonal shape, and corner points made up of symbols defined
with DEFMARK can be added using POLYMARK. POLYFILL fills this Polygon with a
defined pattern, in a defind color. POINT() returns the color of a particular
screen point. FILL fills a bordered area and TEXT makes it possible to display
character strings in arbitrary places on the screen. CLS clears the entire
screen. At the end of the section, the command, BITBLT is covered.
The Origin (location 0,0) with all these graphic commands is located in the
top-left corner of the screen. The coordinates of graphic elements can lie
outside the actual screen display area but only the visible parts of the
graphics are represented.
CLIP
CLIP x,y,w,h [OFFSET x0,y0]
CLIP x1,y1 TO x2,y2 [OFFSET x0,y0]
CLIP #n [OFFSET x0,y0]
CLIP OFFSET x0,y0
CLIP OFF
x, y, w, h, x0, y0, x1, y1, x2, y2, n: iexp
This group of commands provides the 'Clipping' function, i.e. the limiting of
graphic displays within a specified rectangle screen area. CLIP defines a
clipping rectangle for the VDI graphic commands. ACLIP does this for Line-A
graphic routines. The screen area to be operated on, (clipping rectangle) can
be defined by the coordinates of the diagonally-opposite corner points; as well
as the top-left coordinate and the width and height of the clipping rectangle.
The command CLIP x,y,w,h allows the input of the upper y-coordiante 'y', left
x-coordinate 'x' as well as the width 'w' and height 'h' of the clipping
rectangle.
The command CLIP x1,y2 TO x2,y2 offers a further option by accepting the
coordinates of diagonally-opposite corner points (x1,y1) and (x2,y2).
The third variant makes it possible to define the limits of the window 'n'.
The optional additional command OFFSET x0,y0 makes it possible to redefine the
origin of the graphic display.
In addition, the command CLIP OFFSET x0,y0 can
also be used as a command in its own right, and in this case serves the same
purpose in setting the origin for the graphic displays at the ponit (x0,y0).
The command CLIP OFF swithes off the clipping function.
The limiting of graphic displays by CLIPping does not apply to the commands
GET, PUT, and BITBLT, nor to the Line-A calls (where ACLIP should be used) or
AES commands.
Memo: CLIP #0 sets the clipping rectangle to the Desktop area. It's
the same as doing this:
~WIND_GET(0,4,x&,w&,y&,h&) !desktop handle is always 0
CLIP x&,y&,w&,h& OFFSET 0,0
The OFFSET option is not a real VDI function. The x/y values are
actually noted by GFA-Basic itself and then internally added to all
further graphics commands. Thus if you call the VDI directly, this
OFFSET will have no effect at all, and must be simulated.
There's a bug in the startup code related to CLIP. The initial clipping
rectangle is set from values taken from the Line-A variables. Thus it
fails on non-ST video modes. If the graphics commands appear to be not
working and you are in some non-ST mode, add this to the top of the
program: CLIP 0,0 TO WORK_OUT(0),WORK_OUT(1)
vs_clip()+
PLOT
PLOT x,y
LINE x1,y1,x2,y2
DRAW [TO][x,y]
DRAW [x1,y1][TO x2,y2][TO x3,y3][TO...]
x, y, x1, y1, x2, y2, x3, y3: iexp
PLOT draws a point with the coordinates x,y on the screen. LINE draws a line
between the coordinate pairs x1,y1 and x2,y2. The style and color of this line
can be defined by means of the commands DEFLINE and COLOR.
DRAW x,y corresponds to the command PLOT. By means of DRAW TO x,y, a line is
drawn between the coordinates x,y and the last set point, regardless of whether
this point was set by PLOT, LINE, or DRAW.
A further variant of the command, DRAW x1,y1 TO x2,y2 corresponds to the LINE
command, and addionally with this command, further coordinates can be specified
allowing shapes such as polygons to be produced. This latter variant of the
command makes it possible to create structures which are similar to the
turtle-graphic commands of Logo and the Hewlett-Packard standard plotter
language, HPGL. In this way, it is possible to simulate a plotter on the
screen.
Examples:
x=50
y=50
LET color=POINT(x,y)
PRINT color
PLOT x,2*50
LINE 200,200,400,100
PRINT POINT(x,100)
--> The program examines the color of the point 50,50 and prints this out on
the screen. It then plots a second point, plots a line and reports on the
color of the second point plotted.
DO
MOUSE mx,my,mk
IF mk=1
DRAW TO mx,my
ENDIF
EXIT IF mk=2
LOOP
--> When the left mouse key is pressed a line is drawn between the last set
point and the absolute coordinates mx,my. The loop is terminated by
pressing the right mouse button.
v_pline()+
SETDRAW
DRAW expression
DRAW(i)
SETDRAW x,y,a
i, x, y, a: iexp
expression: a mixture of sexp and aexp, a sexp must be first and the individual
parts must be seperated by a comma (,), semicolon (;), or an
apostrophe (')
With DRAW an imaginary pen is moved over the screen and draws relative to the
last point. The DRAW command's structure resembles the turtle-graphic commands
of the programming language Logo. The parameters of the DRAW command can
contain a large number of individual commands, which are all passed to the
command in the form of a string. Parts of the expression can be given in
floating-point format, allowing for the use of variables. In this 'Logo like'
convention, an imaginary 'pen' is controlled by means of the graphic commands
and its movement over the 'paper' creates the graphic image. The statement
below is given as an example of how these commands may be used:
DRAW "FD 100 RT ",angle," PU BK ";50
The available commands are:
FD n ForwarD Moves the pen 'n' pixels forward.
BK n BacKward Moves the pen 'n' pixels backwards.
SX x Scale X Scales the 'pen movement' for FD and BK by the
SY y Scale Y specified factor. The scale with SX an SY works only
with the commands FD and BK. With SX0 or SY0 the scale
is switched off. This is quicker than scaling with the
factor 1 (SX1, SY1).
LT a Left Turn Turns the pen to the left through the specified angle
'a', this being given in degrees.
RT a Right Turn Turns the pen as LT, but to the right.
TT a Turn To Turns the pen to the absolute angle 'a'. (See notation
below:)
0
|
|
270-Zero point-90
|
|
180
The data for the angle, 'a' is specified in degrees.
MA x,y Move Absolute Moves the pen to the absolute coordinates for x and y.
DA x,y Draw Absolute Moves the pen to the absolute coordinates for x and y
and draws a line in the current color from the last
position to the point (x,y).
MR x,y Move Relative Moves the pen position in the x and y directions
releative to the last position.
DR x,y Draw Relative Moves the pen by the specified displacement relative to
its last position and draws a line in the current color
from the last position to this point.
CO c COlor Sets the drawing color to 'c' (see COLOR command).
PU Pen Up Lift the pen up from the paper.
PD Pen Down Lowers the pen down onto the paper.
The command SETDRAW x,y,a is an abbreviation for the expression
DRAW "MA ";x,y;"TT ";a.
Additionally the following pen interrogation functions are available:
DRAW(0) x-position
DRAW(1) y-position
DRAW(2) Angle in degrees
DRAW(3) x-axis scale factor
DRAW(4) y-axis scale factor
DRAW(5) Pen flag (-1=PD, 0=PU)
Note: All of these functions return floating point values.
Example:
DRAW "ma 160,200 tt 0" !start at 160,200 and angle 0
FOR i&=3 TO 10
polygon(i&,90) !draws a Polygon with i& corners
NEXT i&
'
PROCEDURE polygon(n&,r&) !n&=number of corners and r&=length of sides
LOCAL i&
FOR i&=1 TO n&
DRAW "fd ",r&," rt ",360/n&
NEXT i&
RETURN
--> Draws a set of ploygons with an increasing number of sides.
FOR i=0 TO 639 STEP 8
SETDRAW 320,200,i
GRAPHMODE 3
DRAW "fd 45 rt 90 fd 45 rt 90 fd 45 rt 90 fd 45"
DRAW "bk 90 rt 90 bk 90 rt 90 bk 90 rt 90 bk 90"
GRAPHMODE 1
DRAW "fd 45 rt 90 fd 45 rt 90 fd 45 rt 90 fd 45"
DRAW "bk 90 rt 90 bk 90 rt 90 bk 90 rt 90 bk 90"
NEXT i
--> Forms a shape from two small sqaures and two large ones, and then rotates
it through 360 degrees.
l%=48
' Square:
DRAW "ma 60,100 tt 45"
DRAW "fd ",l%,"rt 90 fd ",l%,"rt 90 fd ",l%,"rt 90 fd ",l%,"rt 90"
' Diamond, tall:
DRAW "mr 100,0 tt 45"
DRAW "sx 0.5 sy 0"
DRAW "fd ",l%,"rt 90 fd ",l%,"rt 90 fd ",l%,"rt 90 fd ",l%,"rt 90"
' Diamond, wide:
DRAW "mr 100,0 tt 45"
DRAW "sx 0 sy 0.5"
DRAW "fd ",l%,"rt 90 fd ",l%,"rt 90 fd ",l%,"rt 90 fd ",l%,"rt 90"
' Diamons, large and tall
DRAW "mr 100,0 tt 45"
DRAW "sx 3 sy 2"
DRAW "fd ",l%,"rt 90 fd ",l%,"rt 90 fd ",l%,"rt 90 fd ",l%,"rt 90"
--> Draws a square at an angle, followed by three diamonds of various sizes.
These diamonds are produced by changing the x and y scales and redrawing
the original square.
SETDRAW 100,100,90
DRAW "PU FD 40 PD FD 40"
PRINT DRAW(0) !x-coodinate
PRINT DRAW(5) !Pen flag
--> A horizontal line is drawn and the numbers 180 and -1 printed.
v_pline()+
BOX
BOX x1,y1,x2,y2
PBOX x1,y1,x2,y2
RBOX x1,y1,x2,y2
PRBOX x1,y1,x2,y2
x1, y1, x2, y2: iexp
BOX draws a rectangle on the screen. The coordinates of the two opposite
corners are specified by x1,y1 and x2,y2. Similarly PBOX draws a filled
rectangle, RBOX a rectangle with rounded off corners, and PRBOX a filled
rectangle with round corners.
Example:
BOX 20,20,120,120
RBOX 170,20,270,120
x=150
DEFFILL 1,2,4
PBOX 20,20+x,120,120+x
PRBOX 170,20+x,270,120+x
~INP(2)
--> An ordinary rectangle is drawn, followed by one with rounded off corners.
Finally both shapes are drawn again but with a different fill pattern. A
key press is then waited for.
v_pline()+, v_bar()+, v_rbox()+, v_rfbox()+
CIRCLE
CIRCLE x,y,r[,w1,w2]
PCIRCLE x,y,r[,w1,w2]
ELLIPSE x,y,rx,ry[,w1,w2]
PELLIPSE x,y,rx,ry[,w1,w2]
x, y, r, rx, ry, w1, w2: iexp
CIRCLE draws a circle with center coodinates x,y and radius r. Addtional
starting and ending angles w1 and w2 can be specified to draw a circular arc.
Similarly, PCIRCLE draws a filled circle or filled circular arc.
ELLIPSE draws an ellipse with the center coordinates x,y and horizontal radius
rx and vertical radius ry. Optional starting and ending angles w1 and w2 can be
specified to draw an elliptical arc. Similarly, PELLIPSE draws a filled ellipse
or a filled elliptical arc. The angles should be specified in 1/10 degress
(0-3600) and are measured in an anti-clockwise direction with zero pointing to
the right. See notation below.
900
|
1800-angle-0
|
2700
Example:
CIRCLE 320,200,100
ELLIPSE 320,200,200,100,900,1800
PCIRCLE 320,200,100,1800,2700
PELLIPSE 320,200,200,100,2700,3600
--> A circle is drawn along with 3 more arc segments.
v_arc()+, v_circle()+, v_ellarc()+, v_ellipse()+, v_ellpie()+, v_pieslice()+
POLYLINE
POLYLINE n,x(),y() [OFFSET x_off,y_off]
POLYMARK n,x(),y() [OFFSET x_off,y_off]
POLYFILL n,x(),y() [OFFSET x_off,y_off]
n, x_off, y_off: iexp
x(), y(): avar-array
POLYLINE draws a polygon with n corners. The x,y coordinates for the corner
points are given in arrays x() and y(). The first corner points are in x(0) and
y(0), the last in x(n-1) and y(n-1). An optional parameter, OFFSET, can be
added to these coordinates, the magnitude of offset being given by x_off and
y_off.
POLYMARK marks the corner points with the shape defined by DEFMARK.
POLYFILL fills the polygon with the pattern and color previously defined by
DEFFILL. The first and last corner points are connected automatically.
Example:
DIM x%(3),y%(3)
FOR i%=0 TO 3
READ x%(i%),y%(i%)
NEXT i%
DATA 120,120,170,170,70,170,120,120
POLYLINE 4,x%(),y%()
POLYFILL 3,x%(),Y%() OFFSET -50,-50
DEFMARK ,4,10
POLYMARK 3,x%(),y%() OFFSET 40,-80
~INP(2)
--> Draws an outline triangle and a filled triangle, as well as rectangular
corner marks of a further triangle. A key is then waited for.
Memo: Byte arrays are not accepted.
The first and last corner points are connected automatically only in the
case of POLYFILL.
Parameter 'n' is limited to 512. If exceeded:
Interpreted: An error is generated.
Compiled: Only the first 512 points will be drawn.
This limit does not match error message #27 which states a maximum of
128 points. Anything over 128 points causes an internal buffer overrun.
v_pline()+, v_pmarker()+, v_fillarea()+
POINT
POINT(x,y)
x, y: iexp
The color of the point with coordinate x,y is determined with this function.
Values between 0 and 15 are returned for a low resolution screen, between 0 and
3 for medium, and 0 and 1 for high resolution.
Example:
a=POINT(100,100)
PLOT 100,100
PRINT a,POINT(100,100)
--> The computer read the color at 100,100, plots a point there and rereads its
color.
Memo: This command only works on palette based modes.
For high color and true color you must call the VDI directly.
v_get_pixel()+
FILL
FILL x,y[,f]
x, y, f: iexp
This command fills any enclosed area. The filling procedure begins at the
coordinates x,y. If the optional paramter 'f' is present then the filling
procedure is limited only by points of the color 'f' and the edges of the
screen. If 'f' is not present, or with f=-1, any point with a color other than
the starting point x,y will be taken to be the edge of the area to be filled.
Examples:
LINE 0,180,639,180
FOR i=1 TO 19
BOX i*20,100,i*20+18,180
TEXT i*20-4,195,i
DEFFILL ,2,i
FILL i*20+1,101
NEXT i
PAUSE 100
FILL 0,180
--> This draws a straight line, placing a row of filled boxes above it. After a
seconds pause, the computer proceeds to fill in the straight line, and
anything joining it, thus partly destroying the fill patterns.
LINE 0,280,639,280
FOR i=1 TO 19
BOX i*20,200,i*20+20-i,280
TEXT i*20-4,295,i
DEFFILL ,2,i
FILL i*20+1,201,1
NEXT i
--> The same result as above occurs, except that the resulting fill patterns
will be different, due to the extra parameter in the fill commmand causing
a slightly different fill mechanism to be used.
v_contourfill()+
CLS
CLS [#n]
n: iexp
Erases the screen by using ESC-E-CR (CHR$(27)+"E"+CHR$(13)) of the VT-52
Emulator. It can also be rerouted to a data file.
Example:
PBOX 100,100,500,200
REPEAT
UNTIL MOUSEK
CLS
--> Fills the screen partly with a rectangle and deletes it after a mouse
button it pressed.
Memo: CLS #n appears to be almost useless. What's the point of writing
ESC-E-CR (3 bytes) to a file? Might be ok for other devices.
The extra CR is also not needed.
This is actually a bios() call to bconout(DEV_CON) using a VT-52 ESCape.
TEXT
TEXT x,y[,l],expression
x, y, l: iexp
expression: aexp or sexp
Displays the text in 'expression' starting at the point with the graphic
coodinates x,y. This point refers to the bottom left corner of the first
character of the expression. The parameter 'l' sets the length of the text in
pixels. With 'l' as positive, the spacing between characters will be adjusted
to achieve the length, whereas with 'l' negative, the length is achieved by
altering the size of the spaces between words. When 'l' is zero, the unchanged
text is displayed.
Using DEFTEXT, various attributes of text can be altered. DEFTEXT however, only
works with the TEXT command and with the PRINT command when used inside a
window.
Example:
s$="this is an example"
FOR i=0 TO 23
DEFTEXT 1,i,0,6
TEXT 50,i*16+16,s$
NEXT i
DEFTEXT 1,0,0,13
TEXT 350,50,350-50
TEXT 350,100,s$
TEXT 350,150,250,s$
TEXT 350,200,-250,s$
~INP(2)
--> Writes text in various forms on the screen and then waits for a key to be
pressed.
Memo: Clips text off at 119 characters.
v_gtext()+, v_justified()+, vst_alignment()+
SPRITE
SPRITE bit_pattern$[,x,y]
bit_pattern$: svar
x, y: aexp
The SPRITE command enables a 16x16 pixel block to be moved around the screen.
The appropriate bit information for the pattern and its mask is put into the
string bit_pattern$. All values must be given in word size. For this purpose
one can use the command MKI$(), so bit_pattern$ is formed as follows:
bit_pattern$ = MKI$(x-coordinate of action point)
+ MKI$(y-coordinate of action point)
+ MKI$(0) !0=normal or -1=XOR
+ MKI$(mask color) !usually 0
+ MKI$(sprite color) !usually 1
+ sprite$
With 'SPRITE bit_pattern$,x,y' the sprite is first drawn or moved if already on
the screen. With 'SPRITE bit_pattern$' the sprite is erased from the screen
display.
Contained in sprite$ is the bit information for the sprite shape and its mask,
which must be specified, unlike DEFMOUSE, not successively but alternately.
Example:
gfa$=MKI$(1)+MKI$(1)+MKI$(0)
gfa$=gfa$+MKI$(0)+MKI$(1)
FOR i%=1 TO 16
READ pattern%,mask%
gfa$=gfa$+MKI$(mask%)+MKI$(pattern%)
NEXT i%
DATA 0,0,0,32256,15360,16896,8192,24064
DATA 8192,24560,11744,21008,9472,23280,9472,23295
DATA 15838,16929,274,32493,274,749,286,737
DATA 18,1005,18,45,18,45,0,63
REPEAT
ADD mx%,(MOUSEX-mx%)/50
ADD my%,(MOUSEY-my%)/50
SPRITE gfa$,mx%,my%
UNTIL MOUSEK=2
SPRITE gfa$
--> A sprite moves over the screen, following the movement of the mouse
pointer.
Memo: This should be considered a Line-A command.
Use it carefully or not at all.
Sprite strings must be exactly 74 bytes in length.
Line-A Draw Sprite+, Line-A Undraw Sprite+
CURVE
CURVE x0,y0,x1,y1,x2,y2,x3,y3
x0, y0, x1, y1, x2, y2, x3, y3: iexp
The command CURVE is based upon the Bezier Curve function.
The Bezier Curve starts at x0,y0, and ends at x3,y3. The curve at x0,y0 is at a
tangent with a line from x0,y0 to x1,y1; and at x3,y3 is at a tangent with a
line between x3,y3 and x2,y2.
Example:
x0=10
y0=10
x1=50
y1=110
x2=150
y2=200
x3=350
y3=300
LINE x0,y0,x1,y1
LINE x2,y2,x3,y3
CURVE x0,y0,x1,y1,x2,y2,x3,y3
--> Draws a sample Bezier Curve on the screen.
Memo: GFA computes the curve itself and draws it with VDI function
v_pline(). GFA does not call VDI function v_bez() at all.
The compiler uses twice as many iterations when drawing the curve.
v_bez()+
Grabbing Sections of the Screen
SGET, SPUT
GET, PUT
VSYNC
BITBLT
GETSIZE()
SGET
SGET screen$
SPUT screen$
screen$: svar
SGET copies the entire screen (32000 bytes) into a string. Similarly, SPUT
copies a 32000 byte long string into the screen memory, thus displaying it.
Example:
PCIRCLE 100,100,50
SGET b$
~INP(2)
CLS
~INP(2)
SPUT b$
--> Draws a filled circle on the screen. After a key is pressed it disappears,
after a another key is pressed it reappears.
Memo: Only works in ST compatible modes that require exactly 32000 bytes.
vro_cpyfm()+
GET
GET x1,y1,x2,y2,section$
PUT x1,y1,section$[,mode]
x1, y1, x2, y2, mode: iexp
section$: svar
GET puts a section of screen into a string variable (x1,y1 and x2,y2 are
coordinates of diagonally opposite corners). Similarly PUT places a screen
section (read in with GET) onto the screen at coordinates x1,y1. Using 'mode'
it is possible to control the way the string is placed on the screen in
relation to the existing screen contents. In the following table the
relationship between the new picture and the existing one are shown for each
value of mode. The term 's' represents a pixel from the new picture (the source
picture), and 'd' the corresponding pixel from the existing screen (the
destination).
Mode Placing rule Effect
0 0 All points are cleared.
1 s AND d Only the points which are set in both screens remain set.
2 s AND (NOT d) Sets only the points which are set in the source and clear
in the destination.
3 s The new source screen is simply transferred (GRAPHMODE 1 -
- Default).
4 (NOT s) AND d Only the points which are clear in the source and set in
the destination are set.
5 d The screen remains unchanged.
6 s XOR d Only those points which are set in one but not both remain
set (GRAPHMODE 3).
7 s OR d All points are set in which either or both the source and
destination are set (GRAPHMODE 2).
8 NOT (s OR d) All points which are clear in both screens become set.
9 NOT (s XOR d) All points where both source and destination are set, or
both are clear, are set.
10 NOT d The destination screen is inverted.
11 s OR (NOT d) A point is set if either the source is set, or the
destination is clear, or both.
12 NOT s The source screen is inverted before the placing.
13 (NOT s) OR d GRAPHMODE 4
14 NOT (s AND d) All points which were not set in both screens become set.
15 1 All points are set.
The important modes are:
3 Replace (default)
4 XOR
7 Transparent
13 Inverse transparent
Memo: Only works if the block requires no more than 32000 bytes.
The resulting string will always be 6 bytes larger than expected.
The header is as follows: MKI$(width&-1)+MKI$(height&-1)+MKI$(planes&)
There is some undocumented option related to the mode parameter.
If bit 4 of the mode parameter is set, it calls VDI function vro_cpyfm()
instead of the Line-A blit function. However it's so buggy that it's
non-functional and results in a crash.
Original manual said this: (There are no such blitmodes supported by the VDI.)
In addition, if the current fill pattern is a user-defined one and bit 4 of
'mode' is set, then the result of the above calculations will be ANDed with the
user-defined pattern.
Line-A BitBlt+, vro_cpyfm()+
VSYNC
VSYNC
This command is used for the synchronisation of the screen display. When this
command is issued, the computer pauses until the vertical scanning line (raster
scan) reaches the top of the screen. This results in much less screen flicker.
VSYNC can be used, for example, in the animation of screen sections using GET
and PUT.
Example:
t%=TIMER
FOR i%=1 TO 100
VSYNC
NEXT i%
PRINT SUB(TIMER,t%)/200
--> This displays the time for 100 scans of the screen to occur.
Vsync()+
BITBLT
BITBLT s_mfdb%(),d_mfdb%(),par%()
s_mfdb%(), d_mfdb%(), par%(): integer-array
The command BITBLT allows the copying of rectangular screen sections. It is
similar to the commands GET and PUT but it is quicker and more flexible.
However, it is also more complicated to use.
The parameters of the command are stored in three arrays. The first one,
s_mfdb%(), contains the structure of the source screen - the one to be copied.
In the same way, d_mfdb%() contains the structure of the destination, i.e. the
place where the picture is to be copied to. The third array contains the
coordinates of the source and target areas and also the copy mode.
This command has a VDI routine as its basis. During BITBLT adr% and BITBLT x%()
a Line-A routine is called (see the section on Line-A calls).
The structure of the source (s_mfdb%) is same as that of the destination screen
(d_mfdb%). The abbreviations mean:
s_mfdb%() Source Memory Form Description Block
d_mfdb%() Destination Memory Form Description Block
The Array Elements are: (OPTION BASE 0 is assumed)
x_mfdb%(0) Contains the source/destination address. This address must be an
even number. Usually either s_mfdb%(0) or d_mfdb%(0) equals the
screen address (XBIOS(2)).
x_mfdb%(1) Width of the screen in pixels. This value must be divisible by 16.
x_mfdb%(2) Height of the screen in pixels.
x_mfdb%(3) Screen width in words (equals pixel count/16).
x_mfdb%(4) Format type.
0 = Device specific (normally this is used)
1 = VDI format
x_mfdb%(5) Number of bit planes:
1 = 2 colors (mono)
2 = 4 colors
4 = 16 colors
8 = 256 colors
16 = 32768/65536 high color
24 = True color
32 = True color (extra alpha byte)
x_mfdb%(6) Reserved field. (should be set to 0)
x_mfdb%(7) Reserved field.
x_mfdb%(8) Reserved field.
If x_mfdb%(0)=0, the VDI will fill in the rest of the x_mfdb() parameters by
itself, pointing to the current screen.
The array par%() has the following structure:
par%(0) Left x-coordinate of the source block
par%(1) Upper y-coordinate of the source block
par%(2) Right x-coordinate of the source block
par%(3) Lower y-coordinate of the source block
par%(4) Left x-coordinate of the destination block
par%(5) Upper y-coordinate of the destination block
par%(6) Right x-coordinate of the destination block
par%(7) Lower y-coordinate of the destination block
par%(8) Copy mode
The values for 'copy mode' correspond to those with GET/PUT. The important ones
are:
3 = Replace (GRAPHMODE 1)
6 = XOR (GRAPHMODE 2)
7 = Transparent (GRAPHMODE 3)
13 = Inverse transparent (GRAPHMODE 4)
Example:
DIM smfdb%(8),dmfdb%(8),p%(8)
'
FOR i%=0 TO 639 STEP 8
LINE i%,0,639,399
NEXT i%
'
GET 0,0,639,399,a$
mirrorput(0,0,a$)
'
PROCEDURE mirrorput(x%,y%,VAR x$)
IF LEN(x$)>6 !Only if something there
a%=V:x$
b%=INT{a%}
h%=INT{a%+2}
'
smfdb%(0)=a%+6
smfdb%(1)=(b%+16) AND &HFFF0
smfdb%(2)=h%+1
smfdb%(3)=smfdb%(1)/16
smfdb%(5)=DPEEK(a%+4)
'
dmfdb%(0)=XBIOS(3)
dmfdb%(1)=640
dmfdb%(2)=400
dmfdb%(3)=40
dmfdb%(5)=1
'
p%(1)=0
p%(3)=h%
p%(4)=x%+b%
p%(5)=y%
p%(6)=x%+b%
p%(7)=y%+h%
p%(8)=3
FOR i%=0 TO b%
p%(0)=i%
p%(2)=i%
BITBLT smfdb%(),dmfdb%(),p%()
DEC p%(4)
DEC p%(6)
NEXT i%
'
ENDIF
RETURN
--> Draws a set of lines, forming a triangle. The entire screen is read into a
string and then each pixel-wide column is placed back on the screen on the
other side. This has the effect of reflecting the screen in an axis down
the center of the screen (see BITBLT in the section on Line-A calls).
Memo: This is the only variation of BITBLT that is based on a VDI call.
The other variants are Line-A calls and should be avoided.
This call does not fill in the reserved fields even if you pass them.
vro_cpyfm()+
GETSIZE
GETSIZE(x1,y1,x2,y2)
x1, y1, x2, y2: iexp
The TT does not have a constant screen memory of 32000 bytes like the ST. A
screen could require much more memory (153600 bytes). The commands GET and PUT
are limited to 32000 bytes and therefore a function has been introduced to
support the larger screen resolutions that require more than 32000 bytes.
This function will return the number of bytes required by the screen between
the coordinates x1,y1 and x2,y2. Several GET or PUT commands could be used to
address the entire screen.
Note: If x1 or y1 are off screen, this function returns 0.
Example:
' low resolution
PRINT GETSIZE(0,0,319,199)
--> Prints the value 32006 on the screen.
Memo: Seems to only work correctly in standard ST and TT video modes.
Internally this command uses the Line-A variables.
The extra 6 bytes account for the string header used by GET and PUT.
GETSIZE() -> V_REZ_HZ, V_REZ_VT, PLANES (Line-A variables)
Line-A Variable Table+
Chapter 9 - Event, Menu, and Window Management
MENU
MENU()
ON MENU
ON MENU BUTTON
ON MENU KEY
ON MENU IBOX
ON MENU OBOX
ON MENU MESSAGE
There are commands in GFA-Basic which allow the monitoring of GEM Events in a
straightforward way. These events are the pressing of a key or a mouse button,
the arrival of the mouse pointer inside or outside one of two specified
rectangular screen areas, and the arrival of a 'GEM message', in which
information about window management is passed.
The monitoring of these events is set up by ON MENU xxx GOSUB, where xxx is the
event to be reacted to, and is actually invoked within a program by the ON MENU
command. Each time this command is encountered, a check is made to see if an
Event has occured. If so, and if there was a previous ON MENU xxx GOSUB to
define the reaction to that event, then the program branches to the appropriate
procedure.
ON MENU [t]
t: iexp
The command ON MENU supervises Event handling. Before using it, the required
reaction should have been specified with an ON MENU xxx GOSUB command, the
variants of which are explained in the remainder of this chapter. For constant
supervision of Events it is necessary to use this command repeatedly. For this
reason, the ON MENU command is normally found in a loop.
The parameter 't' contains the time (in thousandths of a second) to elapse
before the ON MENU command is terminated. The reason for this delay is that
occasionally GEM does not notice the releasing of a mouse button (typical
effect: When the 'Close' box of a window is clicked, the window sometimes
remains open until the button is energetically clicked a few times). By giving
a suitable value to 't', this should be prevented.
It is a good idea to use the parameter 't' even if a program is not
specifically concerned with the mouse buttons, as other programs, or GEM
routines called from within it, may do so.
Example:
ON MENU BUTTON 1,1,1 GOSUB test
t%=TIMER
REPEAT
PRINT (TIMER-t%)/200
ON MENU 2000
UNTIL MOUSEK=2
PROCEDURE test
RETURN
--> The time since the program started is displayed every two seconds. If the
left mouse button is pressed, then the Event occurs, and ON MENU is
terminated before the expiry of the two second period. A press of the right
mouse button ends the program. If one changes the first line to 'ON MENU
BUTTON 0,0,0 GOSUB test' then the mouse monitoring is switched off, and the
time parameter behind ON MENU will have no effect.
evnt_multi()+, evnt_timer()+
MENU(x)
x: aexp (from -2 to 15 inclusive)
The variables MENU(-2) to MENU(15) contain all the relevant information from an
Event. In the case when an item in a menu is selected, the index of the
selected item in the item list will be found in MENU(0) (see next section on
Pull-down Menus).
MENU(-2) and MENU(-1) contain the address of the Message buffer and the address
of the menu Object tree respectively. The Message buffer lies in the variables
MENU(1) to MENU(8) and the AES Integer Output Block in MENU(9) to MENU(15). The
use of these variables to determine specific information is only briefly
discussed here, starting with MENU(1) and the Message buffer.
The Identification number of an Event when it occurs can be found in MENU(1).
The other elements of the message buffer contain various values, the
interpretation of which depends on the value in MENU(1), as shown in the
following table, where different possible values of MENU(1) are listed together
with the meanings of other relevant MENU(x) variables in each case. The values
relating to window management will tend to be the most extensively used.
MENU(1)=10 A menu item was chosen:
MENU(0) Menu item index in the item list
MENU(4) Object number of the menu title
MENU(5) Object number of the chosen menu item
MENU(1)=20 A redraw of a rectangular window area is required:
MENU(4) Identification number (handle) of the window
MENU(5) x-coordinate of top-left corner
MENU(6) y-coordinate of top-left corner
MENU(7) Width of the redraw area
MENU(8) Height of the redraw area
(See ON MENU MESSAGE for example.)
MENU(1)=21 A window was clicked (this normally means that a user wishes to
activate this window):
MENU(4) ID (handle) of the clicked window
MENU(1)=22 The 'Close' box (top left) of a window was clicked:
MENU(4) ID of the window
MENU(1)=23 The 'Full' box (top right) of a window was clicked (this normally
means that the user wants to bring that window to maximum size):
MENU(4) ID of the window
MENU(1)=24 One of the four arrow boxes or a slider bar area of the window
border was clicked. The movement of the slider bar is reported by
MENU(1)=25 or MENU(26). MENU(1)=24 only shows that one of the gray
areas was clicked:
MENU(4) ID of the window
MENU(5) The area that was clicked:
0: Above the vertical slider
1: Below the vertical slider
2: Up arrow
3: Down arrow
4: To the left of the horizontal slider
5: To the right of the horizontal slider
6: Left arrow
7: Right arrow
MENU(1)=25 The horizontal slider was moved:
MENU(4) ID of the window
MENU(5) Position of the moved slider (a number between 1 and 1000)
MENU(1)=26 The vertical slider was moved:
MENU(4) ID of the window
MENU(5) Position of the moved slider (a number between 1 and 1000)
MENU(1)=27 The size of the window was changed by means of the 'Size' box
(lower right):
MENU(4) ID of the window
MENU(5) New x-coordinate of top-left corner
MENU(6) New y-coordinate of top-left corner
MENU(7) New width of the window
MENU(8) New height of the window
MENU(1)=28 The position of the window was changed:
MENU(4) ID of the window
MENU(5) New x-coordinate of top-left corner
MENU(6) New y-coordinate of top-left corner
MENU(7) New width of the window
MENU(8) New height of the window
MENU(1)=29 A new GEM window was activated. This can happen with the closing of
another active window, for example one which was used by a Desk
Accessory:
MENU(4) ID of the window
MENU(1)=40 An accessory was selected:
MENU(5) Menu identification number of the accessory
MENU(1)=41 Current application terminated. This value can only be received by
an accessory, but serves no purpurse under a multi-tasking
operating system.
MENU(4) Menu identification number of the accessory
The variable MENU(9) contains bit information on which kind of event has
occured. If the bit for the appropriate event is set, the variables MENU(9) to
MENU(15) and GINTOUT(0) to GINTOUT(7) will contain information as follows:
Bit Event
0 Keyboard
1 Mouse button
2 Mouse has entered/exited rectangle 1
3 Mouse has entered/exited rectangle 2
4 A message arrived in the message buffer
5 Timer
MENU(10) x-position of the mouse when event terminated
MENU(11) y-position of the mouse when event terminated
MENU(12) Mouse buttons pressed:
0: None
1: Left
2: Right
3: Both buttons
(See ON MENU BUTTON for an example.)
MENU(13) Returns the status of the keyboard 'modifier' keys, for each pressed
key a bit is set as follows:
0: Right shift
1: Left shift
2: Control
3: Alternate
(See ON MENU KEY for an example.)
MENU(14) Returns information about a pressed key. The low-order byte contains
the ASCII code of the character, and the high-order byte contains the
keyboard Scan Code. (See ON MENU KEY for an example.)
MENU(15) Returns the number of mouse clicks (single click, double-click, etc.)
that caused the event.
Memo: This table does not seem to have a limit. Values less than -2 or
greater than 15 do not generate an error message.
evnt_mesag()+
ON MENU BUTTON clicks,but,state GOSUB proc
clicks, but, state: iexp
proc: procedure name
This sets up the action to be taken when one or more clicks of the mouse are
received. With a subsequent ON MENU command, the named procedure will be
branched to if the conditions imposed by the parameters are met:
clicks - Sets the maximum number of clicks which generates a responce.
but - The expected button combination as follows:
0: None
1: Left
2: Right
3: Both
state - Specifies which button state (up or down) will cause the Event. With
state=0, the Event will be prompted by the button(s) being up, and
with state=1, the button(s) being down will cause the Event.
proc - The name of the procedure to which the program will branch if the
above conditions are met.
Example:
ON MENU BUTTON 1,1,0 GOSUB box
GRAPHMODE 3
REPEAT
ON MENU
UNTIL MOUSEK=2
'
PROCEDURE box
ADD i%,7
IF i%>200
i%=3
ENDIF
BOX 320-i%,200-i%,320+i%,200+i%
RETURN
--> Boxes increasing in size are drawn on the screen so long as the left mouse
button is not pressed. The program will terminate if the right mouse button
is pressed.
Memo: If the procedure used with ON MENU BUTTON is undefined the compiler
will not issue and error message. Instead the compiler writes a bad
binary where ON MENU BUTTON is translated into JSR 0.l!
evnt_button()+
ON MENU KEY GOSUB proc
proc: procedure name
This command enables the monitoring of the keyboad. The parameter proc is the
name of a procedure to which the program branches, if a key was pressed during
an ON MENU command.
Example:
ON MENU KEY GOSUB key_output
REPEAT
ON MENU
UNTIL MOUSEK=2
'
PROCEDURE key_output
PRINT "keyboard shift keys: ";MENU(13)
PRINT "ASCII-code: ";BYTE(MENU(14))
PRINT "Scan-code: ";SHR(MENU(14),8)
PRINT
RETURN
--> With the press of a key the current condition of the keyboard modifier keys
(Shift, Control, Alternate) is displayed as well as the ASCII code and Scan
Code of the pressed key. A press of the right mouse button terminates the
program. For the meaning of MENU(13) and MENU(14) see function MENU().
Memo: If the procedure used with ON MENU KEY is undefined the compiler
will not issue and error message. Instead the compiler writes a bad
binary where ON MENU KEY is translated into JSR 0.l!
evnt_keybd()+
ON MENU IBOX n,x,y,w,h GOSUB proc
ON MENU OBOX n,x,y,w,h GOSUB proc
n, x, y, w, h: iexp
proc: procedure name
These two commands monitor the mouse coordinates. If the mouse enters (IBOX) or
leaves (OBOX) a rectangle display area, the procedure proc is branched to.
It is possible to define two rectangle display areas which are supervised
seperately. 'n' is the number (1 or 2) of the appropriate rectangle, x is left
x-coordinate, y the upper y-coordinate, w the width, and h the height of the
rectangle. The monitoring takes place during the execution of an ON MENU
command.
Example:
ON MENU IBOX 1,250,130,140,140 GOSUB enter_box
ON MENU OBOX 2,50,50,540,300 GOSUB exit_box
'
GRAPHMODE 3
BOX 250,130,390,270
BOX 50,50,590,350
REPEAT
ON MENU
UNTIL MOUSEK=2
'
PROCEDURE enter_box
BOX 250+i%,130+i%,390-i%,270-i%
IF i%=70
i%=0
ENDIF
ADD i%,2
RETURN
'
PROCEDURE exit_box
BOX 0+j%,0+j%,639-j%,399-j%
IF j%=0
j%=50
ENDIF
SUB j%,2
RETURN
--> When the mouse enters the inner rectangle, shrinking boxes appear inside
it. When it leaves the outside rectangle, growing boxes appear there.
Pressing the right mouse button terminates the program.
Memo: If the procedure used with IBOX or OBOX is undefined the compiler
will not issue and error message. Instead the compiler writes a bad
binary where IBOX or OBOX are translated into JSR 0.l!
evnt_mouse()+
ON MENU MESSAGE GOSUB proc
proc: procedure name
If a message arrives in the message buffer, then the program branches to the
procedure with the name proc. The monitoring of the message buffer takes place
with each ON MENU command. The structure of the message buffer is discussed in
the section concerning MENU().
Example:
DIM m$(10)
FOR i%=0 TO 10
READ m$(i%)
NEXT i%
DATA Desk,Redraw,-------------------------
DATA 1,2,3,4,5,6,"",""
OPENW 4,0,0
MENU m$()
ON MENU MESSAGE GOSUB read_message
PRINT AT(1,1);
REPEAT
ON MENU
UNTIL MOUSEK=2
'
PROCEDURE read_message
IF MENU(1)=20
PRINT CHR$(7);
PRINT "A screen section must be redrawn"
ELSE
PRINT CHR$(7);
PRINT "Something has happened !!!"
ENDIF
RETURN
--> To test this program, an accessory must be loaded. If selected, then the
program announces that a screen section was covered and has to be redrawn
(see also MENU()). At the beginning this message appears once. The program
can be terminated with a press of the right mouse button.
Memo: If the procedure used with ON MENU MESSAGE is undefined the compiler
will not issue and error message. Instead the compiler writes a bad
binary where ON MENU MESSAGE is translated into JSR 0.l!
evnt_mesag()+
ON MENU GOSUB
MENU, MENU OFF, MENU KILL
In this section the commands specific to GFA BASIC 3 for control of
pull-down-menus are given. Unfortunately a certain confusion prevails in the
literature on this topic as to the meaning of some of the terms used. They
shall therefore be stated here as they are used in this manual. We use the term
'pull-down-menu' as a general term for menu titles or headings. In the top
screen line the constantly visible part of the menu, is where the menu list is
located. This contains the individual headings. If the mouse arrow arrives at
one of these headings, then under it a so-called menu which unfolds. Each part
of this menu can be selected individually as a menu entry. This choice of
terminology is not generally obligatory but is used throughout this manual,
elsewhere slightly different definitions are used.
During the creation of a menu its entries are set in an array m$(). With the
command MENU m$() this pull-down-menu is displayed on the screen. The command
ON MENU GOSUB determines which procedure the program branches to on the
selection of a menu entry. When the program is running, a check is made to see
whether an entry was selected on each occurrence of an ON MENU command.
The command MENU OFF returns reverse video entries in the menu list to normal
display. With MENU KILL the menu is switched off. The command MENU x,y enables
menu entries to be provided with checkmarks or to be displayed in light text,
making this menu entry non-selectable.
Memo: If the procedure used with ON MENU is undefined the compiler will
not issue and error message. Instead the compiler writes a bad binary
where ON MENU is translated into JSR 0.l!
ON MENU GOSUB proc
MENU m$()
MENU OFF
MENU KILL
MENU x,y
MENU x,text$
proc: procedure name
m$(): string-array
x, y: iexp
text$: sexp
These commands are responsible for generating and managing a menu, and are
supported by the commands and variables in the previous section (ON MENU,
MENU()).
With ON MENU GOSUB proc, the procedure to which control will be passed on
selection of a menu entry is determined. If an accessory is currently open, the
procedure will not be called. Within the procedure, which menu entry was
selected can be found by using the variable MENU(0). MENU(0) is the index of
the selected entry in the array of the entries m$(), and m$(MENU(0)) indicates
the text clicked on the menu if OPTION BASE 0 is currently selected. If OPTION
BASE 1 has been chosen, then the text of the selected item is in m$(MENU(0)+1).
The command MENU m$() puts the menu onto the screen. The string array m$()
contains the headings, entries and reserved space for the accessories. The
following format must be used during the arrangement of the entries in the
array m$():
m$(0) Heading of the first menu in which accessories can exist.
m$(1) Name of the first entry in the first menu.
m$(2) A line of minus signs.
m$(3) - m$(8) Reserved space for accessories. These elements need only be
a single character long, as their contents are ignored. If
an accessory was loaded when the computer was switched on,
this will take up one of these strings. Otherwise they will
not be printed.
m$(9) An empty string, which marks the end of the first menu.
All further menus have the following format:
1. Heading of the menu.
2. List of the menu entries.
3. An empty string which marks the end of the menu.
After the last menu another further empty-string marks the end of the entire
Pull-down-menu. A menu entry which begins with a minus sign is represented but
is not selectable and is shown in light text.
MENU OFF returns a menu title to 'normal video' display mode. (After an item is
chosen from a menu, the menu title is displayed in inverse video).
MENU KILL deactivates a menu but does not, however, remove the menu title list
from the screen. In addition MENU KILL turns off the ON MENU GOSUB options.
With the MENU x,y instruction the x-th entry in a menu can be given certain
attributes. The numbering of the entries corresponds to the indexing of the
array of menu entries, counting from zero and including titles, entries for
Accessories and null strings ("").
The second parameter y specifies the attribute to be given, or removed from,
the x-th menu entry as follows:
y Effect
0 Checkmark to be removed, if present, from in front of a menu item
1 Checkmark to be placed in front of a menu item ->
2 Menu item to be made non-selectable, and printed in light characters
3 Menu item to be made selectable, and written in normal characters
With the MENU x,text$ instruction the x-th entry of a menu can have it's text
altered. The numbering of the entries corresponds to the indexing of the array
of menu entries, counting from zero and including titles, entries for
Accessories and null strings ("").
Sample Pull-down menu program:
DIM entry$(20)
DATA "Desk"," Test "
DATA ----------------,1,2,3,4,5,6,""
DATA "File"," Load "," Save "
DATA ---------," Quit ",""
DATA "Titles"," Entry 1 "," Entry 2 ",""
DATA End
'
i%=-1
REPEAT
INC i%
READ entry$(i%)
UNTIL entry$(i%)="End"
entry$(i%)=""
'
MENU entry$()
ON MENU GOSUB evaluate
OPENW 0
'
REPEAT
ON MENU
UNTIL MOUSEK=2
'
PROCEDURE evaluate
MENU OFF
' MENU(0) contains array index of selected item
m%=MENU(0)
PRINT entry$(m%)
'
ALERT 0,"Checkmark before item?",0," Yes | No ",a%
IF a%=1
MENU m%,1
ELSE
MENU m%,0
ENDIF
'
ALERT 0,"Lightened characters?|(Not selectable)",0," Yes | No ",a%
IF a%=1
MENU m%,2
ELSE
MENU m%,3
ENDIF
RETURN
--> A menu is created and monitored. When a menu item is selected, its text is
printed and the user is asked first if it is to be checkmarked, and then
whether it should be 'non-selectable' or not.
Memo: Menu titles are limited to 10 characters.
Menus don't display correctly in N.Aes if hidemenu=true. This happens in
the editor or compiled.
The library does not honor the character width returned from
graf_handle() and assumes 8. However the editor is ok.
The MENU m$() commmand is limted to 18 titles.
Object count is limited to 200 entries.
String space is limted to about 4000 bytes.
MENU x,y will accept any value for y and not complain.
All the MENU commands will do nothing if no menubar is active.
No error will be issued, they are simply ignored.
menu_bar()+, menu_tnormal()+, menu_icheck()+, menu_ienable()+, menu_text()+
Window Commands
OPENW, CLOSEW
W_HAND(), W_INDEX()
CLEARW
TITLEW, INFOW
TOPW
FULLW
WINDTAB, WINDTAB()
GFA-Basic offers a number of commands for simple window management: (OPENW,
CLOSEW, CLEARW, TITLEW, INFOW), but if one wants to program windows more
efficiently, taking full advantage of the GEM facilities, then the appropriate
AES routines will need to be used (see Chapter 11 - AES Libraries).
Additionally the functions W_HAND() and W_INDEX() are available as a link
between the simpler window management commands and the more extensive AES
functions in the Window Library.
With the simplest of the instructions, OPENW, all four windows share a common
corner, their other corners all lying on the screen edges. When this method is
used, only one pair of coordinates is needed to define the size and position of
all four windows, these being the coordinates of the common corner.
After a window has been opened, most commands (PRINT, PRINT AT, TEXT, etc.)
will take as their origin, the top left corner of the work-area of the window,
but commands such as GET, PUT, and BITBLT, which access the screen memory
directly, will still take the top left corner of the screen for their origin.
Graphics and text which leave the current window area are automatically
clipped.
OPENW
OPENW nr[,x_pos,y_pos]
OPENW #n,x,y,w,h,attr
CLOSEW nr
CLOSEW #n
nr, x_pos, y_pos: aexp
n, x, y, w, h, attr: iexp
With 'OPENW nr' window number nr is opened. The parameters x_pos and y_pos
determine the position of the 'free' window corner, i.e. the one which is not
on the edge of the screen. The AES routines, 'OPENW #n' or WINDTAB() are
required for more flexible window management. The coordinates of the possible
windows set up with this instruction (assuming high-resolution mode) will be:
Number Top left corner Lower right corner
1 0,19 x_pos,y_pos
2 x_pos,19 639,y_pos
3 0,y_pos x_pos,399
4 x_pos,y_pos 639,399
Arranged as follows:
0 x_pos 639
19 -----------------------------
| | |
| 1 | 2 |
| | |
y_pos |--------------|--------------|
| | |
| 3 | 4 |
| | |
399 -----------------------------
The point (x_pos,y_pos) is thus the point of contact of the four possible
windows.
With the instruction 'OPENW 0' no genuine window is opened, but the coordinate
origin is moved to (0,19). Thus the upper 19 lines of the screen are protected
from graphical or text output. This usually protects a menu bar against
accidental overwriting.
The instruction 'CLOSEW nr' closes the window with number nr, 'CLOSEW #n'
closes the window with the arbitrarily assigned number n. (See also example
program at the end of this section.)
Example:
REPEAT
IF MOUSEK=1
CLOSEW 1
OPENW 4,320,200
ENDIF
IF MOUSEK=2
CLOSEW 4
OPENW 1,100,100
ENDIF
UNTIL MOUSEK=3
CLOSEW #1
CLOSEW #4
--> Pressing the left mouse button opens window 4 and closes window 1, or
pressing the right mouse button opens window 1 and closes window 4.
Simultaneously pressing both mouse buttons terminates the program.
The second variant, 'OPENW #n', opens a window with the arbitrarily assigned
number 'n', with the position, size, and attributes specified in x, y, w, h,
and attr. The expression attr determines which window components (title bar,
sliders, etc.) the window is to have (see WINDTAB() below or WIND_CREATE() in
the AES section). 'n' is then the number to be used with TITLEW, INFOW, etc. -
it is NOT the GEM 'handle' of the window.
'CLOSEW #n' closes such a window.
Example:
TITLEW #1," Title 1 " !Gives title to window #1
INFOW #1,STRING$(15,"...| ") !Allocates info line
OPENW #1,16,32,600,300,&X111111111111 !Sets coords + attributes and opens a window
~INP(2)
CLOSEW #1 !Important! Closes window
--> Opens a window with a title and an info line. Pressing a key terminates the
program.
Memo: None of these commands properly check the window number.
This is true for the editor and the library.
'OPENW n,x,y' will ignore the command if the x or y are off screen.
'OPENW #n,x,y,w,h,a' will accept index 0 then ignore the rest of the
parameters. This appears to be a bug.
wind_create()+, wind_open()+, wind_close()+, wind_delete()+
W_HAND
W_HAND(#n)
W_INDEX(#hd)
n, hd: aexp
W_HAND() returns the GEM 'handle' (identification number) of the window whose
'channel number' was specified in 'n' (1 to 4).
W_INDEX() performs the inverse function and returns the window number (1 to 4)
for the specified GEM handle (1 to ?).
Note: The window number is the value used in the simple window control
commands. The GEM handle is a different value (used by AES) which refers
to the same window. The GEM handle should be used to specify a
particular window when using the AES routines.
Example:
OPENW 2
PRINT W_HAND(#2)
~INP(2)
CLOSEW #2
--> Prints the AES 'handle' of the window numbered 2 on the screen. Pressing a
key terminates the program.
Memo: W_HAND() does not return the desktop handle correctly.
Negative offsets result in access below the table.
Too large of values not checked, results in access beyond the table.
W_INDEX() returns 0 for any AES handle it cannont find.
These problems occur in the editor as well as the library.
wind_get()+
CLEARW
CLEARW [#]n
TITLEW [#]n,title$
INFOW [#]n,info$
TOPW #nr
FULLW [#]n
n: aexp
nr: iexp
title$, info$: sexp
CLEARW deletes the contents of window number 'n'.
TITLEW writes the text in 'title$' in the top line of the window.
INFOW writes the text 'info$' on the second (information) line of the window.
TOPW activates the window number 'nr'.
FULLW brings window 'n' to full screen size.
CLEARW clears every visible part of a window, without activating it.
Internally it is done by WIND_UPDATE() and WIND_GET().
Example:
DEFFILL 1,2,4
PBOX 0,0,639,399
OPENW 1
PAUSE 50
FULLW #1
PRINT " Window 1 "
OPENW 4,100,100
PAUSE 50
CLEARW 1
OPENW 3
PAUSE 50
TOPW #1
PAUSE 50
CLOSEW #1
TITLEW 4," Window 4 "
INFOW 3," Window 3 "
PAUSE 100
CLOSEW #3
CLOSEW 4
--> Some windows are opened, altered and then closed again.
wind_set()+
Memo: TITLEW and INFOW internally clip the string off at 78 characters.
The compiler contains a bug such that CLEARW x and CLEARW #x call
the same library routine. The library contains two routines:
CLEARW x - tops the window then clears it (never used)
CLEARW #x - walks the rectangle list (all calls end up here)
FULLW x and FULLW #x call different routines in the library:
FULLW x - not sure exactly what this one does yet
FULLW #x - seems more straight forward
If you don't use any of the GFA window commands the buffers for the
TITLEW and INFOW strings are not even linked, so no memory is wasted.
None of these commands properly check the window number.
This is true for the editor and the library.
WINDTAB
WINDTAB
WINDTAB(i,j)
i, j: iexp
The value of WINDTAB gives the address of the Window Parameter table, where the
information which determines the appearance of a window is stored. The next
piece of information following the table is the coordinates of the graphics
origin.
The table consists of 68 bytes and is constructed in word (2-byte) format. The
use of the table is shown at the end of the section in a sample program, where
the parameters of the window to be created are placed directly into the window
table and the window then opened with a simple OPENW instruction.
WINDTAB, in a similar way to INTIN(), etc., can be used as a two-dimensional
array, WINDTAB(). The first index refers to the number of the window (1 to 4,
or 0). Zero is a special case and refers to the Desktop. The second index is:
0 Handle
1 Attributes
2 x-coordinate
3 y-coordinate
4 Width
5 Height
The Window Parameter table can also be modified by using
'DPOKE WINDTAB+offset', the offsets have the following meanings:
Offset Description
0 Window 1: Handle
2 Window 1: Attributes (see structure below)
4 Window 1: x-coordinate
6 Window 1: y-coordinate
8 Window 1: Width
10 Window 1: Height
12-22 Window 2: Handle, Attributes, x, y, w, h
24-34 Window 3: Handle, Attributes, x, y, w, h
36-46 Window 4: Handle, Attributes, x, y, w, h
48-58 Window 0: Handle (-1), Attributes (0), x, y, w, h (Desktop window)
60-62 Coordinates of the 'join point' of the four windows (OPENW x,y)
64-66 Origin for graphic instructions (CLIP OFFSET x,y)
The graphic origin is applicable to AES, Line-A, and direct VDI calls but PUT,
GET, and BITBLT always use the top left corner of the screen as their origin.
The window attribute word is constructed bit by bit, with each set bit denoting
the presence of a particular window component.
Bit Component
0 Window title
1 Close box (top left)
2 Full box (top right)
3 Move line, with which the window can be moved
4 Information line
5 Size box (bottom right)
6 Up arrow
7 Down arrow
8 Vertical slider bar (right)
9 Left arrow
10 Right arrow
11 Horizontal slider bar (bottom)
Example:
' It is also possible to imply WINDTAB manipulation
' using the OPENW #n,x,y,w,h,attr instruction,
' where with Version 2 only WINDTAB was available.
'
OPENW #1,100,120,200,70,&HFFF
'
' corresponds to
'
DPOKE WINDTAB+2,&HFFF
DPOKE WINDTAB+4,100
DPOKE WINDTAB+6,120
DPOKE WINDTAB+8,200
DPOKE WINDTAB+10,70
OPENW 1
'
' or
'
WINDTAB(1,1)=&HFFF
WINDTAB(1,2)=100
WINDTAB(1,3)=120
WINDTAB(1,4)=200
WINDTAB(1,5)=70
OPENW 1
--> Three methods for opening a window are shown. This example is not meant to
be executed.
Memo: The editor has a bug and does not catch negative window numbers.
The WINDTAB structure is 34 words (68 bytes) in size.
This function has the following limits: WINDTAB(0-4,0-5)
Only the first 30 words (60 bytes) can be read/written with WINDTAB().
If you do not use any of the GFA window commands, the first 64 bytes
(0-63) can be used to store any data you like.
Example:
CHAR{WINDTAB}="Test"
PRINT CHAR{WINDTAB}
' or...
BYTE{WINDTAB}=2
PRINT BYTE{WINDTAB}
Avoid OPENW, CLOSEW, CLEARW, FULLW, TITLEW, INFOW, TOPW, W_HAND(), and
W_INDEX() or your data could be clobbered.
RC_INTERSECT()
RC_COPY
ALERT
FILESELECT
RC_INTERSECT
RC_INTERSECT(x1,y1,w1,h1,x2,y2,w2,h2)
x1, y1, w1, h1: iexp
x2, y2, w2, h2: ivar
The function RC_INTERSECT() (rectangle intersection) can be used to find
whether two rectangles overlap. The rectangles are specified by the coordinates
of the top left corner 'x,y', and the width 'w' and height 'h'.
If the rectangles overlap, then the logical value TRUE (-1) is returned and,
after the function call, x2, y2, w2, and h2 will contain the coordinates and
size of the rectangular area which is common to both rectangles.
If they do not overlap, FALSE (0) is returned and x2, y2, w2, and h2 will
contain the coordinates and size of a rectangle which lies between the two
specified rectangles. In this case, either the width 'w2' or the height 'h2',
or both, will be negative or zero.
This function is normally used for the control of 'Redraws' with GEM windows.
Examples:
BOX 100,100,400,300
x=200
y=200
w=300
h=150
BOX x,y,x+w,y+h
'
IF RC_INTERSECT(100,100,300,200,x,y,w,h)
PBOX x,y,x+w,y+h
ENDIF
--> Two rectangles are drawn and the common area is represented in black.
oldmx=0
oldmy=0
DO
MOUSE mx,my,mk
IF mx<>oldmx OR my<>oldmy
CLS
oldmx=mx
oldmy=my
x=120
y=100
w=75
h=75
BOX x,y,x+w,y+h
BOX mx,my,mx+50,my+50
PRINT RC_INTERSECT(mx,my,50,50,x,y,w,h)
PBOX x,y,x+w,y+h
ENDIF
LOOP
--> Two boxes are drawn on the screen, one which can be moved about with the
mouse. The rectangle returned by the function RC_INTERSECT() is shown in
black. The value -1 (TRUE), or 0 (FALSE) is shown in the top left corner of
the screen, depending on whether or not the moving rectangle overlaps the
fixed one.
Memo: For compiler options see section 'RC_INTERSECT() Parameters'.
RC_COPY
RC_COPY s_adr,sx,sy,w,h TO d_adr,dx,dy[,m]
s_adr, sx, sy, w, h, d_adr, dx, dy, m: iexp
The instruction RC_COPY makes possible the copying of rectangular 'screen'
sections between areas of memory, each of which represents a screen display
which may be sent to the monitor by specifying the screen address appropriately
(see XBIOS(2)). The parameters s_adr and d_adr contain the starting addresses
of the source and destination screens. The coordinates of the top left corner
and the width and height of the rectangle to be copied should be specified in
sx, sy, w, and h. The coordinates of the top left corner of the destination
rectangle are dx and dy. An optional logical operation may be preformed between
the source and destination rectangles, given by 'm' in the range 0 to 15 (see
PUT). The default value for 'm' is 3 (replace mode).
Example:
FOR r=1 TO 400
CIRCLE 320,200,r
NEXT r
SGET pic$
s_adr=V:pic$
d_adr=XBIOS(2)
'
FOR i%=1 TO 1000
RC_COPY s_adr,RAND(10)*64,RAND(10)*40,64,40 TO d_adr,RAND(10)*64,RAND(10)*40
NEXT i%
--> A simple picture is drawn and stored in pic$. RC_COPY then copies random
'screen' sections from pic$ in memory to the current screen memory (given
by XBIOS(2)).
Memo: Undocumented feature. If mode is >255 the value is used as an
op_tab parameter. This is a Line-A call.
vro_cpyfm()+
Line-A BitBlt+
ALERT
ALERT sym,text$,default,button$,choice
sym, default: iexp
text$, button$: sexp
choice: avar
The command ALERT creates an Alert box. The expression 'sym' determines which
symbol is to appear in the box. The following are valid:
0 --> No symbol
1 --> Exclamation mark
2 --> Question mark
3 --> Stop sign
4 --> Information AES v4.1
5 --> Floppy disk AES v4.1
The text to appear in the box is given by the expression 'text$'. A maximum of
4 lines is permitted, with a maximum of 30 characters per line, seperated by
'pipe' (|) characters. Lines which are longer than 30 characters are truncated.
The expression 'default' specifies which of the box's buttons is to be the one
with a bold border, selectable by pressing Return or Enter. As no more than
three buttons are allowed, 'default' can take a value form 0 to 3, 0 indicating
that there will be no default button and selection can only be made by clicking
with the mouse.
The string expression 'button$' contains the text for the buttons, with a
maximum of 8 characters per button. The individual button legends are seperated
by 'pipe' (|) characters.
On exiting from the Alert box, the variable 'choice' contains the number (1 to
3) of the selected button (see FORM_ALERT()).
Example:
ALERT 1,"Pick a|button",1,"Left|Right",a%
ALERT 0,"You pressed|button "+STR$(a%),0,"Ok",a%
--> A box with two buttons appears. After the selection has been made a second
box materialises stating which button in the first box was chosen. The
second Alert box has no symbol and no default button.
Memo: Values larger than 3 for parameter 'sym' do not work.
To use the newer alert icons one must call FORM_ALERT() instead. ALERT
can be fatal on some AES versions if the default button exceeds the
actual button count.
form_alert()+
FILESELECT
FILESELECT [#title$,]path$,default$,name$
title$, path$, default$: sexp
name$: svar
This instruction causes a File Select box to be created on the screen, enabling
the user-friendly selection of a file name.
The expression 'title$' can be a maximum of 30 characters and allows a header
to be placed in the File Select box - available from TOS 1.4 onwards. In the
expression 'path$' the initial drive- and path-name should be specified. If no
drive is specified, then the current drive is assumed. 'default$' contains the
name of the file which will appear as the current choice. This can be selected
by pressing Return, edited or deleted (by pressing ESCape). After exiting from
the File Select box, the name of the selected file will be found in the string
'name$'. If the Cancel button was selected, then 'name$' will contain a null
string ("").
The format of path$, default$, and name$ conform to the conventions of the
Hierarchical Filing system, described in 'Chapter 6 - Input and Output',
section 'File Management'.
See also FSEL_INPUT().
Example:
DO
FILESELECT "A:\*.PRG","GFABASIC.PRG",name$
IF name$=""
PRINT "You clicked the Cancel button"
ELSE IF RIGHT$(name$)="\"
PRINT "You clicked the Ok button without naming a file"
ELSE
PRINT "You have selected the file ";name$
ENDIF
LOOP
--> A File Select box appears and responds to the choice made by the user.
Note: The parameter 'title$' is optional and if left out the older File
Select routine is called which does not allow a user-defined header.
Memo: Avoid using the built in FILESELECT command as it only buffers
older 32k ST video modes properly. If you want your application to
function properly in all video modes call FSEL_INPUT() via the AES
directly. Your program might receive an AES redraw message when calling
FSEL_INPUT().
Does not handle long file names correctly.
The path and file name are both forced to upper case.
Paths over 150 characters will be truncated.
File names over 12 characters will be ignored.
Internal TOS v1.4 check is incorrect, it actually checks for v1.04.
fsel_input()+, fsel_exinput()+
Chapter 10 - System Routines
BIOS(), XBIOS(), GEMDOS()
W:, L:
Cookie Jar
BIOS, XBIOS, and GEMDOS
BIOS(n[,x,y,...])
XBIOS(n[,x,y,...])
GEMDOS(n[,x,y,...])
n, x, y: iexp
These functions are used to call BIOS(), XBIOS(), and GEMDOS() routines, in
each case the optional parameter list is passed to the function number n. In
order to be able to pass the parameters in the correct variable size, they can
be prefixed with W: or L:, to denote word (16-bit) and longword (32-bit) sized
values respectively.
The number and meaning of the parameters depends, as does the returned value,
on the system routine being called. (See also Appendix.)
Examples:
IF GEMDOS(17)
PRINT "Printer ready"
ELSE
PRINT "Printer not ready"
ENDIF
--> Checks if the printer is ready to receive data through the parallel
interface and reports the status as a logical (TRUE or FALSE) value.
REPEAT
UNTIL BIOS(11,-1) AND 4
--> Waits until the Control key is pressed. BIOS(11,-1) reports on the current
status of the keyboard 'shift' keys:
Bit Key
0 Right shift
1 Left shift
2 Control
3 Alternate
4 Caps Lock
CIRCLE 320,200,180
PAUSE 30
BMOVE XBIOS(2),XBIOS(2)+16000,16000
--> Draws a circle and copies its upper half to the lower part of the screen.
XBIOS(2) returns the address at which the physical screen memory begins.
Memo: GEMDOS() functions that do not exist always return -32.
XBIOS() functions that do not exist seem to return the opcode.
This is not very reliable for detecting invalid calls.
BIOS() functions that do not exist seem to return the opcode.
This is not very reliable for detecting invalid calls.
However, under MiNT the return value seems to be -32.
Internally, the Editor uses d7 to save and restore the stack during
these system calls. If d7 is altered by a custom trap handler the Editor
will crash. UNSQUISH.PRG does this with two custom calls. In my opinion
DC Squish II is to blame here as it breaks the most basic OS rules.
The compiler however works differently and the same call won't crash.
Clean way to get Cookie Jar pointer:
LPEEK(&H5A0) -> BIOS(5,W:SHR&(&H5A0,2),L:TRUE)
This only works for addresses divisible by 4.
W:
W:x
L:x
x: iexp
These two functions enable the user to pass numerical expressions to Operating
System functions and C-routines as either word (2-byte, W:) or longword
(4-byte, L:). By default the word format is used.
Example:
DIM screen_2|(32255)
phys_base%=XBIOS(2)
old_screen%=phys_base%
log_base%=V:screen_2|(0)+255 AND &HFFFFFF00
~XBIOS(5,L:log_base%,L:phys_base%,-1)
SWAP log_base%,phys_base%
REPEAT
IF MOUSEK=1
~XBIOS(5,L:log_base%,L:phys_base%,-1)
SWAP log_base%,phys_base%
REPEAT
UNTIL MOUSEK=0
ENDIF
PLOT MOUSEX,MOUSEY
UNTIL MOUSEK=2
~XBIOS(5,L:old_screen%,L:old_screen%,-1)
--> XBIOS(5) is used to switch between two display screens each time the left
mouse button is pressed. Moving the mouse causes points to be plotted on
the screen which is not currently visible. Pressing the right mouse button
terminates the program.
Line-A Calls
ACLIP
PSET, PTST()
ALINE, HLINE
ARECT
APOLY
ACHAR, ATEXT
BITBLT adr%, BITBLT x%()
L~A
In the following section a group of instructions are discussed which correspond
in principle to instuctions that have already been presented in the graphics
chapter. The output is substantially quicker, however a slightly different
syntax is used. For Line-A graphics, clipping should always be switch on (with
ACLIP), since areas of memory can be overwritten by a line leaving the screen
area, for example. Otherwise the clipping area is that set by the last used
graphics command (AES or VDI), for example OPENW, FILESELECT, ALERT, etc.
A VDI call changes the ACLIP setting previously set with ACLIP. Line-A calls
are independent of the VDI DEFxxx commands.
Note: The colors specified in the Line-A routines correspond to the
hardware color register numbers (as used by SETCOLOR) and NOT to the
numbers used by the VDI (COLOR). They convert as follows:
VDI: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
Line-A: 00 15 01 02 04 06 03 05 07 08 09 10 12 14 11 13
Line-A: 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
VDI: 00 02 03 06 04 07 05 08 09 10 11 14 12 15 13 01
Memo: Do not use any Line-A calls! Your application will surely fail on
different computer models if you do use Line-A calls. If you don't want
your application to run on all systems or don't care then you can use the
Line-A calls/variables.
Line-A Variable Table+ Line-A Function Reference+
ACLIP
ACLIP flag,xmin,ymin,xmax,ymax
flag, xmin, ymin, xmax, ymax: iexp
This instruction makes it possible to define a 'clipping' rectangle, to which
Line-A screen output will be limited. The coordinates of the top left and
bottom right corners of the Clipping rectangle are given by xmin, ymin, xmax,
and ymax. If 'flag' is given a non-zero value the clipping is active, otherwise
(if flag=0) it is switched off. ACLIP is not valid (unfortunately) for PSET,
PTST(), ALINE, HLINE, and BITBLT.
Memo: This is not really a Line-A function per say.
It simply writes the parameters into the Line-A variables.
ACLIP -> CLIP, XMINCL, YMINCL, XMAXCL, YMAXCL (Line-A variables)
Line-A Variable Table+
PSET
PSET x,y,f
x, y, f: iexp
PSET corresponds to the PLOT command, and will set the point x,y to color f,
which can take values from 0 to 15, depending on the current screen resolution.
Example:
FOR x%=0 to 15
FOR y%=0 to 100 STEP 2
PSET x%,y%,x%
NEXT y%
NEXT x%
--> Draws vertical dotted lines in the 15 colors.
Line-A Plot Pixel+
PTST
PTST(x,y)
x, y: iexp
The function PTST() corresponds to the function POINT(). It returns the color
of the pixel at screen position x,y.
Example:
PSET 100,100,6
x=PTST(200,100)
PRINT x,PTST(100,100)
--> Prints the colors of the pixels at screen positions (200,100) and
(100,100).
Line-A Get Pixel+
ALINE
ALINE x1,y1,x2,y2,f,ls,m
x1, y1, x2, y2, f, ls, m: iexp
ALINE corresponds to the command LINE, where (x1,y1) and (x2,y2) are the
coordinates of the end points of the line. The expression f contains the color,
which, depending on the current screen resolution, takes values from 0 to 15.
'ls' contains 16 bits of information for the desired style of line (solid,
dashed, dotted, etc.). Each set bit corresponds to one point to be plotted.
The paramter m determines the graphic mode and can take values from 0 to 3:
m Mode
0 Replace
1 Transparent
2 Xor
3 Reverse Transparent
Example:
ym%=INT{L~A-4}-1
FOR i%=0 to 255
style%=256*i%+i%
ALINE i%,0,i%,ym%,1,style%,0
NEXT i%
--> Draws vertical lines of varying dottedness extending from the top to the
bottom of the screen. The term INT{L~A-4} returns the maximum y coordinate
of the screen, this being stored four bytes before the beginning of the
Line-A Variable Table (which starts at the address L~A).
Line-A Arbitrary Line+
HLINE
HLINE x1,y,x2,f,m,addr,num_pattern
x1, y, x2, f, m, addr, num_pattern: iexp
HLINE is similar to the ALINE command, but only horizontal lines can be drawn.
x1 and x2 contain the x-coordinates of the line end points, and y the common
y-coordinate. The expression f contains the color which, depending on the
current screen resolution, takes values from 0 to 15. The parameter m
determines the graphics mode as with ALINE.
addr is the address of a block of memory which contains bit information for
several line styles (each 16 bits). Which style is used for a given line
depends on both the y-coordinate and the parameter num_pattern. They are ANDed
together and the resulting number used as an index to the style table. Thus
num_pattern should generally be one smaller than the power of two (0, 1, 3, 7,
15, etc.), giving the effect that, with num_pattern=7, the first eight styles
will be used sequentially as the y-coordinate moves down the screen. If
num_pattern=3, one of the first four styles will be used, depending on the
y-coordinate.
Example:
ACLIP 1,0,0,639,399
'
pattern%=&X11111111111111111010101010101010
x%=V:pattern%
'
FOR i%=0 to 199
HLINE 0,i%,639,1,0,z%,1
NEXT i%
--> Two 16-bit line patterns are put into the variable pattern%. The last
parameter is 1 (implying 2 possible styles). The lines drawn then use the
two 16-bit line patterns in pattern% alternately.
Memo: Internally Line-A offset MFILL is set to FALSE.
Thus only single plane patterns can be used.
Line-A Horizontal Line+
ARECT
ARECT x1,y1,x2,y2,f,m,addr,num_pattern
x1, y1, x2, y2, f, m, addr, num_pattern: iexp
ARECT corresponds to PBOX. (x1,y1) and (x2,y2) are the coordinates of the two
opposite corners of the rectangle. The parameters f, m, addr, and num_pattern
have the same meaning as for HLINE.
Example:
ACLIP 1,0,0,639,399
DIM pattern&(1)
'
pattern&(0)=-21846
pattern&(1)=21845
'
pattern_adr%=V:pattern&(0)
ARECT 100,100,200,200,1,0,pattern_adr%,1
--> A rectangle filled with a checker-board pattern (equivalent to using PBOX
after DEFFILL 2,2,4 except that no border is drawn).
Memo: Internally Line-A offset MFILL is set to FALSE.
Thus only single plane patterns can be used.
Line-A Filled Rectangle+
APOLY
APOLY adr_pnt,num_pnt,y0 to y1,f,m,addr,num_pattern
adr_pnt, num_pnt, y0, y1, f, m, addr, num_pattern: iexp
APOLY is similar to the POLYFILL command. It draws an (invisible) sequence of
joined lines, with 'num_pnt' corners and fills the resulting area with a user
defined pattern. 'adr_pnt' is the address of the array which contains
alternating x- and y-coordinates of the corner points. The parameter 'num_pnt'
contains the number of corner points. y0 and y1 specify the lowest and highest
parts of the screen where filling can take place - it is like a vertical-only
clipping facility. The parameters f, m, addr, and num_pattern correspond to
those of HLINE.
Example:
DIM x&(9),pattern&(1)
FOR i%=0 to 7
x&(i%)=RAND(100)
NEXT i%
x&(8)=x&(0)
x&(9)=x&(1)
'
adr_corners%=V:x&(0)
pattern&(0)=-1
adr_pattern%=V:pattern&(0)
'
ACLIP 1,0,0,200,200
APOLY adr_corners%,4,0 TO 100,1,1,adr_pattern%,0
--> Draws a random filled quadrilateral.
Memo: Internally APOLY does not set Line-A offset MFILL even though
the documentation states the pattern parameters are identical to HLINE.
Internally HLINE always sets Line-A offset MFILL.
INT{L~A+52}=0 ;mfill (mono)
Line-A Filled Polygon+
ACHAR
ACHAR code,x,y,font,style,angle
code, x, y, font, style, angle: iexp
By means of ACHAR an individual character with the ASCII value 'code' can be
displayed at the point with graphics coordinates (x,y). The numerical
expression 'font' can except values between 0 and 2 as follows:
Font Size
0 6x6 (Icon font)
1 8x8 (Normal color font)
2 8x16 (Normal monochrome font)
Larger values for 'font' are taken to be Font-Header addresses. The font must
be present in the format into which it is converted by GDOS on loading, that is
in the Motorola format High-byte before Low-byte.
Text 'style' (bold, light, etc: 0 to 31) and output 'angle' (0, 900, 1800,
2700) can be specified as for TEXT with DEFTEXT. In contrast to these TEXT
commands, the x and y coordinates refer to the top left corner of the
character, not the bottom left corner.
Memo: This command will not render the underlined (bit 3) effect.
For some odd reason it is ignored by this Line-A call.
This is not a bug in GFA-Basic.
Line-A TextBlt+
ATEXT
ATEXT x,y,font,s$
x, y, font: iexp
s$: sexp
The command ATEXT outputs character strings at arbitrary screen positions but,
unlike with ACHAR, no character style or output angle can be specified. The
parameters x, y, and font are the same as for ACHAR.
Example:
OPENW 0 !Protect the top line from overwriting
EVERY 400 GOSUB a_clock !Every 2 seconds call a_clock
FOR i%=1 TO 100000
PRINT USING "######",i%; !Display numbers
NEXT i%
'
PROCEDURE a_clock
ACLIP 1,20,0,120,15 !Switch clipping on,
' oterwise it will remain as set by OPENW 0,
' i.e. nothing will be seen
ATEXT 20,20,2,TIME$ !Display the time
RETURN
--> Numbers are printed continuously, but every 2 seconds a time display is
updated on the top line.
Line-A TextBlt+
BITBLT adr%
BITBLT adr%
BITBLT x%()
adr%: iexp
x%(): four byte integer array
The command BITBLT calls the Line-A routine of the same name, where as the
command with three parameter arrays calls a VDI-routine. In the command
variation for which an address is given as a parameter, a 76 byte long table
must start at this address. The meaning of the values in this storage area can
be taken from the table that follows. The offset distances of the elements from
the start of the table are shown in the column 'offset'.
In the command variation with the one four byte-Integer array, this array must
have at least 23 elements, a specified parameter standing in each. Which
parameter must stand in which array element can be seen in the column 'index'
in the following table.
The parameters marked with a star are affected by the routine, therefore one
should normally work with the command variant which uses an array parameter,
since a copy of the array is used by the BITBLT routine, the array itself will
not be altered. In contrast, the table elements which were given by the passing
of an address will be changed.
Name Index Offset Meaning
B_WD 00 00 Screen width in pixels
B_HT 01 02 Screen height in pixels
PLANE_CT * 02 04 Number of bit-planes
FG_COL * 03 06 Foreground color
BG_COL * 04 08 Background color
OP_TAB 05 10 Logical 'put' mode 0 to 15 (see PUT)
S_XMIN 06 14 x offset for source
S_YMIN 07 16 y offset for source
S_FORM 08 18 Address of the source screen
S_NXWD 09 22 Offset to the next word of the same bit-plane
S_NXLN 10 24 Offset to the next line of the source screen
S_NXPL 11 26 Offset to the next bit-plane (always 2)
D_XMIN 12 28 x offset for destination
D_YMIN 13 30 y offset for destination
D_FORM 14 32 Address ofthe destination screen
D_NXWD 15 36 Offset to the next word ofthe same bit-plane
D_NXLN 16 38 Offset to the next line of the destination screen
D_NXPL 17 40 Offset to the next bit-plane (always 2)
P_ADDR 18 42 Pointer to fill pattern table (0=no pattern,
Source ANDed with pattern before moving)
P_NXLN 19 46 Offset to the next line of the mask
P_NXPL 20 48 Offset to the next plane of the pattern
P_MASK 21 50 Mask as for HLINE
SPACE * 22 52 Next 24 bytes are workspace for the Blitter
Examples:
DIM x%(1000)
'
FOR i%=0 TO 639 STEP 8
LINE i%,0,639,399
NEXT i%
'
GET 0,0,639,399,a$
mirrorput(0,0,a$)
'
PROCEDURE mirrorput(x%,y%,VAR x$)
IF LEN(x$)>6 ! Only do it if something present
xx%=V:x%(0)
a%=V:x$
b%=INT{a%}
h%=INT{a%+2}
'
INT{xx%}=1
INT{xx%+2}=h%
INT{xx%+4}=1
INT{xx%+6}=1
INT{xx%+8}=0
{xx%+10}=&H3030303
INT{xx%+14}=9999
INT{xx%+16}=0
{xx%+18}=a%+6
INT{xx%+22}=2
INT{xx%+24}=SHR(b%+16,4)*2
INT{xx%+26}=2
INT{xx%+28}=9999
INT{xx%+30}=0
{xx%+32}=XBIOS(3)
INT{xx%+36}=2
INT{xx%+38}=80
INT{xx%+40}=2
{xx%+42}=0 ! p_addr
INT{xx%+46}=0 ! p_nxln
INT{xx%+48}=0 ! p_nxpl
INT{xx%+50}=0 ! p_mask
'
ABSOLUTE i&,xx%+14
ABSOLUTE di&,xx%+28
'
FOR i&=0 TO b%
INT{xx%+4}=1
di&=SUB(639,i&)
BITBLT xx%
NEXT i&
'
ENDIF
RETURN
--> An example of BITBLT adr%.
DIM x%(1000)
'
FOR i%=0 TO 639 STEP 8
LINE i%,0,639,399
NEXT i%
'
GET 0,0,639,399,a$
mirrorput(0,0,a$)
'
PROCEDURE mirrorput(x%,y%,VAR x$)
IF LEN(x$)>6 ! Only do if something present
a%=V:x$
b%=INT{a%}
h%=INT{a%+2}
'
x%(0)=1
x%(1)=h%
x%(2)=1
x%(3)=1
x%(4)=0
x%(5)=&H3030303
x%(6)=9999
x%(7)=0
x%(8)=V:x$+6
x%(9)=2
x%(10)=SHR(b%+16,4)*2
x%(11)=2
x%(12)=9999
x%(13)=0
x%(14)=XBIOS(3)
x%(15)=2
x%(16)=80
x%(17)=2
x%(18)=0 ! p_addr
x%(19)=0 ! p_nxln
x%(20)=0 ! p_nxpl
x%(21)=0 ! p_mask
'
FOR i%=0 TO b%
x%(6)=i%
x%(12)=639-i%
BITBLT x%()
NEXT i%
'
ENDIF
RETURN
--> An example of BITBLT x%().
Both routines reflect a picture about a vertical line down the center of the
screen. In the routine which uses BITBLT adr%, the number of bit-planes must be
re-specified each time the instruction is issued. Which routine to use is more
or less a matter of taste, as there is very little difference in speed between
the two. A VDI version of the program producing the same effect is listed under
BITBLT in 'Chapter 8 - Graphics'.
Line-A BitBlt+
L~A
L~A
The function L~A returns the base address of the Line-A Variable Table (see
Appendix).
Example:
PRINT INT{L~A}
--> Gives the number of bit planes in the current resolution. See also the
examples under BITBLT.
Memo: Line-A variables as defined by Atari VDI:
See LINEAVAR.H and LINEAEQU.S
Line-A Initialize+
VDI Routines
CONTRL, CONTRL()
INTIN, INTIN()
INTOUT ,INTOUT()
PTSIN, PTSIN()
PTSOUT, PTSOUT()
VDISYS
VDIBASE
WORK_OUT()
The VDI functions are divided into seven categories:
Control functions
Output functions
Attribute functions
Raster functions
Input functions
Inquire functions
Escape functions
Three kinds of parameters are distinguished: Input, Output, and those used for
both input and output. These parameters belong in five arrays:
CONTRL Control
INTIN Integer input
PTSIN Point coordinate input
INTOUT Integer output
PTSOUT Point coordinate output
The input parameters are stored in:
CONTRL(0) Function opcode
CONTRL(1) Number of points in the PTSIN array
CONTRL(3) Length of the INTIN array
CONTRL(5) Sub-opcode
INTIN() Integer value input array
PTSIN() Point coordinate input array
The output parameters are:
CONTRL(2) Number of points in the PTSOUT array
CONTRL(4) Length of the INTOUT array
INTOUT() Output array of integer values
PTSOUT() Output array of point coordinates
Input and output parameters are:
CONTRL(6) Workstation handle
CONTRL(7-n) Opcode dependent information
The array elements meaning depends on which VDI function is being called.
Memo: Programs which use the VDI to do all graphics output will work on
machines equiped with video graphics cards.
The compiler only initializes the VDI if some module is linked that
actually calls the VDI. The editor on the other hand always does this.
If you suspect the VDI is not initialized it can be forced with a
call to any VDI function. I suggest using some inquire function like
POINT().
VDI Function Reference+
VDI Functions by Opcode+
CONTRL
These functions give the addresses in the VDI Parameter Block, which are the
addresses of the first bytes of the CONTRL, INTIN etc. arrays. The arrays can
be accessed by placing an index value in brackets after the array name, for
example CONTRL(2)=x& corresponds to DPOKE CONTRL+4,x& and x&=CONTRL(2) to
x&=DPEEK(CONTRL+4). The other arrays are also organised in word format.
The meanings are:
CONTRL --> Address of the VDI control table
INTIN --> Address of the VDI integer input table
PTSIN --> Address of the VDI point coordinate input table
INTOUT --> Address of the VDI integer output table
PTSOUT --> Address of the VDI point coordinate output table
These tables (2-byte word arrays) contain the parameters for VDI calls.
Memo: These built in tables have the following limits:
CONTRL(0-11)
INTIN(0-127)
PTSIN(0-31) <- Bug in the editor, should be 0-255
INTOUT(0-127)
PTSOUT(0-255)
This appears to be a 'worst case senerio', as newer VDI versions allow
larger table sizes. If you exceed these values in a compiled program
there is no error message, instead some memory location gets changed
unexpectedly.
VDISYS
VDISYS [opcode[,c_int,c_pts[,subopc]]]
opcode, c_int, c_pts, subopc: iexp
With the instruction VDISYS the VDI function with the function code 'opcode' is
called. If opcode is not specified, then the function code must, like the other
parameters, be place in the control block with 'DPOKE CONTRL,opcode' or
'CONTRL(0)=opcode'.
The number of values in the integer and point-coordinate input arrays can be
specified in the parameters c_int and c_pts. These values need not then be
placed into the Control Block. The optional parameter 'subopc' contains the
sub-opcode of the routine to be called. This must only be specified for some
VDI routines, for example Escape function routines. The parameters c_int,
c_pts, and subopc will be inserted into the CONTRL block like so:
opcode --> CONTRL(0)
c_int --> CONTRL(3)
c_pts --> CONTRL(1)
subopc --> CONTRL(5)
Examples:
CONTRL(1)=3
CONTRL(5)=4
PTSIN(0)=320
PTSIN(1)=200
PTSIN(4)=190
VDISYS 11
PAUSE 25
CLS
'
PTSIN(0)=320
PTSIN(1)=200
PTSIN(4)=190
VDISYS 11,0,3,4
PAUSE 25
CLS
'
PCIRCLE 320,200,190
--> Three different ways of drawing the same filled circle.
VDISYS 5,0,0,13
PRINT "Inverted"
VDISYS 5,0,0,14
PRINT "Normal"
--> Prints 'Inverted' in inverse video and 'Normal' normally.
Memo: Calling a function which does not exist is usually fatal.
VDIBASE
VDIBASE
The system variable VDIBASE contains the address starting from which the
current GEM version puts parameters for use in the VDI routines (text style,
clipping, etc). The structure of this area could well be different in future
versions of GEM. VDIBASE is contained as a keyword in GFA-Basic in order to
give programmers the ability to access all VDI parameters.
Memo: See VDIBASE.TXT and ATTRDEF.H for more information.
WORK_OUT
WORK_OUT(x)
x: iexp
This function determines the values found in INTOUT(0) to INTOUT(44), PTSOUT(0)
and PTSOUT(11) after returning from the function V_OPNWK(). The index 'x' can
take values from 0 to 56 (see section VDI WORK_OUT() Array Table in the
Appendix).
Example:
screen_width&=WORK_OUT(0)
screen_height&=WORK_OUT(1)
PRINT screen_width&,screen_height&,WORK_OUT(10)
--> The numbers 639 and 399 (in monochrome mode) for the screen width and
height are printed, followed by a 1 for the number of the available
character sets (WORK_OUT(10)).
Memo: This table has the following limit:
WORK_OUT(0-56)
Special VDI Routines and GDOS
GDOS?
V~H
V_OPNWK(), V_CLSWK()
V_OPNVWK(), V_CLSVWK()
V_CLRWK()
V_UPDWK()
VST_LOAD_FONTS(), VST_UNLOAD_FONTS()
VQT_EXTENT()
VQT_NAME()
The following VDI Workstation and query functions are available only if GDOS
(release 1.0 and later) has been installed and a valid ASSIGN.SYS file is
available.
The machine independent GDOS (Graphics DEVICE Operating System) contains
graphics functions and works together with device dependant drivers for
different output devices (screen, printer, plotter, metafiles, etc.).
The ASCII file ASSIGN.SYS contains all necessary data concerning the current
device configuration. In this file all current Operating System and character
sets must be registered, and if necessary the access path to the Operating
System must be specified, if it is not on drive A:. The following syntax should
be noted:
PATH=d:\path\
id DEVICE.SYS
; Remarks
PART1.FNT
PART2.FNT
...
PARTN.FNT
id contains a number between 1 and 32767. With it the type of device is
determined as follows:
01 ... Screen
11 ... Plotter
21 ... Printer
31 ... Metafile
41 ... Camera
51 ... Graphic-Tablet
If the Operating System is located on drive C: in the folder GEMSYS, then the
associated ASSIGN.SYS file looks, for example, like this:
PATH=c:\gemsys\
01p SCREEN.SYS ;Screen driver in ROM, therefore a 'p' after the ID
ATSS10.FNT
ATSS12.FNT
02p SCREEN.SYS ;Driver for low resolution
ATSS10.FNT
ATSS12.FNT
03p SCREEN.SYS ;Driver for medium resolution
ATSS10CG.FNT
ATSS12CG.FNT
04p SCREEN.SYS ;Driver for high resolution
ATSS10.FNT
ATSS12.FNT
21 FX80.SYS ;Printer driver for the FX-80 and compatible
ATSS10EP.FNT
ATSS12EP.FNT
31 META.SYS ;Metafile driver
ATSS10MF.FNT
ATSS12MF.FNT
The screen drivers SCREEN.SYS are only dummy entries, required by the GDOS
syntax checker. The ID's (2, 3, and 4) have only to assign, for each
resolution, the order of the given fonts. Therefore the call to open a virtual
screen memory workstation is V_OPNVWK(XBIOS(4)+2)). GFA-Basic 3 makes this call
internally.
GDOS?
GDOS?
GDOS? returns TRUE if GDOS (release 1.0 or later) is resident and FALSE
otherwise.
Example:
IF NOT GDOS?
ALERT 1,"GDOS not found.",1," OK ",r%
END
ENDIF
--> If GDOS is not installed an alert box appears.
GDOS+, vq_gdos()+
V~H
V~H
With the following functions, 'hd' stands for the VDI handle and 'id' for the
identification of an output device. With this in mind, consider the following
functions:
V~H Returns the internal VDI handle of GFA Basic. (e.g. PRINT V~H)
V~H=x Sets the internal VDI handle (accessible through CONTRL(6)) to the
value x.
V~H=-1 Sets the VDI handle (CONTRL(6)) to the value resulting from the
internal V_OPNVWK().
Memo: The compiler/linker can build applications that do not initialize
the VDI. V~H will equal zero if this occurs.
V_OPNWK
V_OPNWK(id[,1,1,1,1,1,1,1,1,1,2])
V_CLSWK()
id: iexp
The numbers 1 and 2 are default values for the settings of the VDI parameters.
They can be changed (see WORK_OUT()).
The function V_OPNWK() (Open Workstation) returns the handle 'hd' for the
specified device 'id'. In addition, further information about the device may be
requested by means of INTOUT() and PTSOUT() (see VDISYS in the section 'System
Routines').
The function V_CLSWK() (Close Workstation) closes the current workstation
opened with V_OPNWK() and flushes its buffers. In addition a V~H=-1 is carried
out.
Example: See V_CLRWK().
Memo: V_OPNWK() with the extra parameters does not work correctly in the
editor or compiled.
v_opnwk()+, v_clswk()+
V_OPNVWK
V_OPNVWK(id[,1,1,1,1,1,1,1,1,1,2])
V_CLSVWK()
id: iexp
The function V_OPNWK() (Open Virtual Workstation) opens a virtual screen driver
and returns the handle 'hd' for the specified device 'id' (see V_OPNWK()).
The function V_CLSWK() (Close Virtual Workstation) closes a virtual workstation
opened with V_OPVNWK(). In addition a V~H=-1 is issued.
Memo: V_OPNVWK() with the extra parameters does not work correctly in the
editor or compiled.
v_opnvwk()+, v_clsvwk()+
V_CLRWK
V_CLRWK()
V_UPDWK()
The function V_CLRWK() (Clear Workstation) clears the output buffer. For
example, the screen or printer buffer is cleared.
For output of graphics to a printer, all commands are collected in a buffer.
The function V_UPDWK() (Update Workstation) sends these buffered graphic
instructions to the attached device. Unlike printer graphics, for example, all
graphic instructions sent to the screen are implemented immediately.
Example:
' If GDOS is resident
RESERVE 25600 !Reserve sufficient storage memory
handle&=V_OPNWK(21) !Determine identification for output device
'
IF handle&=0
ALERT 3,"Installation error!",1,"Cancel",r%
END
ENDIF
'
x_res&=INTOUT(0) !Determine x- and y-resolution
y_res&=INTOUT(1) !of the attached device
'
V~H=handle& !Sets the internal VDI handle to printer identification
~V_CLRWK() !Clear buffer
'
CLIP 0,0,x_res&,y_res&
BOX 0,0,x_res&,y_res&
LINE 0,0,x_res&,y_res&
LINE 0,y_res&,x_res&,0
'
~V_UPDWK() !Carry out Graphic commands
~V_CLSWK()
'
RESERVE !Return memory to GFA Basic
--> Sends a rectangle with a diagonal line through it to an attached printer,
if GDOS is resident.
v_clrwk()+, v_updwk()+
VST_LOAD_FONTS
VST_LOAD_FONTS(x)
VST_UNLOAD_FONTS(x)
x: iexp
The function VST_LOAD_FONTS() loads the additional character sets specified in
ASSIGN.SYS, if sufficient memory is available, and the number of loaded fonts
is returned. If no further fonts are available, zero is returned.
The parameter x should be zero with present versions of GEM, though this may
change in the future. It is important to reserve sufficient memory for the
additional character sets, using RESERVE.
The function VST_UNLOAD_FONTS() removes the character sets loaded previously
with VST_LOAD_FONTS() from memory. The parameter x is currently zero as for
VST_LOAD_FONTS().
Example:
RESERVE 25600
'
num_fonts%=VST_LOAD_FONTS(0) !How many additional character sets?
'
FOR i%=1 to num_fonts%
face%=VQT_NAME(i%,font$) !Index and name of loaded Font
DEFTEXT ,,,,face%
TEXT 80,80,"This is the "+font$+" font."
~INP(2)
NEXT i%
'
~VST_UNLOAD_FONTS(0) !Remove fonts
'
RESERVE
--> Displays the names of the loaded character sets in their own fonts.
vst_load_fonts()+, vst_unload_fonts()+
VQT_EXTENT
VQT_EXTENT(text$[,x1,y1,x2,y2,x3,y3,x4,y4])
text$: sexp
x1, y1, x2, y2, x3, y3, x4, y4: ivar
The function VQT_EXTENT() returns the corner coordinates of a rectangle which
will surround the text in text$. The coordinates can either be found in the
variables x1,y1 to x4,y4, or in PTSOUT(0) to PTSOUT(7). The corner points are
numbered in the counter-clockwise direction:
Corner point Position
x1,y1 Bottom left
x2,y2 Bottom right
x3,y3 Top right
x4,y4 Top left
Which would be interpreted as:
X-axis
^
|
|
|
|
x4,y4 x3,y3
--------
| |
| |
-------- --------> Y-axix
x1,y1 x2,y2
Example
INPUT text$
CLS
ATEXT 100,25,2,text$
~VQT_EXTENT(text$,x1,y1,x2,y2,x3,y3,x4,y4)
BOX x4+100,y4+25,x2+100,y2+25
--> The input text is put at the arbitrary screen position (100,25), and a box
is neatly put around it.
Memo: This function does not return a result.
vqt_extent()+
VQT_NAME
VQT_NAME(i,font_name$)
i: ivar
font_name$: svar
The function VQT_NAME() returns the handle of the font with the identification
number 'i' and places the name of the loaded character set into the string
variable font_name$.
Example:
RESERVE 25600
'
num_fonts%=VST_LOAD_FONTS(0)
face%=VQT_NAME(num_fonts%,font$) !Index and name of loaded Font
'
h%=12 !Text height
s$="example text"
x0%=80 !Output coordinats for s$
y0%=80
DEFTEXT 1,0,0,h%,face%
'
~VQT_EXTENT(s$,x1%,y1%,x2%,y2%,x3%,y3%,x4%,y4%)
'
GRAPHMODE 4
TEXT x0%,y0%,s$
PBOX x0%+x1%,y0%+y1%-h%-1,x0%+x3%,y0%+y3%-h%
'
~VST_UNLOAD_FONTS(0) !Remove fonts
'
RESERVE
--> The string s$ is displayed inverted on the screen at (x0%,y0%).
Memo: Clobbers INTOUT(33) thus the font type can't be discovered.
vqt_name()+
Non-BASIC Routine Calls
C:
MONITOR
CALL
RCALL
EXEC, EXEC()
The commands explained in this section enable subroutines which are written in
C or assembler to be called.
Memo: For an alternate method of calling non-BASIC routines via the
compiler see section 'Externally Linked Routines'.
C:
C:addr([x,y,...])
addr: avar (at least 32-bit, ideally integer-type: adr%)
x, y: iexp
The function C: calls a C or assembler subroutine, located at the address addr.
The parameters in brackets (x, y...) will be passed to the routine. The
parameter passing is via the stack, as in C. The parameters can be sent as
32-bit longwords with the prefix 'L:', or 16-bit words with the prefix 'W:'.
If there is no prefix, a word value will be sent. When the function is called,
first the return address and then the parameters will be found on the stack.
So, for example:
VOID C:adr%(L:x,W:y,z) leads to the following situation on the stack:
(sp) --> Return address (4 bytes)
4(sp) --> x (4 bytes)
8(sp) --> y (2 bytes)
10(sp) --> z (2 bytes)
The value returned by the function is the contents of register d0 on return
from the subroutine (for which RTS must be used).
Example:
The assembler program used here fills an area of memory (e.g. an array)
starting from a certain address with the numbers (longwords) from 0 to n.
206F0004 move.l 4(sp),a0 ; Start address
202F0008 move.l 8(sp),d0 ; Number of values
7200 moveq.l #0,d1 ; Counter
6004 bra.s ct_2 ; Loop re-entry point
20C1 ct_1: move.l d1,(a0)+ ; Loop, value write
5281 addq.l #1,d1 ; Increment counter
B081 ct_2: cmp.l d1,d0 ; finished?
64F8 bcc.s ct_1 ; no, around again ->
4E75 rts ; Return to GFA BASIC
The GFA-Basic program is:
FOR i%=1 TO 11
READ a%
asm$=asm$+MKI$(a%)
NEXT i%
DATA $206F,$0004,$202F,$0008,$7200,$6004
DATA $20C1,$5281,$B081,$64F8,$4E75
'
DIM x%(10000)
asm%=V:asm$
~C:asm%(L:V:x%(0),L:10000)
PRINT "E.g. x%(12) = ";x%(12)
--> The array x%() is filled with the numbers from 0 to 10000, corresponding
to:
FOR i%=1 TO n%
x%(i%)=i%
NEXT i%
To insert an assembler program in a GFA BASIC 3 program, the INLINE command can
also be used. First a file is created containing the assembler code above by
using (after the above read-data loop):
BSAVE "COUNT.INL",V:asm$,22
Then type in the following program:
INLINE asm%,22
DIM x%(10000)
~C:asm%(L:V:x%(0),L:10000)
Then, while still in the Editor with the cursor on the line containing the
INLINE instruction, press the Help key. From the resulting menu choose 'Load',
and from the File select box select the file COUNT.INL. It will be loaded into
and area specially allocated within the program, and will be saved with the
program when it is Saved in the normal way. See INLINE, Chapter 2, section
Memory Management.
Memo: For compiler options see section 'Register Saving'.
The 'C' routine must be written using the 'cdecl' parameter passing
method. Registers a3 to a7 must remain unchanged.
MONITOR
MONITOR [x]
x: iexp
This instruction enables one to call assembler subroutines or debugging
programs or other utilities. For this purpose the 'illegal instruction vector'
(address 16) must be set to the address of the subroutine. The MONITOR
instruction then produces an illegal Instruction exception, which causes the
computer to branch to the subroutine. This subroutine must end with RTE (ReTurn
from Exception). The parameter x is passed to the subroutine in register d0.
An example of its use is with tracing a C program, using a debugger. GFA-Basic
should be loaded and started from the debugger. Then, after inputting the C
program, insert the line 'MONITOR asm%' directly before the INLINE statement.
After the start of the C program the debugger will respond because of the
'Illegal Instruction exception' generated by the MONITOR command. Now one can
disassemble, single-step or edit the C program at the address now in register
d0. When the C program has been edited/examined satisfactorily, one can
continue the execution of the program with the 'GO' instruction of the
debugger. If the 'Break' keys Shift-Control-Alternate are pressed whilst in the
debugger, a flag will be set which will cause the BASIC program to halt as soon
as control is returned to it.
CAUTION:
Before using this command you must make sure that a machine language monitor
has initialized the monitor vector. GFA-Basic cannot set this vector before
the jump to its address because it does not know where the monitor is. If the
monitor is not at the current vector address this results in the program or
system crash (bombs error #4).
CALL
CALL addr[(x,y$,...)]
addr: avar (at least 32-bit, ideally integer-type: adr%)
x: iexp
y: sexp
Assembler or C subroutines can also be called with the instruction CALL, where
'addr' is the address of the assembler program, which must end with an RTS
instruction. It is possible to pass a parameter list to the routine. When the
CALL is made, the return address is found at the top of the stack followed by
the number of parameters given as a 16-bit word, and finally the address, as a
32-bit longword, of the parameter list. All parameters will be put into memory
as long (32-bit) words.
Strings may also be passed to the subroutine, in which case it will be the
address of the string which is found in the parameter list.
Stack structure:
(sp) --> Return address
4(sp) --> Number of parameters (16-bit)
6(sp) --> Address of the parameters (32-bit)
Example: CALL addr%(a&,b&)
To locate the parameters:
lea 6(sp),a0
(a0) --> a& (4 bytes)
4(a0) --> b& (4 bytes)
Memo: This command is broken in the editor, but works compiled.
For compiler options see section 'Register Saving'.
Registers a3 to a7 must remain unchanged.
RCALL
RCALL addr,reg%()
addr: iexp
reg%(): integer array (4-byte)
The instruction RCALL enables the assembler routine to start with pre-allocated
values in the registers, and the BASIC program to query the register contents
when the routine returns. The integer-sized array reg%(), which must have at
least 16 elements, serves this purpose. Before the assembler routine is
started, the entries in this array are automatically copied into the
appropriate registers. At the end of the routine the contents of the registers
are written back into the appropriate elements. The registers and array
elements are related as follows (assuming OPTION BASE 0):
Data registers d0 to d7 <--> reg%(0) to reg%(7)
Address registers a0 to a6 <--> reg%(8) to reg%(14)
User stack pointer (a7) --> reg%(15) (return only)
Example:
The assembler listing below expects the address (logical or physical) of the
screen memory in a0. It then inverts the screen display between the given y
coordinates, which are passed in d0 and d1. With a color display, the y
coordinates will have to be adjusted accordingly.
sub d0,d1 ; Number of lines to invert
mulu #20,d1 ; Number of bytes to invert
subq #1,d1 ; Number of bytes to invert
mulu #80,d0 ; Number bytes not to be inverted
add.l d0,a0 ; Address of first byte to be inverted
loop: ; Loop start
not.l (a0)+ ; Long (4-byte) inversion, also a0=a0+4
dbra d1,loop ; Decrement byte count and loop round
rts ; Return to GFA BASIC
The GFA-Basic program to call this routine reads:
DO
READ a%
EXIT IF a%=-1
a$=a$+MKI$(a%)
LOOP
DATA 37440,49916,20,21313
DATA 49404,80,53696
DATA 18072,20937,65532,20085,-1
'
DIM r%(16)
xb2%=XBIOS(2)
HIDEM
FOR j%=1 TO 50
FOR i%=0 TO 190 STEP 10
r%(0)=i%
r%(1)=399-i%
r%(8)=xb2%
RCALL V:a$,r%()
NEXT i%
NEXT j%
--> The program produces a graphic display. It is also possible, as with C:, to
use the INLINE command.
Memo: Registers a3 to a6 are saved/restored automatically by the compiler.
EXEC
EXEC mod,nam,cmdl,envs
EXEC(mod,nam,cmdl,envs)
mod: iexp
nam, cmdl, envs: sexp
EXEC can be used as a command or as a function. It enables the loading and
starting of programs from disk, which return to the calling program after
completion. Before the EXEC call, the calling program must have allocated
enough memory space for the program (see example). The parameter 'mod'
specifies the 'Call mode' as follows:
0 --> Load and Start program.
3 --> Load program only.
The string expression 'nam' contains the file name of the program to be loaded
(and optionally started). The format of the file name conforms to the rules of
the hierarchical filing system, described in 'Chapter 6 - Input and Output'.
The expression 'cmdl' contains the command line, which is registered in the
BASEPAGE of the called program. The first character of the command line
contains it's length (maximum 127). As a rule, this byte is ignored, as if it
were zero, Therfore it is normally sufficient to insert a dummy character (e.g.
"*").
The string 'envs' contains the Environment. This is a string terminated by
CHR$(0). For a C-program, the Environment is a series of strings, each
terminated by CHR$(0), and the whole series terminated by two CHR$(0)'s (these
are added automatically by GFA BASIC). This Environment is used by many Shell
programs in order to store variables and their names, and also by many
compilers, in order to determine access paths etc.
If one calls EXEC as a function, then one receives the program's returned
value, or, for mod=3, the address of the BASEPAGE of the called program. EXEC 3
is only for special programs which include overlays, debugging programs etc.
Example:
FILESELECT "\*.PRG","",f$
RESERVE 100
SHOWM
a%=EXEC(0,f$,"","")
RESERVE
PRINT "Back in GFA BASIC. Returned value=";a%
--> A program is loaded and called (if it does not require too much memory) and
returns to the interpreter on completion. The returned value, which is
returned by the EXEC function, can also be given by GFA-Basic programs by
terminating them with QUIT n or SYSTEM n.
Memo: At the moment a process is started the processor looks like this:
d0-d7 -> ?
a0 -> BASEPAGE - Application was started as a desk accossory (<>0)
a1-a6 -> ?
a7 -> End of application memory
4(a7) -> BASEPAGE - Application was started as a normal program
Pexec()+
STE?
TT?
These commands allow one to detect which hardware your GFA-Basic programs are
running on.
The function STE? returns the following:
0 = Stereo 8-bit playback not available
2 = Stereo 8-bit playback available
The function TT? returns the following:
0 = 68000 (normal ST)
1 = 68030 or 68020
3 = 68881 or 68882 fitted
These functions will use the FPU: SIN, COS, TAN, EXP, LOG, and LOG10
Example:
PRINT TT? !Prints 3 if ran on an Atari TT030
Memo: These functions should not be used to determine what hardware an
application might be running on, instead look in the system cookie jar.
The cookie jar contains much more detailed information about the
hardware.
The STE? function doesn't seem to work as the documentation states.
Original documentation states this:
The function STE? returns -1 for STE (or TT), otherwise 0.
The TT? function doesn't seem to work as the documentation states.
Original documentation states this:
The function TT? returns -1 for 68020 or 68030 processor, otherwise 0.
The TT? function when compiled uses self modifying code and thus is
rather unstable if used on a cpu (68040/060) with the caches enabled.
These functions SIN, COS, TAN, EXP, LOG, and LOG10 by default do not use
the FPU even if its present. The function TT? must be called at least
once to activate the faster math functions. It cannot be disabled once
activated. Example:
CLS
t=TIMER
FOR x=1 TO 65000
y=LOG(x)
NEXT x
PRINT "time: ";(TIMER-t)/200
~TT? !activate the faster math functions
t=TIMER
FOR x=1 TO 65000
y=LOG(x)
NEXT x
PRINT "time: ";(TIMER-t)/200
The Cookie Jar+
Chapter 11 - AES Libraries
GCONTRL, GCONTRL()
GINTIN, GINTIN()
ADDRIN, ADDRIN()
GINTOUT, GINTOUT()
ADDROUT, ADDROUT()
GEMSYS
This chapter gives an overview of the AES libraries (AES = Application
Environment Services). A detailed description of these routines would be beyond
the scope of this manual (we refer the reader to the extensive literature
already published on GEM), hence information is given in compressed form, as
follows:
a) The name of the appropriate library routine.
b) A short description of the function.
c) The complete GFA BASIC 3 syntax for the function call, with the meaning
of all the applicable variables explained.
The chapter closes with longer example programs.
Before beginning the descriptions of the functions in the 11 AES Libraries, it
is important that the reader becomes familiar with the most important data
structures used by the AES. These are the OBJECT, TEDINFO, ICONBLK, CICONBLK,
BITBLK, APPLBLK, and PARMBLK structures.
The following AES functions are implemented in a similar way to GFA BASIC
version 2:
GCONTRL
ADDRIN
ADDROUT
GINTIN
GINTOUT
GB
They represent the addresses of the AES parameter blocks. Specifically:
GCONTRL --> address of the AES Control block
ADDRIN --> address of the AES Address Input block
ADDROUT --> address of the AES Address Output block
GINTIN --> address of the AES Integer Input block
GINTOUT --> address of the AES Integer Output block
GB --> address of the AES Parameter block
With an index in brackets after these functions, the appropriate parameter
positions within the block are accessed directly, for instance, x=GCONTRL(3)
corresponds to x=DPEEK(GCONTRL+6), or GCONTRL(3)=x corresponds to DPOKE
GCONTRL+6,x.
GCONTRL, GINTIN, and GINTOUT expect words (2 bytes) as their parameters,
whereas ADDRIN and ADDROUT expect long words (4 bytes). So ADDRIN(2)=x
corresponds to LPOKE ADDRIN+2*4,x.
The GB block address cannot be used with an index, on grounds of compatibility
with ST-BASIC; with GINTIN etc. indices are available. For example, the second
long word in the GB block ({GB+4}) is the address of the GEM internal global
array.
Memo: Not all TOS machines have the same AES version so care should be
taken when calling these functions. For the most part all AES calls in
GFA-Basic work fine except a few. Functions denoted in lower case are not
built into GFA-Basic.
These tables have the following limits:
GCONTRL(0-5)
ADDRIN(0-9)
ADDROUT(0-9)
GINTIN(0-19)
GINTOUT(0-19)
GB (GEM Base) consists of the following pointers:
GB +0 GCONTRL
GB +4 global
GB +8 GINTIN
GB +12 GINTOUT
GB +16 ADDRIN
GB +20 ADDROUT
GB +24 CONTRL
GB +28 INTIN
GB +32 PTSIN
GB +36 INTOUT
GB +40 PTSOUT
Memo: Example how to access the AES Global array:
bit_planes&=WORD{LONG{GB+4}+20}
rsrc_base%=LONG{LONG{GB+4}+10}
mtos_!=WORD{LONG{GB+4}+2}<>1 !false=SingleTOS/true=multi-tasking
ST-BASIC originally defined GB as only 24 bytes (6 longs).
The compiler only initializes the AES if some module is linked that
actually calls the AES. The editor on the other hand always does this.
If you suspect the AES is not initialized it can be forced with a
call to any AES function. I suggest using some inquire function like
GRAF_HANDLE().
appl_init()+
AES Function Reference+
AES Functions by Opcode+
GEMSYS
GEMSYS [n]
n: iexp
The commnad GEMSYS calls an AES routine by specifying the routine number n.
The parameters necessary for the operation of the routine must first be placed
in the appropriate AES parameter blocks.
Example:
REPEAT
GINTIN(0)=60
GINTIN(1)=30
GINTIN(2)=10
GINTIN(3)=10
GINTIN(4)=200
GINTIN(5)=200
GEMSYS 72
UNTIL MOUSEK
--> A moving rectangle is drawn on the screen, as function number 72 is
GRAF_MOVEBOX().
Memo: The parameter n is optional. If parameter n is omitted then the
necessary parameters for the call must be place in the GCONTRL parameter
block. See appl_search() for an example listing. Calling a function which
does not exist is usually fatal.
Object Structure
Offset Name Type Meaning
00 ob_next word pointer to the next object
02 ob_head word pointer to the first child
04 ob_tail word pointer to the last child
06 ob_type word type of object
08 ob_flags word object information (see below)
10 ob_state word status of the object (see below)
12 ob_spec long pointer to further information (see below)
16 ob_x word x-position of the object
18 ob_y word y-position of the object
20 ob_w word width of the object
22 ob_h word height of the object
So the memory requirements of an object are these 24 bytes plus further
descriptive structures, e.g. TEDINFO or BITBLK structures.
OB_NEXT points to the following object on the same level, or, if it is the last
object on that level, to the parent object, or contains -1 if none.
OB_HEAD points to the object's first child, or contains -1 if none.
OB_TAIL points to the object's last child, or contains -1 if none.
The value -1 in this context is also referred to as NIL (Not In List).
Depending on the value in OB_TYPE, OB_SPEC has the address of different data
structures, as shown in the following table:
OB_TYPE Name OB_SPEC
20 G_BOX BOX information, see below
21 G_TEXT Pointer to TEDINFO graphic text
22 G_BOXTEXT Pointer to TEDINFO text-in-a-box
23 G_IMAGE Pointer to BITBLK bit image graphic
24 G_USERDEF Pointer to APPLBLK structure
25 G_IBOX BOX information, see below.
26 G_BUTTON Pointer to centered C-string, to go in a box
27 G_BOXCHAR BOX information, see below.
28 G_STRING Pointer to C-string menu item structure
29 G_FTEXT Pointer to TEDINFO editable graphic text
30 G_FBOXTEXT Pointer to TEDINFO editable text-in-a-box
31 G_ICON Pointer to ICONBLK structure
32 G_TITLE Pointer to C-string menu title structure
33 G_CICON Pointer to CICONBLK structure (AES => v3.3)
For G_BOX, G_IBOX and G_BOXCHAR, OB_SPEC contains information concerning
character-content, border-type and color of the appropriate object. The upper 8
bits are only used by G_BOXCHAR and contain the ASCII code of the character to
appear in the box.
They contain the following values for the border:
0 = no border
1 to 128 = the border extends 1 to 128 pixels inside the object
-1 to -128 = the border extends 1 to 128 pixels outside the object
The bit allocation for the object color word is:
1111 2222 3444 5555
where:
1 = Border color (0 to 15)
2 = Text color (0 to 15)
3 = Text mode (0 = transparent, 1 = overwritten)
4 = Fill pattern (0 to 7)
5 = Color of object interior (0 to 15)
OB_FLAGS Hex Bit
NORMAL &H0000 -
SELECTABLE &H0001 0
DEFAULT &H0002 1
EXIT &H0004 2
EDITABLE &H0008 3
RBUTTON &H0010 4
LASTOB &H0020 5
TOUCHEXIT &H0040 6
HIDETREE &H0080 7
INDIRECT &H0100 8
OB_STATE Hex Bit
NORMAL &H0000 -
SELECTED &H0001 0
CROSSED &H0002 1
CHECKED &H0004 2
DISABLED &H0008 3
OUTLINED &H0010 4
SHADOWED &H0020 5
The structures described in the preceding section are addressed in GFA-Basic 3
with the following syntax (for both reading and writing):
OB_NEXT(tree%,obj&)
OB_HEAD(tree%,obj&)
OB_TAIL(tree%,obj&)
OB_TYPE(tree%,obj&)
OB_FLAGS(tree%,obj&)
OB_STATE(tree%,obj&)
OB_SPEC(tree%,obj&)
OB_X(tree%,obj&)
OB_Y(tree%,obj&)
OB_W(tree%,obj&)
OB_H(tree%,obj&)
OB_ADR(tree%,obj&)
...where tree% is the address of the object tree and obj& the object number.
In addition the address of an individual object can be determined with
address=OB_ADR(tree%,obj&).
Memo: OB_TYPE() always reads and writes a word value. The following
code can be used to read/write the extended and standard object types
seperately.
' read/write extended object type
FUNCTION ob_extype(tr%,ob&)
$F%
RETURN BYTE{tr%+MUL(ob&,24)+6}
ENDFUNC
PROCEDURE ob_extype(tr%,ob&,ty&)
BYTE{tr%+MUL(ob&,24)+6}=ty&
RETURN
' read/write standard object type
FUNCTION ob_type(tr%,ob&)
$F%
RETURN BYTE{tr%+MUL(ob&,24)+7}
ENDFUNC
PROCEDURE ob_type(tr%,ob&,ty&)
BYTE{tr%+MUL(ob&,24)+7}=ty&
RETURN
OBJECT+
Text Data Structure (TEDINFO)
Offset Name Type Meaning
00 te_ptext long Pointer to text
04 te_ptmplt long Pointer to text mask
08 te_pvaiid long Pointer to validation string for input
12 te_font word Font
14 te_resvd word -reserved-
16 te_just word Text justification
18 te_color word Color of the surrounding box
20 te_resvd2 word -reserved-
22 te_thickness word Character thickness
24 te_txtlen word Text length
26 te_tmplen word Text mask length
TEDINFO+
Icon Data Structure (ICONBLK)
Offset Name Type Meaning
00 ib_pmask long Pointer to icon mask
04 ib_pdata long Pointer to icon data
08 ib_ptext long Pointer to icon text
12 ib_char word The single character within the icon
14 ib_xchar word x-position of the character relative to icon origin
16 ib_ychar word y-position of the character relative to icon origin
18 ib_xicon word x-position of the icon relative to icon origin
20 ib_yicon word y-position of the icon relative to icon origin
22 ib_wicon word Width of the icon
24 ib_hicon word Height of the icon
26 ib_xtext word x-position of the text relative to icon origin
28 ib_ytext word y-position of the text relative to icon origin
30 ib_wtext word Text width in pixels
32 ib_htext word Text height in pixels
34 ib_resvd word -reserved-
Memo: To display an icon without a text label set the x/y of the text
beyond the clipping rectangle.
ICONBLK+
Bit Image Block Structure (BITBLK)
Offset Name Type Meaning
00 bi_pdata long Pointer to image data
04 bi_wb word Width of the image in bytes
06 bi_hi word Height of the image in pixels
08 bi_x word x-position of the image
10 bi_y word y-position of the image
12 bi_color word Image color
BITBLK+
Application Block Structure (APPLBLK)
Offset Name Type Meaning
00 ab_code long Pointer to a user assembly language routine to draw the
object.
04 ab_parm long Pointer to a PARMBLK structure.
APPLBLK+
Parameter Block Structure (PARMBLK)
Offset Name Type Meaning
00 pb_tree long Pointer to object tree
04 pb_obj word Object number
06 pb_prevstate word Previous status
08 pb_currstate word Current status
10 pb_x word x-position of object
12 pb_y word y-position of object
14 pb_w word Width of object
16 pb_h word Height of object
18 pb_xc word x-position of clipping rectangle
20 pb_yc word y-position of clipping rectangle
22 pb_wc word Width of the clipping rectangle
24 pb_hc word Height of the clipping rectangle
28 pb_parm long Parameter from the APPLBLK structure
It should be noted that some functions return not only a function value, but
also return values in variables made available for that purpose. If the
function value is to be ignored, then the function should be called with VOID
or its abbreviation '~'. (In the same way as for the INP() function: the
returned function value may be printed with PRINT INP(2), or ignored with
~INP(2).) When parameters have to indicate addresses, at least 4-byte long
variable types must be used, and coordinate entries must take place in variable
types of at least 2 bytes (word or greater).
PARMBLK+
Color Icon Data Structure (CICONBLK)
Offset Name Type Meaning
00 monoblk ---- Same structure as an ICONBLK
..
34 mainlist long Pointer to linked list (CICON structure)
CICONBLK+ ciconblk+
Color Icon Structure (CICON)
Offset Name Type Meaning
00 num_planes word Bit planes
02 col_data long Pointer to unselected data
06 col_mask long Pointer to unselected mask
10 sel_data long Pointer to selected data
14 sel_mask long Pointer to selected mask
18 next_res long Pointer to next CICON structure (null = end list)
CICON+
Application Services Library
APPL_EXIT()
APPL_FIND()
appl_getinfo()
APPL_INIT()
APPL_READ()
appl_search()
APPL_TPLAY()
APPL_TRECORD()
APPL_WRITE()
appl_yield()
The Application Services Library controls the accessing of other AES libraries.
The functions APPL_INIT() and APPL_EXIT() are called automatically by GFA-Basic
when a program is started or ended.
Application Services Library+
APPL_EXIT
APPL_EXIT()
APPL_EXIT() informs the system that the program (application) has finished,
causing its identification number to be released and made available for other
programs.
APPL_EXIT() exists in GFA-Basic only as a dummy function, since a QUIT or
SYSTEM command accomplishes this automatically.
In case of error, 0 is returned.
appl_exit()+
APPL_FIND
APPL_FIND(fname$)
fname$: sexp
The identification number of another application in the system is determined
from its file name, e.g. for information exchange with other current programs.
fname$ - The 8-character file name (without extension) of the sought-after
application. The file name supplied must be exactly 8 characters
long, if necessary padded out with spaces, and characters must be
in upper case.
If no error occurs, the requested ID is returned, otherwise (if the application
is not found), -1 is returned.
Example:
PRINT APPL_FIND("CONTROL ")
--> Prints '65535' (-1) if the Control desk accessory cannot be found. If it is
found, the ID number (e.g. 2) is printed. Besides Accessories, one can also
find the ID of GFA-Basic (ap_id=0) and the screen manager "SCRENMGR"
(ap_id=1), which is responsible for the menu handling.
appl_find()+
appl_getinfo
appl_getinfo(type,out1,out2,out4,out4)
type: iexp
out1, out2, out3, out4: ivar
This call returns information about the AES.
type - Specifies the type of information to be returned.
out1 - Requested information is returned in this variable.
out2 - Requested information is returned in this variable.
out3 - Requested information is returned in this variable.
out4 - Requested information is returned in this variable.
Returns 1 if an error occured or 0 otherwise.
Note: appl_getinfo() returns different values for different AES verisons
so one should seek the proper documentation before using this call.
Memo: This call is not bulit into GFA-Basic so it is included below:
FUNCTION appl_getinfo(gtype&,VAR gout1&,gout2&,gout3&,gout4&)
$F%
GCONTRL(0)=130
GCONTRL(1)=1
GCONTRL(2)=5
GCONTRL(3)=0
GCONTRL(4)=0
GINTIN(0)=gtype&
GEMSYS
gout1&=GINTOUT(1)
gout2&=GINTOUT(2)
gout3&=GINTOUT(3)
gout4&=GINTOUT(4)
RETURN GINTOUT(0)
ENDFUNC
appl_getinfo()+
APPL_INIT
APPL_INIT()
Returns the identicifation number (ap_id) of the application (program).
The current program is announced as an application. The function APPL_INIT()
returns an Application ID that acts as the 'handle' of the current GFA-Basic
program. This identification number is, for example, important for the
installation of additional fonts.
APPL_INIT() is used for APPL_READ(), APPL_WRITE(), and MENU_REGISTER().
This function in GFA-Basic is a dummy function, which carries out no operating
system call, since APPL_INIT() is already impemented by the start of the
GFA-Basic interpreter.
This call does the same as appl_id&=WORD{LONG{GB+4}+4}
Memo: See GB for information on accessing the AES Global array.
Auto folder detection:
If APPL_INIT() = 0 then GEM is not initialized.
Desk ACC detection:
dacc_!=LONG{ADD(BASEPAGE,36)}=FALSE !desk acc flag [false=prg true=acc]
appl_init()+
APPL_READ
APPL_READ(id,len,adr_buffer)
id, len, adr_buffer: iexp
With this instruction bytes can be read from an event buffer (message pipe).
id - Identification number of the application, from whose buffer
reading is to be done.
len - Number of bytes to be read.
adr_buffer - Address of the buffer.
Returns 0 if an error occured.
appl_read()+
appl_search
appl_search(mode,fname$,type,ap_id)
mode: iexp
fname$: svar
type, app_id: ivar
Provides a method for identifying all of the currently running processes.
mode - Specifies the search mode.
fname - Returns the file name.
type - Returns the type.
ap_id - Returns the application identifier.
Returns 0 if no more applications exist or 1 when more processes exist that
meet the search criteria.
Note: Please refer to other AES documentation for proper use.
Memo: This call is not built into GFA-Basic so it is included below:
FUNCTION appl_search(mode&,VAR fname$,type&,apid&)
$F%
INLINE fname%,9
GCONTRL(0)=18
GCONTRL(1)=1
GCONTRL(2)=3
GCONTRL(3)=1
GCONTRL(4)=0
GINTIN(0)=mode&
ADDRIN(0)=fname%
GEMSYS
fname$=CHAR{fname%}
type&=GINTOUT(1)
apid&=GINTOUT(2)
RETURN GINTOUT(0)
ENDFUNC
appl_search()+
APPL_TPLAY
APPL_TPLAY(num,speed,mem)
APPL_TRECORD(mem,num)
num, speed, mem: iexp
APPL_TRECORD() makes a record of user activities (mouse movement, key presses,
etc.), and APPL_TPLAY() plays it back at a specified speed (speed = 1 to 1000).
These functions do not work as specified in some older documentation.
With newer ROM versions these functions work approximately as specified, except
that instead of 6 bytes per event 8 bytes are used and also the speed factor
works differently. Everything else appears reliable, but these functions should
be used advisedly.
num - Number of events to record or playback.
Thus 8 events would require a buffer 64 (8*8) bytes in size.
speed - Playback speed. (1-1000)
200 = Double speed
100 = Normal speed
50 = Half speed
Other values are interpreted accordingly.
mem - Address of an array of EVNTREC structures for recording or
playback. Each EVNTREC structure is 8 bytes (2 longs).
Data format: <event><value>,<event><value>,<event><value>,...
Name Event Value
------------------ -------- -------------------------------
0 APPEVNT_TIMER Timer Elapsed time in milliseconds
1 APPEVNT_BUTTON Button high word = number of clicks
low word = state (1 = down)
2 APPEVNT_MOUSE Mouse high word = X position
low word = Y position
3 APPEVNT_KEYBOARD Keyboard bits 0-7 = ASCII code
bits 8-15 = scan code
bits 16-31 = modifier key state
Note: See kbshift() for modifier key state.
Example:
x&=100
y&=100
INLINE adr%,8
LONG{adr%}=2
LONG{adr%+4}=OR(SHL(x&,16),y&)
~APPL_TPLAY(1,100,adr%)
--> The mouse cursor jumps to coordinates 100,100
Memo: The parameters for APPL_TPLAY() are documented incorrectly in the
GFA manual. Parameter order does not match offical docs.
APPL_TPLAY() does not work compiled as the library contains a bug.
appl_tplay()+, appl_trecord()+, Kbshift()+
APPL_WRITE
APPL_WRITE(id,len,adr_buffer)
id, len, adr_buffer: iexp
With this instruction bytes can be written into an event buffer (message pipe).
id - Identification number of the application, into whose buffer
writing is to be done.
len - Number of bytes to be written.
adr_buffer - Address of the buffer.
Returns 0 if an error occured.
appl_write()+
appl_yield
appl_yield
Forces the AES event dispatcher to perform a task switch.
Note: This call should work on all TOS versions.
Memo: This call is not built into GFA-Basic so it's listed below:
PROCEDURE appl_yield
' _appl_yield:
' move.w #$c9,d0
' trap #2
' rts
' .end
LOCAL asm%
INLINE asm%,8
LONG{asm%}=&H303C00C9
LONG{asm%+4}=&H4E424E75
~C:asm%()
RETURN
Event Library
EVNT_BUTTON()
EVNT_DCLICK()
EVNT_KEYBD()
EVNT_MESAG()
EVNT_MOUSE()
EVNT_MULTI()
EVNT_TIMER()
The Event Library allows a program to react to input from the mouse, keyboard,
etc, or to time-dependant events.
Event Library+
EVNT_BUTTON(clicks,mask,state[,mx,my,button,k_state])
clicks, mask, state: iexp
mx, my, button, k_state: ivar
Waits for one or more mouse clicks, e.g. double-click, triple click, etc.
Returns the number of clicks.
clicks - Maximum allowable clicks.
mask - Mask for the desired mouse button:
Bit 0: Left button
Bit 1: Right button
state - Desired status, in order to terminate the event.
Bit allocation as for 'mask'
mx - Returns x-coordinate of mouse pointer when event is terminated.
my - Returns y-coordinate of mouse pointer when event is terminated.
button - Returns state of mouse buttons when event is terminated.
k_state - Returns state of keyboard 'shift' keys when event is terminated.
Bit 0: Right shift key
Bit 1: Left shift key
Bit 2: Control key
Bit 3: Alternate key
Bit 7: AltGr (Milan)
The parameters mx, my, button, and k_state are optional, these values can also
be found by querying GINTOUT(1) to GINTOUT(4).
Example:
DO
SELECT EVNT_BUTTON(2,1,1,mx%,my%,bu%,kb%)
CASE 1
TEXT mx%,my%,"1"
CASE 2
TEXT mx%,my%,"2"
CASE 3
TEXT mx%,my%."3"
ENDSELECT
LOOP UNTIL BTST(kb%,2) !until Control key also pressed
--> Waits for mouse clicks with the left mouse button. The number of clicks
appears on the screen at the mouse position. The program is ended by
holding down the Control key as well as clicking.
evnt_button()+
EVNT_DCLICK
EVNT_DCLICK(new,get_set)
Sets the mouse double-click response rate.
new - New rate (0 to 4).
get_set - Determines whether the rate is to be set, or just read.
0: Return the current rate (then 'new' is a dummy).
1: Sets 'new' as new rate.
evnt_dclick()+
EVNT_KEYBD
EVNT_KEYBD()
Waits for a key to be pressed and returns a word-sized value, with the
low-order byte containing the ASCII code, and the high-order byte containing
the keyboard Scan code.
Example:
DO
PRINT HEX$(EVNT_KEYBD(),4)
LOOP
--> Prints values corresponding to pressed keys.
evnt_keybd()+
EVNT_MESAG
EVNT_MESAG(adr_buffer)
adr_buffer: iexp
Waits for the arrival of a message in the event buffer.
The returned value is always 1.
adr_buffer - address of a 16-byte buffer for the message. If 0 is given for
adr_buffer, the system message buffer is used, i.e. MENU(1) to
MENU(8).
evnt_mesag()+, MU_MESAG+
EVNT_MOUSE
EVNT_MOUSE(flag,mx,my,mw,mh[,mcur_x,mcur_y,button,k_state])
flag, mx, my, mw ,mh: iexp
mcur_x, mcur_y, button, k_state: ivar
Waits for the mouse pointer to be located inside (or, optionally, outside) a
specified rectangular area of the screen.
The returned value is always 1.
flag - Presence inside (0) or outside (1) of the area is detected.
mx - x-coordinate of top left corner of rectangle.
my - y-coordinate of top left corner of rectangle.
mw - Width of rectangle.
mh - Height of rectangle.
mcur_x - Returns x-coordinate of mouse pointer when event occurs.
mcur_y - Returns y-coordinate of mouse poniter when event occurs.
button - Returns mouse button status when event occurs.
Bit 0: Right button
Bit 1: Left button
k_state - Returns state of the keyboard 'shift' keys when event occurs.
Bit 0: Right shift key
Bit 1: Left shift key
Bit 2: Control key
Bit 3: Alternate key
Bit 7: AltGr (Milan)
The parameters mcur_x, mcur_y, button, and k_state are optional, these values
can also be found by querying GINTOUT(1) to GINTOUT(4).
Example:
DO
~EVNT_MOUSE(0,100,100,200,90,mx%,my%,bu%,kb%)
IF bu%
PBOX mx%-10,my%-10,mx%+10,my%+10
ELSE
PLOT mx%,my%
ENDIF
LOOP UNTIL BTST(kb%,2)
--> The program waits until the mouse pointer is located inside the rectangle.
Then a point is plotted at the mouse position, or a small square is drawn
if the left mouse button is pressed. The program is ended if the Control
key is held down while the pointer is within the rectangle. Compare the
effect produced by making the first parameter 1 instead of 0.
Note: While a GEM routine is being executed, the 'break' keys
(Control-Shift-Alternate) can be pressed, but will not take effect until
execution has returned to the BASIC part of the program. In general
though, it is best to exit from programs in the manner provided by the
program, otherwise memory restoration, etc, may not take place.
evnt_mouse()+
EVNT_MULTI
EVNT_MULTI(flag,clicks,mask,state,
m1_flags,m1_x,m1_y,m1_w,m1_h,m2_flags,m2_x,m2_y,m2_w,m2_h,
adr_buffer,count[,mcur_x,mcur_y,button,k_state,key,num_clicks])
flag, clicks, mask, state: iexp
m1_flags, m1_x, m1_y, m1_w, m1_h: iexp
m2_flags, m2_x, m2_y, m2_w, m2_h: iexp
adr_buffer, count: iexp
mcur_x, mcur_y, button, k_state, key, num_clicks: ivar
Waits for the occurrence of selected events.
Returns the event which actually occured (see 'flag' below).
flag - Sets the events to be awaited as follows:
Bit 0: Keyboard MU_KEYBD
Bit 1: Mouse button MU_BUTTON
Bit 2: First mouse event MU_M1
Bit 3: Second mouse event MU_M2
Bit 4: Message event MU_MESAG
Bit 5: Timer MU_TIMER
num_clicks - Returns the number of mouse clicks.
The parameters were already described for EVNT_BUTTON(), EVNT_KEYBD(),
EVNT_MESAG(), and EVNT_MOUSE(). However, it should be noted that two different
mouse events (m1 and m2) can be awaited. With ON MENU, which uses this routine
internally, the parameters are installed for the instruction ON MENU xxx GOSUB,
e.g. 'count' is specified directly.
The parameters mcur_x, mcur_y, button, k_state, key, and num_clicks are
optional, these values can also be found by querying GINTOUT(1) to GINTOUT(6).
MENU(1) to MENU(8) Message buffer
MENU(9) Return value
MENU(10)=mcur_x x mouse position
MENU(11)=mcur_y y mouse position
MENU(12)=button Mouse button state
MENU(13)=k_state 'Shift' key state (BIOS(11,-1))
MENU(14)=key ASCII and Scan code
MENU(15)=num_clicks Number of mouse clicks
evnt_multi()+, MU_MESAG+
EVNT_TIMER
EVNT_TIMER(count)
count: iexp
This function waits for a period of time expressed in milliseconds (see DELAY).
The returned value is always 1.
count - Number of milliseconds.
evnt_timer()+
menu_attach()
MENU_BAR()
MENU_ICHECK()
MENU_IENABLE()
menu_istart()
menu_popup()
MENU_REGISTER()
menu_settings()
MENU_TEXT()
MENU_TNORMAL()
Used for drawing the Menu Bar and managing its operation.
Menu Library+
menu_attach(flag,tree,item,mdata)
flag, tree, item, mdata: iexp
Allows an application to attach, change, or remove a sub-menu.
Returns 0 if if an error occured and the sub-menu could not be attached or 1 if
the operation was successful.
flag - Action to be carried out.
tree - Pointer to tree.
item - Object number within tree.
mdata - Pointer to MENU structure.
Note: Please refer to AES documentation for proper use.
Memo: This call is not built info GFA-Basic and is included below:
FUNCTION menu_attach(flag&,tree%,item&,mdata%)
$F%
GCONTRL(0)=37
GCONTRL(1)=2
GCONTRL(2)=1
GCONTRL(3)=2
GCONTRL(4)=0
GINTIN(0)=flag&
GINTIN(1)=item&
ADDRIN(0)=tree%
ADDRIN(1)=mdata%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
menu_attach()+, MENU+
MENU_BAR(tree,flag)
tree, flag: iexp
Displays or erases a menu bar (loaded from a Resource file). Compare to MENU
x$() and MENU KILL.
Returns 0 if an error occured.
tree - Address of the menu object tree.
flag - 0: Erase menu bar (happens automatically at the end of a program).
1: Display menu bar.
menu_bar()+
MENU_ICHECK(tree,item,flag)
tree, item, flag: iexp
Adds or reomves a checkmark in front of a menu item (which should have at least
2 spaces reserved for it.)
Returns 0 if an error occured.
tree - Address of the menu object tree.
item - Object number of the menu item.
flag - 0: Delete checkmark
1: Add checkmark ->
menu_icheck()+
MENU_IENABLE(tree,item,flag)
tree, item, flag: iexp
This causes the enabling or disabling of menu items. The menu item will then
appear with normal characters (selectable), or gray characters (not selectable)
respectively. Compare to MENU x,2 and MENU x,3.
Returns 0 if an error occured.
tree - Address of menu object tree.
item - Object number of menu entry.
flag - 0: Disabled -> Sample
1: Enabled
menu_ienable()+
menu_istart(flag,tree,imenu,item)
flag, tree, imenu, item: iexp
Shifts a sub-menu that is attached to a menu item to align vertically with the
specified object in the sub-menu.
Returns 0 if an error occured or the positive object index of the sub-menu item
which is currently aligned with its parent menu item.
flag - Action to be carried out.
tree - Pointer to object tree.
imenu - Object number.
item - Object number.
Note: Please refer to AES documentation for proper use.
Memo: This call is not built into GFA-Basic and is included below:
FUNCTION menu_istart(flag&,tree%,imenu&,item&)
$F%
GCONTRL(0)=38
GCONTRL(1)=3
GCONTRL(2)=1
GCONTRL(3)=1
GCONTRL(4)=0
GINTIN(0)=flag&
GINTIN(1)=imenu&
GINTIN(2)=item&
ADDRIN(0)=tree%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
menu_istart()+
menu_popup(menu,xpos,ypos,mdata)
menu, xpos, ypos, mdata: iexp
Displays a popup menu and returns the user's selection.
Returns 0 if an error occured or 1 is successful.
menu - Pointer to MENU structure.
xpos - x-coordinate of upper left corner.
ypos - y-coordinate of upper left corner.
mdata - Pointer to MENU structure.
Note: Please refer to AES documentation for proper use.
Memo: This call is not built into GFA-Basic and is included below:
FUNCTION menu_popup(menu%,xpos&,ypos&,mdata%)
$F%
GCONTRL(0)=36
GCONTRL(1)=2
GCONTRL(2)=1
GCONTRL(3)=2
GCONTRL(4)=0
GINTIN(0)=xpos&
GINTIN(1)=ypos&
ADDRIN(0)=menu%
ADDRIN(1)=mdata%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
menu_popup()+, MENU+
MENU_REGISTER(ap_id,m_text$)
ap_id: iexp
m_text$: sexp
Registers desk accessories in the 'Desk' menu and renames MultiTOS applications
which appear there.
Returns -1 if an error occured or a menu identifier if successful.
ap_id - Application identifier of the accessory.
m_text$ - Name under which the accessory is to be entered into the menu
(normally this is the accessory name).
Memo: Never use the built in MENU_REGISTER() funtion, instead call the
AES directly. Calling MENU_REGISTER() seems to work but for some reason
the entry itself under the 'Desk' drop down turns to garbage after a
while.
FUNCTION menu_register(ap_id&,m_text%)
$F%
GCONTRL(0)=35
GCONTRL(1)=1
GCONTRL(2)=1
GCONTRL(3)=1
GCONTRL(4)=0
GINTIN(0)=ap_id&
ADDRIN(0)=m_text%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
menu_register()+
menu_settings(flag,set)
flag, set: iexp
Changes the global settings for popup and scrollable menus.
Return value will always be 1.
flag - Action to be carried out.
set - Pointer to a MN_SET structure.
Note: Please refer to AES documentation for proper use.
Memo: This call is not built into GFA-Basic and is included below:
FUNCTION menu_settings(flag&,set%)
$F%
GCONTRL(0)=39
GCONTRL(1)=1
GCONTRL(2)=1
GCONTRL(3)=1
GCONTRL(4)=0
GINTIN(0)=flag&
ADDRIN(0)=set%
GEMSYS
RETURN GINTOUT(0)
ENDFUNC
menu_settings()+, MN_SET+
MENU_TEXT(tree,item,new_text$)
tree, item: iexp
new_text$: sexp
Changes the text of a menu item. This functions permits the adapting of menu
entries while a program is running.
Returns 0 if an error occured.
tree - Address of menu object tree.
item - Object number of the item to be modified.
new_text$ - A string containing the new menu item (may not exceed the
length of the old one).
Memo: This command copies the characters of new_text$ into the object tree
structure. Effectively overwriting the old string data. Care must be
taken not to exceed the length of the old string buffer.
Memo: Fails in the editor, but works compiled.
menu_text()+
MENU_TNORMAL(tree,item,flag)
tree, item, flag: iexp
Menu title switches to inverse or normal text. Compare to MENU OFF.
Returns 0 if an error occured.
tree - Address of the menu object tree.
item - Object number of the menu item.
flag - 0: Inverse text
1: Normal text
menu_tnormal()+
Object Library
OBJC_ADD()
OBJC_CHANGE()
OBJC_DELETE()
OBJC_DRAW()
OBJC_EDIT()
OBJC_FIND()
OBJC_OFFSET()
OBJC_ORDER()
objc_sysvar()
The Object Library contains routines for the definition, drawing, and
alteration of objects.
Object Library+
OBJC_ADD
OBJC_ADD(tree,parent,child)
tree, parent, child: iexp
An object is added to a given object tree and pointers between existing objects
and the new object are created.
Returns 0 if an error occured.
tree - Address of the object tree.
parent - Object number of the parent object, of which the new object is to
be a child.
child - Object number of the 'child object' to be added.
objc_add()+
OBJC_CHANGE
OBJC_CHANGE(tree,obj,res,cx,cy,cw,ch,new_status,re_draw)
tree, obj, res, cx, cy, cw, ch, new_status, re_draw: iexp
This function changes the status of an object (OB_STATE) and, if necessary,
inverts (displays in inverse video) that section of the object lying inside the
clipping rectangle. (Normally OB_STATE would be changed directly and the object
redrawn with OBJC_DRAW().)
Returns 0 if an error occured.
tree - Address of the object tree.
obj - Number of the object to be changed.
res - Reserved (always 0).
cx - x-coordinate of the top left corner of clipping rectangle
cy - y-coordinate of the top left corner of clipping rectangle
cw - Width of clipping rectangle
ch - Height of clipping rectangle.
new_status - New object status (see OB_STATE())
re_draw - 0: Do not redraw object
1: Redraw object
Memo: This call only updates the state. This will appear to fail:
CHAR{OB_SPEC(tree%,obj&}="blah..." !this change won't be seen
~OB_CHANGE(tree%,obj&,0,x&,y&,w&,h&,&X1,1) !object will be selected
' however, if you call objc_draw() the new text string will be seen
' tested under SingleTOS and N.Aes
objc_change()+
OBJC_DELETE
OBJC_DELETE(tree,del_obj)
tree, del_obj: iexp
An object is deleted from an object tree by changing pointers in the tree. The
object itself will still be there and can be restored later by restoring the
pointers.
Returns 0 if an error occured.
tree - Address of the object tree.
del_obj - Object number of the object to be deleted.
objc_delete()+
OBJC_DRAW
OBJC_DRAW(tree,start_obj,depth,cx,cy,cw,ch)
tree, start_obj, depth, cx, cy, cw, ch: iexp
This function draws whole objects or parts of objects on the screen. A clipping
rectangle can be specified, to which the drawing is limited.
Returns 0 if an error occured.
tree - Address of the object tree.
start_obj - Object number of the first object to be drawn.
depth - Number of object levels to be drawn (0 = only first object).
cx - x-coordinate of top left corner of clipping rectangle
cy - y-coordinate of top left corner of clipping rectangle
cw - Width of clipping rectangle.
ch - Height of clipping rectangle.
objc_draw()+
OBJC_EDIT
OBJC_EDIT(tree,obj,char,old_pos,flag,new_pos)
tree, obj, char, old_pos, flag: iexp
new_pos: ivar
Facilitates the input and editing of text in the G_TEXT and G_BOXTEXT object
types.
Returns 0 if and error occured.
tree - Address of the object tree.
obj - Object number.
char - Input character (including Scan code).
old_pos - Current cursor position in input string.
flag - Function selection:
0: Reserved (function call does nothing) ED_START
1: String is formatted and cursor switched on ED_INIT
2: Character processed and string re-displayed ED_CHAR
3: Text cursor switched off ED_END
new_pos - Returns the new cursor position in input string.
Memo: ED_INIT always places the cursor at the end of the string.
objc_edit()+
OBJC_FIND
OBJC_FIND(tree,start_obj,depth,fx,fy)
tree, start, depth: iexp
fx, fy: ivar
This function determines which object is found at a given coordinate.
Returns the object number, or -1 if no object is found at the given coordinate.
tree - Address of the object tree to be examined.
start_obj - Number of the object from which the search is begun.
depth - Number of object levels to be searched (0=only first object).
fx - x-coordinate
fy - y-coordinate
objc_find()+
OBJC_OFFSET
OBJC_OFFSET(tree,obj[,x_abs,y_abs])
tree, obj: iexp
x_abs, y_abs: ivar
Computes the absolute screen coordinates of the specified object.
Returns 0 is an error occured.
tree - Address of the object tree.
obj - Object number.
x_abs - Returns the computed x-coordinate.
y_abs - Returns the computed y-coordinate.
The parameters x_abs and y_abs are optional, these values can also be found
by querying GINTOUT(1) to GINTOUT(2).
objc_offset()+
OBJC_ORDER
OBJC_ORDER(tree,obj,new_pos)
tree, obj, new_pos: iexp
Re-positions an object within a tree.
Returns 0 if an error occured.
tree - Address of the object tree.
obj - Object number.
new_pos - New level number:
-1: One level higher
0: Bottom level
1: Bottom level + 1
2: Bottom level + 2
etc.
objc_order()+
objc_sysvar
objc_sysvar(mode,which,in1,in2,out1,out2)
mode, which, in1, in2: iexp
out1, out2: ivar
Modifies or returns information about the color and placement of 3D object
effects.
Returns 0 if an error occured or non-zero if successful.
mode - Action to be carried out.
which - Attribute to be modified or read.
in1 - New attribute.
in2 - New attribute.
out1 - Return attribute.
out2 - Return attribute.
Note: Please refer to AES documentation for proper use.
Memo: This call is not built into GFA-Basic and is included below:
FUNCTION objc_sysvar(mode&,which&,in1&,in2&,VAR out1&,out2&)
$F%
GCONTRL(0)=48
GCONTRL(1)=4
GCONTRL(2)=3
GCONTRL(3)=0
GCONTRL(4)=0
GINTIN(0)=mode&
GINTIN(1)=which&
GINTIN(2)=in1&
GINTIN(3)=in2&
GEMSYS
out1&=GINTOUT(1)
out2&=GINTOUT(2)
RETURN GINTOUT(0)
ENDFUNC
objc_sysvar()+
FORM_ALERT()
FORM_BUTTON()
FORM_CENTER()
FORM_DIAL()
FORM_DO()
FORM_ERROR()
FORM_KEYBD()
The Form Library contains routines to Form management, i.e. manipulation of
objects in Dialog bexes etc.
Form Library+
FORM_ALERT(button,string$)
button: iexp
string$: sexp
Creates a general-purpose Alert box (see ALERT command).
Returns the number of the clicked button which caused the function to
terminate.
button - Number of the default (thick-bordered) button:
0: None
1: First
2: Second
3: Third
string$ - A string defining the contents of the Alert box. The string has
the following format (note that the square brackets are part of
the string):
[i][Message][Buttons]
The meaning of the sections inside the brackets is as follows:
'i' The required symbol in the Alert box:
0: No icon
1: Exclamation mark
2: Question mark
3: Stop sign
4: Lowercase 'i' (AES => v4.1)
5: Floppy disk (AES => v4.1)
'Message' Can be at the most 5 lines of text, with a maximum of
30 characters per line, with the lines seperated with
the pipe '|' character.
'Buttons' Can be a maximum of 3 button names, seperated by the
pipe '|' character.
Example:
a$="[1][This is the first line|+|+|+|This is the fifth line][One|Two|Three]"
DO
PRINT FORM_ALERT(1,a$)
LOOP
--> Prints 1, 2, or 3 depending on which button is clicked, or pressing Return
selects the highlighted button. The program can be exited by pressing the
break keys (Shift-Control-Alternate) but this will only take effect after
the next click.
Memo: FORM_ALERT() can be fatal on some AES versions if the default button
exceeds the actual button count.
form_alert()+
FORM_BUTTON(tree,obj,clicks,new_obj)
tree, obj, clicks: iexp
new_obj: ivar
Makes possible mouse input in a Form.
Returns 0 if the Form was left by clicking on an object with EXIT or TOUCHEXIT
status. Returns a value >0 if the Form should continue to be processed.
tree - Address of the object tree.
obj - Currnet object number.
clicks - Maximum expected number of mouse clicks.
new_obj - Returns the next object to be edited.
Explanation: This routine is a subroutine of FORM_DO().
form_button()+
FORM_CENTER(tree[,fx,fy,fw,fh])
tree: iexp
fx, fy, fw, fh: ivar
This function centers the tree, i.e. Dialog box, ect, on the screen. Its
position can then be found.
Return value will always be 1.
tree - Address of the object tree.
fx - Returns the x-coordinate of the top left corner.
fy - Returns the y-coordinate of the top left corner.
fw - Returns the width of the centered box.
fh - Returns the height of the centered box.
The parameters fx, fy, fw, and fh are optional, these values can also be found
by querying GINTOUT(1) to GINTOUT(4).
form_center()+
FORM_DIAL(flag,mi_x,mi_y,mi_w,mi_h,ma_x,ma_y,ma_w,ma_h)
flag, mi_x, mi_y, mi_w, mi_h, ma_x, ma_y, ma_w, ma_h: iexp
This function serves to reserve (or release) a rectangular screen area and for
drawing expanding or shrinking rectangles.
Returns 0 if an error occured.
flag - Function type:
0: Reserves a display area FMD_START
1: Draws an expanding rectangle FMF_GROW
2: draws a shrinking rectangle FMD_SHRINK
3: releases reserved display area FMD_FINISH
mi_x - x-coordinate of top left corner at minimum size
mi_y - y-coordinate of top left corner at minimum size
mi_w - Width of rectangle at minimum size
mi_h - Height of rectangle at minimum size
ma_x - x-coordinate of top left corner at maximum size
ma_y - y-coordinate of top left corner at maximum size
ma_w - Width of rectangle at maximum size
ma_h - Height of rectangle at maximum size
Example:
~FORM_DIAL(1,0,0,0,0,100,100,300,100)
--> Draws an expanding rectangle. The parameter group '0,0,0,0' means that the
rectangle grows from the center of what will be the full-size rectangle.
form_dial()+
FORM_DO(tree,start_obj)
tree, start_obj: iexp
This function takes over the complete management of a Form object, until and
object with EXIT or TOUCHEXIT status is clicked.
Returns the number of the object whose clicking or double-clicking caused the
function to be ended. If it was a double-click, bit 15 will be set.
tree - Address of the object tree.
start_obj - Number of the first editable object in the object tree, where
the cursor is initially to be positioned. If there is no
editable object the value in this parameter should be 0.
form_do()+
FORM_ERROR(err)
err: iexp
Displays the warning Alert box associated with the DOS Error 'err'.
Returns the number of the button which terminated the function.
err - Error number.
Example:
FOR x=0 TO 63
PRINT FORM_ERROR(x);
NEXT x
--> The boxed error messages are displayed.
form_error()+
FORM_KEYBD(tree,obj,char,next_obj[,new_obj,next_char])
tree, obj, next_obj, char, new_obj: iexp
next_char: ivar
Allows a form to be filled out via the keyboard (see OBJC_EDIT()).
Returns 0 if the Form was left by clicking on an object with EXIT or TOUCHEXIT
status. Returns a value >0 if the Form should continue to be processed.
tree - Address of the object tree.
obj - Number of the object to be edited.
char - Input character.
next_obj - Number of the next EDITable object in the tree.
new_obj - Returns the object to be EDITed on the next call.
next_char - Returns the next character (derived form the keyboard, etc).
The parameters new_obj and next_char are optional, these values can also be
found by querying GINTOUT(1) to GINTOUT(2).
Explanation: This routine is a subroutine of FORM_DO() and makes it possible to
test a character in BASIC before it is passed to GEM, e.g. to test for Return
character, which would normally cause an exit from the Form and allow it to be
used to terminate an individual enrty, etc.
Memo: In the original manual parameters 'char' and 'next_obj' are swapped.
The function works fine. Parameter order does not match offical docs.
form_keybd()+
Graphics Library
GRAF_DRAGBOX()
GRAF_GROWBOX()
GRAF_HANDLE()
GRAF_MKSTATE()
GRAF_MOUSE()
GRAF_MOVEBOX()
GRAF_RUBBERBOX()
GRAF_SHRINKBOX()
GRAF_SLIDEBOX()
GRAF_WATCHBOX()
The Graphics Library provides routines for screen effects, mouse control, and
obtaining basic screen attributes.
Graphics Library+
GRAF_DRAGBOX
GRAF_DRAGBOX(iw,ih,ix,iy,rx,ry,rw,rh[,last_ix,last_iy])
iw, ih, ix, iy, rx, ry, rw, rh: iexp
last_ix, last_iy: ivar
This function allows a rectangle to be moved about the screen with the mouse.
Its movement is restricted to the interior of a larger specified rectangle. The
function should only be called when the left mouse button is held down, as it
terminates when the button is released.
Returns 0 is an error occurred.
iw - Width of moving rectangle.
ih - Height of moving rectangle.
ix - Initial x-coordinate of top left corner of moving rectangle.
iy - Initial y-coordinate of top left corner of moving rectangle.
rx - x-coodinate of top left corner of limiting rectangle.
ry - y-coodinate of top left corner of limiting rectangle.
rw - Width of limiting rectangle.
rh - Height of limiting rectangle.
last_ix - Returns x-coordinate of top left corner of moving rectangle when
function terminates.
last_iy - Returns y-coordinate of top left corner of moving rectangle when
function terminates.
The parameters last_ix and last_iy are optional, these values can also be found
by querying GINTOUT(1) to GINTOUT(2).
Example:
REPEAT
UNTIL MOUSEK=1
~GRAF_DRAWBOX(25,25,50,50,10,10,150,150,lx%,ly%)
BOX lx%,ly%,lx%+25,ly%+25
--> When the left mouse button is pressed, a small rectangle will move with the
mouse pointer, provided that this does not take it outside the specified
larger rectangle (in this case 10, 10 - 160, 160). When the button is
released, the function terminates and the smaller rectangle is redrawn at
its final position with the standard BOX command.
graf_dragbox()+
GRAF_GROWBOX
GRAF_GROWBOX(sx,sy,sw,sh,dx,dy,dw,dh)
sx, sy, sw, sh, dx, dy, dw, dh: iexp
This function draws an expanding rectangle.
Returns 0 if an error occurred.
sx - Initial x-coordinate of the top left corner of the rectangle.
sy - Initial y-coordinate of the top left corner of the rectangle.
sw - Initial width of the rectangle.
sh - Initial height of the rectangle.
dx - Final x-coordinate of the top left corner.
dy - Final y-coordinate of the top left corner.
dw - Final width.
dh - Final height.
Example:
BOX 100,100,110,110
PAUSE 25
~GRAF_GROWBOX(100,100,10,10,0,0,300,180)
BOX 0,0,300,180
graf_growbox()+
GRAF_HANDLE
GRAF_HANDLE([char_w,char_h,box_w,box_h])
char_w, char_h, box_w, box_h: ivar
Returns the identification number of the current VDI Workstation, which is used
internally for AES calls, and returns the size of a character from the system
character set.
char_w - Returns the width in pixels of a character from the standard set.
char_h - Returns the height in pixels of a character from the standard set.
box_w - Returns the width of a standard character cell.
box_h - Returns the height of a standard character cell.
The parameters char_w, char_h, box_w, and box_h are optional, these values can
also be found by querying GINTOUT(1) to GINTOUT(4).
graf_handle()+
GRAF_MKSTATE
GRAF_MKSTATE([mx,my,m_state,k_state])
mx, my, m_state, k_state: ivar
This function returns the current mouse pointer coordinates and the status of
the mouse buttons and the keyboard 'shift' keys.
This is an AES routine to query the mouse. Unlike MOUSEX etc., the function
gives valid results if the pointer is within a menu bar.
Return value will always be 1.
mx - Currnet x-coordinate of the mouse.
my - Current y-coordinate of the mouse.
m_state - Mouse button status:
Bit 0: Left button
Bit 1: Right button
k_state - Status of keyboard 'modifier' keys (if key is pressed bit is set):
Bit 0: Right shift key
Bit 1: Left shift key
Bit 2: Control key
Bit 3: Alternate key
The parameters mx, my, m_state, and k_state are optional, these values can
also be found by querying GINTOUT(1) to GINTOUT(4).
Memo: GRAF_MKSTATE() with no parameters crashes the compiler.
graf_mkstate()+
GRAF_MOUSE
GRAF_MOUSE(m_form,pattern_adr)
m_form, pattern_adr: iexp
This function allows the appearance of the mouse pointer to be changed. Eight
pre-defined pointers are available, or on may be defined by the user.
(However, the command DEFMOUSE is more convenient to use.)
Returns 0 if an error occurred.
m_form - Number of the mouse pointer shape:
0 : Arrow
1 : Text cursor
2 : Busy bee
3 : Pointing hand
4 : Open hand
5 : Thin cross-hair
6 : Thick cross-hair
7 : Outlined cross-hair
8 : Arrows pointing in all directions NAES
9 : Arrows pointing left and right NAES
10 : Arrows pointing up and down NAES
255: User defined
256: Hide mouse pointer (HIDEM)
257: Show mouse pointer (SHOWM)
258: Save current mouse form AES4
259: Restore saved mouse form AES4
260: Restore previous mouse form AES4
pattern_adr - Address of bit information defining the mouse pointer as
desired. 37 word-sized values are expected, as follows:
1 : x-coordinate of the action point (i.e. the
point referred to by MOUSEX, MOUSEY etc.)
2 : y-coordinate of the action point
3 : Number of color levels, always 1
4 : Mask color, always 0
5 : Pointer color, always 1
6 to 21 : Mask definition (16 words, i.e. 16x16 bits)
22 to 37: Pointer definition (16 words, i.e. 16x16 bits)
graf_mouse()+
GRAF_MOVEBOX
GRAF_MOVEBOX(w,h,sx,sy,dx,dy)
w, h, sx, sy, dx, dy: iexp
This function draws a moving rectangle with constant width and height.
Returns 0 if an error occurred.
w - Width of the rectangle.
h - Height of the rectangle.
sx - Initial x-coordinate of top left corner of the rectangle.
sy - Initial y-coordinate of top left corner of the rectangle.
dx - Final x-coordinate of the top left corner.
dx - Final y-coordinate of the top left corner.
Example:
~GRAF_MOVEBOX(25,25,0,0,150,150)
graf_movebox()+
GRAF_RUBBERBOX
GRAF_RUBBERBOX(lx,ty,min_w,min_h[,last_w,last_h])
lx, ty, min_w, min_h: iexp
last_w, last_h: ivar
This function draws an outline of a rectangle while the left button is held
down. The top left corner is fixed, but the width and height of the rectangle
change with the position of the mouse. The function should be called only when
a button is pressed, since it terminates when the button is released.
Returns 0 if an error occured.
lx - x-coordinate of top left corner.
ty - y-coordinate of top left corner.
min_w - Minimum width of rectangle.
min_h - Minimum height of rectangle.
last_w - Returns width of rectangle when function terminates.
last_h - Returns heigth of rectangle when function terminates.
The parameters last_w and last_h are optional, these values can also be found
by querying GINTOUT(1) to GINTOUT(2).
Example:
DO
~EVNT_BUTTON(1,1,1,mx%,my%,bu%,kb%)
~GRAP_RUBBERBOX(mx%,my%,1,1,w%,h%)
BOX mx%,my%,mx%+w%,my%+h%
LOOP UNTIL BTST(kb%,3)
--> EVNT_BUTTON() waits for the left button to be pressed, then puts the mouse
coordinates into mx% and my%, and the status of the keyboard 'modifier'
keys into kb%. The variables mx% and my% are then passed to
GFAF_RUBBERBOX(), which continuously draws rectangles from (mx%, my%) to
the current mouse position. When the function is terminated by releasing
the button, GRAF_RUBBERBOX() puts the last width and height into w% and h%.
A fixed box is then drawn with the standard BOX command. The program then
ends if the Alternate key was held down when the mouse button was first
pressed (i.e. bit 3 of kb% is set to 1), or otherwise loops around to draw
another box.
graf_rubberbox()+
GRAF_SHRINKBOX
GRAF_SHRINKBOX(sx,sy,sw,sh,dx,dy,dw,dh)
sx, sy, sw, sh, dx, dy, dw, dh: iexp
This function draws an shrinking rectangle.
Returns 0 if an error occurred.
sx - Final x-coordinate of the top left corner of the rectangle.
sy - Final y-coordinate of the top left corner of the rectangle.
sw - Final width of the rectangle.
sh - Final height of the rectangle.
dx - Initial x-coordinate of the top left corner.
dy - Initial y-coordinate of the top left corner.
dw - Initial width.
dh - Initial height.
Note: The final coordinates are given first.
Example:
BOX 0,0,300,180
PAUSE 25
~GRAF_SHRINKBOX(100,100,10,10,0,0,300,180)
BOX 100,100,110,110
graf_shrinkbox()+
GRAF_SLIDEBOX
GRAF_SLIDEBOX(tree,parent_obj,slider_obj,flag)
tree, parent_obj, slider_obj, flag: iexp
This function also really should be in the Object Library. It moves one
rectangle object within another in a similar way to GFAF_DRAGBOX(). However,
the object can only be moved horizontally or vertically and, in addition, it
must be a 'child' of the limiting rectangle (object). The function call should
only take place when a mouse button is pressed, since the function terminates
when the button is released. The most common application is the movement of
slider bars in windows.
Returns the position of the sliding rectangle relative to the limiting
rectangle:
Horizontally: 0=far left 1000=far right
Vertically : 0=top 1000=bottom
tree - Address of the object tree.
parent_obj - Object number of the limiting rectangle.
slider_obj - Object number of the sliding rectangle.
flag - Direction:
0: Horizontal
1: Vertical
graf_slidebox()+
GRAF_WATCHBOX
GRAF_WATCHBOX(tree,obj,in_state,out_state)
tree, obj, instate, out_state: iexp
This function (which really belongs in the Object Library) monitors an object
in a tree while a mouse button is pressed, checking whether the mouse pointer
is inside it or outside. When the button is released, the status of the object
takes one of two specified values (normal selected/normal), depending on
whether the pointer was located inside the object, or outside.
Returns 1 if the mouse pointer was inside the object when the button was
released, or 0 if it was outside.
tree - Address of the object tree.
obj - Number of the object to be monitored.
in_state - Status (OB_STATE) to be given to the object if the mouse is
found to be within it.
out_state - Status (OB_STATE) to be given to the object if the mouse
pointer is found to be outside it. The appropriate bit
allocation is found under OB_STATE().
graf_watchbox()+
Scrap Library
SCRP_READ()
SCRP_WRITE()
Conatins routines enabling the exchange of data between different applications.
Scrap Library+
SCRP_READ
SCRP_READ(path$)
path$: svar
This function returns the current clipboard directory.
Returns 0 if the clipboard path was never set, and non-zero if set correctly.
path$ - Returns the current clipboard path.
Examle:
~SCRP_READ(c$)
PRINT c$
--> Displays 'C:\CLIPBRD\' on the screen, assuming the clipboard path was
previously set correctly.
scrp_read()+
SCRP_WRITE
SCRP_WRITE(path$)
path$: sexp
This function sets the location of the clipboard directory.
Returns 0 if an error occured or non-zero otherwise.
path$ - String containing a valid path. (i.e. "C:\CLIPBRD\")
Example:
~SCRP_WRITE("C:\CLIPBRD\")
scrp_write()+
File Selector Library
fsel_exinput()
FSEL_INPUT()
The File Selector Library contains routines to allow the user to select a file
from a displayed directory, or to specify a file by typing its name.
File Selector Library+
fsel_exinput(title$,path$,file$,button)
title$: sexp
path$, file$: svar
button: ivar
Displays the systen File Selector Box and offers the user an opportunity to
chose a complete GEMDOS path specification. See also the FILESELECT command.
Returns 0 if an error occured or 1 otherwise.
On entry:
title$ - Title to appear (maximum of 30 characters).
path$ - Initial directory.
file$ - Default file name.
On exit:
path$ - Final directory.
file$ - Chosen file name.
button - Returns the button clicked:
0: 'Cancel' was clicked.
1: 'Ok' was clicked.
Note: Please refer to AES documentation for proper use.
Memo: This call is not built into GFA-Basic and is included below:
FUNCTION fsel_exinput(title$,VAR path$,file$,button&)
$F%
title$=MID$(title$,1,30)+CHR$(0)
path$=path$+CHR$(0)+STRING$(256,0)
file$=file$+CHR$(0)+STRING$(256,0)
GCONTRL(0)=91
GCONTRL(1)=0
GCONTRL(2)=2
GCONTRL(3)=3
GCONTRL(4)=0
ADDRIN(0)=V:path$
ADDRIN(1)=V:file$
ADDRIN(2)=V:title$
GEMSYS
path$=CHAR{V:path$}
file$=CHAR{V:file$}
button&=GINTOUT(1)
RETURN GINTOUT(0)
ENDFUNC
fsel_exinput()+
FSEL_INPUT(path$,name$[,button])
path$, name$: svar
button: ivar
This function invokes the standard File Selector Box, and corresponds to the
FILESELECT instruction. The initial directory path and the default file name
are contained in the string variables path$ and name$. After the file selector
box has been used in the normal way, and the function exited by clicking on
'Ok' or 'Cancel', these strings contain the last used directory path and chosen
file name respectively. The optional integer variable 'button' contains 1 or 0,
depending on whether the 'Ok' or 'Cancel' button was clicked.
Returns 0 if an error occured or 1 otherwise.
On entry:
path$ - Initial directory path.
mane$ - Default file name.
On exit:
path$ - Final directory path.
name$ - Chosen file.
button - Returns the button clicked:
0: 'Cancel' was clicked.
1: 'Ok' was clicked.
The parameter button is optional, this value can also be found by querying
GINTOUT(1).
Example:
p$="a:\*.*"
n$=""
DO
~FSEL_INPUT(p$,n$,b)
CLS
PRINT p$
PRINT n$
PRINT b
LOOP UNTIL b=0
--> Various file names can be slected and displayed. The program finishes when
the 'Cancel' button is clicked.
Memo: Does not handle long file names correctly.
Paths over 100 characters will be truncated.
File names over 50 characters will be truncated.
A bug in the editor causes path$ to be +1 longer than it should be.
A hidden trailing null is left on the end of the string.
fsel_input()+
Window Library
WIND_CALC()
WIND_CLOSE()
WIND_CREATE()
WIND_DELETE()
WIND_FIND()
WIND_GET()
wind_new()
WIND_OPEN()
WIND_SET()
WIND_UPDATE()
The Window Library contains all the functions releating to window management.
Window Library+
WIND_CALC
WIND_CALC(w_type,attr,ix,iy,iw,ih[,ox,oy,ow,oh])
w_type, attr, ix, iy, iw, ih: iexp
ox, oy, ow, oh: ivar
This function computes the total size of a window (including slider bars, etc.)
from the size of the work area, or conversely, the size of the work area from
the total size of the window.
Returns 0 if an error occurred.
w_type - Type of calculation to preform:
0: Compute total size
1: Compute work area size
attr - Window attributes as follows: Bit
&H0001 NAME Title bar with name 0
&H0002 CLOSE Close box 1
&H0004 FULL Full box 2
&H0008 MOVE Move box 3
&H0010 INFO Information line 4
&H0020 SIZE Size box 5
&H0040 UPARROW Up arrow 6
&H0080 DNARROW Down arrow 7
&H0100 VSLIDE Vertical slider bar 8
&H0200 LFARROW Left arrow 9
&H0400 RTARROW Right arrow 10
&H0800 HSLIDE Horizontal slider 11
ix - Known left x-coordinate.
iy - Known top y-coordinate.
iw - Known width.
ih - Known height.
ox - Returns computed left x-coordinate.
oy - Returns computed top y-coordinate.
ow - Returns computed width.
oh - Returns computed height.
The parameters ox, oy, ow, and oh are optional, these values can also be found
by querying GINTOUT(1) to GINTOUT(4).
wind_calc()+
WIND_CLOSE
WIND_CLOSE(handle)
handle: iexp
This function is the counterpart of WIND_OPEN() and closes the specified
window. Compare to CLOSEW.
Returns 0 is an error occured.
handle - Identification number of the window.
wind_close()+
WIND_CREATE
WIND_CREATE(attr,wx,wy,ww,wh)
attr, wx, wy, ww, wh: iexp
This function allocates a new window, specifying the attributes and maximum
size. The window identification number (handle) is returned. Compare to OPENW
#n,x,y,w,h,attr.
Returns window identification handle, or a negative value if an error occured.
attr - Window attributes as follows: Bit
&H0001 NAME Title bar with name 0
&H0002 CLOSE Close box 1
&H0004 FULL Full box 2
&H0008 MOVE Move box 3
&H0010 INFO Information line 4
&H0020 SIZE Size box 5
&H0040 UPARROW Up arrow 6
&H0080 DNARROW Down arrow 7
&H0100 VSLIDE Vertical slider bar 8
&H0200 LFARROW Left arrow 9
&H0400 RTARROW Right arrow 10
&H0800 HSLIDE Horizontal slider 11
&H4000 ICONIFY Iconifier 14 (AES v4.1)
wx - Maximum x-position of left edge
wy - Maximum y-position of left edge
ww - Maximum width of the window
wh - Maximum height of the window
wind_create()+
WIND_DELETE
WIND_DELETE(handle)
handle: iexp
This function deletes a window allocation and frees the reserved memory and
window identification number for re-use.
Returns 0 if an error occurred.
handle - Identification number of the window.
wind_delete()+
WIND_FIND
WIND_FIND(fx,fy)
fx,fy: iexp
This funtion determines the identification number of a window at a specified
coordinate.
Returns the identification number of the window found, or 0 meaning no window
(desktop was found instead).
fx - x-coordinate.
fy - y-coordinate.
wind_find()+
WIND_GET
WIND_GET(handle,code[,w1,w2,w3,w4])
handle, code: iexp
w1, w2, w3, w4: ivar
This function returns information about a window.
Returns 0 if an error occurred.
handle - Identification number of the window.
code - Depending on the code specified, information is returned in
w1, w2, w3, and w4 as follows:
4 : WF_WORKXYWH returns the size of the window work area:
w1 - returns left x-coordinate
w2 - returns top y-coordinate
w3 - returns width
w4 - returns height
5 : WF_CURRXYWH returns the total size of the entire window
including the borders:
w1 - returns left x-coordinate
w2 - returns top y-coordinate
w3 - returns width
w4 - returns height
6 : WF_PREVXYWH returns the total size of the previous window:
w1 - returns left x-coordinate
w2 - returns top y-coordinate
w3 - returns width
w4 - returns height
7 : WF_FULLXYWH returns the total maximum size of the window
(set by WIND_CREATE()):
w1 - returns left x-coordinate
w2 - returns top y-coordinate
w3 - returns width
w4 - returns height
8 : WF_HSLIDE returns the position of the horizontal slider:
w1 - returns slider position (0=far left, 1000=far right)
9 : WF_VSLIDE returns the position of the vertical slider:
w1 - returns slider position (0=top, 1000=bottom)
10: WF_TOP returns the identification number of the top
(active) window:
w1 - returns the identication number
11: WF_FIRSTXYWH returns the coordinates of the first
rectangle in the specified window's rectangle list. (The
list of rectangles required to build up the window: an
unobscured window has one rectangle in its list, a window
partially obscured by another window has several, a
totally obscured window has none):
w1 - returns left x-coordinate
w2 - returns top y-coordinate
w3 - returns width
w4 - returns height
12: WF_NEXTXYWH returns the coordinates of the next rectangle
in the specified window's rectangle list:
w1 - returns left x-coordinate
w2 - returns top y-coordinate
w3 - returns width
w4 - returns height
13: WF_RESVD reserved
15: WF_HSLIZE returns the size of the horizontal slider bar
compared to its maximum possible size:
w1 - returns slider size (1=small, 1000=full width)
16: WF_VSLIZE returns the size of the vertical slider bar
compared to its maximum possible size:
w1 - returns slider size (1=small, 1000=full height)
The parameters w1, w2, w3, and w4 are optional, these values can also be found
by querying GINTOUT(1) to GINTOUT(4).
wind_get()+
wind_new
wind_new
This function closes and deletes all of the application's windows. In addition,
the state of WIND_UPDATE(), and the mouse pointer hide count is reset. This
call should only be used to clean up after a fatal error.
Return value is not used.
Note: Please refer to AES documentation for proper use.
Memo: This command is not built to GFA-Basic and is included below:
PROCEDURE wind_new
IF WORD{LONG{ADD(GB,4)}}=>&H140
GCONTRL(0)=109
GCONTRL(1)=0
GCONTRL(2)=0
GCONTRL(3)=0
GCONTRL(4)=0
GEMSYS
ENDIF
RETURN
wind_new()+
WIND_OPEN
WIND_OPEN(handle,wx,wy,ww,wh)
handle, wx, wy, ww, wh: iexp
This function draws on the screen a window previously created with
WIND_CREATE(). Compare to OPENW.
Returns 0 if an error occurred.
handle - Identification number of the window.
wx - Left x-coordinate.
wy - Top y-coordinate.
ww - Initial width of the window.
wh - Initial height of the window.
wind_set()+
WIND_SET
WIND_SET(handle,code,w1,w2,w3,w4)
handle, code, w1, w2, w3, w4: iexp
This function changes parts of a window according to the specified function
code.
Returns 0 if an error occured.
handle - Identification number of the window.
code - Specifies components to be changed:
1 : WF_KIND sets new window components (as with
WIND_CREATE()):
w1 - New window part
2 : WF_NAME sets the title
w1 - High-word of the address of the string
w2 - Low-word of the address of the string
Note the string must be terminated with a null (0) byte.
3 : WF_INFO sets the information line:
w1 - High-word of the address of the string
w2 - Low-word of the address of the string
Note the string must be terminated with a null (0) byte.
5 : WF_CURRXYWH sets the total window size:
w1 - Left x-coordinate
w2 - Top y-coordinate
w3 - Width
w4 - Height
8 : WF_HSLIDE set the position of the horizontal slider:
w1 - Slider position (1=far left, 1000=far right)
9 : WF_VSLIDE set the position of the vertical slider:
w1 - Slider position (1=top, 1000=bottom)
10: WF_TOP Sets the top (currently active) window:
w1 - Handle of window to make active
14: WF_NEWDESK sets a new desktop background
w1 - High-word of the address of the tree
w2 - Low-word of the address of the tree
15: WF_HSLIZE sets the size of the horizontal slider bar
compared to its maximum possible size:
w1 - Slider size (1=small, 1000=full width)
16: WF_VSLIZE sets the size of the vertical slider bar
compared to its maximum possible size:
w1 - Slider size (1=small, 1000=full height)
wind_set()+
WIND_UPDATE
WIND_UPDATE(flag)
flag: iexp
This function coordinates all functions connected with screen redrawing, in
particular in combination with Pull-dowm Menus.
Returns 0 if and error occurred.
flag - Function:
0: Screen redraw completed END_UPDATE
1: Screen redraw starting BEG_UPDATE
2: Application relinquishes mouse supervision END_MCTRL
3: Application takes over mouse supervision BEG_MCTRL
GEM functions for menus and window handling are inactive.
wind_update()+
Resource Library
RSRC_FREE()
RSRC_GADDR()
RSRC_LOAD()
RSRC_OBFIX()
rsrc_rcfix()
RSRC_SADDR()
The Resource Library provides routines for the creation of a graphical user
interface (i.e. dialog boxes, etc.) which allows, independantly of the current
screen resolution, the exchange of data between the user and program.
Resource Library+
RSRC_FREE
RSRC_FREE()
This function releases the memory space reserved by RSRC_LOAD().
Returns 0 if an error occured.
Example:
~RSRC_FREE()
rsrc_free()+
RSRC_GADDR
RSRC_GADDR(type,index,addr)
type, index: iexp
addr: ivar
The function determines the address of a resource structure after it has been
loaded with RSRC_LOAD(). Depending on the version of GEM, this function may
only work for object trees and alerts (ad_frstr).
Returns 0 if an error occured.
type - Type of structure whose address is to be found:
0 : Object tree the tree loaded with RSRC_LOAD()
1 : OBJECT object
2 : TEDINFO text information
3 : ICONBLK icon information
4 : BITBLK bit-mapped graphic information
5 : STRING text
6 : image data bit-mapped graphic
7 : obspec object specification
8 : te_ptext string
9 : te_ptmplt text template
10: te_pvalid text validation string
11: ib_pmask icon display mask
12: ib_data icon bit map
13: ib_text icon text
14: bi_pdata image data
15: ad_frstr address of pointer to free string
15: ad_frimg address of pointer to free string
index - The number (not the object number) of the object whose address is
requested, counting objects of that type one by one from the
beginning of the Resource file.
addr - Returns the requested address.
Example:
~RSRC_GADDR(0,0,tree%)
rsrc_gaddr()+
RSRC_LOAD
RSRC_LOAD(name$)
name$: sexp
This function reserves memory and loads a resource file. Then internal pointers
are set and the coordinates of characters converted into pixel format. (For
Resources which have been defined directly in memory, with POKE, etc,
RSRC_OBFIX() must be used to do this). If the file cannot be found, RSC_LOAD()
automatically does a little searching, as detailed under SHEL_FIND().
Returns 0 if an error occured.
name$ - File specification of the Resource file.
Example:
~RSRC_LOAD("TEST.RSC")
Memo: If your *.ACC uses a resource file it should either be contained
within the binary itself or loaded by you and then fixed up. If you call
RSRC_LOAD() to load it and a resolution change takes place then TOS does
not free the ram allocated to the resource.
rsrc_load()+
RSRC_OBFIX
RSRC_OBFIX(tree,obj)
tree, obj: iexp
This function converts the coordinates of an object within a tree, from
character coordinates to pixel coordinates, taking into account the current
screen resolution. It is called automatically by RSRC_LOAD(), but must be used
if the object is created directly in memory by POKE, etc.
Return value will always be 1.
tree - Address of the appropriate object tree.
obj - Object number of the object to be adjusted.
rsrc_obfix()+
rsrc_rcfix
rsrc_rcfix(rc_header)
rc_header: iexp
Fixes up coordinates and memory pointers of raw resource data in memory.
Returns 0 if successful or non-zero otherwise.
rc_header - Address of raw resource data in memory.
Note: Please refer to AES documentation for proper use.
Memo: This call is not built into GFA-Basic and is included below.
FUNCTION rsrc_rcfix(header%)
$F%
GCONTRL(0)=115
GCONTRL(1)=0
GCONTRL(2)=1
GCONTRL(3)=1
GCONTRL(4)=0
ADDRIN(0)=header%
RETURN GINTOUT(0)
ENDFUNC
rsrc_rcfix()+
RSRC_SADDR
RSRC_SADDR(type,index,addr)
type, index, addr: iexp
This function sets the address of a resource structure.
Returns 0 if an error occurred.
type - Type of structure to modify (see RSRC_GADDR()).
index - The number (not the object number) of the object whose address is
to be set, counted object by object from the beginning of the
Resource file.
addr - The address.
rsrc_saddr()+
Shell Library
SHEL_ENVRN()
SHEL_FIND()
SHEL_GET()
SHEL_PUT()
SHEL_READ()
SHEL_WRITE()
The Shell Library routines enable one application to call another, preserving
both the original application and it's environment.
Shell Library+
SHEL_ENVRN
SHEL_ENVRN(addr,search$)
addr: avar (32-bit)
search$: sexp
This function determines the values of variables in the GEM environment.
Return value is always 1.
addr - Returns the address of the byte following the specified string.
search$ - The string to be sought.
Example:
PRINT SHEL_ENVRN(a%,"PATH")
PRINT CHAR{a%-4}
--> Displays 'PATH=;A:\' on the screen.
shel_envrn()+
SHEL_FIND
SHEL_FIND(path$)
path$: svar
This function searches for a specified file and returns the full file
specification. Frist, the specified path on the current drive is searched, then
the root directory of the current drive, then the root directory of drive A:.
Returns 0 if the file name was not found, or 1 if it was.
On entry:
path$ - String containing the sought-after file name.
On exit:
path$ - Returns the full file specification if the file was found,
otherwise it is unchanged.
Memo: A bug in the editor causes path$ to be +1 longer than it should be.
A hidden trailing null is left on the end of the string.
shel_find()+
SHEL_GET
SHEL_GET(len,x$)
len: iexp
x$: svar
This function reads data from the GEMDOS environmental string buffer (into
which the file DEKTOP.INF is read on start-up).
Returns 0 if an error occurred.
len - Number of byte to be read.
x$ - Returns data read.
Example:
PRINT SHEL_GET(500,x$)
PRINT x$
~INP(2)
--> Either the contents of DESKTOP.INF or data for the default Desktop is read
into x$, and printed.
shel_get()+
SHEL_PUT
SHEL_PUT(len,x$)
len: iexp
x$: sexp
This function writes data into the GEMDOS environmental string buffer.
Returns 0 if an error occurred.
len - Number of bytes to be written.
x$ - Data to be written.
Example:
' Register GFA-BASIC
~SHEL_GET(2000,a$)
q%=INSTR(a$,CHR$(26))
IF q%
a$=LEFT(a$,q%-1)
IF INSTR(a$,"GFABASIC.PRG")=0
a$=a$+"#G 03 04 A:\GFABASIC.PRG@*.GFA@"+MKI$(&HD0A)+CHR$(26)
~SHEL_PUT(LEN(A$),a$)
ENDIF
ENDIF
--> The program 'registers' A:\GFABASIC.PRG, so that with a double-click on a
.GFA program file, GFA-Basic is loaded which then loads and runs the
program which was clicked on.
Note: To save this in the DESKTOP.INF file:
~SHEL_GET(3000,a$)
OPEN "O",#1,"A:\DESKTOP.INF"
PRINT #1,LEFT$(A$,INSTR(A$,CHR$(26)))'
CLOSE #1
' The CHR$(26) is important
shel_put()+
SHEL_READ
SHEL_READ(cmd$,tail$)
cmd$, tail$: svar
This function allows the program to identify the command by which it was
invoked, and returns the name and the command line, if any.
Returns 0 if an error occurred.
cmd$ - Returns the program name.
tail$ - Returns the command line.
Memo: A bug in the editor causes cmd$ to be +1 longer than it should be.
A hidden trailing null is left on the end of the string.
shel_read()+
SHEL_WRITE
SHEL_WRITE(mode,gr,cr,tail$,cmd$)
mode, gr, cr: iexp
tail$, cmd$: sexp
This function informs the AES that another application is to be started after
the current one has terminated. In contrast to Pexec() (GEMDOS 75), however,
the current program does not remain resident in memory.
Returns 0 if an error occurred.
mode - 0: Back to the Desktop.
1: Load new program.
gr - 0: TOS program.
1: Graphics application.
cr - 0: Not GEM application.
1: GEM application.
tail$ - Command line string.
cmd$ - Name of next application.
Example:
~SHEL_WRITE(1,1,1,"","GFABASIC.PRG")
--> After running this, quitting BASIC and returning to the Desktop will
result in BASIC being restarted.
Memo: The built in command SHEL_WRITE() has parameters tail$ and cmd$
swapped when compared to other AES manuals. However it does work. The
information about the command itself is not very accurate. One should
consult additional documentation for the proper use of this call.
shel_write()+
Sample Programs
In this last section example programs are provided, dealing with the Graphics
Library, Dialog boxes, Menus, and Window programming. Note that it is important
to exit from all these programs in the ways specified, not by just breaking in
with Shift-Control-Alternate, otherwise memory re-allocation, etc. will not
take place and the programs (or other programs) may subsequently fail to work
without resetting the computer.
GRAF_SMP.GFA - Graphics Library
DIAL_SMP.GFA - Dialog Boxes Example
MENU_SMP.GFA - Menu management
WIND_SMP.GFA - Window demonstration
GRAF_SMP.GFA
' ** Graphics Library
' GRAF_SMP.GFA
'
REPEAT
CLS
PRINT CHR$(27)+"p";
PRINT "| <F1> rubber | <F2> drag | <F3> move |";
PRINT " <F4> grow_shrink | <F10> quit |"
choice|=INP(2)
'
SELECT choice|
CASE 187 ! F1
rubber
CASE 188 ! F2
drag
CASE 189 ! F3
move
CASE 190 ! F4
grow_shrink
ENDSELECT
'
PRINT CHR$(27)+"q";
'
UNTIL choice|=196 ! quit with F10
'
EDIT
'
PROCEDURE rubber
GRAPHMODE 3
DEFFILL 1,2,4
REPEAT
MOUSE mx%,my%,mk%
IF mk% AND 1
x1%=mx%
y1%=my%
~GRAF_RUBBERBOX(x1%,y1%,16,16,lx%,ly%)
PBOX x1%,y1%,x1%+lx%,y1%+ly%
ENDIF
UNTIL mk% AND 2
RETURN
'
PROCEDURE drag
GRAPHMODE 3
BOX 40,40,400,300
lx%=50
ly%=50
REPEAT
BOX lx%,ly%,lx%+150,ly%+100
'
REPEAT
mk%=MOUSEK
UNTIL mk% ! i.e. until mousek<>0
'
IF mk% AND 1 ! left button
BOX lx%,ly%,lx%+150,ly%+100
~GRAF_DRAGBOX(150,100,lx%,ly%,40,40,360,260,lx%,ly%)
BOX lx%,ly%,lx%+150,ly%+100
ENDIF
BOX lx%,ly%,lx%+150,ly%+100
UNTIL mk% AND 2 ! right button
GRAPHMODE 1
RETURN
'
PROCEDURE move
GRAPHMODE 1
DEFFILL 1,2,4
w%=100
h%=100
FOR i%=0 TO 639-w% STEP w%
FOR j%=0 TO 399-h% STEP h%
~GRAF_MOVEBOX(w%,h%,i%,j%,639-i%,399-j%)
NEXT j%
NEXT i%
RETURN
'
PROCEDURE grow_shrink
GRAPHMODE 1
~GRAF_GROWBOX(319,199,16,16,0,0,639,399)
ALERT 0,"That was a growing box!",1,"Continue",r%
~GRAF_SHRINKBOX(319,199,16,16,0,0,639,399)
ALERT 0,"That was a shrinking box!",1," Yes ",r%
RETURN
--> Pressing F1 to F4 causes the program to branch to the appropriate
procedure. If F1 is pressed, the outline of a rectangle appears on the
screen when the left mouse button is pressed and held down. The top left
corner is fixed, but the diagonally opposite corner moves with the mouse.
When the rectangle has the desired shape and size, and the left button is
released, the rectangle is fixed and filled. More rectangles can be drawn,
or the procedure exited by pressing the right button.
Pressing F2 causes a small rectangle to be drawn within a larger one. With
the left button pressed and held down, the smaller rectangle can be moved
about within the limits imposed by the larger one. Pressing the right
button ends the procedure.
F3 calls up the demonstration of GRAF_MOVEBOX(), where sequences of boxes
move round the screen. This procedure ends by itself after a few seconds.
Finally, with F4, a growing box is drawn with GRAF_GROWBOX(), and, after
pressing Return, a shrinking box is drawn with GRAF_SHRINKBOX().
Pressing F10 ends the whole program.
DIAL_SMP.GFA
** Dialog Box Example
' DIAL_SMP.GFA
'
DIM r%(3)
'
form1%=0 ! 0 = Dialog
icon1%=1 ! ICON in tree FORM1
ch_name%=2 ! FTEXT in tree FORM1
sur%=3 ! FTEXT in tree FORM1
str%=4 ! FTEXT in tree FORM1
town%=5 ! FTEXT in tree FORM1
cancel%=6 ! BUTTON in tree FORM1
ok%=7 ! BUTTON in tree FORMl
r%(1)=8 ! BUTTON in tree FORM1
r%(2)=9 ! BUTTON in tree FORM1
r%(3)=10 ! BUTTON in tree FORM1
output%=11 ! STRING in tree FORM1
'
~RSRC_FREE()
~RSRC_LOAD("\DIALOG.RSC") ! Load Resource file
~RSRC_GADDR(0,0,tree_adr%) ! Get address of Object tree
~FORM_CENTER(tree_adr%,x%,y%,w%,h%) ! Center the coordinates, depending on the current resolution
'
' Define initial editable strings
CHAR{{OB_SPEC(tree_adr%,ch_name%)}}="Sherlock"
CHAR{{OB_SPEC(tree_adr%,sur%)}}="Holmes"
CHAR{{OB_SPEC(tree_adr%,str%)}}="221b Baker Street"
CHAR{{OB_SPEC(tree_adr%,town%)}}="London N1"
'
~OBJC_DRAW(tree_adr%,0,1,x%,y%,w%,h%) ! Draw Object tree
'
REPEAT
ex%=FORM_DO(tree_adr%,0) ! Clicked an object with EXIT status?
'
' Put the texts from the Edit fields into the appropriate strings
ch_name$=CHAR{{OB_SPEC(tree_adr%,ch_name%)}}
surname$=CHAR{{OB_SPEC(tree_adr%,sur%)}}
street$=CHAR{{OB_SPEC(tree_adr%,str%)}}
town$=CHAR{{OB_SPEC(tree_adr%,town%)}}
'
FOR i%=1 TO 3
IF BTST(OB_STATE(tree_adr%,r%(i%)),0) ! Which radio-button was selected?
radio%=r%(i%)
ENDIF
NEXT i%
UNTIL ex%=ok% OR ex%=cancel%
'
~RSRC_FREE() ! Release reserved memory
'
CLS
PRINT "Ended with : ";ex%
PRINT "Christian name : ";ch_name$
PRINT "Surname : ";surname$
PRINT "Street : ";street$
PRINT "Town : ";town$
PRINT "Radio : ";radio%
--> The file "DIALOG.RSC" is loaded, the address of the object tree is
determined and the object tree coordinates are centered.
Then the function OB_SPEC() is used to define the initial editable strings:
OB_SPEC() returns a pointer to a TEDINFO structure, which itself contains
pointers to data pertaining to editable text (validation string, color,
text, and template addresses, etc.). So the 'pointer path' to the actual
information is shown overleaf:
Object --> TEDINFO structure --> String
OB_SPEC(tree%,ch_name%) returns a pointer to the TEDINFO structure.
{OB_SPEC(tree%,ch_name%)} returns the address held at that point in
TEDINFO.
CHAR{{OB_SPEC(tree%,ch_name%)}} gives the string initially inserted by the
Resource Construction Set, in this case: 0123456789012345678901.
CHAR{{OB_SPEC(tree%,ch_name%)}}="Sherlock'" assigns this preset character
string a new value (namely 'Sherlock'). This is repeated for the rest of
the initial data.
Then the object tree is drawn and, inside the REPEAT-UNTIL loop, the main
FORM_DO() routine is called. Its returned value 'ex%' determines when the
loop is exited.
The (edited) strings are then put back into their respective variables,
after which the object status (found by OB_STATE()) of the 'radio' buttons
is examined in a FOR-NEXT loop. Specifically, Bit 0 is tested with BTST().
If it is set (=1), then the corresponding button must have been selected
(only one radio button can be selected at a time), and the object number of
the button is stored in radio%.
Finally the memory space reserved for the Resource is released again with
RSRC_FREE(). (This is important!!, since otherwise the available free
memory shrinks each time the program is started, which soon causes the
computer to crash.)
The button which caused the exit of the REPEAT-UNTIL loop is printed (6 =
Cancel, 7 = Ok), followed by the data strings as they were when FORM_DO()
was done for the last time and the object number of the last-selected radio
button.
' ** Menu management
' MENU_SMP.GFA
'
RESERVE FRE(0)-33000 ! Reserve space for the Resource file
' File is not in 'folder' but RSRC_LOAD() looks further and should find it on current drive
IF RSRC_LOAD("folder\RCS2.RSC")=0
ALERT 1,"Resource not found",1,"End",a%
END
ENDIF
~RSRC_GADDR(0,0,menu_adr%) ! Get menu address
~MENU_BAR(menu_adr%,1) ! Display menu bar
'
' Reserve a Message Buffer of 16 bytes and give variable names to positions within it:
DIM message_buffer&(7) ! Eight words (including 0)
mesg_adr%=V:message_buffer&(0)
ABSOLUTE mesg_type&,mesg_adr%
ABSOLUTE m_title&,mesg_adr%+6
ABSOLUTE m_item&,mesg_adr%+8
'
REPEAT
ev%=EVNT_MULTI(&X110000,0,0,0,0,0,0,0,0,0,0,0,0,0,mesg_adr%,500)
IF BTST(ev%,4) ! a new message has arrived
IF mesg_type&=10 ! reporting a menu event
title$=CHAR{OB_SPEC(menu_adr%,m_title&)} ! find out what it was
item$=CHAR{OB_SPEC(menu_adr%,m_item&)}
PRINT AT(3,20);"Menu title : ";title$;SPC(10)
PRINT AT(3,21);"Menu item : ";item$;SPC(10)
~MENU_TNORMAL(menu_adr%,m_title&,1) ! Un-invert menu title display
ENDIF
ENDIF
UNTIL MOUSEK=2
'
~MENU_BAR(menu_adr%,0) ! Remove menu bar
~RSRC_FREE() ! Release Resource memory
RESERVE ! Return reserved memory to GFA BASIC
END
--> At the beginning of the program a 33k byte area of memory is reserved. It
is returned to the GFA-Basic interpreter at the end of the program.
The Resource file is then loaded into the freed memory area, the address of
the menu tree is determined and the menu is displayed.
EVNT_MULTI() supervises the menu tree, and, in the event that a menu item
is selected, appropriate messages are written into the Message buffer. This
is a 16-byte long area of memory, divided into eight 2-byte words,
conveniently allocated by means of a word-sized array. Using the ABSOLUTE
command, some variables are defined as being located in this array,
enabling elements of it to be referred to by name.
In a REPEAT-UNTIL loop (exited by pressing the right mouse button),
EVNT_MULTI() is called. The first word of the Message buffer (defined as
mesg_type&) then contains the value 10 if a menu item was selected. The
fourth word (m_title&, the 6th and 7th bytes) contains the object number of
the menu title, from beneath which the item was chosen. The object number
of the item is in the fifth word (m_item&, bytes 8 and 9). The other
elements of the buffer are not required here.
Knowing the object numbers of the menu title and the menu item, and that
OB_SPEC(...), in the case of Dialog Box Buttons and Menu items, returns the
address of text terminated with a zero byte, CHAR{} can be used to extract
the texts and put them into strings.
After displaying the menu title and item on the screen, the inverted menu
title is returned to its normal state with MENU_TNORMAL().
WIND_SMP.GFA
' ** Window demonstration
' WIND_SMP.GFA
'
DEFFILL 1,2,4
PBOX 0,19,639,399
DEFFILL 1,0
'
DIM message_buffer&(7) ! 16 Bytes
adr_mes%=V:message_buffer&(0)
'
ABSOLUTE word0&,adr_mes%
ABSOLUTE x&,adr_mes%+8
ABSOLUTE y&,adr_mes%+10
ABSOLUTE w&,adr_mes%+12
ABSOLUTE h&,adr_mes%+14
'
handle&=WIND_CREATE(&X101111,0,19,639,380)
'
title$="Window"+CHR$(0)
adr_title%=V:title$
~WIND_SET(handle&,2,CARD(SWAP(adr_title%)),CARD(adr_title%),0,0)
~WIND_OPEN(handle&,100,100,200,100)
~WIND_GET(handle&,4,wx&,wy&,ww&,wh&)
PBOX wx&,wy&,wx&+ww&,wy&+wh&
'
finish!=FALSE
REPEAT
~EVNT_MULTI(&X110000,0,0,0,0,0,0,0,0,0,0,0,0,0,adr_mes%,100,d%,d%,d%,d%,d%,d%)
SELECT word0&
' Depending on word0&, one of the following cases is dealt with:
CASE 22 ! WM_CLOSED - closed
finish!=TRUE
CASE 23 ! WM_FULLED - full size
~WIND_SET(handle&,5,1,19,638,380)
~WIND_GET(handle&,4,wx&,wy&,ww&,wh&)
PBOX wx&,wy&,wx&+ww&,wy&+wh&
word0&=0
CASE 27,28 ! WM_SIZED, WM_MOVED - re-sized or moved
IF w&<100
w&=100
ENDIF
IF h&<80
h&=80
ENDIF
~WIND_SET(handle&,5,x&,y&,w&,h&)
~WIND_GET(handle&,4,wx&,wy&,ww&,wh&)
PBOX wx&,wy&,wx&+ww&,wy&+wh&
word0&=0
ENDSELECT
UNTIL finish!
~WIND_CLOSE(handle&)
~WIND_DELETE(handle&)
--> First a Message Buffer is allocated, as in the example program
MENU_SMP.GFA, and some words within it are given variable names.
Then the window is created and its handle number determined with
WIND_CREATE(), and a title is assigned to it with WIND_SET().
After opening the window with WIND_OPEN() the coordinates of the work area
of the window are found with WIND_GET(), and the whole area is covered with
a white rectangle.
In the REPEAT-UNTIL loop, control of the window elements is supervised by
EVNT_MULTI(). Different events (signalled by word0&, the first word in the
message buffer) are dealt with by the associated CASE selection. If the
'Close Window' symbol is clicked, the loop terminates and so does the
program, after closing the window and deleting it from memory.
Chapter 12 - Appendix
Memory Map+
Native File Formats+
Compatibility with GFA-BASIC 2
It is possible in GFA BASIC 3 to use programs from older GFA-Basic versions.
For this purpose, programs written in the earlier version must be stored as
ASCII files, using the SAVE,A command. They can then be loaded into Version 3
by means of MERGE and, there after, treated as GFA-Basic 3 programs being SAVEd
and LOADed in the normal way.
Version 3 contains all the commands which are in earlier versions of the
interpreter, although there are some small differences in the interpretation of
commands which may make some modification of earlier programs necessary.
MUL, DIV
The commands MUL and DIV work in GFA-Basic 3 with integer variables (|,&,%) and
integer parameters only.
In the earlier versions, the program:
a%=10
MUL a%,2.5
PRINT a%
produced the output 25.
In Version 3, however, MUL does not take account of the fractional parts of
inputs, treating them all as integers. Thus, the value to the right of the
decimal point is ignored, so, in the above example, the integer a% is set to
20. This incompatibility between versions is the price paid for these commands
being many times faster than their counterparts in the earlier versions of
GFA-Basic, the increase in speed coming from the use of true integer
arithmetic. This incompatibility does, of course, only apply to integer
variables.
PRINT USING
PRINT USING displays only the numbers that fit in the designated format. This
can mean that it is possible that wrong values will be displayed, instead of
wrong formats as in earlier versions, if the length of the number is too great.
The actual accuracy is, of course, not affected just the display. Care must
therefore be taken when using this command.
CLS, PRINT, TAB()
At CLS, the string ESC-E-CR is now issued, so that the PRINT command will be
able to treat TAB() correctly.
KEYPAD
A program, which queries the keys of the numeric key-pad and Alternate and/or
Control, requires that a KEYPAD 0 be issued to switch this off now. The same
is valid for the function keys with Alternate.
MOUSEX, MOUSEY
If windows are active and MOUSEX or MOUSEY are interrogated, then negative
coordinates arise above and to the left of the window border (e.g. CLIP
OFFSET). In Version 2.x CARD(MOUSEX) or CARD(MOUSEY) returned these values.
OPTION
In version 2 the command OPTION was used to control the compiler. This command
has been replaced by the $ command in version 3.
Licence
Programs written to run in Interpreted mode can be run by means of the Run-only
Interpreter which is supplied with the GFA-Basic Interpreter. This contains all
the routines necessary for the running of GFA-Basic programs and can be
distributed by bonafide GFA-Basic owners along with their programs, thus
allowing all ST users to run any software written in GFA-Basic. The Interpreter
itself is sold for use by the owner, on one machine and copies may not be
passed on to another user.
Programs written in GFA-Basic Version 3 will be capable of being speeded up in
operation by the use of the GFA-Basic 3 compiler. This is designed to produce
programs which are executable without the need for supporting code, i.e. they
are true stand-alone .PRG files which can be distributed freely by the author.
Our only request is that an acknowledgement that they were produced using GFA
BASIC be included.
GEMDOS() Table
Any program that uses GEMDOS() directly will run much better on all TOS
machines.
One other thing that is worth noting. You can completely avoid GFA's built in
error handling if you access GEMDOS() directly for all your file I/O needs. I
recommend all file I/O be done through direct GEMDOS() calls. This will also
allow you to trap any file errors yourself rather than rely on the error
handling built into GFA-Basic.
Not all TOS machines have the same GEMDOS() version so care should be taken
when calling these functions.
GEMDOS() Function Reference+
GEMDOS() Functions by Opcode+
GEMDOS() Error Codes+
BIOS() Table
For proper use of these calls please refer to a BIOS() manual.
BIOS() Function Reference+
BIOS() Functions by Opcode+
BIOS() Error Codes+
XBIOS() Table
Don't use the XBIOS(4) function to determine screen size and color depth,
instead check the WORK_OUT() values provided by the VDI.
Not all TOS machines have the same XBIOS() version so care should be taken when
calling these functions. Since the XBIOS() does not provide a version number
itself the cookie jar should be checked to see what hardware is available.
XBIOS() Function Reference+
XBIOS() Functions by Opcode+
Line-A Variable Table
The base addresses of the Line-A variables are returned by means of L~A:
{L~A-906} Address of the current font-header
L~A-856 37 words, active DEFMOUSE
{L~A-460} Pointer to the current font-header
L~A-456 Array from four pointers, of which the last must be zero
Each pointer points to a concatenated list of character sets. The fist two
pointers are valid for resident fonts. Third is for the GDOS-Fonts, of this
with each VDI-CALL is put back.
INT{L~A-440} Total number of this Fonts
INT{L~A-46} Text line height
INT{L~A-44} Maximum splits
INT{L~A-42} Maximum cursor line
INT{L~A-40} Length of a text line in bytes
INT{L~A-38} Text background color
INT{L~A-36} Text foreground color
{L~A-34} Address of the cursor in screen memory INT{L~A-30}
Distance of first text line from the upper screen edge
INT{L~A-28} CRSCOL
INT{L~A-26} CRSLIN
BYTE{L~A-24} Cursor blink period
BYTE{L~A-23} Cursor blink count
{L~A-22} Address of the data for the mode
INT{L~A-18} Last ASCII character of the font
INT{L~A-16} First ASCII character of the font
INT{L~A-12} Horizontal resolution in pixels
{L~A-10} Address of the table
INT{L~A-4} Vertical resolution in pixels
INT{L~A-0} Number of bit planes
INT{L~A+2} Number of bytes per screen line
{L~A+4} Pointer for the CONTRL field
{L~A+8} Pointer for the INTIN field
{L~A+12} Pointer for the PTSIN field
{L~A+16} Pointer for the INTOUT field
{L~A+20} Pointer for the PTSOUT field
INT{L~A+24} Color value for bit level 0
INT{L~A+26} Color value for bit level 1
INT{L~A+28} Color value for bit level 2
INT{L~A+30} Color value for bit level 3
INT{L~A+32} Flag, do not draw last pixel of a line
INT{L~A+34} Line pattern
INT{L~A+36} GRAPHMODE
INT{L~A+38} until
INT{L~A+44} 2 coordinate pairs
{L~A+46} Pointer to current fill pattern
{L~A+50} Pointer to the current fill pattern mask
INT{L~A+52} Flag for multi-colored fill pattem
INT{L~A+54} Clipping-flag
INT{L~A+56} until
INT{L~A+64} Clipping-coordinates
INT{L~A+66} Enlargement factor
INT{L~A+68} Enlargement direction
INT{L~A+70} Flag for proportional script
INT{L~A+72} x-offset for text blit
INT{L~A+74} y-offset for text blit
INT{L~A+76} x-coordinate of a character on the screen
INT{L~A+78} y-coordinate of a character on the screen
INT{L~A+80} Width of a charaeter
INT{L~A+82} Height of a character
{L~A+84} Pointer to character set image
{L~A+88} Width of character set image
INT{L~A+90} Text style
INT{L~A+92} Mask for shaded text output
INT{L~A+94} Mask for italic script
INT{L~A+96} Additional width for wide script
INT{L~A+98} Italic script offset on the right
INT{L~A+100} Italic script offset on the left
INT{L~A+102} Enlargenment flag
INT{L~A+104} Text rotation angle
INT{L~A+106} Text color
{L~A+108} Pointer in buffer for text effects
INT{L~A+112} Offset for a second text effects buffer
INT{L~A+114} Color of the text background
INT{L~A+116} Flag for copy screen form, <>0 for transparent
{L~A+118} Pointer to routine, which terminates filling procedure -
with V 3 by means of Shift-Altenate-Control
Line-A Variable Table+
In addition to the values given below, the following default values are used: x
Device identification number (standard)
1. :Screen 11. :Plotter
21. :Printer 31. :Metafile
41. :Camera 51. :Graphics tablet
1 Line type
1 Line color
1 Mark type
1 Mark color
1 Text style
1 Text color
1 Fill type
1 Fill style
1 Fill color
2 Coordinate stytem (0: NDC, 1: reserved, 2: RC)
VDI WORK_OUT() Array Table
With V_OPNWK() and V_OPNVWK() the resultant values are returned in INTOUT(0) to
INTOUT(44) and in PTSOUT(0) to PTSOUT(11).
WORK_OUT(0) Maximum picture width in pixels minus 1
WORK_OUT(1) Maximum picture height in pixels minus 1
WORK_OUT(2) Device coordinate units flag:
0: Exact scaling possible
1: Not possible
WORK_OUT(3) Width of a pixel in microns
WORK_OUT(4) Height of a pixel in microns
WORK_OUT(5) Number of character heights (0: Modifiable)
WORK_OUT(6) Number of line types
WORK_OUT(7) Number of line widths (0: Modifiable)
WORK_OUT(8) Number of marker types
WORK_OUT(9) Number of marker sizes (0: Modifiable)
WORK_OUT(10) Number of faces supported by device
WORK_OUT(11) Number of patterns
WORK_OUT(12) Number of hatching patterns
WORK_OUT(13) Number of pre-defined colors/pens
WORK_OUT(14) Number of basic graphic functions (GDP)
WORK_OUT(15) List of basic graphic functions (GDP)
Ten basic functions are supported:
1: Bar
2: Arc
3: Pie
4: Circle
5: Ellipse
6: Elliptical arc
7: Elliptical pie
8: Rounded rectangle
9: Filled rounded rectangle
10: Justified graphic text
WORK_OUT(24) ...end of GDP list (the end of this list is marked with a -1)
WORK_OUT(25) List of attributes of basic graphic functions:
0: Polyline
1: Polymarker
2: Text
3: Filled area
4: None
WORK_OUT(34) ...End of attribute list
WORK_OUT(35) Color capability flag:
0: Colors are not representable
1: Are representable
WORK_OUT(36) Text rotation flag:
0: Text cannot be rotated
1: Can be rotated
WORK_OUT(37) Fill area capability flag:
0: Fill functions are not possible
1: Fill functions are possible
WORK_OUT(38) Cell array capability flag:
0: Unavailable
1: Available
WORK_OUT(39) Number of representable colors:
0: >32767
2: Monochrome
>2: Color
WORK_OUT(40) Number of locator devices:
1: Keyboard only
2: Keyboard and other
WORK_OUT(41) Number of valuator devices:
1: Keyboard only
2: Keyboard and other
WORK_OUT(42) Number of choice devices:
1: Function keys
2: Function key and keypad
WORK_OUT(43) Number of string devices:
1: Keyboard
WORK_OUT(44) Work station type:
0: Output only
1: Input only
2: In/output
3: Metafile
WORK_OUT(45) Minimum character width in pixels
WORK_OUT(46) Minimum character height in pixels
WORK_OUT(47) Maximum character width in pixels
WORK_OUT(48) Maximum character height in pixels
WORK_OUT(49) Minimum line width
WORK_OUT(50) Reserved, always 0
WORK_OUT(51) Maximum line width
WORK_OUT(52) Reserved, always 0
WORK_OUT(53) Minimum marker width
WORK_OUT(54) Minimum marker height
WORK_OUT(55) Maximum marker width
WORK_OUT(56) Maximum marker height
VDI WORK_OUT() Array Table+
VT-52 Escape Code Table
The Atari ST contains a VT-52 emulator which is modeled on a widely-used
terminal and by means of this, can be used for screens that do not contain
windows. The routines of this emulator can be called by the output of the
strings given in the folowing table by means of PRINT and these all start with
the ESCape code (CHR$(27)).
CHR$(27)+"A"; Cursor moves up one line (stops at the upper edge of the screen)
CHR$(27)+"B"; Cursor moves down one line (stops at the lower edge of the screen)
CHR$(27)+"C"; Cursor moves to the right (stops at the right-hand side)
CHR$(27)+"D"; Cursor moves to the left (stops at the left-hand side)
CHR$(27)+"E"; Clear screen (CLS)
CHR$(27)+"H"; Cursor moves to Home position (LOCATE 1,1)
CHR$(27)+"I"; Cursor moves up one line and scrolls at the upper edge
CHR$(27)+"J"; Erases from cursor to the end of page
CHR$(27)+"K"; Erases from cursor to the end of line
CHR$(27)+"L"; Inserts blank line at cursor position
CHR$(27)+"M"; Deletes line at cursor position (lines below scroll up)
CHR$(27)+"Y"+CHR$(y+32)+CHR$(x+32); Move cursor to x,y (LOCATE y,x)
CHR$(27)+"b"+CHR$(f); Selects f as text color
CHR$(27)+"c"+CHR$(f); Selects f as background color
CHR$(27)+"d"; Erase from top of page to cursor
CHR$(27)+"e"; Enable cursor
CHR$(27)+"f'; Disable cursor
CHR$(27)+"j"; Store cursor position
CHR$(27)+"k": Restore cursor to position stored with ESC j
CHR$(27)+"l"; Erase line in which the cursor lies
CHR$(27)+"o"; Erase line from beginning to cursor position
CHR$(27)+"p"; Switch on reverse video
CHR$(27)+"q"; Switch off reverse video
CHR$(27)+"v"; Switch on word wrap at line end
CHR$(27)+"w"; Switch off word wrap at line end
VT-52 Escape Code Table+
Scan Code Table
Code Description Info
$49 Page Up Milan
$4F End Milan
$50 Page Down Milan
? F11 Milan
? F12 Milan
Scan Code Table+
ASCII Table
ASCII+
Special ASCII Characters
0 NUL 1 SOH 2 STX 5 ETX
4 EOT 5 ENQ 6 ACK 7 BEL
8 BS 9 HT 10 LF 11 VT
12 FF 13 CR 14 SO 15 SI
16 DLE 17 DC1 18 DC2 19 DC3
20 DC4 21 NAK 22 SYN 23 ETB
24 CAN 25 EM 26 SUB 27 ESC
28 FS 29 GS 30 RS 31 US
127 DEL
ä Ä á à â À
132 142 160 133 131 182
ë é è ê É
137 130 138 136 144
ï í ì î
139 161 141 140
ö ö ó ò ô
148 153 162 149 147
ü ü ú ù û
129 154 163 151 150
Fill Pattern Table
vsf_interior()+, vsf_style()+
Line Style Table
vsl_type()+, vsl_ends()+
Error Codes
Editor Error Messages
Interpreter Error Codes (compiled code)
BIOS Error Codes (compiled code)
GEMDOS Error Codes (compiled code)
Bomb Error Codes (compiled code)
Note: The ones marked (compiled code) can also appear in compiled programs.
Memo: Error codes as defined by MiNT -> ERRNO.H
Bomb Error Codes+
BIOS() Error Codes+
GEMDOS() Error Codes+
Editor Error Messages
missing Select
missing Endselect
- Müll - Editor Fehler
missing Wend
missing Until
missing Loop
missing Next
missing While
- missing Repeat
missing Do
missing For
missing Endif
missing If
Exit without loop
missing Return
Procedure in loop
Procedure redefined
missing Endfunc
Function in loop
Function redefined
missing Procedure
Label redefined
Local without Procedure/Function
Local in loop
* Function redefined
Goto into/outof For-Next, Procedure or Function
Resume in For-Next
+ Resume without Procedure
Resume in Function
missing Function
Syntax Error
Line too long
Memo: Error message key:
- Never used by the editor
* Never used by the editor, duplicate error message
+ Incorrect error message, should be 'Resume without Procedure'
Interpreter Error Codes
0 Division by zero
1 Overflow
2 Not Integer -2147483648 .. 2147483647
3 Not Byte 0 .. 255
4 Not Word -32768 .. 32767
5 Square root only for positive numbers
6 Logarithm only for numbers greater than zero
7
8 Out of memory
9 Function or command not yet implemented
10 String too long max. 32767 characters
11 Not GFA-BASIC 3.5 program
12 Program too long memory full NEW
13 Not GFA-BASIC program file too short NEW
14 Array dimensioned twice
15 Array not dimensioned
16 Array index too large
17 Dim index too large
18 Wrong number of indices
19 Procedure not found
20 Label not found
21 On Open only "I"nput "O"utput "R"andom "A"ppend "U"pdate allowed
22 File already open
23 File # wrong
24 File not open
25 Input wrong not numeric
26 End of file reached
27 Too many points for Polyline/Polyfill/Polymark max. 128
28 Array must have one dimension
29 Number of points too large for array
30 Merge - Not an ASCII file
31 Merge - Line too long aborted
32 ==> Syntax error program aborted
33 Undefined label
34 Out of data
35 Data not numeric
36
37 Disk full
38 Command not allowed in direct mode
39 Program error Gosub not possible
40 Clear not allowed in For-Next loops or Procedures
41 Cont not possible
42 Parameter missing
43 Expression too complex
44 Undefined function
45 Too many parameters
46 Parameter wrong must be a number
47 Parameter wrong must be a string
48 Open "R" Record length wrong
49 Too many "R"-files (max 31)
50 Not an "R"-File
51
52 Fields larger than record length
53
54 GET/PUT Field string length changed
55 GET/PUT Record number wrong
56
57
58
59
60 Sprite String length wrong
61 Error while RESERVE
62 MENU error
63 RESERVE error
64 Pointer (*x) error
65 Array too small (<256)
66 No VAR-Array
67 ASIN/ACOS error
68 VAR-Type mismatch
69 ENDFUNC without RETURN
70
71 Index too large
72
73
74
75
76
77
78
79
80 Matrix operations for one and two dimensional arrays only
81 Matrices are of different order
82 Vector product not defined
83 Matrix product not defined
84 Scalar product not defined
85 Transposition for two dimensional arrays only
86 Non square matrix
87 Transposition not defined
88 FACT/COMBIN/VARIAT not defined
89
90 LOCAL error
91 FOR error
92 Resume (next) not possible Fatal, For or Local
93 Stack error
94
95
96
97
98 Command only available on STE
99
100 GFA BASIC Version 3.6 TT E © Copyright 1986-1991 GFA Systemtechnik GmbH
Memo: Blank entries produce 'Undefined error XXX'
Missing from the actual source code:
#72 -> _DATA=x -> Invalid DATA pointer
Never actually used: #55 #63
RUN!Lib adds error message #99:
'Redimensionierung nur mit|gleicher Anzahl von Dimensionen'
BIOS Error Codes
-1 General error
-2 Drive not ready
-3 Unknown command
-4 CRC error disk checksum wrong
-5 Bad request
-6 Seek error track not found
-7 Unknown media boot sector wrong
-8 Sector not found
-9 Out of paper
-10 Write fault
-11 Read fault
-12 General error 12
-13 Write protected
-14 Media change detected
-15 Unknown device
-16 Bad sector (verify)
-17 Insert other disk (request)
-18
-19
-20
-21
-22
-23
-24
-25
-26
-27
-28
-29
-30
-31
Memo: Blank entries produce 'Undefined error -XXX'
BIOS() Error Codes+
GEMDOS Error Codes
-32 Invalid function number
-33 File not found
-34 Path not found
-35 Too many open files
-36 Access denied
-37 Invalid handle
-38
-39 Out of memory
-40 Invalid memory block address
-41
-42
-43
-44
-45
-46 Invalid drive specification
-47
-48
-49 No more files
-50
-51
-52
-53
-54
-55
-56
-57
-58
-59
-60
-61
-62
-63
-64 GEMDOS range error seek wrong
-65 GEMDOS internal error
-66 Invalid executable file format
-67 Memory block growth failure
-68
-69
-70
-71
-72
-73
-74
-75
-76
-77
-78
-79
-80
-81
-82
-83
-84
-85
-86
-87
-88
-89
-90
-91
-92
-93
-94
-95
-96
-97
-98
-99
-100
-101
-102
-103
-104
-105
-106
-107
-108
-109
-110
-111
-112
-113
-114
-115
-116
-117
-118
-119
-120
-121
-122
-123
-124
-125
-126
-127
Memo: Blank entries produce 'Undefined error -XXX'
GEMDOS() Error Codes+
Bomb Error Codes
101
102 2 bombs - bus error Peek or Poke possibly wrong
103 3 bombs - address error Odd word address! Possibly at Dpoke, Dpeek, Lpoke or Lpeek
104 4 bombs - illegal instruction executed in machine code
105 5 bombs - divide by zero in 68000 Machine Code
106 6 bombs - CHK exception 68000 interrupted by CHK
107 7 bombs - TRAPV exception 68000 interrupted by TRAPV
108 8 bombs - privilege violation by 68000 Machine Code
109 9 bombs - trace exception
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
Memo: Blank entries produce 'Undefined error XXX'
Bomb Error Codes+
GFA-Basic Compiler/Linker Manual
Contents
Introduction
Getting Started
The Function of the Compiler
Commands Not Accepted by the Compiler
Interpreter - Compiler Differences
Using the Menu Shell Program
The File Menu
The Options Menu
The Sets Menu
The Shell-Listing
Using with DOS Shells
Program Return Value
The Compiler
Array Index Checking
Integer Overflow
The Compiler Options
Overview of Compiler Options
Integer Division
Integer Multiplication
Reserving Memory Space
Return Value of a Function
RC_INTERSECT() Parameters
Externally Linked Routines
Checking the BREAK keys, EVERY and AFTER
Interrupt Routines
SELECT-CASE Parameter
SELECT-CASE Optimisation
Error Messages
Error Numbers Instead of Bombs
Subroutines
ENDFUNC Generation
Register Saving
FOR-NEXT Loop Checking
Integer Rounding
The Linker
The Linker Options
Overview of Linker Options
Symbol Table
Library Selection
Linking Object Files
Do not Link TEST.O
Run in TT Ram
Including C Functions
Linking C Functions without C Libraries
Linking with C Libraries
Some Peculiarities
Linker Error Messages
Programming Accessories
The Structure of Accessories
Programming Example
Longer Programming Examples
Program Optimization
Additional Information
Simple Additions
Multiplication
Division
More Complicated Calculations
Loop Commands
Character Strings
Local and Global Variables
Technical Support
Author/Publisher
This manual is suitable for GFA-Basic Compiler versions 3.0 upwards. All
references to GFA-Basic 3.0 refer to all releases of version 3. References to
GFA-Basic 3.6, ie version 3, release 6, are specific to 3.6 and upwards. This
was last updated to include the new features of GFA-Basic Compiler 3.6. See the
README file on disk for any additional information.
Author/Publisher
ATARI ST
GFA
BASIC
Version 3
Compiler/Linker
/-------------------\
| GFA |
|-------------------|
| SOFTWARE |
| TECHNOLOGIES INC. |
\-------------------/
No part of this publication may be copied, transmitted or stored in a retrieval
system or reproduced in any way including but not limited to photography,
photocopy, magnetic or other recording means, without prior permission from the
publishers, with the exception of material entered and executed on a computer
for the readers own use.
Every care has been taken in the writing and presentation of this book but no
responsibility is assumed by the author or publishers for any errrs or
omissions contained herein.
ISBN 1 85552 002 8
First Printed July 1989, reprints: May 1991
COPYRIGHT © GFA Software Technologies, Inc.
27 Congress St.
Salem, MA 01970
Program author Frank Ostrowski
Manual author Gottfried P. Engels
English translation Gunter Minnerup
Typeset/layout Melanie Player
Licence
Compiled GFA BASIC programs may be distributed without licence payments to GFA,
as long as it is mentioned in the program, on the disk or in the manual that
the software was written in GFA-Basic 3.0x.
This book was edited, compiled and typset on an Atari ST and an Atari SLM804
laser printer.
Introduction
Getting Started
This section describes how to convert a GFA-Basic 3.0 source listing into an
executable program, and is intended for those readers who want to try out the
compiler quickly.
Before you continue you should take a backup copy of your original disk.
To generate a program you need the following files:
GFA_BCOM.PRG GFA-Basic 3.0 Compiler
GL.PRG GFA-Basic 3.0 Linker
GFA3BLIB Linker library
GFA3BLIB.NDX Linker library index file
MENU.PRG Menu program for the GFA system
*.GFA GFA-Basic 3.0 source files
GFABASIC.PRG GFA-Basic 3.0 Interpreter
RCS2.PRG Resource Construction Set required if your program will
support RCS files
To quickly compile one of the GFA-Basic source files (*.GFA) into a program
which can run without the Interpreter, do the following:
1) Start the MENU.PRG program.
2) In the File menu choose the entry entitled Select.
3) In the File Select box specify the GFA file to be compiled.
4) Press the F10 key. The source program will then be compiled and linked.
5) The compiled and linked code is now in the file called TEST.PRG on the
diskette. You can execute it either by using the TEST entry in the File
menu, or by exiting the menu program and running TEST.PRG
The Function of the Compiler
The Computer cannot understand BASIC commands directly. A BASIC program,
therefore needs to be translated into a language the computer understands. The
Interpreter reads the program line by line, translates each line into machine
code and then executes the machine code.
This method has advantages and disadvantages. The two most important
disadvantages are:
1) The program needs the Interpreter to run.
2) Since each BASIC command must be first translated before it can be executed,
running programs can be relatively slow.
The Compiler is a program which converts all the BASIC source code into machine
code without executing the resulting code. The compiled program can then be
saved.
The Compiler, therefore, assembles an executable program from the individual
BASIC commands. This program then runs independently of the Interpreter and
Compiler. Program execution is fast because the commands are already in
translated format, ie machine code.
The GFA-Basic Compiler described in this book can only compile programs written
in GFA-Basic version 3.x. These programs must be stored using the SAVE command
in the GFA-Basic 3.0 Interpreter. The Compiler will not work with any program
stored using the SAVE,A command, nor will it compile GFA-Basic version 2.0
programs, or any other versions of BASIC.
Earlier versions of the GFA-Basic interpreter may be incompatible with later
versions of the GFA-Basic compiler. If in doubt, use the latest versions.
Commands Not Accepted by the Compiler
There are some commands which the Compiler will not accept; for example, the
commands such as TRON, TROFF, and TRACE$, commands which affect the output
listing.
The DEFLIST command is ignored by the Compiler, and the DUMP command will not
be accepted, since the compiled program does not recognize variables by name.
As you cannot load, save, or list a compiled program, the LOAD, SAVE, PSAVE,
LIST, and LLIST commands cannot be executed from a compiled program.
Memo: The command '==>' is also not accepted by the compiler.
Interpreter - Compiler Differences
The CHAIN command works differently depending on whether it is interpreted or
compiled. In a compiled program the specified name is given to the AES function
SHEL_WRITE(), and the program which is running is terminated with a QUIT
command. The program called by the CHAIN command is then started.
The called program does not therefore take up any more space.
A command line up to 128 bytes can be passed to the chained program. The
command line should be placed at BASEPAGE+128.
At least 32500 bytes must be free for a compiled program before calling the
FILESELECT command.
Memo: STOP returns error code -128.
The editor always intializes the AES and the VDI, however the compiler
will only do this if some AES or VDI call is made. It's possible the
ID returned from APPL_INIT() is invalid, or the handle from V~H is
invalid. Simply making an AES or VDI call will force the compiler to
link the initialization code.
Also ~INP(2) will appear to fail under MiNT if the AES is not
initialized.
The menu program enables programs to be called up easily, and parameters to be
passed to these programs. When a program executed from the menu program has
finished, the user is returned to the menu program.
The menu shell program for the GFA-Basic 3.0 Compiler resides on the
distribution disk, and enables you to call the Interpreter, Compiler, Linker,
and Resource Construction Set, implement Compiler and Linker options.
The first entry in the drop down File menu is Select. When this entry is
chosen, a File Select box appears for you to enter the GFA file on which you
want to work. As with all the other commands, you can also make this selection
using keys; the Select menu entry can also be activated up using
Control and S.
The Compiler menu entry sends the file selected to the Compiler, which will
create an object file called TEST.O. The Compiler can also be activated
using Control and C.
The next menu entry can be used to call the Interpreter. The file assigned is
the one given in the Select entry. The Interpreter function can also be
activated using Control and I.
The Linker entry can be selected using Control and L, to create
an executable program called TEST.PRG from the file TEST.O created by the
Compiler.
The RCS entry will call the RCS2.PRG. An alternative program name can
be placed in the variable gfarcs$. The RCS function can also be
activated by Control and R.
Selecting the Test entry, or Control and T, will initiate the
execution of the program TEST.PRG.
The Execute entry. The Execute function can also be activated by
Control and X. An external program can be run from this command. The
file selection will appear, requesting you to enter the program to be executed.
The F10 key, calls the Compiler and then the Linker, and is thus a short cut
for Control and C and then Control and L.
The next drop down menu gives the Compiler and Linker options. These are
described fully in sections 2.0 and 3.0.
The options are listed in the following table, with their respective menu entry
and key combination used to control the option:
Entry Keys to activate Option
Interrupts Alternate+I I+
Select Alternate+S S& or S< or both
Functions Alternate+F F<
Procedures Alternate+P P>
IntDiv Alternate+/ %3
IntMul Alternate+* *&
Error Alternate+E E$
Memory Alternate+M mxxxx
DebugSym Alternate+D -s
TT Alternate+T T
You can activate or suspend the options by using the keys or by selecting the
menu entry. With the Memory option you are asked for the amount of storage
space required by the program.
All these options, with the exception of DebugSym, are concerned with the
Compiler. The table entry for Select shows several possibilities of two
options. Selecting the menu entry once specifies the first option, selecting
the entry a second time specifies the second option, selecting the entry a
third time specifies both options.
The selected options are displayed on the top left of the screen. While the
Compiler is active the Basic line number being compiled is displayed in the
drop down menu list.
In the last menu, entitled Sets, certain parameters can be set. These
parameters are described below.
The G3WAIT parameter determines whether or not, during compilation and
linking, a key is to be pressed before a file is opened. Such files could be
for example, the program being compiled, the object file, GFA3BLIB.NDX,
GFA3BLIB and the PRG file.
The purpose of this option is to allow you to change the disk before pressing
the key to continue. This is essential if you have only one disk drive, and the
necessary files reside on more than one disk.
After selecting this option, all the parameters in the Sets menu are displayed
on the screen. From this display you can see whether G3WAIT has been turned on
or off.
You can also see from this display whether the next parameter on the menu,
G3MOVE, is on or off. If G3MOVE is on, G3MOVE=ON is displayed on the
screen.
Enabling G3MOVE directs the Compiler to manage the available storage space
economically during compilation. To begin the task the source code is loaded,
and compilation started. The compiled code is also held in store until it is
moved out.
In the case where you have a very large program and only a small amount of free
space, the source code and object program together may be too large to fit
completely in memory.
By activating G3MOVE, as each procedure is compiled the source code is moved
out of memory. Naturally, this packing of memory during compilation is time
consuming, so G3MOVE should only be enabled when necessary.
If you only select the entry G3OBJ, you can change the default name of
the object file (normally TEST.O). Similarly, using G3PRG you can
change the default name of the compiled and linked object program (normally
TEST.PRG).
G3LIB enables you to change the name of the library normally called
GFA3BLIB. These options can, of course, be used not only for naming the
individual files, but also for establishing the path to the files.
The parameters can also be called by typing the letter following G3.
PRG=GFA, also selected with F2 key. In this mode the file name
given to the compiled code is derived from the .GFA file (rather than be called
TEST.PRG). By selecting F2 (or by setting auto& in the MENU.PRG to 1), a GFA
file can be quickly selected and compiled with the sequence:
F2
CTRL S (entering name in File Select box)
F10
C Object, also selected with C key. With this option you can
enter the names of the object files to be linked to the compiled code (Turbo C,
DR C, or assembler).
Therefore:
W or w for G3WAIT
M or m for G3MOVE
O or o for G3OBJ
P or p for G3PRG
L or l for G3LIB
F2 for PRG=GFA
C for C Object
Pressing the Help key clears the screen and displays the current state
of the Sets menu parameter entries.
Pressing the Undo key clears the screen but does not display the
parameter values.
The Shell-Listing
You can find a listing of the shell on your disk. In the listing you can set
the parameters described in the previous section. You will find the following
lines in the first part of the listing:
gfaints$="GFABASIC.PRG"
gfacom$="GFA_BCOM.PRG"
gfalnk$="GL.PRG"
These define the names of the interpreter, compiler, and linker and can, of
course, be altered.
The parameters G3OBJ, G3PRG, and G3LIB take their default values from the
following lines:
tobj$="G3OBJ=TEST.O"
tprg$="G3PRG=TEST.PRG"
tlib$="G3LIB=GFA3BLIB"
The parameters G3WAIT and G3MOVE get their values from these lines in the shell
listing:
t_wait$="G3WAIT=ON"
t_move$="G3MOVE=ON"
You can enable these options by deleting the underscore character in the
variable name.
The lines:
coi&=0 ! No I
cos&=3 ! S& and S<
cof&=0 ! F<
cod&=0 ! No %3
com&=0 ! No *&
coe&=0 ! No E
cop&=0 ! No P>
dbsym&=0 ! No -s
auto&=0 ! not xxx.prg from xxx.gfa
define the the default compiler and linker options.
The line INLINE irq%,&HD6 contains an interrupt routine which during
compilation displays the number of the currently compiled line. Should you wish
to save the shell as a LST file, the INLINE section needs to be saved
separately (go to INLINE line, press Help and save. See a full explanation of
INLINE in the Basic Interpreter manual).
The following line:
{irq%+2}=V:a&
declares a 16-bit variable to be displayed in the interrupt.
The lines:
BYTE{irq%+6}=32+35
BYTE{irq%+7}=32+10
define column 35 as the X position for the text output of the interrupt routine
and column 10 as the Y position.
When examining the shell program on the disk, you may notice that no redraw
routine has been implemented. This makes the program shorter and saves memory
space (shells ought to be small). The primary reason for this, however, is to
keep visible the screen contents left behind by a program which has just been
run by the menu item "Test".
Using with DOS Shells
The compiler and linker may be controlled not only by the Shell, but also by a
DOS shell (command line interpreter). This section describes the use of a DOS
shell or similar interface.
The compiler parameters can be passed in the same form as they appear in the
shells screen display, i.e.
gfa_bcom name S& %3
Much the same applies to the linker parameters. Linking with generation of a
symbol table is achieved by
gl -s
To include a file named c_tst,
gl c_tst
may be entered.
In this example, test.o, c_tst.o and gfa3blib are linked. The # character in
the parameter list prevents the file test.o being linked.
The line
gl # c c_tst
would link the files c.o, c_tst.o and gfa3blib, but not test.o. In order to use
a library other than gfa3blib, you can enter its name prefixed with a plus
sign. Thus
gl +new_lib
ensures that test.o and new_lib are linked. The linker considers all parameters
which are not prefixed by a plus sign and are not -s or # as the names of
object files to be linked.
Memo: These do not work quite right from the command line:
$I+ !only works if it is the very first command
$B+ !always fails
Input parameters are as follows:
Compiler:
via command line: *.GFA source, $commands
via environment variables: G3OBJ=, G3WAIT=, G3MOVE=
Linker:
via command line: #, *.o, +library, -s, -t
via environment variables: G3OBJ=, G3PRG=, G3LIB=, G3WAIT=
Program Return Value
After every program call, the return value is ouput on the screen. A 0 return
is OK, a negative number denotes an error (eg File not found), and a positive
number indicates other error conditions. Thus for example, the compiler could
return the number of uncompiled instructions and the linker the number of
undefined symbols.
Memo: Error codes are as follows:
Compiler values:
<0 = Gemdos error code unless otherwise noted
-1 = Disk full/Structure errors detected
-8 = Out of memory
-100 = Bad verion or file ID
0 = Ok
>0 = Total number of errors detected
Linker values:
<0 = Gemdos error code
-1 = Disk full
0 = Ok
>0 = Total number of symbol errors detected
Note: The return value appears to be a signed byte under some versions of MiNT.
This is a bug in MiNT. For example: A missing file returns 223, thus 223
- 256 = -33 See 'Linker Error Messages' for more information.
The Compiler
Array Index Checking
If you wish to use arrays in your program, these have to be dimensioned with
DIM. This involves specifying the size of the largest array index. During
execution of the program, the GFA-BASIC Interpreter will check your array index
value for legality. If found too high, error 16 (Array index too large) is
reported. This also applies to the compiler for GFA-Basic 2.0.
There is no such array index checking in programs generated with the GFA-Basic
3.0 compiler. If an illegal large value appears for the array index, there is
no error message. The absence of this check makes programs shorter and quicker.
The following example shows the effect of there being no array index checking.
The program writes the numbers 0 to 5 to the screen. The interpreter generates
the error message "Array index too large". The error message is triggered
because the dimensioning has limited the maximum index size to 5, yet the FOR
loop attempts to address an array element x(6).
DIM x(5)
FOR i=0 TO 6
x(i)=i
PRINT x(i)
NEXT i
When you compile and run this program, it writes the numbers from 0 to 6 to the
screen and no error message appears. The program acts as if the array x() in
the first line had been dimensioned to a sufficient size. You cannot tell from
the behaviour of the compiled program that it contains a serious mistake.
The example raises the question of what the compiled program would do if the
array index were too large. The DIM command reserves memory space for the
specified number of array elements. Without the programmer noticing this, the
array index is used in order to calculate the addresses of the array elements.
Compiled programs will do this even where the array index is too large. The
address calculated is outside the memory area reserved for the array. If the
array index is too large therefore, data outside the area reserved for the
array will be overwritten.
Normally the RAM space thus overwritten will contain data which is essential
for the error-free execution of the remaining program. If this data is
overwritten, the program can generate errors or even crash.
So far we have described the disadvantages of the absence of array index
checking. An excessively large index, however, will not figure in a finished
program since the programmer will have hopefully eliminated such mistakes. The
interpreter used for program development has supported him in this by its array
index checking.
Index checking is therefore unnecessary in the compiled program. It requires
time and space. The GFA-Basic 3.0 compiler is about four to five times as fast
as the Basic 2.0 compiler in simple operations with array elements (allocation,
addition of two array elements etc) and ten to twelve times as fast as the
Basic 3.0 interpreter.
Integer Overflow
When changing integer variables, the GFA BASIC interpreter checks that the
value of the variable lies within the range for this variable type. The legal
ranges for the three types of integer variables are:
Type Postfix Minimum Maximum
Byte | 0 255
Word & -32768 32767
Long % -2147483648 2147483647
When the legal range is exceeded, error numbers (depending on the type of
variable affected) 2, 3 or 4 are triggered (Number not integer, byte, or word).
Such an error is known as integer overflow.
A program generated with the GFA-Basic 3.0 compiler will not always be checked
for integer overflow. Such a check is superfluous in an error-free program and
only requires time and space. It is only sensible during program development
with the interpreter.
The program:
x&=10000
y&=4*x&
PRINT y&
generates the error message "Number not word" in the interpreter, whereas the
compiled program writes -25536 to the screen with no error message.
From the first two lines of the program, the compiler will generate the
following code (without the comments, of course):
move.w #$2710,-$8000(a5) ;$2710 is 10000 decimal
;$8000(a5) is the address of x&,
;the instruction therefore equals
;the line x&=10000.
move.w -$8000(a5),d0 ;x& is written into data
;register 0.
asl.w #$2,d0 ;The multiplication with a power
;of 2 (4 in this case) is
;executed with a fast bit shifting
;command.
move.w d0,-$7ffe(a5) ;-$7ffe(a5) is the address of
;y&. Thus result of the
;multiplication is assigned to
;y&.
The advantage of the non-existing integer overflow check results in the high
speed of the code. A program with a FOR loop and simple additions and
subtractions of integer variables is faster than in the interpreter by a factor
of 26.
The Compiler Options
Overview of Compiler Options
This section will first briefly describe which compiler options are available
and how you can set them. After that, each option is described in a section of
its own.
$B+ ERROR messages instead of bombs.
$C+ C:()/CALL should save/restore registers A3 to A6 on the stack.
$C- C:()/CALL shouldn't save/restore registers A3 to A6 on the stack.
$E$ ERROR messages displayed as text.
$E# ERROR messages displayed as numbers.
$F% RETURN value of a FUNCTION will be any integer type.
$F> Enable ENDFUNC checking.
$F< Disable ENDFUNC checking.
$I+ Enable interrupt routines.
$I- Disable interrupt routines.
$M xxxx The program should only use xxxx bytes of ram.
$N+ Enable FOR-NEXT range checking.
$N- Disable FOR-NEXT range checking.
$P> Do not optimize subroutines that have no parameters/LOCALs.
$P< Optimize subroutines that have no parameters/LOCALs.
$RC& RC_INTERSECT() parameters treated as 2 byte values.
$RC% RC_INTERSECT() parameters treated as 4 byte values.
$S> Optimise SELECT-CASE for execution time.
$S< Optimise SELECT-CASE for program length.
$S| Treat SELECT-CASE parameters as 1 byte values.
$S& Treat SELECT-CASE parameters as 2 byte values.
$S% Treat SELECT-CASE parameters as 4 byte values.
$U Check EVERY/AFTER and Break Keys once.
$U+ Enable EVERY/AFTER and Break Keys after each instruction.
$U- Disable EVERY/AFTER and Break Keys checking.
$X name The routine name to be taken from a linked file.
$*& Longword multiplication with muls.
$*% Longword multiplication without muls.
$%0 Variables are converted to floating point and then divided.
$%3 Always execute integer division as an integer division.
$%6 Round integers up.
Memo: These commands must be placed in the source code itself and do
not always work as expected via the command line:
$B+ !always fails
$F% !not supported
$I+ !only works if its the very first command
$Ux !locks up the compiler!
$X !not supported
Integer Division
The compiler options $%0 and $%3 influence the division of integer variables
(longwords). If the $%0 option is active, the variables to be divided are made
into floating point variables and then divided. The result of such a division
is a floating point variable.
If the $%3 option is enabled, the two integer variables are not made into
floating point variables. The result of the integer division will then be
interpreted as an integer value.
Example: Once compiled, the program
$%0
x%=5
y%=2
PRINT x%/y%
produces the output 2.5. The fact that the digit behind the decimal point was
output indicates that x% and y% have been converted into floating point numbers
before the division took place. Compiler option $%3 will produce 2 as a result,
since x% and y% are interpreted as integers without decimal points and
therefore only an integer division is carried out. This option has no effect in
the interpreter, of course, where you will get 2.5 in both cases.
The code generated by the two options will illustrate the difference once
again.
The lines
$%0
a%=x%/y%/z%
will generate the code:
move.l -$7ffc(a5),d0
bsr FITOF
move.l d0,-(a7)
move.w d2,-(a7)
move.w d1,-(a7)
move.l -$7ff8(a5),d0
bsr FITOF
move.w (a7)+,d4
move.w (a7)+,d5
move.l (a7)+,d3
bsr FXDIV
move.l d0,-(a7)
move.w d2,-(a7)
move.w d1,-(a7)
move.l -$7ff4(a5),d0
bsr FITOF
move.w (a7)+,d4
move.w (a7)+,d5
move.l (a7)+,d3
bsr FXDIV
bsr FFTOI
move.l d0,-$8000(a5)
In this listing, you will notice that the subroutine FLTOF (integer to float),
which converts the integers into floating point numbers, is called three times.
Since the result is returned to an integer variable, the routine FFTOI (float
to integer) is also required. The division is carried out with (FXDIV), a
division routine producing floating point results.
By contrast, the program
$%3
a%=x%/y%/z%
generates the assembler listing
move.l -$7ffc(a5),d0
move.l -$7ff8(a5),d1
bsr LDIV
move.l -$7ff4(a5),d0
bsr LDIV
move.l d0,-$8000
This short listing simply calls a fairly straight forward subroutine to divide
two longwords (LDIV) and can therefore be processed much faster than under the
$%0 option. The difference in speed is of a factor around 10 to 11.
If two integer variables are divided and the result is returned to an integer
variable without any further processing, the compiler option %0 is of no
consequence. In that case, only pure integer arithmetic is being used.
In the event of two-byte variables being defined, the Motorola 68000
processor's div command is used instead of the LDIV routine (see the section on
division in the Program Optimisation chapter).
Memo: $%0 is the default.
Integer Multiplication
The $*& option influences the multiplication of two integer variables, of which
at least one is a four-byte variable. Normally in such cases a subroutine to
multiply two four-byte variables is called. If the $*& option is enabled,
however, the Motorola 68000 processor's muls instruction is used instead.
This has two consequences:
1. Program execution is speeded up.
2. The muls instruction multiplies two two-byte values and produces a four-byte
value as the result. Therefore, if the four-byte variables to be multiplied
contain values in excess of the range of a two-byte variable, the use of
only two bytes will generate a different result from when option $*& is not
enabled.
Example: The lines
$*&
b%=40000
c%=10
a%=b%*c%
PRINT a%
will produce the expected result of 400000 in the interpreter. The compiled
program, however, outputs -255360 because only two bytes of b% have been used,
and these two bytes cannot represent as large a value as 40000.
The difference is once again illustrated by the code generated from the line
a%=b%*c% with and without option $*&:
with $*& with $*%, without $*&
move.l -$7ff8(a5),d0 move.l -$7ff8(a5),d0
move.l -$7ffc(a5),d1 move.l -$7ffc(a5),d1
muls d1,d0 bsr LMUL
move.l d0,-$8000(a5) move.l d0,-$8000(a5)
The default setting is option *% which leads to LMUL being used.
Memo: $*% is the default.
Reserving Memory Space
The compiler option $Mx is used to generate a program which will simply reserve
x bytes for itself. Normally a program generated with the GFA-Basic 3.0
compiler claims all available memory space (minus 16 kb) for itself.
The instruction RESERVE can be used to force a program to claim only part of
the free memory, but this has an effect different from the $mx option. A
program beginning with RESERVE 25600, for example, will first claim all free
memory when run. The GFA BASIC instruction RESERVE will only then be executed
and release some of the reserved space again.
By contrast, the compiler option $m25600 will ensure that not all free memory,
but only 25600 bytes (if available) will be used by the program. This compiler
option must be used in accessories which may only use part of the free memory.
You can find an example in the chapter on accessories.
Memo: The space between the option and the number is optional.
Example: $m 2048
The compiler does not actually accept values in the range of 0 to 999.
Any value in this range is automatically replaced with 1000.
Odd values are rounded down (made even): $M65535 -> allocates 65534 kb
Important: If the exact value cannot be allocated (ram to low) it
gives the application all the available ram minus 16384 bytes. This
could cause a program to behave strangely or crash, since the program
doesn't know it was given a smaller amount than requested.
This situation can be detected with the following code:
IF MALLOC(TRUE)<=16384
PRINT "$M failed, program terminated!"
EDIT
ENDIF
Under MiNT memory is rounded to an 8kb boundary, so you might as well
request a size pre-rounded up, this way your program can use the ram
that would normally be wasted.
Return Value of a Function
The $F% option must be entered as the first line of a function to have an
effect. It instructs the compiler to output the return value of the function
as an integer. The default output is a floating point value.
This default behavior is probably some throw back to the classic days of BASIC
where everything was floating point. Unless you care about it yourself at each
and every function, you will always get the slower floating point.
$F% does not specifically imply long% type only. The compiler actually checks
the variable at 'RETURN x' and adjusts the code automatically based on the
variable type. In other words the compiler will auto cast it to the correct
integer type. String functions are handled automatically and $F% is ignored.
To be more precise, the '%' (percent sign) means return any integer type, it
does not mean return only long type. The compiler does not report syntax
errors within compiler commands, it simply ignores them.
Not only does this speed up your functions but it reduces the code size of
each function. Option $F% eliminates two library calls, BSR FITOF (integer to
float) and BSR FFTOI (float to integer). Both of these add several lines of
needless assembler overhead to each function call made! Quite literally if
$F% is missing the function converts the output to floating point and then the
assignment to some variable converts it back. The effect of this at each call
of a function is, integer -> float -> integer, which is for sure not very
optimal.
Memo: The compiler requires this command to be on the very 1st line of the
funcition or it has no effect at all. Example:
a%=@test !BSR FFTOI (flt to int)
PRINT a%
EDIT
FUNCTION test
$F% !absolutely has to be the very 1st line!
RETURN 1.23456789 !BSR FITOF (int to flt)
ENDFUNC
A space between '$' and 'F%' will cause it to fail. Example:
$ F% !compiler fails to see the option
According to some French manuals $F| and $F& are valid options.
These do not work, in fact it will result in a float being returned!
I've also seen $F$ and $F! in other peoples source listings and they
do not work.
To be precise, no where in the compiler source code is a check for
$F!, $F!, $F&, or $F$. All of these produce slower floating point
output. The compiler has exactly one check for '$F%' only. Any books
or manuals that state otherwise are incorrect.
DEFFN functions always return floating point values.
They must be recoded into multi-line functions to speed them up.
RC_INTERSECT() Parameters
The compiler options $RC& and $RC% are used to control the interpretation of
the RC_INTERSECT() parameters. By default, these parameters are converted by
the compiler into four-byte parameters.
In many cases, however, the range of two-byte integer variables is quite
sufficient for these parameters. Using option $RC&, you can make the compiler
interpret the RC_INTERSECT() parameters as two-byte parameters.
This option is important only exceptionally and in special cases. The
RC_INTERSECT() function is principally intended for calculating the size of
overlapping rectangles within a redraw.
For a redraw, only two-byte parameters are required since coordinates can only
be two bytes large under GEM. But the speed gain through using the $RC& option
can be neglected here because, on the one hand, other instructions (such as the
screen section renewal) within a redraw take more time than the window overlap
calculation, and on the other, the RC_INTERSECT() function will only be called
a few times in such a case.
However, the $RC& option does save some memory space when using 16 bit
variables. Another application can be found in the context of hidden line
calculations.
Memo: $RC% is the default.
Externally Linked Routines
The $X name must be the first line in a procedure or function. In this event,
the contents of the procedure or function is not compiled, but a message is
left for the linker to instruct it to take the routine "name" from an object
file to be linked in.
The use of this option is explained in the section
"Linking C Functions without C Libraries".
** The manual ends here, the following is what I found to be true. **
Parameters are always passed on the stack.
Only words and longs will be passed.
Floats are a special case and passed as two longs.
In order to use floats in assembler one would need to know GFA's internal
float format.
Bytes and boolean values are cast into words.
Strings and VAR parameters are cast as long pointers.
In the case of strings or arrays, the address of the descriptor is passed.
The assembler routine receives the parameters in the reverse order starting at
offset 4(sp).
Example call:
@test(long1%,long2%,long3%)
In assembler:
move.l 4(sp),d3 ;long3%
move.l 8(sp),d2 ;long2%
move.l 12(sp),d1 ;long1%
Your routines should always end with an RTS instruction.
The assembler routine should not alter the stack, because GFA itself removes
the parameters from the stack after the call for you. If you do need to alter
the stack, be sure to save and restore it.
Also registers a3 to a6 should not be altered. However you can use these so
long as you save and restore them.
When coding functions, d0 is always used to return a long value.
$F% is automatically implied.
Memo: The space between the option and the name can be left out.
Example: $Xname
A space between '$' and 'X' will cause it to fail.
Example: $ Xname !compiler fails to see the option
$X contains a serious bug: It does not fix the stack correctly after
the call in all cases.
It only works correctly for PROCEDURES that do not use VAR.
With VAR it calculates too small of a stack correction.
With FUNCTION it does no stack correction at all!
The problem is the parameters are actually left on the stack.
Thus each call eats stack space, until eventually the stack collides with
GFA's internal structures.
Devpac v3.1 can be used to build DRI format object files.
Registers a3 to a7 must remain unchanged.
Checking the BREAK keys, EVERY and AFTER
During program execution the GFA-Basic interpreter normally offers the ability
to abort the program by simultaneously pressing the Control, Left Shift, and
Alternate keys.
This ability does not exist as default in a compiled program. However, using
the $Ux compiler option you can enable it. To enable any scanning of the stop
keys at all, the I+ option must be active.
The scanning of the break keys is linked to a test for the EVERY and AFTER
conditions. Also, a RESUME/NEXT is prepared. Therefore all instructions which
could generate errors should be enclosed by $u (or, to put it more accurately,
$u safeguards the program counter PC, the stack pointer SP and the BASIC stack
pointer A3. Hence no DIMs, ERASEs or GOSUBs, FNs must be executed between the
$u and the error).
The x parameter can have the following values, with the possibilities indicated
here:
$U inserts a check
$U+ inserts a check at each instruction generating code
$U- disables the checking.
The following program cannot be interrupted by pressing the three stop keys in
its first loop, but these keys are enabled (after pressing the right mouse
button) in the second loop.
$U-
REPEAT
UNTlL MOUSEK
DO
$U
LOOP
The DO LOOP cannot be aborted if the listing is changed to
$U+
DO
LOOP
because the checking only takes place after LOOP and not after DO, as DO is not
a code-generating instruction.
If you wish to use the RESUME command you must have U+ switched on.
Memo: $U- is the default.
Interrupt Routines
The $I+ and $I- compiler options can be used to enable or disable the interrupt
routines for:
- EVERY and AFTER
- the stop/break keys (Control-Shift-Alternate)
- the ASCII code entry via Alternate-number
- the function key configuration (KEYPAD and KEYDEF)
- the enabling of the mouse pointer in the event of disk errors
(eg. Please insert Disk B in Drive A)
- Error messages instead of bombs
Using these options lengthens the compiled code.
Memo: $I- is the default.
$B+ is also linked to $I+ (missing from the original manual)
SELECT-CASE Parameter
Using the $S& option, you can make the SELECT-CASE instruction treat all
following expressions as two-byte parameters. The default $S% option makes
SELECT and CASE treat all values as four-byte parameters.
A look at the resulting code illustrates the differences. The listing
SELECT a%
CASE 1
case_1:
INC a%
CASE 2
case_2:
INC a%
DEFAULT
default:
INC a%
ENDSELECT
endsel:
INC a%
contains markers to make the symbolically disassembled code more transparent.
Each marker is followed by an instruction (INC a%) as a placemarker for the
individual instruction blocks.
Use of the $S& option results in the following code:
move.l -$8000(a5),d0
bra.s L1
_CASE_1: addq.l #$1,-$8000(a5)
bra.s _ENDSEL
_CASE_2: addq.l #$1,-$8000(a5)
bra.s _ENDSEL
_DEFAULT: addq.l #$1,-$8000(a5)
bra.s _ENDSEL
L1: cmpi.w #$2,d0 ;CASE evaluation
beq.s _CASE_1
cmpi.w #$2,d0
beq.s _CASE_2
bra.s _DEFAULT
_ENDSEL addq.l #$1,-$8000(a5)
The L1 label is not generated here.
The listing first places the four-byte value a% into d0. Then the routine to
branch to the individual CASE instruction blocks is called. This is marked in
the listing by the comment "CASE evaluation". There cmpi.w (compare integer
words) is used to compare, for wordlength only, the values after CASE with the
contents of d0.
If these values are found to be identical, beq.s (branch equal) jumps to the
block after the appropriate CASE. This block ends with the jump to the line
behind the SELECT-ENDSELECT block. Here the jump is made using bra.s _ENDSEL.
If none of the values after CASE fits, the DEFAULT block is called. Without the
S& option the comparisons made here would be for longword length.
Memo: $S% is the default.
Whilst viewing a diss-assembly of the GFA Compiler I discovered a check
for the $S| command. However, my tests seem to indicate that it's
identical to the $S& command. The reason is simple, there is no size or
speed advantage to byte comparisons on the 68000. The $S| command seems
to have been added just for completeness.
SELECT-CASE Optimisation
The $S> and $S< options determine the optimising criterion for the SELECT-CASE
instructions. $S> leads to optimisation by execution time, $S< according to
program length.
You have seen in the last section how, at the end of the program blocks after
the CASE and the DEFAULT instructions, bra.s branches into the line following
ENDSELECT. However, if the program blocks are longer than in the last section,
where they only contained an addq, bra must be used instead of bra.s.
The space required for the specification of the jump distance is larger with
bra than with bra.s. The $S< option can be used to save this space. It results
in the bra instruction at the end of a CASE block to be directed to the bra
instruction of the next block (after the next CASE or DEFAULT), as long as the
jump distance is small enough.
This could result in a chain of short branch jumps which finally ends behind
ENDSELECT. This chain of jumps from bra.s to bra.s may again be altered by the
compiler at a later stage of optimisation.
This not altogether straight forward problem is clarified by the following
listing:
move.l -$8000(a5),d0
bra L1
_CASE_1: addq.l #$1,-$8000(a5)
bra.s L0
_CASE_2: addq.l #$1,-$8000(a5)
L0: bra L2
_DEFAULT: addq.l #$1,-$8000(a5)
...
Many instructions
...
L2: bra.s _ENDSEL
L1: cmpi.w #$1,d0 ;CASE evaluation
beq _CASE_1
cmpi.w #$2,d0
beq _CASE_2
bra _DEFAULT
_ENDSEL addq.l #$1,-$8000(a5)
The crucial point here is the line bra.s L0. This branch should really go to
behind ENDSELECT. But the distance would be too far for a bra.s because of the
many instructions in the DEFAULT block. Hence the branch is to the bra command
in the next CASE program block.
While this method is executed more slowly, it requires less space than the code
generated with $S>, which does without such jumps.
Memo: $S> is the default.
Error Messages
Should an error appear in a compiled program, an error message describing the
nature of the error is displayed. You can use options $E$ and $E# to choose
between numbers and text for these error messages.
The $E$ option displays error messages as text. Since the message texts must be
part of the compiled code, this increases its length slightly.
The selected option always applies to the whole program. Unlike other options,
it cannot be altered for different parts of the program.
Memo: $E# is the default.
Error Numbers Instead of Bombs
The $B+ option makes error numbers appear instead of "bombs". This option must
not be used in accessories. The $B+ option can only be enabled, and will be
disabled again once the program has been executed.
Never use $B+ in an accessory, otherwise you might trap bombs generated by the
application.
Memo: This option should not be used under MiNT. All bomb errors
generated by any running programs will be sent to your application!
The same problem occurs as with an accessory.
Requires $I+ be enabled or the following problems occur:
Bomb handler will not be unhooked
Supervisor stack is not correctly saved/restored
Subroutines
Procedures and functions will be compiled as GFA BASIC subroutines if the $P>
option is enabled, thus allowing the passing of parameters and problem-free
recursive calls.
The $P< option leads to procedures and function without parameters or local
variables to be compiled as simple 68000 subroutines. This can produce problems
in recursive calls with stack overflows. On the other hand, they are executed
more quickly. Also, no RESUME or RESUME NEXT is possible with $P<.
Memo: $P< is the default.
ENDFUNC Generation
In a GFA-Basic listing, a function always ends with ENDFUNC. When this line is
reached, error message 69 appears (ENDFUNC without RETURN) because a function
must always encounter RETURN before it reaches ENDFUNC.
If the $F> function is used, this also applies to the compiled program. The $F<
option prevents the error message from being displayed. The code will then
simply continue to be executed after the function, with unpredictable results.
As a rule, compiled programs have been thoroughly tested. If this is the case,
error 69 should not appear. Using $F< will then produce slightly shorter
program code.
Memo: $F> is the default.
$F< will save about 4 bytes per FUNCTION.
Register Saving
The GFA-Basic manual indicates that the C: and CALL routines must not, as in
common to C routines on 68000 computers, change the registers A3 to A6 and A7,
even though this has normally no consequences in the interpreter. Also with C:
there is hardly ever a parameter in D0, which is a coincidental feature of the
interpreter.
Memo: $C- is the default.
FOR-NEXT Loop Checking
If a FOR-NEXT loop spans the entire range of a variable type, it will become
endless and loop. For example:
FOR i|=0 TO 255
...
NEXT i|
This will loop as i| will never reach 256 and end the loop. (A byte variable
will only hold 0 to 255). $N+ will ensure the loop terminates correctly.
Memo: $N- is the default.
Integer Rounding
With this option, the compiler is forced to round up integers. For example:
x%=RND*640
will generate numbers from 0 to 639
The Linker
The Linker Options
Overview of Linker Options
In this section all the linker options will be briefly introduced and their
settings described. In subsequent sections, each option will be described in
detail.
-s Append symbol table.
+NAME Use library NAME instead of GFA3BLIB.
NAME Include object file NAME.O.
# Do not include TEST.O.
-T Produce code to run in TT ram
The settings in G3OBJ, G3PRG, G3LIB and G3WAIT are passed to the linker by the
shell.
Symbol Table
The -s option tells the linker to append a symbol table so that the program can
be disassembled and debugged using symbols. The names of the procedures and
functions as well as label names are taken from the GFA-Basic listing and
written as symbols.
Only the first seven characters of a procedure, function or label name are used
in this process, and are prefixed with an underscore character.
Library Selection
The +lib option selects the library lib_name to be used by the linker. If this
option is not enabled, the linker will look for a library under the name
GFA3BLIB.
The section headed "Linking with C Libraries" describes in more detail how a
library is created or how GFA3BLIB can be extended. In that section you are
shown how to include the Turbo C libraries.
Linking Object Files
To link an object file, which must be DR format, you can pass the file name
without the .O extender to the linker.
The section "Linking C Functions without C Libraries" will describe in more
detail how you can use the routines contained in the object files in your
GFA-Basic programs.
Do not Link TEST.O
Using the # parameter, the linker can be made not to link the TEST.O file. By
default, the linker looks for a file of that name, since the compiler gives
this name to all object files created by it.
Run in TT Ram
With the -T flag set, code will be generated that will load into the Atari TT
ram area. The default (not set) will assume that the code is to run in ST ram
area.
Memo: Default program flags are as follows:
Private
Fastload
With option -T on:
Private
Fastload
Load Alt
Malloc Alt
Including C Functions
This section deals with the question of how routines written in the C
programming language can be included in compiled GFA-Basic 3.0 programs. The
method described here requires the C compiler to be able to generate object
files in the DR format, as can DR C and Turbo C.
Linking C Functions without C Libraries
The basic method will now be demonstrated with the aid of an example. The
routine to be included is to fill the elements of a two-byte array with numbers
from 0 to n, passing the address and the size of the array. The parameter
passed for the array size will only be a two-byte variable so that the size of
the array is limited to 32267 elements. The function carrying out this task
will work without the use of library functions.
The GFA-Basic program is to be written in such a way that it can also be run by
the interpreter. In the interpreter, of course, the C routine cannot be
included through the linker. Therefore it is made executable within the
interpreter by a GFA-Basic routine taking over the task of the C routine to be
linked.
The GFA-Basic program looks like this:
DlM x&(32000),y&(32000)
'
t1%=TIMER
f_gfa(32000)
t2%=TIMER
PRINT "In GFA-Basic:"'(t2%-t1%)/200
FOR i&=0 TO 39
PRINT x&(i&),
NEXT i&
'
t1%=TIMER
f_c(V:y&(0),32000)
t2%=TIMER
PRINT "In Turbo C:"'(t2%-t1%)/200
FOR i&=0 TO 39
PRINT y&(i&),
NEXT i&
'
PROCEDURE f_gfa(n&)
FOR i&=0 TO n&
x&(i&)=i&
NEXT i&
RETURN
'
PROCEDURE f_c(adr%,n&)
$X fill
i&=0
a%=adr%
WHILE i&<=n&
WORD{a%}=i&
INC i&
ADD a%,2
WEND
RETURN
First, two arrays are dimensioned. Then two timings are taken: the first calls
the f_gfa routine which assigns values of 0 to 32000 to the elements of the
array x&(). For display purposes, the first 40 elements of the array are then
displayed on screen.
The second of the timings calls the routine f_c. This routine, too, is to
assign values of 0 to 32000 to an array, but this task is to be performed in
the compiled and linked program by a C routine. Therefore this routine is
supplied with the field address and the number of values to be written.
In the first line of the procedure f_c you will find an instruction which tells
the linker to include the C function "fill". The name of the function can be
found after the $X option. This line must always be the first line of the
procedure.
The linker replaces the contents of the procedure with the C routine named
after $X. In the interpreter, this line is ignored and the command lines
following $X c_routine are executed. There are three of these in the given
example, which perform the same function as the C routine and also work in the
same way as the C routine by carrying out value assignments through a pointer.
Now to the structure of the C program carrying out the assignment. It was
written in Turbo C and reads:
void cdecl fill(n,adr)
int n;
int *adr;
{
int i; int *a;
a = adr;
for( i=0 ; i<=n ; *a++ = i++ );
}
The first line contains the name of the function which appears after $X in the
GFA-Baisc listing. This function has no return value and has therefore been
declared as void.
Before the function name there is the instruction cdecl. It tells Turbo C to
receive the parameters via the stack. Some other C compilers, such as DR C, do
this automatically. In the GFA BASIC listing the parameters are passed in the
order adr%, n&.
C takes the parameters from the stack in the reverse order, i.e. first the
two-byte value n and then the address of a four-byte variable adr. The
following lines then carry out the assignment of values to the field elements.
This completes the description of the structure of the GFA-Basic and the C
listings. It only remains to explain how you can get the linker to insert the C
function in the position of $X fill. To do this, you only need to specify the
name of the object file generated by the C compiler.
This file name can simply be entered in the command line if a DOS shell is
used. In the shell supplied the variable G3OBJ can be amended.
The execution time of the GFA-Basic loop is around 0.51 seconds, while the
Turbo C loop only requires about 0.115 seconds. This shows how assignments
using pointer operations can be effectively optimised in Turbo C.
Thus the following steps have to be followed:
1. You write a procedure in the GFA BASlC program, the first line of which
contains the $X option followed by a C function name.
2. You write a C program containing this function. This must take the
parameters and place them on the stack. There the parameters are placed in
the reverse of the order that they have when passed by the GFA-Basic
program.
3. When linking, the object file of the C listing with the routine to be linked
must be specified.
If the DR C compiler is used, one point to be noted is that this compiler
prefixes C function names with the underscore character. Hence, instead of $X
fill, $X _fill would have to be entered.
In our example, the C function had no return value and was therefore declared
as void. However, a C function can be employed not only in place of a GFA-Basic
procedure, but also in place of a GFA-Basic function.
The appropriate GFA-Basic listing could be, for example:
value%=100
PRINT @doub(value%)
'
FUNCTION doub(a%)
$X double
ALERT 1,"Place marker for|a C function.",1,"Return",a&
RETURN 0
ENDFUNC
In this example, the GFA-Basic function does not perform the task of the C
routine to be linked in. The simple C programs follows:
long cdecl double(x)
long x;
{
return x+x;
}
The return value of such an external function is always an integer value.
You can, of course, also link assembler routines. These must take their
parameters from the stack and must not change the stack pointer SP or the
registers A3, A4, A5 and A6.
Linking with C Libraries
In the C routines used so far only C keywords have been used, but no library
routines. If, for example, you wanted to use a printf in one of the C routines,
you would have to link the appropriate routine from the libraries.
This can be done by extending the GFA-Basic compiler's library. The following
small program enables you to integrate the Turbo C libraries into the GFA-Basic
compiler's library. Your C routines can then contain all the C instructions
from the libraries. The program reads likes this:
OPEN "O",#2,"NEW_LIB"
OPEN "I",#1,"GFA3BLIB"
l%=LOF(#1)
WHILE l%>32000
PRINT #2,INPUT$(32000,#1);
SUB l%,32000
WEND
PRINT #2,INPUT$(l%,#1);
CLOSE #1
@append("TCSTDLIB.LIB")
@append("TCEXTLIB.LIB")
@append("TCGEMLIB.LIB")
@append("TCTOSLIB.LIB")
@append("TCFLTLIB.LIB")
CLOSE #2
'
PROCEDURE append(lib$)
RELSEEK #2,-2
OPEN "I",#1,lib$
l%=LOF(#1)-2
SEEK #1,2
WHILE l%>32000
PRINT #2,INPUT$(32000,#1);
SUB l%,32000
WEND
PRINT #2,INPUT$(l%,#1);
CLOSE #1
RETURN
To use this program, you may have to change the path name of the files. To use
the new library, you will require the appropriate index files (NDX files),
which can be generated with the library manager of the GFA-Assembler, for
instance, or similar programs (DOINDEX).
As soon as both files are created, you can use all instructions from the Turbo
C libraries in the C routines to be linked. You simply need to tell the GFA
BASIC linker that you wish to use the new library and not GFA3BLIB. This is
done with the +lib_name linker option if you are using a DOS shell (in our
example, +NEW_LIB).
The linker may, under certain circumstances, report back that it does not
recognise the variable errno. C compilers do not take this from the libraries
as it is part of the startup code.
One precondition for the trouble-free use of the new library is that the Turbo
C and the GFA3BLIB libraries do not contain any functions which exist under the
same name in both libraries. We do not know of any such function in the present
version of Turbo C.
Some Peculiarities
In larger programs it is generally necessary to avoid using PC-related calls.
In Turbo C, this can be avoided with the -P compiler option.
The C routines must not alter the registers A3 to A6, or expect particular
values from them. Turbo C and DR C conform with this requirement, but Megamax
C, for example, does not. C programs have about 4 kb available for the stack.
Memo: The following was taken from the amiga version of the manual:
You may require an assembler interface like:
name: movem.l a3-a6,regsave
jsr c_name
movem.l regsave,a3-a6
rts
regsave: ds.l 4
You may then need to employ an extra dummy parameter in your C routine, to
mask the return address of 'jsr c_name'. For example:
name (long x, long y)
c_name(long dummy, long x, long y)
Linker Error Messages
The GL linker outputs some brief error messages:
?xxxxxxxx means unknown symbol xxxxxxxx
+xxxxxxxx means symbol redefinition
>xxxxxxxx means 16 bit offset too large
Memo: The linker will only report a bad symbol if the procedure or
function is actually called.
Programming Accessories
The structure of accessories
An accessory is a program which is installed in RAM after power-on or a reset.
There it waits until it receives an instruction to become active. This
instruction is sent when the user has selected it, usually from the GEM Desktop
menu.
From this simple description you can figure out the rough structure of an
accessory. First we said that an accessory had to be installed. To this end,
the programmer must declare the accessory as a GEM application and pass its
name to GEM so that it can be entered as an item in the first of the dropdown
menus.
Declaration as a GEM application is performed with the APPL_INIT() function,
the return value of which is known as the applications ID.
The value returned by APPL_INIT() can also be used to determine whether a
program was started as an accessory or as a normal program. If the return value
is 0, the program was not started as an accessory, but as a normal program. You
can thus write programs in GFA-Basic 3.0 which are executable both as normal
programs and as accessories.
The applications ID number is also required for passing the accessory name.
This is done with MENU_REGISTER(ap_id,text$).
MENU_REGISTER() returns the accessory number of the current program (0 to 5).
This value is called the menu identification number. A return value of -1 means
that 6 accessories have already been installed, the maximum for GEM, and
therefore there is no room for another one. The two parameters are the
application ID and the accessory name.
Now the accessory has been installed, the next step consists of waiting for it
to be called. An accessory must be programmed as an endless loop within which
the message buffer is scanned.
This scanning can be done, for instance, with the EVNT_MESAG() function. If a 0
is passed to this function, it will write messages coming from GEM into
GFA-Basic's own message buffer which can then be read using MENU(1) to MENU(8).
The most important message type for an accessory is MENU(1)=40 (AC_OPEN). This
message means that the user has selected an accessory. If, however, the
accessory runs in a window, the other messages relating to the selection of
other elements and to the redraw are also of interest.
An accessory normally offers the user the option to remove it again from the
screen. In terms of the program's internal structure this means that the
accessory must return to the endless loop by means of the EVNT_MESAG(10)
instruction. There must be no END or a similar command in an accessory because
that would make the computer "hang".
This description needs one further point to be added. GFA-Basic programs
attempt to claim all free memory space for themselves after they have been
started. You can, of course, release space again with RESERVE, but before the
RESERVE command is executed the initialisation routine of a compiled program
will already have performed the reservation of memory space.
To prevent this, a GFA-Basic accessory must include a line which tells the
compiler that the program to be generated must not claim all the free memory.
This is what the compiler option $mx does, with x being the number of bytes to
be claimed by the compiled program.
The screen area occupied by an accessory must be restored. This is called
redraw. If, for example, you are using dialog boxes, this redraw can be
performed from within your accessory, using GET and PUT to read in the screen
area and then writing it back again.
Programming Example
After this dry run we will now look at an example of an accessory program. A
particularly brief example:
$m1000
ap_id&=APPL_INIT()
IF ap_id&=0
ALERT 1,"I am not|an accessory now.",1,"Return",a&
END
ENDIF
me_id&=MENU_REGISTER(ap_id&," Colour switch ")
DO
~EVNT_MESAG(0)
IF MENU(1)=40
ALERT 1,"Color switch",1,"bw|wb",a&
SETCOLOR 0,a&
ENDIF
LOOP
In the first line, the program reserves for itself 1000 bytes of storage space.
Then it announces itself as a GEM application and obtains an application ID
which it puts into the variable ap_id&. If ap_id& equals 0, the program was not
started as an accessory. It displays a message to this effect and terminates
itself.
The line with MENU_REGISTER() passes the accessory's name to GEM and obtains a
menu ID number me_id&. Then follows an endless loop scanning the message buffer
with EVNT_MESAG().
When the accessory receives the message that it has been called (MENU(1)=40),
it activates itself. In this example, however, the action is rather minimal.
The accessory lets you invert the screen with SETCOLOR and then returns to its
endless Loop.
If more than one accessory exists, it will be necessary to determine which has
been selected. MENU(5) holds the ID of the selected accessory.
Longer Programming Examples
This section will introduce two examples of accessory programming. They do not
perform any meaningful activity but serve illustration purposes only. The first
example program generates a window with a randomly selected fill pattern as its
contents. It runs both as an accessory and as a program. The other example
appears as a dialog box with radio buttons, an edit field and buttons.
First to the window program: it first reserves 5120 bytes for itself and then
obtains its application ID. Then it checks if its ID is 0. A value of 0 would
mean that it had be started as a program and not as an accessory.
If started as an accessory, it now enters its name into the menu. Then it
branches to an endless loop consisting of only two instructions. The first
being EVNT_MESAG(), which waits for events. The 0 parameter ensures that
messages can be evaluated with the aid of MENU(1) to MENU(8). The second
instruction calls the sub-procedure message which reacts to any messages
received.
If not started as an accessory, the program opens a window and defines a
routine for message evaluation. This routine is identical to the one performing
the task of message evaluation in the accessory version. The REPEAT-UNTIL loop
will now wait for events until the procedure message sets the variable exit! to
TRUE.
The procedure message is almost identical in structure to a normal window
management routine in a normal program. It first reads the coordinates of the
current window into the variables x&, y&, b&, and h&.
The SELECT-CASE instruction branches according to the different possible
messages received by MENU(1). The first such message is also the most
important: the redraw message.
As soon as this message is received, the AES is informed about the imminent
screen redraw with WIND_UPDATE(1). We now go through the rectangles list of the
window in which the redraws take place.
Each rectangle is drawn in a random fill pattern. Unless two adjacent
rectangles happen to be drawn in identical fill patterns by chance, you can
examine the way GEM manages the rectangles list. For redrawing the rectangles
it would, strictly speaking, be sufficient to draw the rectangle only in the
area affected by a clipping.
But the method followed is the same as in a conventional window program. The
clipping is imposed on the rectangle to be drawn and the entire working area of
the window is redrawn. In your own program, you would have to replace the PBOX
command with a routine to draw the window contents.
The remaining messages can be dealt with by only a few instructions. In the
example, commands specific to GFA BASIC, such as TOPW, FULLW etc., are
generally used. At the WM_CLOSED message, in addition to CLOSEW, the variable
exit! is set to TRUE. This is to cover the possibility of the program not
running as an accessory.
This routine differs from a normal window management routine by its ability to
react to the message AC_OPEN. This message reports that the user has selected
the accessory. As a result, the window is opened.
The areas over written by the accessory must be redrawn by the program from
which the accessory was called. The task of sending an appropriate redraw
message to that program is performed by GEM and need not be considered in this
listing.
$m5120
ap_id&=APPL_INIT()
'
IF ap_id&<>0
me_id&=MENU_REGISTER(ap_id&," Window-ACC ")
DO
~EVNT_MESAG(0)
message
LOOP
ELSE
TITLEW #1,"Window-Program"
INFOW #1," in GFA-BASIC 3.0"
OPENW #1,50,50,200,100,&X111111
handle&=W_HAND(#1)
ON MENU MESSAGE GOSUB message
exit!=FALSE
REPEAT
ON MENU
UNTIL exit!
ENDIF
'
PROCEDURE message
x&=MENU(5)
y&=MENU(6)
b&=MENU(7)
h&=MENU(8)
'
SELECT MENU(1)
CASE 20 ! /*** WM_REDRAW ***/
~WIND_UPDATE(1)
~WIND_GET(handle&,11,rx&,ry&,rb&,rh&) !First rectangle in the list
~WIND_GET(handle&,4,ax&,ay&,ab&,ah&) !Working area in window
REPEAT
IF RC_INTERSECT(ax&,ay&,ab&,ah&,rx&,ry&,rb&,rh&)
CLIP rx&,ry&,rb&,rh& OFFSET ax&,ay&
DEFFILL 1,2,RAND(25)
PBOX 0,0,PRED(ab&),PRED(ah&)
CLIP 0,0,WORK_OUT(0),WORK_OUT(1)
ENDIF
~WIND_GET(handle&,12,rx&,ry&,rb&,rh&) !Next rectangle in list
UNTIL rb&=0 AND rh&=0 !No more in list
~WIND_UPDATE(0)
CASE 21 ! /*** WM_TOPPED ***/
TOPW #1
CASE 22,41 ! /*** WM_CLOSED and AC_CLOSE ***/
CLOSEW #1
exit!=TRUE
CASE 23 ! /*** WM_FULLED ***/
FULLW #1
CASE 27 ! /*** WM SIZED ***/
~WIND_SET(handle&,5,x&,y&,MAX(180,b&),MAX(80,h&))
CASE 28 ! /*** WM_MOVED ***/
~WIND_SET(handle&,5,x&,y&,b&,h&)
CASE 40 ! /*** AC_OPEN ***/
TITLEW #1,"Window-Accessory"
INFOW #1," in GFA-BASlC 3.0"
OPENW #1,50,50,200,100,&X111111
handle&=W_HAND(#1)
ENDSELECT
RETURN
Now to the next sample program in which a dialog box is used. This program
reserves quite a lot of memory space for itself to begin with, almost 13kb.
This space is required primarily to save, with GET, the screen area covered by
the dialog box.
In the window program, GEM sent out a redraw message when the accessory window
was closed. If the dialog boxes of an accessory are to disappear from the
screen and the old contents of the area restored, another method has to be
chosen.
One possibility is to trigger the redraw message for the screen area affected.
For this purpose, there exists the FORM_DIAL(3,...) routine. Another
possibility is illustrated by the program following. It is possible to read in
the screen area covered by the dialog box with GET, and then to restore it
later with PUT.
Using FORM_DIAL() requires less memory space. However, the program that is to
perform the redraw may need some time for this task. Using GET and PUT is
considerably faster.
This program, by the way, also calls an alert box. The screen area covered is
automatically redrawn by GEM. GEM uses a similar method for this as the one
chosen in our program with GET and PUT. The area covered by the alert box,
therefore, does not have to be redrawn by the BASIC program since GEM will be
doing it.
After determining the application ID the program checks if it has been started
as an accessory. If not, it wiil terminate itself. In contrast to the
previously discussed window demo, this demo will therefore run as an accessory
oniy.
Next the accessory attempts to load in its resource file. If it cannot find
this, it must not be terminated like a normal program because it wouid then get
into an endless loop with an EVNT instruction.
If the resource file has been found, the program assigns object numbers to the
dialog box variables. This part of the program consists of the LST file written
by the Resource Construction Set. Once this is done, the address of the dialog
box tree is obtained and a default text assigned to the editable field.
Only now is the accessory entered into the menu. In the following loop, it
waits to be called via (MENU(1)=40). As soon as this call arrives, the
dimensions of the dialog box are calculated and the corresponding screen area,
with a additional safety margin, is saved. The dialog box can now be drawn and
managed with FORM_DO().
On quitting the dialog box, the exit object is reset to its previous state and
the screen area overwritten by the box restored with PUT.
In the following lines, the information entered into the dialog box by the
user, is read and displayed in an alert box. Then the accessory returns to the
endless loop, where it awaits its next call.
$m12800
ap_id&=APPL_INIT()
IF ap_id&=0
ALERT 1,"Program runs only|as an accessory",1," Return ",a|
END
ENDIF
'
IF RSRC_LOAD("dial_acc.rsc")=0
DO !If the RSC file cannot be found, then
~EVNT_TIMER(-1) !simply wait for as long as it takes
LOOP !because there is nothing to do
ENDIF
'
' Object numbers from the construction set
LET dialog&=0 !RSC_TREE
LET text&=8 !Obj in #0
LET abbruch&=2 !Obj in #0
LET return&=3 !Obj in #0
LET radio1&=5 !Obj in #0
LET radio2&=6 !Obj in #0
LET radio3&=7 !Obj in #0
'
~RSRC_GADDR(0,dialog&,dialog_adr%)
CHAR{{OB-SPEC(dialog_adr%,text&)}}="Testtext"
me_id&=MENU_REGISTER(ap_id&," Dialog-ACC ")
'
DO
~EVNT_MESAG(0)
IF MENU(1)=40
~FORM_CENTER(dialog_adr%,x&,y&,b&,h&)
~WIND_UPDATE(1)
GET x&-4,y&-4,x&+b&+4,y&+b&+4,rette$ !For Redraw.
~OBJC_DRAW(dialog_adr%,0,3,x&,y&,b&,h&)
ex&=FORM_DO(dialog_adr%,0)
~OBJC_CHANGE(dialog_adr%,ex&,0,x&,y&,b&,h&,0,0)
PUT x&-4,y&-4,rette$ !Redraw.
~WIND_UPDATE(0)
t$=CHAR{{OB_SPEC(dialog_adr%,text&)}}
IF BTST(OB_STATE(dialog_adr%,radio1&),0)
r$="1"
ELSE IF BTST(OB_STATE(dialog_adr%,radio2&),0)
r$="2"
ELSE IF BTST(OB_STATE(dialog_adr%,radio3&),0)
r$="3"
ENDIF
a$="Text: "+t$+"|Radio_Button: "+r$+"|Exit-Button: "+STR$(ex&)
ALERT 1,a$,1," Ok ",a|
ENDIF
LOOP
Program Optimization
The GFA-Basic 3.0 compiler generates assembler code. You can support it in this
task by appropriate programming. In this chapter we shall consider, the
question of what a GFA BASIC program should look like in order to make the
resulting compiled program as fast and short as possible. To achieve this, you
have to know how the compiler goes about its optimization.
This chapter contains some assembler listings representing compiler generated
code. If you wish to disassemble programs generated by the compiler yourself,
you should let the linker append the symbol table to the code. The compiled
program always begins with the lines:
STARTADR: lea.l STARTADR-256(pc),a0
lea.l $100(a0),a7
jsr INIT
These three lines are followed by the code in the first lines of your BASIC
program. The end of this code is marked by the label BaseA4. When linking with
the symbol table enabled, the names of procedures and functions are inserted as
symbols (underline character plus name).
You will be able to benefit from this chapter even if you have no knowledge of
assembler, by taking note of the advice derived from the listings - although
you may not, in this case, understand why a certain program formulation is more
efficient than another one.
The knowledge of assembler required to understand the disassembled listings has
been kept to a minimum. This chapter is aimed at GFA-Basic programmers wishing
to familiarise themselves with assembler in order to, for example, write
speed-critical subroutines in that language.
We cannot, of course, discuss all the instructions understood by the compiler,
but can only pick out a few examples of particular importance from the point of
view of optimization.
Simple Additions
The Atari ST's processor, the Motorola 68000, has instructions to process
integer numbers. BASIC lines which simply carry out arithmetic operations on
integer variables can be translated into a few assembler instructions as long
as these lines are not too complex.
Operations on floating point variables require far more assembler instructions,
and this is reflected in the processing time taken. Adding two integer values
to each other is about five to six times faster than the addition of two
floating point values.
The first question to be discussed here is: When does the compiler use the
faster integer arithmetic and when does use floating point arithmetic?
The statements a%=b%+c% and a%=ADD(b%,c%) are processed by the interpreter at
different speeds. The compiler, however, simply generates the same code from
both:
move.l -$7ff8(a5),d0
add.l -$7ffc(a5),d0
move.l d0,-$8000(a5)
The addresses -$xxxx(a5) depend on which variables are used in the program.
The variables can be found from -$8000(a5) onwards.
If you have used two-byte variables, for instance a&=b&+c&, the compiler will
generate the following instructions:
move.w -$7ffc(a5),d0
add.w -$7ffe(a5),d0
move.w d0,-$8000(a5)
With one-byte variables (a|=b|+x|) you get:
moveq.l #$0,d0
move.b -$7ffe(a5),d0
move.b -$7fff(a5),d1
add.l d1,d0
move.b d0,-$8000(a5)
However, a program line such as a=b+c uses floating-point variables. To perform
a floating point addition, the compiler program will contain an appropriate
subroutine. In the disassembled listing of a program with a symbol table you
find:
lea.l -$7ff0(a5),a0
lea.l -$7ff8(a5),a1
bsr VVFADD
lea.l -$8000(a5),a0
move.l d0,(a0)+
move.w d1,(a0)+
move.w d2,(a0)+
This listing contains the line bsr VVFADD. This line branches to the floating
point addition routine, which is processed far more slowly than the
instructions generated by, for example, a%=b%+c%.
The code produced by two-byte additions can be processed most quickly by the
computer. The next fastest is the one-byte addition code, then the four-byte
addition and finally, a long way behind, the floating point addition code.
The following table gives some examples for the different timings for the
different variable types in a simple addition in both the interpreter and the
compiler. A loop with 5000 runs was used, with the time taken by the loop
commands eliminated.
Type Interpreter Compiler Statement
Byte 11.715 0.31 a|=b|+c|
Word 11.715 0.255 a&=b&+c&
Long 11.355 0.335 a%=b%+c%
Float 6.23 1.925 a=b+c
Similar timings apply to subtraction.
Multiplication
The optimization used by the compiler with multiplication contains a special
feature. The Atari ST's processor does have multiplication instructions, but it
requires a large number of tact cycles for their execution and only knows these
instructions for two-byte values. Therefore the GFA-Basic 3.0 compiler has to
coordinate the multiplication of a constant with a four-byte variable while
avoiding the use of the assembler instructions mulu and muls.
The line
x%=y%*4
for example, can be simply translated into the code:
move.l -$8000(a5),d0
lsl.l #$2,d0
move.l d0,-$7ffc(a5)
since 4 is the square of 2. Coding the statement:
x%=y%*21
is somewhat more involved, since 21 equals binary 10101. To be able to better
understand the code generated by the compiler, let us assume in the comments
that y%=100. The code generated is:
move.l -$8000(a5),d0 ;y%, that is 100, into register d0
move.l d0,d2 ;copy of y% into register d2
lsl.l #$2,d0 ;d0 times 4, d0 contains 400, d2=100
add.l d0,d2 ;add 400 to 100, therefore d0=400,
;d2=500
lsl.l #$2,d0 ;d0 times 4, therefore d0=1600,
;d2=500
add.l d2,d0 ;add d2 to d0: d0=2100, d2=500
move.l d0,-$7ffc(a5) ;writes result 2100 to x%
This code uses an extra 6 bytes of memory compared to a muls #$15,d0 (which,
however, does not exist for four-byte values), but is faster with 52 tact
cycles execution time (without the first and the last move instruction).
By contrast, the statement
x&=y&*21
was coded using muls. In the case of 100,000 multiplications with 21,
therefore, the four-byte variables statement is a little faster:
Statement Time
x%=y%*21 0.975
x&=y&*21 1.08
However, if the multiplication is not with 21 but with values whose translation
into the assembler statements add, sub, lsl and asl requires relatively lengthy
code, the four-bytes variant not only generates considerably more code, but
also executes more slowly than the two-bytes statement working with muls. For
example, multiplying with 21845 (binary 101010101010101) instead of 21, the
execution times for 100,000 repeats are:
Statement Time
x%=y%*21845 2.26
x&=y&*21845 1.34
So far we have only looked at multiplications of one variable with one
constant. When multiplying two integer variables, however, the fact that the
mul statement only processes two-bytes values is also of great importance.
The following list shows the code generated by different integer
multiplications and their execution times for 25000 multiplications.
move.l -$7ff4(a5),d0 ;x%=y%*z%, 7.685
move.l -$7ff8(a5),d1
bsr LMUL
move.l d0,-$7ffc(a5)
move.w -$7ff0(a5),d0 ;x%=y%*z&, 6.165
ext.l d0
move.l -$7ff8(a5),d1
bsr LMUL
move.l d0,-$7ffc(a5)
move.w -$7ff0(a5),d0 ;x%=y&*z&, 2.44
muls -$7fee(a5),d0
move.l d0,-$7ffc(a5)
move.w -$7ff0(a5),d0 ;x&=y&*z&, 2.315
muls -$7fee(a5),d0
move.w d0,-$7fec(a5)
The great speed differences between the first and the last two stems from the
fact that in the last two examples, muls could be used instead of the LMUL
routine. The absolute timings also depend on the values found in y%, z%, y&,
and z&. The relative speeds between the different statements, however, remain
broadly the same.
In these two cases, where a four-bytes variable is involved, the $*& compiler
option can also force a use of muls. It has to be remembered, however, that
only two bytes of the four-byte values processed enter into the calculation. A
more detailed description can be found in the chapter on compiler options
(integer multiplication).
The small differences between the two LMUL and the two muls examples stem from
the move.w versus move.l and the ext.l instructions only. When multiplying
integer variables, it is therefore worthwhile using two-byte instead of
four-byte variables.
Division
Divisions of integer variables can produce decimal points, for instance x%=5,
y%=2, x%/y%=2.5. In contrast to multiplication, the compiler would therefore
have to perform division generally as floating point division. This is indeed
what it does, as long as the programmer does not expressly tell it to perform
the division of two integer variables as an integer division with an integer
result.
You can do this by using the compiler option $%3, (the complement $%0 option),
which causes every division to be performed as a floating point division, is
the default. You can see the difference by analysing the code produced by the
line
x=y%/z%
Using the default $%0 option, this produces:
move.l -$7ff8(a5),d0
bsr FITOF
move.l d0,-(a7)
move.w d2,-(a7)
move.w d1,-(a7)
move.l -$7ff4(a5),d0
bsr FITOF
move.w (a7)+,d4
move.w (a7)+,d5
move.l (a7)+,d3
bsr FXDIV
lea.l -$8000(a5),a0
move.l d0,(a0)+
move.w d1,(a0)+
move.w d2,(a0)+
You can see that the two variables to be divided are transformed into floating
point variables using the FITOF (integer to float) routine. The routine for the
division of two floating point values is called (FXDIV) and the result assigned
to the variable x from -$8000(a5).
If the same line is compiled using the $%3 option, the following code results:
move.l -$7ffc(a5),d0
move.l -$7ff8(a5),d1
bsr LDIV
lea.l -$8000(a5),a0
bsr ISTOF
The ISTOF routine performs the assignment to x. Here the LDIV routine for the
division of two long-integer variables is called. If the two values are such
that decimal places are the result of the division, LDIV will not, of course,
return these.
If the line were to read x%=y%/z% instead of, as is the case here, x=y%/z%,
this would be of no consequence as the result would be returned to an integer
variable. In such a case, the GFA BASIC compiler automatically uses LDIV for
the division, even with $%0 enabled.
If two two-byte variables are to be divided, the Motorola 68000 processor's div
instruction can be used, which is of course faster than the LDIV routine. The
code, in this case, is particularly simple and fast.
The line
x&=y&/z&
produces:
move.w -$7ffe(a5),d0
ext.l d0
divs -$7ffc(a5),d0
move.w d0,-$8000(a5)
The conclusion: If at all possible, use two-byte variables for a division and
enable the $%3 option if you are sure that no integer variables which would
produce significant decimal places are being processed.
When dividing by constants, the optimization carried out are similar to those
with multiplications. For example, the division by a value to the power of two
is converted into bit-shift instructions.
More Complicated Calculations
So far we have only considered arithmetic operations on two variables. Now we
must look at operations involving more than two variables. The compiler can
only translate such operations into code which does not contain branches to
subroutines up to a certain level of complexity. The following example will
illustrate this.
To execute the program line
x&=x&+(y&*y&-y&)/y&+z&
fifty thousand times, a compiled program (without the loop commands) requires
about 2.56 seconds. But this line can also be broken up into
x&=x&+(y&*y&-y&)/y&
x&=x&+z&
These two lines perform the same task, from the point of view of the result, as
the first statement. However, the compiled program requires only about 1.875
seconds for the execution of these lines. The rule that can be derived from
this is: Break up lines containing more complicated integer calculations into
several lines.
To understand why the two-line variant executes faster than its one-line
equivalent, we must analyze the corresponding section from the (symbolically)
disassembled program.
The line
x&=x&+(y&*y&-y&)/y&+z&
is translated into
move.w -$7ffe(a5),d0
muls -$7ffe(a5),d0 ;y&*y&
movea.w -$7ffe(a5),a0
sub.l a0,d0 ;-y&
move.w -$7ffe(a5),d1
ext.l d1
bsr LDIV ;/y&
movea.w -$8000(a5),a0
add.l a0,d0 ;+x&
add.w -$7ffc(a5),d0 ;+z&
move.w d0,-$8000(a5)
The addresses of the variables once again depend on the order of their
introduction into the program. Here, for example, the variable x& was
introduced first, y& second, and z& third. Thus their addresses are
x& -$8000(a5)
y& -$7ffe(a5)
z& -$7ffc(a5)
In the listing you will find the line bsr LDIV, calling a subroutine for the
division of two integer values. If you now compare this listing with the
two-line version, you will find that the latter contains no subroutine call.
The statements
x&=x&+(y&*y&-y&)/y&
x&=x&+z&
produces the code:
move.w -$7ffe(a5),d0
muls -$7ffe(a5),d0 ;y&*y&
movea.w -$7ffe(a5),a0
sub.l a0,d0 ;-y&
move.w -$7ffe(a5),d1
divs d1,d0 ;/y&
add.w d0,-$8000(a5) ;End of first line
move.w -$7ffc(a5),d0
add.w d0,-$8000(a5) ;+z&
As you can see, this listing is a few instructions shorter than the previous
one and contains no subroutine calls using bsr (branch subroutine). The code
will become even more efficient, by the way, if you use reverse Polish notation
with ADD x&,... instead of x&=x&+... In the interpreter, the one-line variant
is faster than the two lines. But if you wish to tailor your programs to the
compiler, you should present it with relatively short integer arithmetic
statements only, which it will best be able to code into assembler
instructions.
Brackets are often inserted into calculations for reasons of clarity, although
strictly speaking they are superfluous. Thus instead of
x&=x&+(y&*y&-y&)/y&
you could use the line
x&=x&+((y&*y&)-y&)/y&
We are not concerned here with the clarity of the example. You will find that
in the interpreter, the version with the additionai pair of brackets is slower.
In the compiled program, however, both versions are equally fast since the same
code is generated from them.
So if you want to insert brackets to improve intelligibility, you can do this
without a speed penalty in the compiled program as long as the brackets have no
influence on the result of the calculation.
Loop Commands
The best-known program optimization in GFA-Basic 2.0 was that the FOR-NEXT loop
in the 2.0 interpreter and the REPEAT-UNTIL loop in the 2.0 compiler were the
fastest. It is different with the compiler for GFA-Basic 3.0.
If an empty loop is run 5000 times through the three loop types FOR-NEXT,
REPEAT-UNTIL and WHILE-WEND, the following timings are obtained with a
four-byte variable:
FOR-NEXT REPEAT-UNTIL WHILE-WEND
Interpreter 3.76 14.765 16.42
Compiler 0.77 0.77 0.77
The DO-LOOP loop with EXlT IF and the derivatives of DO-LOOP, such as DO-LOOP
UNTIL, will not be considered here, other than observing that the DO-LOOP loop
with EXlT IF is slower in the compiler (0.875).
As can be seen from the table, the three loop types are all equally fast in the
compiled program. Thus it is no longer sensible to "adapt" a program to the
compiler by altering all loops to REPEAT-UNTIL loops.
The equal execution times may suggest that the code generated by the three
loops must be very similar. This is correct, as the disassembled listings of
the three loop types will now show. We have inserted the statement b%=10 into
each loop in order to make the position of the loop contents recognisable in
the code.
The FOR-NEXT loop
FOR i%=1 TO 10000
b%=10
NEXT i%
generates the following listing (the jump addresses and the variable addresses
are again only examples):
moveq.l #$1,d0 ;Loop starts at 1
move.l d0,-$7ff8(a5) ;Assign start value to i%
L1: moveq.l #$a,d0 ;Assign the value of 10
move.l d0,-$8000(a5) ;to the variable b%
addq.l #$1,-$7ff8(a5) ;Increment i% by 1
cmpi.l #$2710,-$7ff8(a5) ;End of loop reached?
ble.s L1 ;If not, go back
The first two instructions define the loop start value i%. Then follows the
loop contents, here from label L1 in which the value of 10 is assigned to the
variable b% using two instructions.
After that, the variable i% is incremented by 1 and this is followed by
checking whether the loop end value has been reached. The end value was 10000,
that is hex $2710. If the loop counter variable is still smaller than or equal
to this value, the loop must be executed again.
If the end value of a loop is defined not by a constant but by, for instance, a
variable, it will of course have a different structure, as will a loop using
STEP.
Since the addq follows after the loop contents and the exit condition is tested
only after that, i% will equal 10001 on completion of the loop. It is a
convention in the BASlC language that the counter variable of a FOR-NEXT loop
is greater than the loop's end value on exit from the loop. This is because the
exit condition of the loop has been met if the counter is greater than the end
value.
However, when translating your programs into other BASIC dialects or other
languages, you should not rely on this BASIC convention being adhered to.
Now to the REPEAT-UNTIL loop. The BASIC lines
i%=0
REPEAT
INC i%
b%=10
UNTIL i%=10000
translate into the following assembler instructions:
clr.l -$7ff8(a5) ;i%=0.
L1: addq.l #$1,-$7ff8(a5) ;Increment i% by 1
moveq.l #$a,d0 ;Set b% to the
move.l d0,-$8000(a5) ;value of 10
cmpi.l #$2710,-$7ff8(a5) ;Compare 10000 with i%
bne.s L1 ;If i% not equal 10000
In this listing, the instruction clr.l is only executed once, all other
instructions several times. In the listing of the FOR-NEXT loop, the same
instructions are executed several times as in the REPEAT-UNTIL loop: an addq,
a moveq, a cmpi and a branch instruction with a logical condition.
The same execution times for the FOR-NEXT and the REPEAT-UNTIL loops thus
become understandable. In the WHILE-WEND loop it is also the same instructions
which are executed several times. The lines
i%=0
WHILE i%<10000
INC i%
b%=10
WEND
compile into the assembler code:
clr.l -$7ff8(a5) ;i%=0
bra.s L2 ;Jump to cmpi
L1: addq.l #$1,-$7ff8(a5) ;INC i%
moveq.l #$a,d0 ;set b% to the
move.l d0,-$8000(a5) ;value of 10
L2: cmpi.l #$2710,-$7ff8(a5) ;Compare 10000 with i%
blt.s L1 ;If i% smaller, go back
The compilation of the WHILE-WEND loop into assembler differs from the
REPEAT-UNTIL loop in two respects.
1. The logical condition has been formulated differently, in the REPEAT-UNTIL
loop it is an exit condition and in the WHILE-WEND loop it is a
"continuation condition".
2. The WHILE-WEND loop is a descending loop. Its condition is therefore tested
before the first execution of the loop interior. For this reason, the
assembler program first jumps to the loop condition test with a bra
instruction.
In all other respects the implementation of the two loop types is identical.
The identical timings for all loop types enable you as the GFA-Basic programmer
to choose your loop types exclusively from the point of view of program
structure rather than having to choose a less well suited loop for reasons of
execution speed.
Character Strings
In this section we are not discussing speed optimization but the shortening of
the program. If, in a GFA-Basic program, a string variable is assigned a
character string, as for instance a$="Test", the compiler places this character
string into the DATA segment of the program generated.
The compiler attempts to keep the initialised strings section short. When a
character string is assigned to a string variable, the compiler will first
search the already existing character string section to see if the new string
is already present there. If this is the case, it will remember the string's
address.
Example: Suppose you want to translate a program into several languages and you
therefore place all text output into a procedure in the BASIC program in order
to simplify the translation. There you will now find the lines
a$="escape key"
b$="terminate the program"
x$="the escape key will terminate the program"
During symbolic linking, the DATASTAR symbol will be inserted into the DATA
segment of the program to mark the beginning of the string section. There our
three character strings can be found one immediately after the other.
You can change the order of the three lines to
x$="the escape key will terminate the program"
a$="escape key"
b$="terminate the program"
Now you will only find the string "the escape key will terminate the program"
after DATASTAR. The reason is this: First the compiler puts the long text line
into the DATA segment. Then it is asked to initialize a string containing the
text "escape key".
To this end, it searched the DATA segment and found the text "escape key" as a
component of the long text line, noting its position in the DATA segment
without storing it again. The same happened with the text "terminate the
program".
If the long line is listed as the last one of the three, as in the first
version, the compiler will only find fragments of this line in the DATA segment
when initialising the long line. In that event, it will store the complete
string.
With a character string which is also contained in another one, the longer
string must first be assigned to a variable to enable the compiler to optimize
the use of memory space.
Strings in DATA lines are, incidentally, placed after DATASTAR before all
strings assigned to a variable. The DATA segment itself begins with a table of
local variables (VARTAB). Then follows the 48-bytes long TYPETAB, if TYPE or an
assignment using a pointer (e.g. *x=3 or SWAP *x,x%()) have been used.
After VARTAB, or TYPETAB if required, there are the INLINE areas. Only then
follows the DATASTAR symbol, behind which the contents of DATA lines and the
initialised strings can be found.
Local and Global Variables
In the 3.0 interpreter, operations involving local and global variables are
executed at the same speed. This is different with compiled programs. An empty
FOR-NEXT loop with 50000 repeats and a four-byte counter variable requires
about 1.315 seconds in the compiler. This is irrespective of whether the
counter variable is a local or a global variable.
Once compiled, the loop with the local variable takes about 0.595 seconds,
while the loop with the global variable needs only about 0.385 seconds.
This speed ratio between local and global variables is different with some
other languages. In C for instance, as a general rule, routines with local
variables are faster than the same routines with global variables.
Technical Support
Technical support is available to registered users of GFA products. Please
ensure that you complete the registration form and return it to GFA. We will
only provide support to registered users.
Due to the nature of problems associated with programming, it is requested that
all problems are notified in writing, rather than phone. A source code listing
should be provided to support the problem. If such a source code listing is
greater than 20 lines then please supply the source code on a disk (which will
be returned).
GFA is always improving its products and is aiways interested in suggested
improvements. As a result updates will be available to registered users.
Help and advice is also available from the independent GFA USER
Magazine. The magazine is compiled by GFA users for GFA users. GFA USER
Magazine is available from:
GFA User Magazine
186 Holland Street
Crewe
Cheshire
CW1 3SJ
UK
In some cases the compiler will optimize simple math.
In these examples the math/function becomes a single instruction:
GFA code Assembler output
---------- ---------------------
a&=32+1 move.w #33,-32768(a5)
a&=32-1 move.w #31,-32768(a5)
a&=32*2 move.w #64,-32768(a5)
a&=32/2 move.w #16,-32768(a5)
a&=(2*5)+1 move.w #11,-32768(a5)
a&=SUCC(32) move.w #33,-32768(a5)
a&=PRED(32) move.w #31,-32768(a5)
The requirement seems to be that all operands must be numerical constants.
If you mix any variables into the equations it will not be able to optimize
it and it will break it down into multiple assembler instructions.
a&=32 !even though its some fixed value
b&=a&+1 !the compiler will not optimize this
Index
A
About This Manual
ABS
ABSOLUTE
accessories
accessory
ACHAR
ACLIP
ACOS
ADD
ADD()
Additional Information
ADDRIN
ADDROUT
AES
aexp
AFTER
AFTER CONT
AFTER GOSUB
AFTER STOP
ALERT
ALINE
AND
AND()
Antic Software
APOLY
Appendix
APPLBLK
Application Block Structure (APPLBLK)
Application Services Library
APPL_EXIT
APPL_FIND
appl_getinfo
APPL_INIT
APPL_READ
appl_search
APPL_TPLAY
APPL_TRECORD
APPL_WRITE
appl_yield
ARECT
Arithmetic Operators
Array Index Checking
ARRAYFILL
Arrays
ARRPTR
ASC
ASCII
ASCII Table
ASIN
Assembler Notes
Assignment Operator
ATEXT
ATN
ATTRDEF.H
Author/Publisher
AUX:
avar
B
BASEPAGE
BASEPAGE.H
BCHG
BCLR
bexp
BGET
BIN$
BIOS
BIOS Error Codes
BIOS() Table
BIOS, XBIOS, and GEMDOS
Bit Image Block Structure (BITBLK)
Bit Operations
BITBLK
BITBLT
BITBLT adr%
BITBLT x%()
BLOAD
BMOVE
Bomb Error Codes
BOUNDARY
BOX
BPUT
Break Keys
BSAVE
BSET
BTST
BYTE
Byte by Byte Input and Output
BYTE()
C
C:
CALL
CARD
CARD()
CASE
cdecl
CFLOAT
CHAIN
Chapter 1 - Introduction
Chapter 2 - Variables and Memory Management
Chapter 3 - Operators
Chapter 4 - Numerical Functions
Chapter 5 - String Manipulation
Chapter 6 - Input and Output
Chapter 7 - Program Structure
Chapter 8 - Graphics
Chapter 9 - Event, Menu, and Window Management
Chapter 10 - System Routines
Chapter 11 - AES Libraries
Chapter 12 - Appendix
CHAR
Character Strings
CHDIR
CHDRIVE
Checking the BREAK keys, EVERY and AFTER
CHR$
CICON
CICONBLK
CINT
CIRCLE
CLEAR
CLEARW
CLIP
CLIP OFF
CLIP OFFSET
CLOSE
CLOSEW
CLR
CLS
COLOR
Color Icon Data Structure (CICONBLK)
Color Icon Structure (CICON)
COM:
COMBIN
Command line options
Commands and Functions
Commands Not Accepted by the Compiler
Communicating with Peripherals
Comparison Operators
Compatibility with GFA-BASIC 2
CON:
Concatenation Operator
CONT
CONTRL
Cookie Jar
COS
COSQ
CRSCOL
CRSLIN
CURVE
CVD
CVF
CVI
CVL
CVS
D
DATA
Data Commands
Data Input and Output
DATE$
DATE$=
Debugging with GFA-Basic and MiNT
DEC
Decision Commands
DEFAULT
DEFBIT
DEFBYT
DEFDBL
DEFFILL
DEFFLT
DEFFN
DEFINT
DEFLINE
DEFLIST
DEFMARK
DEFMOUSE
DEFNUM
DEFSNG
DEFSTR
DEFTEXT
DEFWRD
DEG
DELAY
DELETE
Deleting and Exchanging
Descriptor
descriptor
DFREE
DIAL_SMP.GFA
DIM
DIM?
DIR
DIR$
Directory Handling
DIV
DIV()
Division
DMACONTROL
DMASOUND
DO
Do not Link TEST.O
DO UNTIL
DO WHILE
Document not found
DOUBLE
DOWNTO
DPEEK
DPOKE
DR
DRAW
DRAW TO
DRAW()
DTA
DUMP
E
EDIT
Editor Error Messages
ELLIPSE
ELSE
ELSE IF
ENCOM
END
ENDDO
ENDFOR
ENDFUNC
ENDFUNC Generation
ENDIF
ENDPROC
ENDREPEAT
ENDSELECT
ENDSUB
ENDSWITCH
ENDWHILE
EOF
EQV
EQV()
ERASE
ERR
ERR$
ERRNO.H
ERROR
Error Codes
Error Handling
Error Messages
Error Numbers Instead of Bombs
EVEN
Event Library
Event Management
EVERY
EVERY CONT
EVERY GOSUB
EVERY STOP
EVNT_BUTTON
EVNT_DCLICK
EVNT_KEYBD
EVNT_MESAG
EVNT_MOUSE
EVNT_MULTI
EVNT_TIMER
EXEC
EXEC()
EXIST
EXIT IF
EXP
Externally Linked Routines
F
FACT
FALSE
fastload
Fastload on TOS 1.00/1.02
FATAL
FGETDTA
FIELD
FIELD #
File Management
File Selector Library
Files
FILES
FILESELECT
FILL
Fill Pattern Table
FIX
FLOAT
FN
FOR
FOR-NEXT Loop Checking
FORM INPUT
FORM INPUT AS
Form Library
FORM_ALERT
FORM_BUTTON
FORM_CENTER
FORM_DIAL
FORM_DO
FORM_ERROR
FORM_KEYBD
FRAC
FRE
fsel_exinput
FSEL_INPUT
FSETDTA
FSFIRST
FSNEXT
FULLW
FUNCTION
Fundamentals
Further Control Commands
Further Editing Commands
G
G3LIB
G3MOVE
G3OBJ
G3PRG
G3WAIT
GB
GCONTRL
GDOS?
GEMDOS
GEMDOS Error Codes
GEMDOS() Table
GEMSYS
General Graphics Commands
General Information
GET
GET #
GETSIZE
Getting Started
GFA Software Technologies, Inc.
GFA-Basic
GFA-Basic Addendum
GFA-Basic Compiler/Linker Manual
GFA-Basic Editor/Interpreter Manual
GFA-Basic History
GFA-Basic v3 float format
GFA_PTCH.TXT
GINTIN
GINTOUT
GOSUB
GOTO
Grabbing Sections of the Screen
GRAF_DRAGBOX
GRAF_GROWBOX
GRAF_HANDLE
GRAF_MKSTATE
GRAF_MOUSE
GRAF_MOVEBOX
GRAF_RUBBERBOX
GRAF_SHRINKBOX
GRAF_SLIDEBOX
GRAF_SMP.GFA
GRAF_WATCHBOX
Graphics Definition Commands
Graphics Library
GRAPHMODE
H
HARDCOPY
Help
HEX$
HIDEM
HIMEM
HLINE
HTAB
HYPertext Version
I
Icon Data Structure (ICONBLK)
ICONBLK
iexp
IF
IF-ENDIF
IKB:
IMP
IMP()
INC
Including C Functions
index
INFOW
INKEY$
INLINE
INP
INP%
INP%()
INP&
INP&()
INP()
INP?
INPAUX$
INPMID$
INPUT
INPUT #
INPUT$
INSERT
INSTR
INT
INT()
Integer Arithmetic
Integer Division
Integer Multiplication
Integer Overflow
Integer Rounding
Interpreter - Compiler Differences
Interpreter Error Codes
Interrupt Programming
Interrupt Routines
INTIN
INTOUT
Introduction
ivar
K
Keyboard and Screen Handling
KEYDEF
KEYGET
KEYLOOK
KEYPAD
KEYPRESS
KEYTEST
KEYxxx Commands
KILL
Known problems with GFA-Basic
L
L:
label:
LEFT$
LEN
LET
LIBPATCH.TXT
Library Selection
LINE
LINE INPUT
LINE INPUT #
Line Style Table
Line-A
LINE-A
Line-A Calls
Line-A Variable Table
LINEAEQU.S
LINEAVAR.H
Linker Error Messages
Linking C Functions without C Libraries
Linking Object Files
Linking with C Libraries
LIST
LLIST
LOAD
LOC
LOCAL
Local and Global Variables
LOCATE
LOF
LOG
LOG10
Logical Operators
LONG
Longer Programming Examples
Lonny Pursell
LOOP
Loop Commands
LOOP UNTIL
LOOP WHILE
Loops
LPEEK
LPENX
LPENx
LPENY
LPOKE
LPOS
LPRINT
LPT:
LSET
LST:
L~A
M
Main
MALLOC
MAT
MAT ?
MAT ABS
MAT ADD
MAT BASE
MAT CLR
MAT CPY
MAT DET
MAT INPUT
MAT INV
MAT MUL
MAT NEG
MAT NORM
MAT ONE
MAT PRINT
MAT QDET
MAT RANG
MAT READ
MAT SET
MAT SUB
MAT TRANS
MAT XCPY
Mathematical Functions
Matrix Commands
MAX
Memory Management
MENU
MENU KILL
Menu Library
MENU OFF
MENU()
menu_attach
MENU_BAR
MENU_ICHECK
MENU_IENABLE
menu_istart
menu_popup
MENU_REGISTER
menu_settings
MENU_SMP.GFA
MENU_TEXT
MENU_TNORMAL
MFREE
MichTron, Inc.
MID$
MID$()
MID:
MIN
Misc Images
MKD$
MKDIR
MKF$
MKI$
MKL$
MKS$
MOD
MOD()
MODE
MONITOR
More Complicated Calculations
MOUSE
Mouse and Joysticks
MOUSEK
MOUSEX
MOUSEY
MSHRINK
MUL
MUL()
Multiple Branching
Multiplication
MW_OUT
N
N.AES Functions
N.AES Objects
NAME
NEW
NEXT
Non-BASIC Routine Calls
NOT
Number Table
O
OBJC_ADD
OBJC_CHANGE
OBJC_DELETE
OBJC_DRAW
OBJC_EDIT
OBJC_FIND
OBJC_OFFSET
OBJC_ORDER
objc_sysvar
OBJECT
Object Library
Object Structure
OB_ADR
OB_FLAGS
OB_H
OB_HEAD
OB_NEXT
OB_SPEC
OB_STATE
OB_TAIL
OB_TYPE
OB_W
OB_X
OB_Y
OCT$
ODD
OFFSET
ON BREAK
ON BREAK CONT
ON BREAK GOSUB
ON ERROR
ON ERROR GOSUB
ON GOSUB
ON MENU
ON MENU BUTTON
ON MENU GOSUB
ON MENU IBOX
ON MENU KEY
ON MENU MESSAGE
ON MENU OBOX
OPEN
OPENW
Operator Hierarchy
Optimizations not covered in the Compiler manual
OPTION
OPTION BASE
OR
OR()
Other Commands
Other System-related Commands
Other Window-related Commands
OTHERWISE
OUT
OUT #
OUT%
OUT% #
OUT&
OUT& #
OUT?
Overview of Compiler Options
Overview of Linker Options
P
PADT
PADx
PADX
PADY
Parameter Block Structure (PARMBLK)
PARMBLK
Patches for GFA-Basic
PAUSE
PBOX
PCIRCLE
PEEK
PELLIPSE
PI
PLOT
POINT
Pointer Operations
POKE
POLYFILL
POLYLINE
POLYMARK
POS
PRBOX
PRED
PRED()
PRINT
PRINT #
PRINT # USING
PRINT AT
PRINT USING
Printing
PRN:
proc
PROCEDURE
Procedures and Functions
Program Optimization
Program Return Value
Program Tracing
Programming Accessories
Programming Example
PSAVE
PSET
PTSIN
PTSOUT
PTST
Publisher
Pull-down Menus
PUT
PUT #
Q
QSORT
QUIT
R
RAD
RAND
RANDOM
Random Access
Random Number Generator
RANDOMIZE
RBOX
RCALL
RC_COPY
RC_INTERSECT
RC_INTERSECT() Parameters
READ
RECALL
RECORD
RECORD #
Register Saving
RELSEEK
REM
RENAME
REPEAT
RESERVE
Reserved Variables
Reserving Memory Space
Resource Library
RESTORE
RESUME
RESUME label
RESUME NEXT
RETURN
Return Value of a Function
RETURN x
RIGHT$
RINSTR
RMDIR
RND
ROL
ROL&
ROL|
ROR
ROR&
ROR|
ROUND
RSET
RSRC_FREE
RSRC_GADDR
RSRC_LOAD
RSRC_OBFIX
rsrc_rcfix
RSRC_SADDR
RUN
Run in TT Ram
S
Sample Programs
SAVE
SCALE
Scan
Scan Code Table
Scrap Library
SCRP_READ
SCRP_WRITE
SDPOKE
SEEK
SELECT
SELECT-CASE Optimisation
SELECT-CASE Parameter
Sequential Access
Serial (RS232) and MIDI Interfaces
SETCOLOR
SETDRAW
SETMOUSE
SETTIME
sexp
SGET
SGN
Shell Library
SHEL_ENVRN
SHEL_FIND
SHEL_GET
SHEL_PUT
SHEL_READ
SHEL_WRITE
Shift Table
SHL
SHL&
SHL|
SHOWM
SHR
SHR&
SHR|
Simple Additions
SIN
SINGLE
SINQ
SLPOKE
Some Peculiarities
SOUND
Sound Generation
SPACE$
SPC
Special
Special ASCII Characters
Special Commands
Special VDI Routines and GDOS
SPOKE
SPRITE
SPUT
SQR
SSORT
ST-Basic float format
Start-up/Shut-down modules
STD:
STE?
STEP
STICK
STOP
STORE
STR$
STRIG
String Manipulation
STRING$
SUB
SUB()
Subroutines
SUCC
SUCC()
svar
SWAP
SWAP()
SWITCH
Symbol Table
SYSTEM
System Routines
T
TAB
TAN
Technical Support
TEDINFO
TEXT
Text Data Structure (TEDINFO)
The Compiler
The Compiler Options
The Cursor Keypad
The Editor
The File Menu
The Function of the Compiler
The Linker
The Linker Options
The Menu Bar and Function Keys
The Numeric Keypad
The Options Menu
The Origins of GFA-Basic
The Sets Menu
The Shell-Listing
The Structure of Accessories
THEN
TIME$
TIME$=
TIMER
TITLEW
TOPW
TOUCH
TRACE$
TRIM$
TROFF
TRON
TRON #
TRON proc
TRUE
TRUNC
TT?
TYPE
Type Transformation
U
UNTIL
UPPER$
Using GFA-Basic 3 For The First Time
Using the Menu Shell Program
Using with DOS Shells
V
V:
VAL
VAL?
VAR
Variable Types
VARIAT
VARPTR
VDI
VDI Routines
VDI WORK_OUT() Array Table
VDIBASE
VDIBASE.TXT
VDISYS
VID:
VOID
VQT_EXTENT
VQT_NAME
VSETCOLOR
VST_LOAD_FONTS
VST_UNLOAD_FONTS
VSYNC
VT-52
VT-52 Escape Code Table
VTAB
V_CLRWK
V_CLSVWK
V_CLSWK
V_OPNVWK
V_OPNWK
V_OPNWK() and V_OPNVWK() Input Parameter Table
V_UPDWK
V~H
W
W:
WAVE
WEND
WHILE
Window Commands
Window Library
WINDTAB
WIND_CALC
WIND_CLOSE
WIND_CREATE
WIND_DELETE
WIND_FIND
WIND_GET
wind_new
WIND_OPEN
WIND_SET
WIND_SMP.GFA
WIND_UPDATE
WORD
WORD()
WORK_OUT
WRITE
WRITE #
W_HAND
W_INDEX
X
XBIOS
XBIOS() Table
XOR
XOR()
xSORT
*
!
$
$%0
$%3
$%6
$*%
$*&
$B+
$C+
$C-
$compiler option
$E#
$E$
$F%
$F<
$F>
$I+
$I-
$M
$N+
$N-
$P<
$P>
$RC%
$RC&
$S%
$S&
$S|
$S<
$S>
$U
$U+
$U-
$Ux
$X
<
<>
<=
>
><
>=
&H
&O
&X
'
*
*var=
*variable pointer
+
-
-s
-t
.dot commands
.FF
.FO
.HE
.IN
.L+
.L-
.LL
.LR
.N0
.Nx
.P+
.P-
.PA
.PL
/
/*
//
=
=<
=>
==
==>
?
@
@func
_C
_DATA
_DATA=
_X
_Y
{}
~
eof