August 17, 1988
Atari Corporation
1196 Borregas Avenue
Sunnyvale. CA 94086
Copyright 1988 by Atari Corp. All rights reserved. No part of this publication may be reproduced, transmitted, transcribed, stored in a retrieval system, or translated into any language or computer language, in any form or by any means, electronic, mechanical, magnetic, optical, chemical, manual, or otherwise, without the prior written permission of Atari Corp., 1 196 Borregas Ave., Sunnyvale, CA 94086.
ATARI CORP. MAKES NO REPRESENTATIONS OR WARRANTIES WITH RESPECT TO THE CONTENTS HEREOF AND SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE. Further, Atari Corp. reserves the right to revise this publication and to make changes from time to time in the content hereof without obligation of Atari Corp. to notify any person of such revision or changes.
Atari, ST, Mega, and TOS are trademarks or registered trademarks of Atari Corporation.
TOS 1.4 Release Notes were printed in the United States of America.
First Edition: August 17, 1988
This document was produced with an Atari Mega 4 computer using Microsoft Write and an Atari SLM804 laser printer.
Changes made:
Changes made:
What follows is supplemental documentation to the existing AES manual, or clarifications of existing documentation.
ob_ednewidx - not used.
ob_edtree - the address of the object tree containing the object with the text to be edited.
ob_edreturn = objc_edit( ob_edtree, ob_edobject, ob_edchar, ob_edidx, ob_edkind);
Purpose: Display an alert.
Section 7.2 describes the complete sequence of calls internal to FORM ALERT.
Parameters:
control(0) = 52 control(1) = 1 control(2) = 1 control(3) = 1 control(4) = 0 int_in(0) = fo_adefbttn intout(0) = fo_aexbttn addr_in(0) = fo_astring
fo_adefbttn the form's DEFAULT exit button (see section 7.1.3.1)
0 - no DEFAULT exit button 1 - first exit button 2 - second exit button 3 - third exit button
fo_aexbttn a number identifying the exit button selected by the user
1 - first exit button in string 2 - second exit button in string 3 - third exit button in string
fo_astring the address of the string containing the alert
Sample call to C language binding:
fo_aexbttn = form_alert( fo_adefbttn, fo_astring);
Purpose: Display an error box.
Parameters:
control(0) = 53 control(1) = 1 control(2) = 1 control(3) = 0 control(4) = 0 int_in(0) = fo_enum nt_out(0) = fo_eexbttn
fo_enum the GEMDOS error codes in PC DOS format (from 1 onwards). fo_eexbttn a code identifying the user's exit button selection.
1 - first exit button in string 2 - second exit button in string 3 - third exit button in string
Sample call to C language binding:
fo_eexbttn = formerror( fo_enum);
Error messages:
fo_enum 2,3,18 This application cannot find the folder or file you just tried to access. fo_enum 4 This application does not have room to open another document. To make room, close any document that you do not need. fo_enum 5 An item with this name already exists in the directory, or this item is set to Read-only status. fo_enum 8, 10, 11 There is not enough memory for the application you just tried to run. fo_enum 15 The drive you specified does not exist.
Purpose: Tells GEM AES whether to run another application and, if so, which application to run.
Parameters:
control(0) = 121 control(l) = 3 control(2) = 1 control(3) = 2 control(4) = 0 int_in(0) = sh_wdoex int_in(1) = sh_wisgr int_in(2) = sh_wiscr int_out(0) = sh_wreturn addr_in(0) = sh_wpcmd addr_in(1) = sh_wptail
Description: sh_wdoex a coded instruction to exit the system or run another application when the user exits the current application.
0 - exit and return to GEM DESKTOP 1 - run another application
sh_wisgr a code for whether the next application is a graphic application.
0 - not a graphic application 1 - graphic application
sh_wiscr currently ignored by the AES. sh_wreturn a coded return message
0 - an error exists n - no error exists
sh_wpcmd the address of the new command file to execute ah_wptail the address of the command tail for the next program
Note: The first byte of the command tail buffer contains the length (in bytes) or the command tail. The actual command tail begins at the second byte of the buffer.
Sample call to C language binding:
sh_wreturn = shel_write(shwdoex, sh_wisgr, sh_wiscr, sh_wpcmd, sh_wptail );
Purpose: Let the application read data from the AESs shell internal buffer. Note: The length of the get data buffer should not be more than 1024 bytes. Parameters:
control(0) = 122 control(l) = 1 control(2) = 1 control(3) = 1 control(4) = 0 intin(0) = sh_glen addr_in(0) = shgbuff int_out(0) = sh_greturn
sh_greturn a coded return message
0 - an error exists n - ( positive integer ) no error exists
sh_glen the length of the buffer. sh_gbuff the address of the buffer.
Sample call to C language binding:
sh_greturn = shel_get( sh_gbuff, sh_glen);
Purpose: Let the application save data into the AES's shell internal buffer. Note: Currently, the AES Desktop uses this buffer to store the desktop.inf data. Any usage of this buffer may corrupt the data that are already stored there. The length of the data that goes into the buffer should be no more than 1024 bytes. Parameters:
control(0) = 123 control(1) = 1 control(2) = 1 control(3) = 1 control(4) = 0 int_in(0) = sh_plen addrin(0) = sh_pbuff int_out(0) = sh_preturn
sh_preturn a coded return message
0 - an error exists n - ( positive integer ) no error exists
sh_plen the length of the buffer. shpbuff the address of the buffer.
Sample call to C language binding:
shpreturn = shel_put( sh_pbuff, sh_plen);
There are two new AES calls, FSEL_EXINPUT and WIND_NEW. They are documented below:
Purpose: This function has the same functionality as the FSEL_INPUT call except that it accepts an additional input parameter called fs_label to display a string of 30 characters on the top of the file selector box. This string will replace the original 'File Selector' string. The purpose of this additional feature is to allow the program to show more information, e.g. Reading or Writing, while the user selects a file. Parameters:
control(0) = 91 control(1) = 0 control(2) = 2 control(3) = 3 control(4) = 0 intout(0) = fs_ireturn int_out(1 ) = fs_iexbutton addr_in(0) = fsiinpath addrin(1) = fs_innsel addr_in(2) = fslabel
fs_ireturn A coded return message.
0 - an error exists n - (positive integer) no error exists
fs_iexbutton A code identifying the exit button selected by the user.
0 - Cancel 1 - OK
fs_iinpath The address of the buffer that holds the initial directory specification displayed in the File Selector dialog box. This buffer will also hold the directory specification that was in the File Selector dialog box when the user selected OK or Cancel. fs_innsel The address of the buffer that holds the initial selection displayed in the File Selector dialog box. This buffer will also hold the selection that was in the File Selector dialog box when the user selected OK or Cancel. fs_label The address of the string that will be displayed on the top of the File Selector box.
Sample call to C language binding:
fs_ireturn = fsel_exinput( fsjnnpath, fsinnsel, &fs_iexbutton, fs_label);
Purpose: Closes and deletes all windows, resets the wind_update() function, flushes all the windows' buffers and restores mouse ownership back to the system. Parameters:
control(0) = 109 control(1) = 0 control(2) = 0 control(3) = 0 control(4) = 0
Sample call to C language binding:
wind_new();
Changes made:
Changes made:
Starting with the 4/22/87 (Mega) ROMs, there are three more system variables which you can access: pointers to them are in the system header block. A pointer to the system header block can be found at address $4f2 (_sysbase).
At offset $20 from the address at _sysbase is a pointer to the variable “_root.” root is a pointer which holds the base of the ospool, the internal memory used by GEMDOS. This pointer is used by FOLDR100.PRG. You can still add pool to the OS the same way as before, but you should know that the OS will take the pool you added and use it D/FFERENTL Yfrom the way it was used before. The rule is: once you give memory to the OS, DON'T TOUCH IT after that.
At offset $24 from _sysbase is a pointer to the variable kbshift, a word which holds the keyboard shift state bits. This is updated at the interrupt level.
At offset $28 from sysbase is a pointer to the variable _run, a longword which holds the process ID (basepage address) of the process GEMDOS is currently executing.
All these variables are for reading only – unpredictable and bad things can happen if they are written to. Kbshift is the most useful of these, because it lets you check for a keyboard shift key sequence very quickly. For instance, the following combination of routines can be used to test for both left and right shift keys down, which you could use to cause a break in your program.
int *p_kbshift; init() { long _sysbase = *( (long*)0x4f2); p_kbshift = *(long *)(_sysbase + 0x24); } #define kbtest() { if ( (*(p_kbshift) & 0x03) == 0x03) abort(); }
After init() is called, using the macro kbtest() inside the main loop of your program is a fast way to detect both shift keys down – a signal that the user wants to abort. This is much faster than using the Kbshift() BIOS call, and amounts to the same thing.
The “reset bailout vector” does not work as previously documented. The old documentation states that you can place the address of a routine at _resvector, place the magic number $3141526 in _resvalid, and your routine will get called when the user hits the reset button. So far, that is all true. The documentation continues, saying that you can return to the reset routine (presumably, after doing whatever you wanted to do at reset time) with the instruction “JMP (a6)” this is incorrect: “JMP $24(a6)” is the correct instruction.
You can add buffers to GEMDOS to improve system performance. There are two buffer lists: one list for the FATs, and one for root directories and the rest of the disks. A buffer control block (BOB) can look like this:
struct _bcb { struct _bcb *blink; /* -> next BCB */ int b_negl; /* initialize to -1 */ int b_private[5]; /* don't touch */ char *b_bufr; /* -> 512-byte buffer */ char b_space[5121; /* 512-byte buffer */ }
[In the OS, the buffer control block and the 512-byte data block are separate, not one after the other like this. That doesn't matter here.]
To add a buffer, do this:
Repeat the above once per buffer you want to ail, cate Then terminate and stay resident, reserving the memory you just gave to the OS.
There are internal limits in GEMDOS which programmers and users must understand. In a broad sense, you should know that these limits have to do with the maximum depth of your hierarchical file structure (subdirectories), and the number of open files you can have at once. In most cases, users will never come up against any of these limits.
The limits come into play when you have lots of files open at the same time, and they are deep in different subdirectory trees. Also, programs which call the operating system function Malloc (memory allocator) influence these limits lots of Malloc calls means less space is available for keeping track of open files and the subdirectories leading up to them.
Technically, the limits are as follows: there are 80 blocks in the system's “OS pool” two blocks are used per active folder. An “active” folder is one which is the root directory of the device it's on, or which has open files, or which is somebody's current directory, or which has an “active” child (subdirectory). Yes, this is a recursive definition. Remember that each process has a current directory on every logical device, but also remember that one folder only takes up two blocks, no matter how many reasons it's “active.”
In addition, one block is used per open file, and 1/4 block is used per memory chunk (allocated or free) in the system memory.
When files are closed, memory chunks are freed, and when processes terminate, blocks are treed back into the OS pool.
The improvement over previous ROMs is this: the old definition of “active” was “seen” getting a list of the files in a directory caused all the folders there to take up blocks in the pool. In addition, blocks were never freed in the pool. Also, once parts of the pool had been used for managing Malloc memory chunks, they were unavailable for managing folders, and vice versa. All these restrictions are lifted.
it is still possible to run out of OS pool, of course. The program FOLDR100.PRG was released by Atari and is part of the HDX (harddisk utilities) distribution. It adds memory to the OS pool, and it still works, adding memory to the new kind of pool, too. Placing this program in your AUTO folder causes 200 more blocks to be added to the OS pool, which is room for 100 more folders (remember, only ACT/L'Efolders take up room) or 800 more memory chunks, or any combination.
The name FOLDR100.PRG can be changed: the three digits in the name are interpreted as the number of “folders” you want to add at two blocks each. So FOLDRO5O.PRG would add only 100 blocks, while FOLDR200.PRG would add 400. No matter where the program is started from, it looks for itself in the \AUTO\ folder of the boot device to determine how many blocks to add.
it is to be stressed that this program usually will not be necessary. Only if you have an inordinate number and depth of folders, open files, etc. will you run out of pool, because it is so much more efficiently managed than before.
In the unlikely event that you do run out of pool, the following message will appear on your screen:
*** OUT OF INTERNAL MEMORY: *** USE FOLDR100.PRG TO GET MORE *** SYSTEM HALTED ***
(This message appears in English regardless of the country you are in.)
It is regrettable but true that there is nothing you can do at this point but hit the reset button or use the keyboard reset combination (CTRL-ALT-DELETE). Remember what you were doing when this happened: were you trying to create a directory that was 50 levels deep in the hierarchy? Were you opening the tenth different file in the tenth different subdirectory? If you really want to be able to do whatever you were stopped from doing, use FOLDR100.PRG (or increase the “100” if you're already using it).
Note: the system call Malloc will never cause a panic: it will just return 0, meaning it couldn't satisfy the request. When this happens, however, your program has stretched the limits of the system, because that means there is not even 1/4 of one block available for the memory manager. At this point a welldesigned program will detect the condition (out of memory) and terminate, freeing up enough blocks to be useful.
Disclaimer: this isn't how it should be; this is how it is.
| Attribute bit | Name | Comments |
|---|---|---|
| 0×01 | Read-only | Denies delete and open for write. |
| 0×02 | Hidden | See below. |
| 0×04 | System | See below. |
| 0×08 | Volume label | Exclusive (no other bits should be set) |
| 0×10 | Subdirectory | Exclusive (no other bits should be set) |
| 0×20 | Archive | File is new or has been modified. (Doesn't work in old system, will in new: literally, “file is new or has been written to.”) |
| 0×40 | RESERVED | |
| 0×80 | RESERVED |
File attribute 0×08 is exclusive: no other bits should be set. Same with 0×10. These restrictions are NOT enforced by the current operating system, but they will be by the g. one. Files with illegal attribute combinations are not guaranteed to work predictably.
This is a list of matching rules for attributes in Fsfirst / Fsnext searches:
So, with “ia” the input attribute and “fa” the file attribute, match if this expression is TRUE:
((!fa && (ia != 8)) || ((ia | 0x21) & fa)) /* A B C D */
(A) && (B) means fa 0 matches any search except 0×08. (C) & (D) means a one bit match between fa and ia matches, but also that fa with archive or read-only set will cause a match regardless.
This means that for a hidden file to be hidden, it can't be R/O or ARCHIVE. Same for a system file. A file which is both hidden and system (but nothing else) will appear when either of these bits is set in the input attrbute.
By #3, subdirectories are included when (input & 0×10) != 0. Same with volume labels and (input & 0×08) != 0.
You can Fcreate files with any combination of the ARCHIVE, R/O, HIDDEN, and SYSTEM bits. You cannot use Fattrib to change to an illegal combination, and you cannot use Fattrib, Frename, Fopen, or Fdelete on labels or subdirectories.
The correct arguments for Pexec are (and always have been):
long errcode = Pexec(0,prgfile,cmdline,envptr); /* load & go */ long basepage = Pexec(3,prgfile,cmdline,envptr); /* load, don't go */ long errcode = Pexec(4,0L,basepage,0L); /* just go */ long basepage = Pexec(5,0L,cmdline,envptr) /* just create a base page */ char *prgfile; /* the file to load */ char *cmdline; /* command line; first byte is its length */ char *envptr; /* 0L or points to double-null-terminated env */
If the envptr argument is 0L, the child inherits a copy of your environment. See the discussion of the environment string for more about this.
The “command line” argument is not a normal “C” string. It is a character buffer where the first byte is the length of the remaining text, and that text is also nullterminated. Pexec copies this buffer up to the first null byte OR up to 126 characters into the new basepage. Argument parsers use the length byte to know when to stop.
Pexec mode 0 is the only one which really works reliably. The others run into trouble with memory and file ownership and things like that. Use them only with extreme caution. The environment string passed to Pexec is defined as a series of null-terminated strings. The suggested format for these strings is the same as MS-DOS and UNIX (UNIX is a trademark of AT&T Bell Labs):
NAME1=value\0 NAME2=value2\0 ... NAMEn=vaIuen\0\0
All that is enforced, however, is the trailing doublenull: the environment string is copied up to the first double-null.
The Desktop starts programs with a slightly different environment string:
PATH=0A:\00
This is a bug, and should not be considered the “official” environment format.
*
*
* mediach: cause media-change on a logical device.
*
* USAGE:
* encode = mediach(devno); /* returns 1 for error */
* int errcode, devno;
*
* This procedure causes a media change by installing a new
* handler for the mediach, rwabs, and getbpb vectors; for device
* devno, the mediach handler returns "definitely changed," and
* the rwabs handler returns E_CHNG, until the new getbpb handler
* is called. The new getbpb handler un-installs the new
* handlers.
*
* After installing the new handlers, this procedure performs a
* disk operation (e.g. open a file) which makes GEMDOS check
* the media-change status of the drive: this will trigger the
* new rwabs, mediach and getbpb handlers to do their things.
*
* RETURNS: 0 for no error, 1 for error (GEMDOS didn't ever do a
* getbpb call; should never happen.)
*
*
.globl _mediach
_mediach:
move.w 4(sp),d0
move.w d0,mydev
add.b #'A',d0
move.b d0,fspec ; set drive spec for search first
loop:
clr.l (sp) ; get super mode, leave old ssp
move.w #$2O,(sp) ; and "super" function code on stack
trap #1
addq #6,sp
move.l d0,(sp)
move.w #$2O,(sp)
move.l $472,oldgetbpb
move.l $47e,oldmediach
move.l $476,oldrwabs
move.l #newgetbpb,$472
move.l #newmediach,$47e
move.l #newrwabs,$476
; Fopen a file on that drive
move.w #0,(sp)
move.l fspec,(sp)
move.w #$3d,(sp)
trap #1
addq #8,sp
; Fclose the handle we just got
tst.l d0
bmi.s noclose
move.w d0,(sp)
move.w #$3e,(sp)
trap #1
addq #4,sp
noclose:
moveq #O,d7
cmp.l #newgetbpb,$472 ; still installed?
bne.s done ; nope
moveq #1,d7 ; yup! remove & return TRUE
move.l oldgetbpb,$472
move.l oldmediach,$47e
move.l oldrwabs,$476
done:
trap #1 ; go back to user mode (use stuff
addq #6,sp ; left on stack above)
move.l d7,d0
rts
*
*
* new getbpb: if it's our device, uninstall vectors;
* in any case, call the old getbpb vector (to really
* get it)
*
*
newgetbpb:
move.w mydev,d0
cmp.w 4(sp),d0
bne.s dooldg
move.l oldgetbpb,$472 ; it's mine: uninstall new vectors
move.l oldmediach,$47e
move.l oldrwabs,$476
dooldg: rnove.l oldgetbpb,a0 ; continue here whether mine or not: call old.
jmp (a0)
*
*
* new mediach: if it's our device, return 2: else call old.
*
*
newmediach:
move.w mydev,d0
cmp.w 4(sp),d0
bne.s dooldrn
moveq #2,d0 ; it's mine: return 2 (definitely changed)
rts
dooldm: move.! oldmediach,a0 ; not mine: call old vector.
jmp (a0)
*
*
* newrwabs: return E_CHG (14) if it's my device
*
*
newrwabs:
move.w mydev,d0
cmp.w $e(sp),d0
bne.s dooldr
moveqi #14,d0
rts
dooldr: move.l oldmediach,a0
jmp (a0)
.data
fspec: dc.b "X:\\X",0 ; file to look for (doesn't matter)
.bss
mydev: ds.w 1
oldgetbpb: ds.l 1
oldmediach: ds.l 1
oldrwabs: ds.l I
*
*
* end of mediach
*
*
The arguments to Fdatime are incorrectly documented: the correct usage is:
Fdatime(timeptr,handle,wflag) int *timeptr; /* ptr to 2 ints */ int handle; /* handle to read/write */ int wflag; /* 1 to write from timeptr to file, 0 to read */
The approved method of determining isatty is as follows:
int isatty(handle) int handle; { long oldoffset; long rc; oldoffset = Fseek(0L,handle,1); rc = Fseek(1L,handle,0); Fseek(oldoffset,handle,0); if (rc == 1 ) return 0; return 1; }
Megamax C implements isatty using Fdatime. GEMDOS error numbers are documented wrong: ENMFIL is -49, not -47, and ENSAME is -48.
Rsconf was documented as 'void' but actually returns the old values of ucr,rsr,tsr,scr registers. They are byte-packed in that order (high-to-low order) in the LONG return value. It always did, but wasn't documented as such until now.
AHDI adds devices to the system starting with drive C, without regard to _drvbits and existing drives. Also, 4/22/87 (Mega) ROMs clear _drvbits on warm boot, unlike 11/20/85 ROMs, so eternal RAMdisks which used that as their telltale stopped working for this reason (possibly among others).
Bconout to the printer returns 0 for failure, !0 for success. This is used for the “your output device is not responding” message in the desktop. This is not handled through the critical error handler. This has been true of all ROMs. (GEMDOS just happens to return the leftover value from D0, so using the GEMDOS Cprnout() function returns this, too. Newer GEMDOS explicitly returns the status from the BIOS call from Cprnout.) The Super() call is incorrectly documented: Super(1L) interrogates supervisor mode. It returns -1L if you're in super mode, and 0L if user mode. [The original documentation said that Super(-1L) returned 1L if in super mode. In fact, Super(-1L) gives an address error.]
Super(0L) returns the old supervisor stack pointer, and returns with the processor in supervisor mode. The argument 0L means “use my old user stack as the supervisor stack.” There is usually plenty of space on the user stack for both you and any interrupts, etc. which come along.
The Super() call is intended to work like this
extern long trap1(); *define Super(x) trap1(0x20,x) super_sample() { long oldssp; /* get super mode */ oldssp = Super(0L); /* do stuff in super mode; ssp is old usp. Don't call AES! */ /* get back to user mode */ Super(oldssp); }
There may be some vagaries of using it in other ways: be careful. Calling AES will blow up in a big way, because AES uses usp to store your registers (even if it's called from supervisor mode). The XBIOS documentation for the Sctscrccn call states that the new physical screen base being set will take effect at the next VBLANK. The fact is, it takes effect immediately.
The system variable screenpt has the behavior that when it is NULL, nothing happens, but when it is nonnull, it gets stuffed into the hardware as the physical screen base at VBLANK time. (Since the VBLANK routine doesn't clear it, it keeps stuffing the same value over and over – no big deal, just wasted time.)
If you mix both of these tricks to change the physical screen base, you will find they don't work together. If you use either one exclusively, it will work as it always has – the documentation notwithstanding.
Do not Frename or Fdelete an open file. If you Fdelete a file which somebody else has open, it will be denied. If you Fdelete a file which YOU have open, GEMDOS closes the file and then deletes it. UNFORTUNATELY there is a bug: GEMDOS closes the file, but not the file's handle. The handle lives on in the OS Pool, taking up space forever. Frename is worse: it doesn't even ATTEMPT to close the file or deny access.
The version number is the best way to check the version of the ROMs. It lives at the second word of the ROM (which is to say, at offset $2 from the start of the OS header, which is pointed to by _sysbase (at $4f2))
The 11/20/85 (original) ROMs have the version number $0100. The 4/22/87 (Mega) ROMs have the version number $0102. The latest ROMs (TOS 1.4) have the version number $0104.
You can check the version number of GEMDOS specifically using its Sversion call, and you can check the date in the OS header, but the version number is the best bet because it is the same across all countries, whereas the date sometimes isn't.