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
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


General Information

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

GFA-Basic v3 float format

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.

ST-Basic float format

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 Transformation

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&#124;(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&#124;(x|,1),8) 6 12 00000110 00001100 130 5 10000010 00000101 x| ROR|(x|,3) BIN$(x|,8) BIN$(ROR&#124;(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%)

Chapter 6 - Input and Output

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

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

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

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

Data Input and Output

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$

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 #

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 #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

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

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

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

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

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()+

Pull-down Menus

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

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(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

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 Library

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

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

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

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

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

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

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

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

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

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+

V_OPNWK() and V_OPNVWK() Input Parameter 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.

Using the Menu Shell Program

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 File Menu

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 Options Menu

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.

The Sets Menu

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

Additional Information

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