Description of the DOS kernel of Mag!X V3.00/V4.xx/V5.xx/V6.xx
##############################################################

Andreas Kromke
Hannover, 1.11.98
English translation: Peter West, April 99

Formatting: Tabulator width 5 columns


Preface to MagiC version 4.50:
------------------------------

This version implements threads and signals. Threads are handled on the 
AES level and are described in THREADS.TXT (in the AES folder), which 
also contains notes for the use of signals in "multi-threaded" programs.
For a general description of the signal concept of MagiC see SIGNALS.TXT, 
for the use of pipes and differences to the MiNT specification see
PIPES.TXT (both are in the topmost folder of the documentation).

Translator's note: Mag!X was renamed to MagiC from version 4.xx onwards.



I Concepts
==========


GEMDOS was till now the most conservative part of the Mag!X operating 
system.  For network drivers practically all DOS calls including Pexec() 
had to be imitated, without being able to intervene at a lower level.
In Mag!X 1.x (as in TOS) the DOS was not even reentrant, as a statically 
created stack was used.

In MultiTOS/MiNT this problem is circumvented in a manner that so to say 
superimposes a system onto GEMDOS that deals with all the higher 
management functions, can handle other (non-DOS) file systems and only 
uses GEMDOS as a "dumb" file system driver. The advantage of this system 
is its great flexibility and extendability, though a decisive drawback 
is the massive overhead when using "normal" DOS file systems, which are 
just the ones that are installed by far the most often.
In addition, the GEMDOS file system can gain nothing in functionality, 
ease of use or speed by the use of MiNT, as it just runs the old 
routines with an additional overhead. Thus file system accesses under 
MiNT are generally not reentrant, so that (as under MS-Windows) every 
floppy or hard disk access paralyses the whole computer.

A further property of MiNT is the endeavour to incorporate the functions 
that are common to all file systems into the kernel. Although this keeps
the file system drivers (MiNT-XFSs) compact, the Inode-oriented makeup
of the kernel functions can in some circumstances force an unfavourable 
structure on the file drivers; furthermore, in general many calls of the 
file system driver are needed for one DOS call. Finally the MiNT kernel 
itself is very long, but lies fallow to a large extent as long as no 
other file systems than DOS are in use.

Under Mag!X a different approach was chosen that consisted of a complete 
rewrite of GEMDOS from the ground up, including the low-level functions 
for sector buffering, and in dividing everything up into three, four or 
five layers that may be accessed from outside (by means of loaded-in 
drivers). A side-effect resulted in extending the functionality of the DOS
file system, and creating an additional file system on logical drive U:.
The whole concept, including accesses to DOS file systems, is reentrant 
and takes place in the background. Thus it is possible to work with 
files on drive A:, for instance, without slowing down the computer to 
any marked extent during disk accesses. Despite this Mag!X till now has 
become only some 10 kB longer. In comparison to MiNT, however, more 
functions were farmed out to the file system drivers, and although this 
makes them larger it gives them the possibility to perform their 
functions much more efficiently. If anything, the DOS file system has 
become somewhat faster rather than slower.

Though realised completely in assembler, we have here an object-oriented 
system with virtual functions and multistage inheritance. A file 
descriptor (FD), as used in the kernel and made available by the XFS, is 
an object with special data fields and functions. But the XFS also 
realises a derived object with additional data fields and functions.
Finally the DFS sub-driver of DOS_XFS must in turn accommodate further 
functions and data fields in the FD and extends the class further. 
Things look exactly the same with the DMD (drive medium descriptor). The 
kernel requires only a little data, the lower layers however appreciably 
more, though always different ones.

The layers in detail:

1. The DOS kernel. The functions are described in this file (MGX_DOS.TXT).
   The kernel is incoprporated in Mag!X itself and is called directly 
   by the application programs via trap #1. It contains modules for 
   memory management, process management and file management.
   The latter has the following "sub levels":
2. The file system (XFS = extended file system). Its makeup differs 
   fundamentally from a MiNT XFS, but fulfills the same purpose.
   MagiC for Atari contains only a single XFS, the so-called "DOS_XFS",
   though others may be installed. MagiC for Macintosh contains 
   internally the Mac-XFS as well.
   The makeup of an XFS is described in the file MGX_XFS.TXT (in the 
   FILESYS folder).
   This file system in particular again makes use of sub-drivers:
2a A DOS file system (DFS), called by the DOS_XFS. It includes only the 
   file functions, while the directory management is undertaken in 
   effect by the DOS_XFS.
   Mag!X directly contains two DFSs. One for drive U:, a second for FAT 
   file systems that are accommodated on BIOS drives.
   Further DFSs can be installed. Less work has to be done by a 
   programmer to create a DFS than an XFS, as many functions will have 
   been performed already by the DOS_XFS. The essential prerequisite is 
   a DOS-conform directory structure (with 32-byte entries and filenames 
   in the format 8+3).
   The structure of a DFS is described in the file MGX_DFS.TXT (in the 
   FILESYS folder). The kernel itself does not come into contact with 
   the DFS, but controls it transparently via the DOS_XFS.
3. The file-drivers (MX_DEV), that essentially look after the reading 
   and writing of a file. They are created and managed by the XFS, but
   for functions such as Fread() and Fwrite() are called directly from 
   the kernel, which creates an exteremely low overhead.
   The DOS_XFS in fact contains only one file-driver. This looks after 
   the updating of the directory during write accesses, for instance, 
   and calls a sub-driver (MX_DDEV) in turn.
3a The sub-driver MX_DDEV, called only by the DOS file-driver of the
   DOS_XFS file system.
   Users can incorporate their own MX_DDEVs via the directory U:\DEV\. 
   The buildup of the U file system is described in MGX_UDFS.TXT, the 
   buildup of the MX_DDEV structure in MGX_DFS.TXT (both again in the 
   SYSTEM folder). The kernel does not come into contact with the 
   sub-drivers.



II The system functions
=======================


unsigned WORD Sversion( void )
------------------------------

This returns the DOS version number in Intel format. The return value in 
Mag!X is actually a "long", the high word is 0.
A version 0.19 will be reported that corresponds to TOS 1.4 (?). One 
can obtain a reliable statement about the Mag!X version number via the  
Mag!X-specific AES variables. Apart from the DOS version number there 
is also the TOS version number (is always 4.0 for Falcon, 3.0 for 
TT and 2.0 for ST) and the AES version number (4.00).


LONG Sconfig( WORD subfn, LONG flags)
-------------------------------------

This manipulates the configuration longword, which is also accessible 
via the MagiC-cookie.

* fn == SC_GETCONF	(0): Get status longword
* fn == SC_SETCONF	(1): Set status value
* fn == SC_DOSVARS	(2): Get pointer to system variable
* fn == SC_MOWNER	(3): Mowner
* fn == SC_WBACK	(4): Configure WB-Daemon
*					subfn == 0:	Read PD of WBDAEMON
*					subfn == 1:	Set PD
*					subfn == 2:	Switch off WB
* fn == SC_INTMAVAIL(5): Scan internal memory availability
* fn == SC_INTGARBC (6):	Garbage collection for internal memory

The variable <flags> has the following significance:

     Bit 0:    Path checking on
     Bit 1:    Insert mode for GEMDOS and dialog boxes
     Bit 2:    Reserved
     Bit 3:    Reserved
     Bit 4:    Fastload for floppy disk off
     Bit 5:    TOS compatibility on
     Bit 6:    "Smart redraw" off
     Bit 7:    Grow- and shrink-boxes off
     Bit 8:    No wait after TOS programs
     Bit 9:    Reserved
     Bit 10:   Pulldown menus
     Bit 11:	DMA parallel operation of floppy disk drive off

The remaining bits are reserved and may not be altered. 
With mode == 0 the bits are read, with mode == 1 written (only 
works with compatibility deactivated), with mode == 2 one obtains 
a pointer to the DOSVARS structure that is defined in MAGX.H:

typedef struct
   {
   long      res0;       	        /* 						*/
   int       *dos_time;               /* Address of DOS time		*/
   int       *dos_date;               /* Address of DOS date		*/
   long      res1;                    /*                            	*/
   long      res2;                    /*                            	*/
   long      res3;                    /* Is 0L                   	*/
   void      *act_pd;                 /* Running program            	*/
   long      res4;                    /*                            	*/
   int       res5;                    /*                            	*/
   void      res6;                    /*                            	*/
   void      res7;                    /* Internal DOS memory list   	*/
   void      (*resv_intmem)();        /* Extend DOS memory          	*/
   long      (*etv_critic)();         /* etv_critic of GEMDOS       	*/
   char *    ((*err_to_str)(char e)); /* Conversion code->clear text 	*/
   long      res8;                    /*                            	*/
   long      res9;                    /*                            	*/
   } DOSVARS;

With the aid of the function resv_intmem() one can reserve memory for 
the internal memory management in a way similar to using FOLDRnnn. In 
contrast to TOS, though, this bears as appreciably lower burden, so that 
generally an extension will not be required. If the memory block has to 
be extended, which can be done with ADDMEM as well, one passes to the 
function resv_intmem() in a0 the address and in d0 the length of the 
memory block to be reserved.
The prototype for the event-critic-handler is named "long etv_critic(int 
errcode, int drvnr)". One should note that the function expects the 
arguments on the stack and hence has to be declared in PureC as "cdecl".
err_to_str() expects in d0 a TOS error code and returns in d0 and a0 a 
pointer to the descriptive character string. For an invalid error code 
one gets a NULL in d0 and a pointer to the character string "TOS Error" 
in a0.


void Syield( void )
-------------------

In MagiC this calls appl_yield() directly. In the AUTO folder this 
command is ignored.


void Ssync( void )
------------------

Opcode 0x150.
This synchronises all "mounted" file systems.
It exists from MagiC 4.01 onwards.


LONG Sysconf( WORD n)
---------------------

Under MiNT this returns global limitations and capabilities of the system.
It is not supported by Mag!X at present.


void Salert( char *mesg )
-------------------------

Under MiNT this sends an error message to the alert-pipe u:\pipe\alert, 
from where a program can do something like a form_alert(). I wonder what 
happens at an overflow of the pipe under MiNT?
It is not supported by Mag!X at present.


LONG Srealloc( LONG len )
-------------------------

Allocates a block of length <len> for the screen memory. If <len> == -1, 
then the maximum possible size of the screen memory will be returned.
The screen memory is a block of ST-RAM whose owner is the boot process.
The address of the screen memory (logbase or physbase) is not affected.


WORD Tgetdate( void )
---------------------

This function under Mag!X is actually an "unsigned long". It returns the 
date of the DOS interrupt clock, which is used for setting the file data.


WORD Tsetdate( WORD date )
--------------------------

This function under Mag!X is actually an "unsigned long". The date of 
both the DOS interrupt clock as well as the realtime clock will be 
altered, i.e. in an ST the IKBD clock, in a Mega the "Mega" clock and in 
a TT the TT clock. The return value is ERROR if the date is invalid, 
else E_OK. In contrast to TOS, month or date 0 as well as a date > 2099 
are recognised as errors.


WORD Tgettime( void )
--------------------

This function under Mag!X is actually an "unsigned long". It returns the 
time of the DOS interrupt clock, which is used for setting the file 
data.


WORD Tsettime( WORD time )
--------------------------

This function under Mag!X is actually an "unsigned long". The time of both 
the DOS interrupt clock as well as the realtime clock will be altered, 
i.e. in an ST the IKBD clock, in a Mega the "Mega" clock and in a TT the 
TT clock. The return value is ERROR if the time is invalid, else E_OK. 
In contrast to TOS, hours > 23 are recognised as an error.



III The memory management functions
===================================


LONG Maddalt( void *start, ULONG size )
---------------------------------------

Adds the block to Mag!X's memory management. The block remains the 
property of DOS and may not be reclaimed. If the added blocks are not 
contiguous (do not lie one after the other), then the number of blocks 
that can be added is restricted to around 12.
Returns: 	ENSMEM    Start address or block length is odd, or too many
                    isolated blocks installed
          E_OK      Block is installed.


void *Mxalloc( ULONG size, WORD mode )
--------------------------------------

mode == 0: ST-RAM only
        1: Alternative RAM only
        2: ST-RAM preferred
        3: Alternative RAM preferred
   Bit 14: Don't free
   Other bits are ignored

Alternative RAM means "everything except ST-RAM", i.e. TT-RAM or RAM 
installed via Maddalt().
If size == 0L, a pointer ((void *) 1L) will be returned; this is for 
reasons of compatibility with older programs. Newer TOS versions report 
an error, so return NULL.
If size == -1L the size of the largest free block will be returned; in 
the case of mode == 2 or mode == 3 the size of the larger block.

Warning:  Under Mag!X, due to constant changes of context, there is
		no guarantee that a call Malloc(Malloc(-1L)) will work.
		Quite apart from the fact that one should never allocate  
		all of the memory!

Under Mag!X since version 1.0 a record is kept of all memory allocations.
If the restriction predefined with LIMITMEM is exceeded then a null-
pointer is returned. In the case of size == -1, the lower of free memory 
and not yet exhausted LIMITMEM restriction is returned. Exceptions to 
this are calls of the screen manager (SCRENMGR) that controls the menus. 
This ensures that even programs restricted with LIMITMEM have no problems 
with menu redraws.


void *Malloc( ULONG size )
--------------------------

This call can be implemented as Mxalloc() with the modes 0 or 3, depending 
on the configuration bits in the program file header. The configuration 
bits are stored in the basepage at present.


long Mfree( void *memblock )
----------------------------

Malloc(0) returns 1L. If this pseudo pointer is passed to Mfree() by 
Mfree(1), then E_OK will be returned. For an odd address or invalid 
region EIMBA will be returned.
Else the block will be marked as free and the memory restriction limit 
(=>LIMITMEM) increased again.
At present no check is made that the memory block to be released really 
belongs to the calling process. This is particularly necessary for 
debuggers that manipulate memory blocks of their child processes. 
Possibly such a check will be built in sometime in the future.

Warning: Mag!X 1.x and 2.x react to odd addresses with bombs.
         Mag!X 1.10, 1.11 and 2.00 can also bomb with invalid memory
         addresses lying outside memory actually present.


long Mshrink( char *memblock, ULONG size )
------------------------------------------

The memory block allocated with M(x)alloc() that starts at address <size>
is assigned a new size. In contrast to TOS one can also increase the 
size of memory blocks, provided that a sufficiently large free block is 
available above it (otherwise EGSBF will be returned). A prerequisite is 
that TOS-compatibility has been deactivated.
If -1L is passed as the size, then the maximum possible size of the 
memory block will be returned.
If 0L is passed as the size, then the block will be released. TOS (at 
least up to 1.4) reacts to this with a total system crash (how could it 
do otherwise!).
The LIMITMEM memory limitation will be respected. For the same reasons 
as with Mfree no check is made whether the block actually belongs to the 
caller.
A check for invalid or odd addresses does not take place at present. 
Normally this call is made only once, namely after the program start, 
but I don't want to exclude the possibility of building in a check at 
some time in the future.



IV Process control
==================


void Pterm0( void )
-------------------

This is executed directly as Pterm(0).


void Ptermres( ULONG size, UWORD exitcode )
-------------------------------------------

With this, first the memory used by the running program is reduced with
Mshrink( act_pd, size ), then Pterm( exitcode ) will be executed. At 
this, though the running program is completely terminated and loses its 
process status, all allocated memory blocks (particularly basepage and 
environment) are preserved. 


void Pterm( UWORD exitcode )
----------------------------

With this, the calling program will be terminated and control returned 
to the parent process, whose Pexec() call receives as return value 
<exitcode> which has been extended to a ULONG. i.e. $ffffffff means 
"Serious error at execution of the Pexec command, the program could not 
be started", $0000ffff on the other hand "Program has run and terminated 
itself with Pterm(-1) or Ptermres(.., -1)". See also => AES /form_xerr().

Remark:   For historical reasons the code for Pterm contains the 
		Alcyon compiler's favourite assembler command "link a6,#0",
		as this is required by some debuggers.

Before any measures are taken, Setexc() is used to read the etv_term 
vector and this is jumped over. Following this the process is removed 
properly, including the VDI workstations, informing all the XFSs about 
xfs_pterm, closing all opened files and current paths and deleting the 
process file in u:\proc\.


long Pexec(UWORD mode, ...)
---------------------------

This creates, loads or starts processes.
A problem with Pexec had to be handled in a special way. Due to the 
interruptibility of the sequence

	Malloc(-1);
	Malloc();
	Pexec();
	Mshrink();

during the loading of auto-start applications and accessories, say, no 
programs could be loaded simultaneously. For this reason task switching 
is inhibited for a given time after the start of a program, until the
Mshrink() call has been made.

In newer versions of MagiC no Fsfirst() call is made any more during 
the loading of a program, so that programs may also have long filenames.
DOS-XFS at present still evaluates wildcards for Fopen(), i.e. calls 
such as Pexec("nvdi.pr?") are possible (but should be avoided!!).
'?' is not possible with the Mac-XFS as well as all future XFSs.
For U:\PROC the name is converted to 8+3 and upper case. If the name 
contains a '?', then it can not be displayed.
The _PNAM environmental variable now contains the filename portion 
that was specified at Pexec(), i.e. purely the name without a path.
The application name is ascertained from the filename, by shortening 
it if necessary.

Mode 0 (EXE_LDEX):
     long Pexec(EXE_LDEX, char *name, char *cmdline, char *env)

     This mode is compatible to TOS.
     The program file with the path <name> will be loaded and started. 
     The command line <cmdline> and the environment <env> will be passed.
     If env == NULL, then the environment of the parent will be inherited.
     If env == -1L, then no environment will be created; the basepage 
     then contains a null-pointer.
     Return is 0x0000yyyyL, if the program was loaded and started and 
     has terminated itself with Pterm(0xyyyy). If the program could not 
     be loaded or started, then a negative longword is returned.

Mode 3 (EXE_LD):
     PD *Pexec(EXE_LD, char *name, char *cmdline, char *env)

     This mode is compatible to TOS.
     The program file with the path <name> will be loaded. 
     The command line <cmdline> and the environment <env> will be passed.
     If env == NULL, then the environment of the parent will be inherited.
     If env == -1L, then no environment will be created; the basepage 
     then contains a null-pointer.
     Return: Pointer to the basepage of the new process or a negative 
     error code.

Mode 4 (EXE_EX):
     long Pexec(EXE_EX, void *dummy, PD *basepage)

     This mode is compatible to TOS.
     The program whose basepage has been passed will be started.
     Return is 0x0000yyyyL, if the program was started and has 
     terminated itself with Pterm(0xyyyy). If the program could not be 
     started, then a negative longword is returned.

Mode 5 (EXE_BASE):
     PD *Pexec(EXE_BASE, void *dummy, char *cmdline, char *env)

     This mode is compatible to TOS.
     A process will be created. The command line <cmdline> and the
     environment <env> will be passed.
     If env == NULL, then the environment of the parent will be inherited.
     If env == -1L, then no environment will be created; the basepage 
     then contains a null-pointer.
     Return: Pointer to the basepage of the new process or a negative 
     error code.

Mode 6 (EXE_EXFR):
     long Pexec(EXE_EX, void *dummy, PD *basepage)

     This mode is compatible to TOS 1.4.
     As Mode 4, but basepage and environment belong to the new process.

Mode 7 (EXE_XBASE):
     PD *Pexec(EXE_BASE, ULONG prgflags, char *cmdline, char *env)

     This mode is compatible to TOS > 3.0 (?).
     As Mode 5, but with <prgflags> one can set flags that determine 
     whether the program runs in TT-RAM or allocates TT-RAM with 
     Malloc() etc.

Mode 102 (XEXE_TERM):
     long Pexec(EXE_TERM, void *dummy, PD *basepage)

     The process will be deleted.

Mode 101 (XEXE_INIT):
     long Pexec(EXE_TERM, void *dummy, PD *child, PD *parent)

     Inherits path- and file-handles

Mode 107 (XEXE_XBASE):
     PD *Pexec(EXE_BASE, ULONG prgflags, char *name, char *env)

     As Mode 7, but in place of a command line the process name will be 
     passed.

Mode 106 (XEXE_EXFR):
     This is no longer supported from Mag!X 2.00 onwards.

Mode 108 (XEXE_EXACC):
     This is used internally for starting an ACC.

Mode 200 (MEXE_LDEXOV):
     long Pexec(MEXE_LDEXOV, char *name, char *cmdline, char *env)

     The so-called "overlay" mode. The running process remains 
     essentially untouched (opened files, current folders, process-ID
     etc. remain unaltered), but it alters its basepage and its name 
     to correspond to the newly loaded program. The execution will be 
     continued at the start of the newly loaded program, all memory 
     blocks allocated previously will be released.
     This is supported from MagiC 6.10 onwards.

Pexec and the ARGV specification:

MultiTOS implements this procedure in the AES. One has to set the 
parameter iscr, which is otherwise occupied in MagiC and is called 
"isover", to 1 and MultiTOS will then create the ARGV in the environment.

MagiC implements ARGV on a lower level. The ARGV specification is 
supported three ways already by Pexec:

     1. If the length byte of the command line is $7f, Pexec assumes
        that the calling program supports ARGV amd that the environment 
        has been manipulated accordingly.
        Pexec therefore does not alter the environment.
     2. If the length byte is $fe, MagiC expects the character string 
        "ARGV=" directly after it, followed by a null-byte and then a 
        list of parameters terminated by two null-bytes. By passing 
        ARGV=NULL..." etc. one can also use the extended ARGV 
        specification that permits passing of empty parameters.
        Pexec deletes any ARGV that may be present and enters the new 
        one in the environment. The command line consists only of $7f
        as an indicator that the parameters lie in the environment.
        This procedure is suitable if one is certain that the called 
        program masters the ARGV procedure.
     3. If the length byte is $ff, MagiC expects directly after it a list 
        of parameters separated by spaces and terminated by a null-byte
        (as is passed generally as a command line).
        Pexec will delete any ARGV that may be present, create from the 
        command line a list of arguments and enter these as ARGV into the 
        environment. argv[0] will be the program file path that was passed 
        to Pexec. Rubbish will result if this path is invalid, so one 
        should pass a sensible program name also for Mode 5 (create 
        basepage). With Mode 7 argv[0] is then simply called "NONAME"
        as no name has been passed here.
        The command line has $7f as a length byte, as an indicator for the 
        presence of ARGV. If the length of the command line is < 127, then 
        this is also copied to the basepage, otherwise the command line 
        consists only of $7f.
        This procedure is suitable if the calling program is not certain 
        that the called program understands ARGV.


WORD Pvfork( void )
-------------------

This works exactly like Pfork(), but the memory contents of the calling 
process will not be saved. Due to this, any change to the memory 
contents by the child process is also valid for the parent process.
This applies particulary to the "user stack", which is why the call can 
NOT be implemented as a normal procedure call in the program library 
(the child process destroys the return jump address for the parent 
process). A Pvfork therefore either has to be called as "inline", or the 
return jump address has to be saved to a fixed memory location.
For the latter solution one also has to cater for nested Pvfork() calls.

It is supported from MagiC 6.10 onwards.


LONG Pwait( void )
------------------

Under MiNT this ascertains stopped or terminated child-processes.
It is supported by MagiC from version 5.04 onwards, and implemented as:

	Pwaitpid(-1, 2, NULL);


LONG Pwaitpid( WORD pid, WORD nohang, LONG *rusage )
----------------------------------------------------

This waits for the temination or stopping of child processes and returns 
their CPU usage and exit code. The parameters have the following meaning:

	pid	-1	Pay regard to all child processes
	     >0	A given child process
	     0	Pay regard to all child processes with the same process 
	     	group as the parent process (= caller)
	     <0	Pay regard to all child processes with process group (-pid).

	nohang
	 Bit 0=0	Wait until an event (termination or stopping of a child 
	 		process) happens.
	      =1	Return 0 if no event has happened.
	 Bit 1=0	Pay regard only to those children that have terminated 
	 		or were stopped with TRACE.
	 	 =1	Pay regard to all stopped or terminated children

	rusage	If != NULL, then the user/system time of the child will
			be returned in rusage[0,1].

The return value has the process-ID in the high word and the return 
value of the child in the low word. EFILNF will be returned if no 
children exist.
It is supported by MagiC since version 5.04, but without paying regard 
to stopped childrern (i.e. only the termination of children will be 
recognised). Furthermore zeros will always be returned in <rusage>.
Process groups are only supported from MagiC 6.10 onwards, as the
Psetpgrp() call is missing in older versions.


WORD Pnice( WORD delta )
------------------------

Under MiNT this alters the priority of the running process.
It is not supported by Mag!X at present.


LONG Pusrval( LONG val )
------------------------

Under MiNT this sets and reads (val == -1) the "user value", a longword, 
that processes bequeath to their children, and that is not used by the 
kernel.
It is supported by MagiC from version 5.04 onwards.


WORD Pdomain( WORD dom )
------------------------

With this call a process can influence the behaviour of some system 
calls. If <dom>=1 is passed then the MiNT mode will be activated, else 
(by default) <dom>=0, which corresponds to the TOS mode.
In each case the value prior to the call will be returned; if one does 
not want to alter it, then one must pass <dom>=-1.
Other values than 0 or 1 lead under MagiC to ERANGE. MagiC supports 
Pdomain() since the version of 5.11.95.
The change of "domain" to MiNT (dom=1) has the following consequences:

In MiNT differences arise for Fread() and Fwrite() on terminals; the 
behaviour is determined by special Fcntl() calls. Furthermore, the calls 
Fsfirst()/Fsnext() can also return filenames that do not correspond to 
the 8+3 upper case letters format.

In MagiC Fsfirst()/Fsnext() always return filenames in 8+3 format. Any 
other procedure is senseless in any case, as "modern" programs always 
use D(x)readdir() in place of this obsolete function; otherwise one 
could also not use any filenames with more than 12 characters.

The corresponding terminal functions are not included in MagiC, so that 
this does not result in any differences to the TOS domain.

But the call is important nevertheless, because it influences the 
behaviour of the file selector dialog when this is called with the 
TOS-compatibility function fsel(ex)input(). In the MiNT domain, the 
maximum possible filename length will be assumed to be 32 (including 
EOS). In the TOS domain the length is limited to 13, and the directories 
in the TOS-compatibility mode will be read with 8+3 upper case filenames 
(=>Dopendir(DOPEN_COMPAT)). More exactly: If the fsel(ex)input() call is 
executed by a program that finds itself in the TOS domain, then
xfsl_do() is called with the mode DOSMODE+SHOW8P3, else with SHOW8P3.

The domain exerts no influence on the "modern" file selector functions
(xfsl_xx()), because here the behaviour and the limits of the file 
selector can be specified explicitly.


LONG Pfork( void )
------------------

This should actually create a copy of the calling process (i.e. not the 
same context, but an equal one, thus a copy). The new process should be 
started in parallel (as with Pexec Mode 104).

Without PMMU it is not possible to implement a P(v)fork() that functions 
as under UNIX. Hence first all of the memory of the calling process is 
saved, then the calling process is put to sleep and the new one is 
started. When the child process terminates or overlays itself with
Pexec Mode 200, the parent process is reawakened and the saved memory 
copied back. Due to the saving of the memory, alteration of the variables
of the child process do not affect the variables of the parent process.

Newer MiNT versions (>= 1.15) permit an asynchronous execution of the 
child process without stopping the parent process, by copying over the 
memory blocks of parent and child processes at each task switching.

The call is supported by MagiC since version 6.10, where the parent 
process is stopped as with MiNT <= 1.14. A waiting parent process can 
be recognised in the MagiC task manager as "waiting for fk".

Return value is 0 for the new process; for the old process on the other 
hand it is the process-ID of the child process or an error code (e.g.
ENSMEM).


LONG Pwait3(WORD flag, LONG *rusage)
------------------------------------

Under MiNT this returns the exit status and the CPU loading of a 
terminated or stopped child process.
It is supported by MagiC from version 5.04 on and is implemented as:

	Pwaitpid(-1, flag, rusage);


void Prusage(LONG *r)
---------------------

Under MiNT this returns information about the CPU and memory loading of 
the current process.
It is not supported by Mag!X at present, although at least the occupied 
memory under r[4] should be incorporated shortly; perhaps one can set 
the other values to 0.


LONG Psetlimit( WORD lim, LONG value )
--------------------------------------

Under MiNT this sets or returns the limit for memory and CPU loading for 
the current process. Under MiNT the following subfunctions are available:

lim = 1:	Limits the processor time. This function is not implemented
		in MagiC.

lim = 2:	Limits the total memory demand of a process, inclusive of the 
		program code. This is not implemented in MagiC, because 
		subfunction 3 is more sensible.

lim = 3:	Under MagiC this is implemented since the version of 17.9.95.
		With this function one sets the limit for memory allocated to 
		the current process. The return value is always the previous 
		setting.
		If one passes, say, the value 8000 for <value>, then the 
		process can allocate 8000 bytes in addition to those used for
		basepage + text segment + data segment + BSS segment.
		If <value> == 0L, the limit will be set to "unlimited".
		If <value> == -1L, only the current value will be returned.

		At Pexec() this limit will be inherited. The started program 
		itself (i.e. the program code) can be any desired size here,
		the limitation applies only to the heap, i.e. at loading the 
		memory block after the BSS segment, later the Malloc calls.
		If a program has been modified with the MagiC service program 
		LIMITMEM, then this setting takes precedence over the memory 
		limit of the called process. 
		Psetlimit is supported by the extended shel_write() mode, so 
		that with it memory-limited applications can also be started 
		in parallel.

Invalid function numbers, and those that are not supported by MagiC,
return EINVFN.


LONG Pmsg( WORD mode, LONG mboxid, struct msg *msgptr )
-------------------------------------------------------

Under MiNT this sends or receives messages. The mechanism is independent 
of the AES functions appl_read/write.
It is not supported by Mag!X at present.


LONG Prenice( WORD pid, WORD delta )
------------------------------------

Under MiNT this alters the priority of a running process.
It is not supported by Mag!X at present.


LONG Pumask( WORD mask )
------------------------

Under MiNT this alters the mode (i.e. the file permissions) with which 
Fcreate() and Dcreate() create files. Here the bits of <mask> determine 
which rights the file should _NOT_ have. As there is no option to just 
verify the mask without altering it, it appears one has to do this the 
'dirty' way, such as

	Pumask((mode = (int)Pumask(0));

The filemask is bequeathed to child processes, and is set to zero by 
MagiC during booting. The mask is not evaluated by any of the internal 
XFSs of MagiC and has a meaning only on UNIX-like file systems.
It is supported by MagiC since version 5.04. For an XFS the mask is 
accessible via offset 0x64 of the basepage (=>MGX_XFS.INC in the 
FILESYS folder).


LONG Psemaphore( WORD mode, LONG id, LONG timeout )
---------------------------------------------------

Sets and creates semaphores (=>MiNT). The parameter <timeout> is only 
used for Mode 2 and specifies the timeout time in ms; a value of -1 
means that the wait will be as long as you like.
Semaphores are released automatically at the termination of their owner 
process, but not deleted.

Mode PSEM_CRGET   (0):
     A new semaphore with the ID <id> will be created and assigned to 
     the process. Internal memory has to be reserved for this, so this 
     call should be used sparingly.
     Although the semaphores are released at the termination of the 
     process (with PSEM_RELEASE), they are not removed (i.e. no 
     PSEM_DESTROY).
     The parameter <timeout> will be ignored.
     Error code EACCDN: Semaphore already exists.

Mode PSEM_DESTROY (1):
     The semaphore <id> will be deleted and the reserved internal 
     memory released again. Plausibility checks ensure that no system 
     sesmaphores can be removed.
     This only works if a PSEM_GET or PSEM_CRGET call was made 
     previously.
     Error code ERANGE: Semaphore does not exist
                EACCDN: Semaphore doesn't belong to me.

Mode PSEM_GET     (2):
     The semaphore <id> will be set, i.e. reserved for the process.
     Error code ERANGE: Semaphore does not exist (any more)
                ERROR:  Semaphore already belongs to me
                EACCDN: Timeout.

Mode PSEM_RELEASE (3):
     The semaphore <id> will be released.
     Error code ERANGE: Semaphore does not exist
                EACCDN: Semaphore does not belong to me.



V Functions for the process-ID
===============================


WORD Pgetpid( void )
--------------------

This returns the process-ID of the current process. There is no error 
case, the process-ID is always valid. The process-ID is the filetype 
under which the current process is being conducted in u:\proc; i.e. if 
the current process has ID 5, then the associated file corresponds to 
the pattern "u:\proc\*.005".
As was always the case in MiNT, from MagiC 4.50 on the process-ID is 
allocated in ascending order and no ID will be reused when a process 
is terminated before all IDs up to 999 have been used.


LONG Pgetppid( void )
---------------------

This returns the process-ID of the parent of the current process. In 
contrast to MiNT an error can arise if the process has no parent, in 
which case -1L will be returned.


WORD Pgetpgrp( void )
---------------------

This returns the current process group number.
It is supported in MagiC from version 6.10 onwards.


LONG Psetpgrp( WORD pid, WORD newgrp )
--------------------------------------

This sets the process group number of the process <pid> to <newgrp>.
With <pid>=0 the current process will be addressed. With <newgrp>=0 the 
process-ID of the specified process will be used as the process group 
number.

With MiNT the user-ID of the caller and the specified process must tally, 
or the specified process must be a child of the calling one. As MagiC at 
present does not support user-IDs there are no restrictions here yet.

The boot-process receives the group number 0, which is first bequeathed 
to all child processes. With the call "Psetgrp(0,0)", for instance, a
process sets its process group number to its process-ID. This process 
and all its children then form a new process group. 
It is supported from MagiC 6.10 onwards.


WORD Pgetuid( void )
--------------------

Under MiNT this returns the user-ID of the current process.


WORD Psetuid( WORD uid)
-----------------------

Under MiNT this alters the user-ID of the current process.
It is not supported by Mag!X at present.


WORD Pgetgid( void )
--------------------

Under MiNT this returns the group-ID of the current process.
It is not supported by Mag!X at present.


WORD Psetgid( WORD uid)
-----------------------

Under MiNT this reads the group-ID of the current process.
It is not supported by Mag!X at present.


WORD Pgeteuid( void )
--------------------

Under MiNT this returns the effective user-ID of the current process.
It is not supported by Mag!X at present.


WORD Pgetegid( void )
--------------------

Under MiNT this returns the effective group-ID of the current process.
It is not supported by Mag!X at present.



VI Signal functions
===================


WORD Pkill(WORD pid, WORD sig)
------------------------------

The function sends the signal <sig> to one or more processes.
The parameter <pid> signifies:

	> 0	Process with the specified pid
	= 0  All processes of the process group of the caller (incl.)
	< 0	To all processes with the group number (-pid).

The signal SIGNULL can be used to test the validity of the parameter <pid>; 
it is not actually a signal.

Return values:

	EFILNF: 	If pid > 0 and the specified process no longer exists
			or if pid < 0 and the specified process group no longer 
             	has any members.

	EACCDN: 	If pid > 0, and the sending process does not have a 
			euid of 0 and moreover the UID of the receiving process 
             	differs from that of the sending one.

	ERANGE: 	sig is not a valid signal (e.g. < 0 or > 30).

In MagiC 4.5, due to simpler process control, only the first version of 
Pkill exists, i.e. one can only specify a pid > 0. From MagiC 6.10 
onwards cases of pid <= 0 are also supported, since only from this 
version onwards have process groups been implemented. EACCDN can not 
yet be returned, as up to now processes do not know any user-IDs. 


LONG Psignal(WORD sig, LONG handler)
------------------------------------

Under MagiC this is implemented as

	Psigaction(sig, {handler,0L,0}, &oact);
	return(oact.handler);

i.e. unlike with Psigaction() the extra mask and flags are simply set to 
zero.
It is supported by MagiC from V4.50 onwards.


LONG Psigblock( LONG mask )
---------------------------

<mask> specifies as a bit mask which signals are blocked additionally 
(i.e. newmask = oldmask OR mask); the old value will be returned.
The non-maskable signals SIGKILL, SIGSTOP and SIGCONT will be filtered 
out automatically from the signal mask.
It is supported by MagiC from V4.50 onwards.


LONG Psigsetmask( LONG mask )
-----------------------------

<mask> specifies as a bit mask which signals will be blocked (i.e. 
newmask = mask); the old value will be returned. The non-maskable 
signals SIGKILL, SIGSTOP and SIGCONT will be filtered out automatically 
from the signal mask.
It is supported by MagiC from V4.50 onwards.


LONG Psigreturn( void )
-----------------------

See =>SIGNALS.TXT (in the top folder).
This is used within a signal handler preparing to exit in order to 
return to the main program with a "longjump".
Under MiNT this leads to a system crash, at least when used in 
connection with the AES.
In MagiC the thread of the active signal handler becomes the main thread 
of the process and is then removed. All other signal handlers will also 
be removed (in cases of nesting).
The blocked semaphores of the main thread will be released. The 
supervisor stack of the main thread will be reset to the value it had at 
the process start.
In MiNT this function is "void". In MagiC, EACCDN will be returned if 
the caller is not a signal handling routine, else E_OK.
It is supported by MagiC from V4.50 onwards.


LONG Talarm( LONG time )
------------------------

In MiNT this initiates an alarm that terminates the current process in 
<time> seconds, if the signal SIGALRM is not caught.
It is not yet supported by Mag!X at present.


void Pause( void )
------------------

As Psigpause(), but the signal mask will not be altered. Due to this,
this function, unlike Psigpause(), is MT-safe.
It is supported by MagiC from V4.50 onwards.


LONG Psigpending( void )
------------------------

This returns the bit mask of the pending, i.e. sent but not yet delivered 
(= blocked), signals.
It is supported by MagiC from V4.50 onwards.


void Psigpause( LONG mask )
---------------------------

The process (or in MagiC the thread) alters the signal mask in <mask> 
and then is suspended until the next signal is received. After the  
signal handler completes its task the process (in MagiC: all waiting 
threads) are reawakened and the signal mask is restored.
If several threads call Psigpause() simultaneously, problems may arise 
because the signal mask is global for all processes (=>SIGNALS.TXT in 
top folder).
It is supported by MagiC from V4.50 onwards.


LONG Psigaction( WORD sig, struct sigaction *sigact, struct sigaction *oact)
----------------------------------------------------------------------------

See also =>SIGNALS.TXT.
This function alters the signal behaviour for the pending signal <sig> 
(if <sigact> != NULL) and optionally verifies the old behaviour (if 
<oact> != NULL).
A <sigaction> structure is built up as follows:

		typedef struct
		{
		        void    cdecl (*sa_handler)( LONG sig );
		        LONG    sa_mask;
		        WORD    sa_flags;
		} SIGACTION;

<sa_handler> is either 0 (default signal handling by the system) or 1
(ignore signal), else the address of a signal handling routine. This 
is executed in user-mode and receives the signal number on the stack 
as a LONG. The signal handler is normally terminated with the end of
the procedure (with rts); alternatively it can be terminated with
Psigreturn() and following longjump. In the latter case ALL running 
signal handling will be terminated and the main program will not be 
resumed but the signal handler becomes the main program instead.

<sa_mask> contains the signals additional to the one currently being 
handled that are to be masked during the signal handling (i.e. in that 
case mask = oldmask+(1<<sig)+sa_mask applies).

<sa_flags> affects the behaviour of the signal:

	SA_NOCLDSTOP (1)
		in MiNT ensures that SIGCHLD will only be delivered at the 
		termination and not stopping of a child process.


A Psigaction call has the side-effect that it automaticallly unmasks the 
signal (i.e. it releases it). Hence a process while handling a signal 
can reset this and then send it to itself anew.

Return values:

	EACCDN: 	Signal can not be caught by the user.
			(SIGKILL or SIGSTOP)
	ERANGE: 	sig is not a valid signal (< 0 or > 30).

It is supported by MagiC from V4.50 onwards.



V Disk management
=================


LONG Dsetdrv( WORD drv )
------------------------

Sets <drv> as the current drive of the current process. Under MagiC 3
values between 0 and 25 are permissible, under TOS only between 0 and 
15. No check is made whether the drive actually exists. The return is
the return value of the BIOS call Drvmap().


LONG Dgetdrv( void )
--------------------

Returns the current drive of the current process. MagiC 3 manages up to 
26 drives (A: to Z:), while older versions as well as all TOS versions 
can manage 16 drives (A: to P:).


LONG Dfree( DISKINFO *d, WORD drivecode )
-----------------------------------------

If <drivecode> is zero then the free space on the drive in the current 
path of the current drive is returned, else the free space on the drive
<drivecode - 1>.
Example: If U: is the current drive and \A\ the current path on U:, then 
in the case of <drivecode>==0 the free space on drive A: will be 
calculated.
<d> should normally return the following data:

     The number of free clusters
     The total number of clusters
     The size of a sector in bytes
     The number of sectors per cluster.


LONG Dlock( WORD mode, WORD drv )
---------------------------------

Locks a BIOS drive. The access to this drive via GEMDOS will be 
prevented completely, the BIOS call Rwabs() is only permitted for the 
locking process. Dlock() is used, for instance, while formatting or 
copying complete floppy disks. After the drive is released, all the 
caches are invalid, as if a media change had taken place.
<mode> has the following meaning:

     (mode & 1) == 1:  	Lock drive. If opened files exist on the drive, 
     				then an error mesage EACCDN will be returned.
                         If the drive is also locked by another process 
                         via Dlock() then ELOCKED will be returned, 
                         unless (mode & 2) == 1, in which case the process
                         ID of the locking process will be returned.
     (mode & 1) == 0:    Unlock drive again. If the drive is not locked, 
                         or locked by another process, then an error 
                         mesage ENSLOCK will be returned. At the 
                         termination of the locking process the drive will 
                         be unlocked again automatically.
     (mode & 2) == 1:    Returns the process ID, if drive is locked.
     (mode & 2) == 0:    Returns ELOCKED.

So actually only modes 0 (unlock), 1 (lock, return ELOCKED if appropriate)
and 3 (lock, return the ID of the locking process if appropriate) exist.
A locking and subsequent unlocking of a drive in a way simulates a media 
change (unless the drive is in use at the time).

Before locking the drive, if a file system exists for the drive the caches 
will be written back via the vector xfs_sync. Then the kernel inquires 
via xfs_drv_close whether the drive can be locked. If it can, then the 
XFS releases its structures and signals the kernel that it too can free 
its structures for the drive and perform the locking.


LONG Dreadlabel( char *dirpath, char *name, UWORD buflen )
----------------------------------------------------------

This is present since MiNT 1.12 and is implemented in MagiC 3.


LONG Dwritelabel( char *dirpath, char *name)
--------------------------------------------

This is present since MiNT 1.12 and is implemented in MagiC 3.



VI Directory management
=======================


LONG Dcreate(char *path)
------------------------

This creates a subdirectory. The call is passed on by the kernel as 
xfs_dcreate with creation mode (=> Fxattr()) %0100000111101101 (i.e. 
"directory file" with access permissions RWXRwXRwX). With Fchmod() one 
can alter the mode afterwards.
The XFS shold not delete any files or subdirectories with the same name 
but in such cases return the error code EACCDN. 
Invalid filenames such as "." or ".." also have to be caught by the XFS.


LONG Ddelete(char *path)
------------------------

This deletes a subdirectory.
From MagiC 4.01 onwards one can also delete symlinks with this. In older 
MagiC versions the directory to which the symlink pointed was always 
deleted, which could give rise to problems with older programs.
The kernel of MagiC 4.01 automatically invalidates any standard paths 
that may have lain in the deleted directory, and further accesses to 
these standard paths lead to EPTHNF, until a new path is set with 
Dsetpath().
Old MagiC versions tested beforehand whether the directory was a standard 
path, and if appropriate returned EACCDN.


LONG Frename(char *oldpath, char *newpath)
------------------------------------------

With this a file (or directory or link or device etc.) is renamed or 
moved in the directory structure on the same drive. As this is similar 
to the creation of a hard link, the same function as used with Flink is 
used when calling the XFS. It is up to the XFS to decide whether 
directories may be renamed or moved.
The integrated DOS-XFS only permits the moving of directories from MagiC 5
onwards. Under TOS/MiNT etc. this is not possible with this function.


LONG Dsetpath( const char *path )
---------------------------------

In contrast to UNIX, GEMDOS manages its own current path for each drive.
Dsetpath() sets the current path for the drive that holds the path 
specified by <path>. This must not necessarily be the one whose drive 
letter is specified in the path, because the path can also point to 
another drive via a symlink. With a "cross drive link" therefore, except 
for drive U:, the current drive will be converted if the call of
Dsetpath() referred to it. An example:

- Let f:\cbin be a symlink to c:\bin, and the current drive be c:. The
  call of Dsetpath("f:\cbin") results in the current path being altered 
  from c: to "\bin\". On the other hand if the current drive is f:, 
  then in addition the current drive will be changed to c:.
- If on the other hand the current drive is u: then this action is not 
  necessary because the current path can simply be altered from "\f\" to 
  "\c\bin\".


LONG Dgetpath( char *pathbuf, int drivecode )
---------------------------------------------

This is executed under MagiC 3 as Dgetcwd( pathbuf, drivecode, 128 ).


LONG Dpathconf( char *path, int mode )
--------------------------------------

This returns information about the limits and capabilities of a file 
system that belongs to the specified <path>. The function should be 
called in MagiC if appropriate after Dopendir(), as Dpathconf() does not 
recognise media changes (if the path is still in the cache there will be 
no disk access and hence a media change will not be recognised).
If one of the values is unlimited then 0x7fffffffL will be returned.
<mode> can take the following values:

 mode =
	DP_MAXREQ (-1):
		Maximum permissible value for <mode> (returns currently "8")

	DP_IOPEN (0):
		Maximum number of simultaneously opened files

	DP_MAXLINKS (1):
		Maximum number of links per file

	DP_PATHMAX (2):
		Maximum length of a full path name, in bytes

	DP_NAMEMAX (3):
		Maximum length of a filename, in bytes

	DP_ATOMIC (4):
		Number of bytes that can be written in one go (per write 
		operation)

	DP_TRUNC (5):
		Information about filename truncation (to 8+3) =>

		DP_NOTRUNC (0):	Long filenames lead to ERANGE
		DP_AUTOTRUNC (1):	Long filenames are truncated automatically
		DP_DOSTRUNC (2):	Rules as for DOS (8+3)

	DP_CASE (6):
		Information about case sensitivity in filenames =>

		DP_CASESENS (0):	Case-sensitive
		DP_CASECONV (1):	Not case-sensitive, always in upper case
		DP_CASEINSENS (2):	Not case-sensitive, but unaffected

	DP_MODEATTR (7):
		Information about supported attributes and modes =>

		DP_ATTRBITS	0x000000ffL	/* Valid TOS attributes */
		DP_MODEBITS	0x000fff00L	/* Valid Unix attributes */
		DP_FILETYPS	0xfff00000L	/* Mask for valid file types */
		DP_FT_DIR		0x00100000L	/* Directories */
		DP_FT_CHR		0x00200000L	/* Character special files */
		DP_FT_BLK		0x00400000L	/* Block special files */
		DP_FT_REG		0x00800000L	/* Regular files */
		DP_FT_LNK		0x01000000L	/* Symbolic links */
		DP_FT_SOCK	0x02000000L	/* Sockets */
		DP_FT_FIFO	0x04000000L	/* Pipes */
		DP_FT_MEM		0x08000000L	/* Shared memory or proc files */

	DP_XATTRFIELDS (8):
		Information about valid fields in XATTR =>

		DP_INDEX		0x0001
		DP_DEV		0x0002
		DP_RDEV		0x0004
		DP_NLINK		0x0008
		DP_UID		0x0010
		DP_GID		0x0020
		DP_BLKSIZE	0x0040
		DP_SIZE		0x0080
		DP_NBLOCKS	0x0100
		DP_ATIME		0x0200
		DP_CTIME		0x0400
		DP_MTIME		0x0800


LONG Dopendir( char *name, WORD flag )
--------------------------------------

This opens a directory for sequential reading (searching) with 
D(x)readdir(). This function should be used instead of Fsfirst/-next() 
with all new programs as it evaluates aliases correctly, permits long 
filenames etc.
The following modes are possible in <flag>:

	#define DOPEN_COMPAT     1
	#define DOPEN_NORMAL     0

With DOPEN_NORMAL the following D(x)readdir() calls return long 
filenames, and moreover these are preceded by a 4 byte file index 
(corresponds to the UNIX Inode). This setting is sensible for modern 
programs.

MiNT mimics the old functions Fsfirst/next with Dopendir()/Dreaddir(). 
It is only for this reason that Dopendir() retains the compatibility 
mode DOPEN_COMPAT. In this mode D(x)readdir() does not return an index 
but only names in the 8+3 upper case format.

Dopendir() returns a (negative) error code or a directory handle. This 
handle is passed to any following D(x)readdir() calls. It is imperative 
to remember to close the directory again at the end of the search with 
Dclosedir().

MagiC protects all files that have been opened with Dopendir() from 
write accesses. The number of directories that may be opened 
simultaneously is limited only by the internal DOS memory. If this 
is insufficient one may use ADDMEM to increase this.


LONG Dreaddir( WORD len, LONG dirhandle, char *buf )
----------------------------------------------------

This reads the next directory entry of a directory opened with Dopendir(), 
whose handle is passed in <dirhandle>. Depending on <flag> for 
Dopendir(), this returns 4 bytes index followed by the name, or just the 
name in the 8+3 format.

In <len> one specifies the length of the buffer to which <buf> points. 
If one takes into consideration the 4 bytes for the index and 1 byte for 
the string end marker, then the longest filename can have a length of 
(len-5) characters.

The "index" should really correspond to the "Inode" of a UNIX-like file 
system (XFS works this way). At least "index" must be unique, i.e. no 
two files or directories may have the same index. More => Fxattr().


LONG Dxreaddir( WORD ln, LONG dirh, char *buf, XATTR *xattr, LONG *xr)
----------------------------------------------------------------------

This function works at first like Dreaddir(), but for a successfully 
read directory entry it also calls internally Fxattr() with Mode 1 and 
return structure <xattr>. This means that symbolic links will not be 
dereferenced automatically. This is sensible, as symbolic links will be 
recognised this way and can then be dereferenced manually with 
Freadlink() and Fxattr() with Mode 0. The return value of Fxattr() will 
be contained in <xr>.

For reasons of speed this call in MagiC-XFS is not performed by many 
individual XFS calls, but by a single one. The XFS function xfs_readdir 
replaces both Dreaddir as well as Dxreaddir; in the first case a pointer 
is NULL.

This function was defined at my request for the introduction of MagiC 3 
and incorporated from MiNT 1.12 onwards, as the individual calls of
Dreaddir/Fxattr that have to be performed repeatedly for every individual 
directory entry were too cumbersome and slow (a complete path evaluation 
each time, etc.). It is interesting to note that some five years later 
the Sun company came to the same conclusion and provided a similar call 
in version 3 of the NFS protocol.


LONG Drewinddir( LONG handle )
------------------------------

This resets the read pointer of an open directory back to the start of 
the directory.


LONG Dclosedir ( LONG dirhandle )
---------------------------------

This closes a directory opened with Dopendir(). Further accesses to the 
<dirhandle> are forbidden.


LONG Dgetcwd( char *pathbuf, int drivecode, int buflen )
--------------------------------------------------------

This returns in <pathbuf> the current path (without drive letter) for the 
specified drive <drivecode>. If <drivecode> == 0 then the current drive 
will be used, 1 corresponds to drive A:, 2 to drive B: etc.
<buflen> is the length of the path buffer; if the current path is too 
long then ERANGE will be returned.



VII Filename functions
======================


void Fsetdta ( DTA *buf )
-------------------------

This sets the buffer used for Fsfirst/-next() ("DTA"). Each process has 
just one active DTA buffer, which is placed at offset 128 of the 
basepage (i.e. on the command line) at the start of the process.
It is imperative to ensure that Fsfirst-/next() are only called when the 
DTA points to a valid memory region. Otherwise there will be a crash.
In newer programs the functions Fsetdta(), Fgetdta(), Fsfirst() and 
Fsnext() should no longer be used, as they do not handle long filenames, 
for instance, and can not protect the directory currently being searched 
from write accesses by other processes.


DTA *Fgetdta ( void )
---------------------

This returns the current DTA of the process.


LONG Fcreate(char *path, int attr)
----------------------------------

This function dereferences symbolic links, i.e. if the file already 
exists as a symbolic link then the file referenced from it will be 
brought to zero length.

This function has 2 subfunctions:

1.   If bit 3 of <mode> is set then a disk name (volume label) will be 
	created. For this the XFS function xfs_wlabel is called. If this 
	function is executed without error then the return value will be
	0x0000fffc. This corresponds to a handle for the file NUL: or 
	u:\dev\null. The user program may or may not close this handle.

     Attention: This subfunction was replaced in MagiC 3 and MiNT 1.12 
     		 by the more powerful function Dwritelabel() and is only
     		 present for reasons of compatibility.

2.   A file with DOS attribute <attr> is created. For this the bits

          FA_RDONLY      (bit 0)
          FA_HIDDEN      (bit 1)
          FA_SYSTEM      (bit 2)
          FA_ARCHIVE     (bit 5)

     are allowed. The bits 6 and 7 are ignored under MagiC 3 for reasons 
     of compatibility. A set bit 4 (FA_SUBDIR) leads to error code
     EBADRQ.
     If a file is created with FA_RDONLY, then although it is open it 
     can not be written to.

	A special case is the creation of a file in U:\PIPE, where pipes 
	will be created. The attribute <attr> in MiNT then has the meanings 
	described in => PIPES.TXT (in the top folder).

     Note: 	Fcreate() should really be replaced in MiNT and MagiC 3 
     		by Fopen() in Mode O_CREAT+O_TRUNC. With this function, 
     		however, the attribute byte 0 will be assumed always, so
               FA_RDONLY must therefore be set, if appropriate, by a 
               following Fchmod() call.
               The attributes exist only on DOS file systems and are 
               ignored or simulated by other file systems. On the 
               Macintosh file system only FA_RDONLY is taken into 
               account. FA_ARCHIVE is superfluous if one is using a 
               correctly set system clock and the date of the last 
               backup is known.


LONG Fopen(char *path, WORD omode)
----------------------------------

This function dereferences symbolic links, i.e. if the file already 
exists as a symbolic link then the file referenced from it will be 
opened or, if O_TRUNC was specified, brought to zero length.

<omode> is the file opening mode. Under TOS only values 0 to 2 are 
permitted here, under MiNT and MagiC the following modes exist:

	O_RDONLY	(0x00)	Read only access
	O_WRONLY	(0x01)	Write only access
	O_RDWR	(0x02)	Read and write access

If no further "sharing mode" flags are used then this corresponds to the 
compatibility mode, i.e. O_COMPAT (0x00). Here MagiC permits multiple 
opening for reading but only a single opening for writing. MiNT, on the 
other hand, differentiates between one's own and "foreign" files; a 
process may open a file several times here, which is however protected 
("denied") for other processes.
The "sharing modes" are:

	O_COMPAT	(0x00)	TOS compatibility
	O_DENYRW	(0x10)	Deny reads and writes
	O_DENYW	(0x20)	Deny writes
	O_DENYR	(0x30)	Deny reads
	O_DENYNONE(0x40)	Deny none

MiNT also "knows" (or maybe not!):

	O_NOINHERIT(0x80)	/* This is currently ignored by MiNT */
	O_NDELAY	(0x100)	/* Don't block for i/o on this file */

MagiC and MiNT also support:

	O_CREAT	(0x200)	Create file, if it does not exist
	O_TRUNC	(0x400)	Set existing file to zero length
	O_EXCL	(0x800)	Do not open existing file


LONG Fdelete( char *path )
--------------------------

This deletes the file. During this no symbolic links will be dereferenced, 
i.e. the link will be deleted, not the file or the folder to which the 
link points.
If the file system in use supports these attributes then Fdelete() also 
deletes files with attributes HIDDEN or SYSTEM.


LONG Fattrib( char *path, int setflag, int new_attrib )
-------------------------------------------------------

With this you can verify and alter the DOS access rights to files. For 
newer applications Fxattr() for verifying the attributes and Fchmod() 
for altering the access rights are more powerful, but are not supported 
by all file systems. Thus the DOS_XFS currently only supports Fxattr(), 
not Fchmod().
If <setflag> == 0, then the attribute of the file or the folder <path> 
is returned. During this disk names (volume labels) will not be found.
If <setflag> == 1, then the attribute of the file <path> is modified 
according to the attribute <new_attrib>. Any attempt to modify a folder 
with this leads to EACCDN.
One may modify the attributes FA_READONLY (0x01), FA_HIDDEN (0x02),
FA_SYSTEM (0x04) and FA_ARCHIVE (0x20). If <new_attrib> contains further 
flags then this leads to error code EACCDN.
Warning:  Older operating system will not find folders here, i.e. 
		access to a folder always results in EFILNF.


LONG Fsfirst( char *path, int sattr )
-------------------------------------

This function performs two different tasks:

1.   If bit 3 of <sattr> is set then the MagiX kernel calls the XFS
	function xfs_rlabel. The calling user program unfortunately can no 
	longer return the date and time of the disk name under MagiC 3. The 
	kernel sets all fields to 0. A Fsnext() must not be executed in 
	that case.

     Note: The function was replaced in MagiC 3 and MiNT 1.12 by 
     	 Dreadlabel(), which also allows reading of long filenames.

2.   Otherwise a search for files will be made, as in TOS. If a file is 
	a symlink, the DOS kernel calls the function Fxattr() in order to 
	follow the symlink. The values returned by Fxattr() are then copied 
	into the DTA.
     Warning: 	MagiC 3 is not in a position to always evaluate correctly 
     		relative symlinks during the Fsfirst/Fsnext mechanism. 
              	There are three ways to overcome this:

              a) Best: Use Dxreaddir().
              b) Only use absolute symlinks.
              c) Always make the search directory the current one.

              MiNT hanles this case correctly, but at the cost of a lot 
              of extra work. The Fsfirst/next concept is basically 
              outdated, ineffective and unsafe and should be avoided 
              both in MiNT as well as in MagiC 3.


LONG Fsnext( void )
-------------------

This returns from the data stored by the system in the current DTA the 
next file matching the search pattern and search attribute, and stores 
its data in the DTA. If there are no more files in the directory being 
searched then ENMFIL will be returned.
With reference to the evaluation of the symlinks => Fsfirst().


LONG Frename( const char *oldpath, const char *newpath )
--------------------------------------------------------

This renames and/or moves a file. In MagiC one can also move folders 
with it.


LONG Fxattr( WORD mode, const char *path, XATTR *xa )
-----------------------------------------------------

This returns extended data for a file or a folder whose name is known. 
Fcntl with mode FSTAT works in an equivalent way for an opened file and 
expects a DOS file handle in place of the path.
With <mode> == 0 symlinks are followed, with <mode> == 1 the XATTR 
structure of the symling itself will be read.
Fxattr() can not be applied to a volume name (=>EFILNF).
The XATTR structure in detail:

typedef struct xattr {
     unsigned short mode;

		Contains the file type and the (UNIX) access permissions. With 
		DOS and Mac partitions the UNIX access permissions are 
		simulated halfway sesnsibly: Files have RWXRWXRWX or, if they 
		are write protected, RwXRwXRwX.
		Further details are in the MiNT documentation.

     long index;

		Contains a longword for unambiguous identification of a file 
		or a folder. The index has to be unique within a file system;
		together with the following field (dev) this completely 
		identifies a file or a folder on a global basis in the system.

		Under UNIX-like file systems <index> is the number of the Inode.

		On Mac partitions the "hard file ID" or the "hard dir ID" is 
		used, which is made available by the MacOS. But the MacOS uses 
		as standard descriptors the "FSSpec". For directories, i.e. 
		for "Directory IDs", there are functions of the MacOS that 
		calculate an FSSpec. Unfortunately the "hard file IDs" can not 
		be used further for normal files (i.e. not subdirectories) as 
		they are not handled by any functions of the MacOS.

		On DOS file systems, in the case of a folder the start-cluster 
		in Motorola format is used, else in the high word the start-
		cluster of the directory and in the low word the position of 
		the associated directory entry divided by 32.
		Unfortunately the start-cluster can not be used for normal 
		files because empty files have the start-cluster 0 and thus 
		all empty files would have an identical index. Furthermore 
		when writing to an empty file its start-cluster and hence its 
		index would be altered.
		The method is similar to that used by Linux and Solaris. The 
 		disadvantage is that files alter their index when moved.

     unsigned short dev;

		Specifies the file system. On the Atari 0..25 are the BIOS
		drives A: to Z:; drive U: or other file sytems use higher 
		numbers.
		On the Mac the "volume ID" is inserted, which is assigned
		by the MacOS.

     unsigned short reserved1;

		Here there is room for future extensions Eric Smith's MiNT.

     unsigned short nlink;

		Number of "hard links" that refer to this file. This is only 
		of interest with UNIX file systems; with DOS file systems and
		Mac partitions there is always a "1" here.

     unsigned short uid;

		The "user ID" of the owner of the file. This is only of 
		interest in multi-user systems, i.e. for UNIX partitions. 
		Mac and DOS partitions always have a "0" here.

     unsigned short gid;

		The "group ID" of the owner of the file. Also only of interest 
		for multi-user systems, i.e. for UNIX partitions. Mac and DOS 
		partitions always have a "0" here.

     long size;

		The (logical) file length, i.e. the number of bytes that one 
		may read with Fread().

		On DOS partitions folders return a length of 0. The actual 
		size can unfortunately not be determined due to limitations of 
		MS-DOS. The size of the root directory can, however, be read.

		On Mac partitions folders always have a length of 0. The 
		actual length can not be determined (at least under System 7 
		and 8).

     long blksize;

		The length of a physical block of the file (in bytes). On DOS 
		partitions the cluster size.

	long nblocks;

		The number of blocks occupied by the file on the device. 
		This makes (blksize * nblocks) the physical file length. 
		For folders the same restrictions apply as for <size>.

     short mtime, mdate;

		Time/date-stamp of the last modification of the file, in 
		GEDMDOS format.

     short atime, adate;

		Time/date-stamp of the last access. On DOS and Mac partitions 
		this is identical to the modification date.

     short ctime, cdate;

		Time/date-stamp of the file's creation. On DOS partitions this 
		is identical to the modification date.

     short attr;

		The byte returned by Fattrib(), i.e. DOS access permissions 
		(ReadOnly or ReadWrite) and DOS flags (Hidden, System, 
		Archive, Subdir).

     short reserved2;
     long  reserved3[2];

		Here there is more room for Eric Smith's MiNT extensions.

} XATTR;


LONG Flink( char *oldname, char *newname )
------------------------------------------

On a file system that supports "real" links (also known as "hard links")
this creates for the file <oldname> a new directory entry <newname> on 
the same drive. Thus this function works in a similar way to Frename(), 
though the old name is not deleted but retained.

This function is supported only by a few (UNIX) file systems.


LONG Fsymlink( char *oldname, char *newname )
---------------------------------------------

The syntax is as for Flink(), though a "symbolic link" (or "alias") is 
created. <newname> can lie on any file system that supports symbolic 
links (Attention: TOS and naturally MiNT too do not support symbolic 
links on FAT drives).

A new, special file is created that contains a cross refrence to 
<oldname>. Actually <oldname> does not even have to exist, as only the 
path as such is saved.

In contrast to the botched concepts in MacOS and Windows 95/NT the 
dereferencing of symbolic links is left completely to the system, so 
that symbolic links are transparent for applications.

The path <oldname> can be relative to <newname>, e.g. with:

	oldname=C:\gemsys\hp850.sys newname=C:\gemsys\hp870.sys

one can create an absolute and with:

	oldname=hp850.sys newname=C:\gemsys\hp870.sys

a relative symbolic link (hp870 is now a kind of pointer to the file 
hp850 lying in the same directory).

There are some restrictions with relative symbolic links: They do not 
work correctly in MagiC with Fsfirst()/next(), and the Mac-XFS for 
MagiCMac unfortunately does not support any relative symbolic links.


LONG Freadlink ( WORD bufsiz, char *buf, char *name )
-----------------------------------------------------

This reads a symbolic link (i.e. verifies the actual path to which the 
link refers).


LONG Fchown ( char *name, WORD uid, WORD gid )
----------------------------------------------

This alters the owner (uid) and group (gid) of the file <name>. It is 
only supported by UNIX-like file systems (Minix-XFS).


LONG Fchmod ( char *name, WORD mode )
-------------------------------------

This alters the file access permissions of the file <name>. It is only 
supported by UNIX-like file systems (Minix-XFS). On FAT file systems 
only Fattrib() is possible.


LONG Dcntl( WORD function, char *path, void *param )
----------------------------------------------------

With this function one normally executes special functions that are 
dependent on the path passed. Depending on the file system that is 
responsible for the passed path, different subfunctions are possible 
which are executed directly by the file system driver.
Furthermore there are several subfunctions that are executed by the 
kernel itself, where the path is ignored. Here MiNT and MagiC differ 
appreciably. Unfortunately the assignment of the Dcntl opcodes led to 
some collisions between MagiC and the Minix-XFS for MiNT. Hence MagiC 
from version 6 onwards contains new codes, though the old ones are still 
supported. The new codes have a 0x6d in the upper byte and this ID is 
reserved for MagiC.
Invalid <function> opcodes return EINVFN.

The following subfunction numbers are defined:

KER_GETINFO (0x0100)
MX_KER_GETINFO (0x6d00) from MagiC 6 onwards

	This function exists only under MagiC. <path> and <param> have to 
	be set to NULL. The return is a pointer to the MagiC kernel 
	structure. It is defined as MX_KERNEL (=>MGX_XFS.TXT and MGX_XFS.H 
	in the FILESYS folder) and is used by file system drivers or device 
	drivers.

KER_DOSLIMITS (0x0101)
MX_KER_DOSLIMITS (0x6d01) from MagiC 6 onwards

	This function exists only under MagiC. <path> and <param> have to be 
	set to NULL. The return is information about the installed FAT file 
	system driver (i.e. the driver for the usual TOS or MS-DOS file 
	system). Dcntl() returns a pointer to a pointer to the structure 
	MX_DOSLIMITS (=>MGX_XFS.H in the FILESYS folder). The pointer itself 
	can therefore be directed to point to its own structure if a new 
	driver is installed.
	Since the conversion to 32-bit sector numbers (from MagiC 4.50 on) 
	a maximum of 4193216 in place of the previous 65536 sectors are 
	permitted for a partition. The number arises from the maximum of
	65519 clusters each with a maximum of 32768 bytes and at least 512 
	bytes per sector.

	This subfunction is normally used only by hard disk drivers (e.g. 
	HDDRIVER).

KER_INTMAVAIL (0x0102)
KER_INTGARBC (0x0103)
KER_SETWBACK (0x0300)

	These functions existed before version 4.01 under MagiC, but were 
	converted to Sconfig calls to prevent conflict with drivers that 
	have problems with unknown Dcntl codes.

KER_DRVSTAT (0x0104)
MX_KER_DRVSTAT (0x6d04) from MagiC 6 onwards

	This function exists only under MagiC (from 9.9.95 onwards).
	<path> is ignored. Simple information about a drive is read from 
	the kernel.
	For this one passes in <param> a pointer to two WORDs. The first 
	must contain a NULL and the second has a drive number between 0
	(for A:) and 25 (for Z:) written to it.
	Dcntl() returns the following values:

		EDRIVE	Drive number invalid (not 0..25)
		ELOCKED	Drive currently locked
		<0		Other error 
		0		Drive currently not mounted (not active)
		>0		Drive mounted (active)

	If a drive has not yet been accessed or if it has been unlocked 
	with Dlock(), had a disk changed or medium ejected, then it is
	"unmounted", i.e. it is not active (any more). At the first 
	access to the drive it will be automatically "mounted" again, for 
	instance by the opening of a drive icon in the shell.

KER_XFSNAME (0x0105)
MX_KER_XFSNAME (0x6d05) from MagiC 6 onwards

	This function exists only under MagiC (from 15.6.96 onwards). 
	<path> is a path (not a file!). The name of the XFS driver that 
	is responsible for this path is read from the kernel.
	For this one passes in <param> a pointer to a buffer with room 
	for at least 9 bytes (char buf[9]); the pointer must point to 
	an even address.
	Dcntl() returns an error code < 0 if the directory is invalid or 
	some other error has arisen, else a value > 0 (!) or = 0 is 
	returned, and the name of the driver is copied to buf[]. 
	At present there are the names:

		"DOS_XFS "		Old DOS-XFS
		"VDOS_XFS"		New DOS-XFS (with VFAT support)
		"MMAC_HFS"		MagicMac-HFS

KER_INSTXFS (0x0200)
MX_KER_INSTXFS (0x6d02) from MagiC 6 onwards

	This function exists only under MagiC. The call:
		kernel = Dcntl(KER_INSTXFS, NULL, &myxfs);
	installs an XFS (=>MGX_XFS.TXT in the FILESYS folder).

CDROMEJECT (0x4309)

	This function exists under MagiC and with restrictions also in
	MiNT. It serves to eject a medium. <param> must be NULL.
	Under MiNT it is only used by CD-ROM drivers and may not be applied 
	to other interchangeable media (SyQuest, Zip...). Under MagiC it is 
	supported completely by the kernel.

	In <path> one passes a path whose associated storage medium is 
	to be ejected.

	For this MagiC first reads all drives that lie on the same medium 
	(the fields d_driver and d_devcode in DMD are used for this => see 
	MGX_XFS.TXT and MGX_XFS.H in the FILESYS folder). This is important 
	for interchangeable media (e.g. SyQuest) with several partitions or 
	for Macintosh volumes with several MagiC drives.

	All these drives will be released ("unmounted"). If an error arises 
	during this because there are still opened files on one of the 
	devices or because one of the drives has been locked with Dlock(), 
	for instance, then ejection is refused and EACCDN or ELOCKED 
	returned respectively.

	Finally the device driver (entry d_driver in DMD) is called to 
	eject the medium. The ejection function is supported for Mac 
	volumes (including floppy disks) as well as devices that are
	addressed by an XHDI-type driver (e.g. HDDRIVER). Some devices
	(hard disks) can not be ejected, so they are only switched off 
	(parked)  by the XHDI driver.
	Floppy disks can not be ejected on the Atari.

DFS_GETINFO (0x1100)
MX_DFS_GETINFO (0x6d40) from MagiC 6 onwards
DFS_INSTDFS (0x1200)
MX_DFS_INSTDFS (0x6d41) from MagiC 6 onwards

	These functions exist only in MagiC and serve for the installation 
	of a DFS (=>MGX_DFS.TXT in the FILESYS folder). They are handled by 
	the internal DOS-XFS.

PROC_CREATE (0xcc00)

	This function is reserved in MagiC up to version 5.20. It is no 
	longer used from MagiC 6 onwards.

DEV_M_INSTALL (0xcd00)
MX_DEV_INSTALL (0x6d20) from MagiC 6 onwards

	This function exists only in MagiC. With:
		Dcntl(DEV_M_INSTALL, "u:\\dev\\mydev", &mydriver);
	a device drive is installed.
	(see =>MGX_UDFS.TXT, MGX_DFS.TXT, MGX_DFS.H in the FILESYS folder).

FUTIME (0x4603)

	This function is executed by the appropriate XFS and is the 
	equivalent to the Fcntl() function with the same name. It is 
	supported by MiNT as well as the DOS-XFS of MagiC. It is not 
	currently supported for Macintosh volumes.
	As <param> a pointer to the following structure is passed:

		struct mutimbuf
		     {
		     unsigned int actime;          /* Access time */
		     unsigned int acdate;
		     unsigned int modtime;         /* Last modification */
		     unsigned int moddate;
		     };

	The structure is defined in MAGX.H (in the MXDEV_DK folder).

VFAT_CNFDFLN (0x5600)

	This function exists only under MagiC (from 2.1.96 onwards).
	For configuration of the VFAT-XFS.
	One must pass "u:\" for the path. The parameter is a bit vector 
	that specifies the drives on which long filenames are permitted.
	The setting only becomes active at the mounting of a file system, 
	so that already mounted file systems can not be affected by this 
	command.
	More exactly this means: During mounting of a file system the 
	VFAT-XFS determines from the bit vector specified in VFAT_CNFDFLN 
	(or with "drives=" in section [vfat] of MAGX.INF) whether a file 
	system is being managed in the "old" DOS mode (with 8+3 filenames) 
	or in the "new" Windows95 mode (with long filenames).
	The bit vector is initialised with 0L during booting, i.e. the boot 
	drive is always opened first in 8+3 mode. Then MAGX.INF is loaded 
	and the section [vfat] evaluated. If appropriate the boot drive is 
	then mounted anew with long filenames.

VFAT_CNFLN (0x5601)

	This function exists only under MagiC (from 2.1.96 onwards).
	For configuration of a VFAT file system.
	This specifies for a mounted drive whether it supports long 
	filenames or not. With it one can overwrite the default value 
	set 	with VFAT_CNFDFLN. So that the conversion becomes visible 
	a SH_WDRAW message should be sent to the shell.

DEV_NEWTTY (0xde00)
DEV_NEWBIOS (0xde01)
DEV_INSTALL (0xde02)
FS_INSTALL (0xf001)
FS_MOUNT (0xf002)
FS_UNMOUNT (0xf003)
FS_UNINSTALL (0xf004)

	These functions are only suported by MiNT and serve for installing/
	deinstalling of file systems and drivers. Due to different driver 
	structures MagiC uses other functions (see above).



VIII File handle functions
==========================


LONG Fclose( WORD handle )
--------------------------

This closes a file. The <handle> was read with Fopen() or Fcreate() or 
Fdup(), or we are dealing with a standard handle (0..5) or a device 
handle (-1, -2, -3, -4). -4 is present only in MagiC (for NUL:).
After an Fclose() the handle may no longer be accessed, as it has been 
so to speak returned to the system. An exception are the (negative)
device handles. With these one only informs the driver that any buffer 
should be written back ("flush buffer").


LONG Fread( WORD handle, LONG count, void *buf )
-----------------------------------------------

This reads <count> bytes from the file <handle> and writes it to the 
memory address <buf>.
The return value can be negative (read error, file locked,...), positive 
and smaller than <count> (file end reached, not all bytes could be read) 
or is equal to <count> (all bytes read).
In old TOS versions one can only read a maximum of 65536 bytes from the 
devices, as TOS ignores the upper 16 bits of <count>.


LONG Fwrite(WORD handle, LONG count, void *buf)
-----------------------------------------------

This writes <count> bytes from address <buf> to the file <handle>.
The return value can be negative (write error, medium write protected, 
file locked,...), positive and smaller than <count> (medium is full, 
not all bytes could be read) or equal to <count> (all bytes written). 
                                                                     
In old TOS versions one can only write a maximum of 65536 bytes to the 
devices, as TOS ignores the upper 16 bits of <count>.

KAOS and MagiC support the truncating of files to the length of the 
current file pointer position via:

	Fwrite(handle, 0L, (void *) -1);

From MagiC 3 on it is better to use Fcntl() with the opcode FTRUNCATE, 
due to compatibility to MiNT.


LONG Fseek( LONG offset, WORD handle, WORD seekmode )
-----------------------------------------------------

This sets the file pointer of the file <handle> to the position <offset>, 
calculated either from the beginning of the file (seekmode = 0), from the 
current position of the file pointer (seekmode = 1) or from the end of 
the file (seekmode = 2). In the last case <offset> should be smaller or 
equal to zero.
If successful the return value is the current file position (absolute, 
i.e. from the beginning of the file).
Fseek returns the error ERANGE if <offset> lies outside the file.
Fseek on pipes returns in MagiC and MiNT EACCDN, so that programs can 
differentiate between, say, devices and pipes.
Fseek to devices is ignored, the return value is always zero.


LONG Fdup( WORD handle )
------------------------

This duplicates a standard handle (0..5). One gets a new handle that 
points to the same file as the passed handle.

KAOS, and MagiC up to version 2.0 inclusive, return a negative ID for 
Fdup() if the standard handle is a device file. For instance Fdup(1) 
usually returns 0x0000ffff, as -1 is the device handle for CON (screen 
and keyboard). Newer MagiC versions always return a handle >= 6 for 
compatibility reasons.

From MagiC 4 onwards one can also duplicate device files (-1, -2, -3, -4).


LONG Fforce( WORD stdhdl, WORD nstdhdl )
----------------------------------------

This redirects the standard file <stdhdl> (must lie between 0..5) to 
the non-standard file <nstdhdl> (can also be a negative device handle).
After this <stdhdl> and <nstdhdl> point to the same file.
What's all this good for? The following procedure saves the setting for 
handle 1 (STDOUT), creates a new file and redirects STDOUT to this new 
file. With Pexec a program is called with the redirected STDOUT. After 
this STDOUT is restored once more.

	saveHandle = Fdup(STDOUT)
	newStdout = Fcreate(...)
	Fforce(STDOUT, newStdout)
	Fclose(newStdout)
	Pexec(...)
	Fforce(STDOUT, saveHandle)
	Fclose(saveHandle)

From MagiC 4 on Fforce() can also be called with device files (-1, -2, -3) 
as <stdhdl>. With this the device files -1, -2, -3 are redirected system 
globally (!). The file -4 (NUL:) can not be redirected.

TOS has a whole heap of errors here. For instance the system becomes 
completely confused if Fforce() is used on a standard file that is 
already pointing to a real file. This can happen quickly if, say in the 
above example, the calling program makes another Fforce() call.


LONG Fdatime( WORD buffer[2], WORD handle, WORD setflag)
--------------------------------------------------------

This sets (setflag = 1) or reads (setflag = 0) the date- and time-stamp 
of the opened file <handle>. buffer[] contains the date and time for 
setting, or the read value respectively.

Early TOS versions yielded unpredictable return values, and some TOS 
versions alter all files in the same directory that are open and have 
zero length. Furthermore, some TOS versions have problems if you do more 
with the file than just Fopen(), Fdatime(), Fclose().


LONG Flock(WORD handle, WORD mode, LONG start, LONG len)
--------------------------------------------------------

This sets (mode = 1) or removes (mode = 0) (write-) locking for portions 
of the file <handle>, starting at position <start> with the length <len>. 
See also Fcntl(F_SETLK).

The function returns special error codes ELOCKED (if an overlapping 
section of the file was already locked) or ENSLOCK (locking can not be 
removed, as not present).

It is supported by MagiC insofar as the call is converted by the DOS 
kernel to the Fcntl() call F_SETLK. This creates a write lock (G_WRLCK). 
With an invalid <mode> the kernel itself will return EINVFN without 
calling up the file driver.

The MagiC file drivers for (V)FAT and Mac-HFS unfortunately do not yet 
support the associated Fcntl code F_SETLK. But this would only be useful 
for network XFS systems (e.g. NFS or SMB).


LONG Fpipe( WORD handles[2] )
-----------------------------

This creates a unidirectional pipe (attribute 0x01), for which a unique 
name of the type "U:\PIPE\SYS$PIPE.nnn" (where 'nnn' is a 3-digit 
integer) is generated. If successful (return E_OK) handles[0] contains 
the pipe opened for reading, handles[1] the one opened for writing.
The call can be imitated with Fcreate() and Fopen(). It is useful for 
shells for redirection of STDIN/STDOUT.


LONG Fcntl( WORD handle, LONG arg, WORD cmd )
---------------------------------------------

This performs various operations on an opened file. Depending on the 
file type, various values are accepted for <cmd>. However some functions 
are general and should be supported by every file type, though this is 
not guaranteed. For invalid commands the file driver returns EINVFN.
The following opcodes are supported by the internal file drivers of 
MagiC:

- FSTAT ($4600)
- FIONREAD ($4601)
  <arg> is of the type (LONG *) and after the call contains the number 
  of bytes that could be read from the file, without having to block the 
  program during reading. This means that if a pipe contains 1000 
  characters then one can read 1000 characters immediately, without 
  having to wait for new data to be written to the pipe.
  For FAT files the actual length minus the current file pointer 
  position is returned. The same applies for "shared memory". Device 
  files (devices) return a 1 if a character is waiting, for which
  Bconstat() is used. For devices that have a read-in buffer, the number 
  of characters present in the buffer should be specified.
  FIONREAD is used by Finstat().
- FIONWRITE ($4602)
  <arg> is of the type (LONG *) and after the call contains the number 
  of bytes that can be written to the file, without having to block the 
  program during writing. This means that if a pipe contains 1000 
  characters then one can write another 1048 characters immediately, 
  without having to wait for new data to be read from the pipe.
  For FAT files 1 is returned. For files with a fixed length, e.g. 
  "shared memory", the length minus the file pointer position is 
  returned.
  Device files (devices) return a 1, if Bcostat() returns an "OK".
  For devices that have a write buffer, the number of characters still 
  free in the buffer should be specified.
  FIONWRITE is used by Foutstat().
- FUTIME ($4603)
- FTRUNCATE ($4604)
  <arg> is of the type (LONG *) and points to the new length of the 
  file to be truncated.
  In MagiC 3 this is at present supported only by the FAT-DFS.
- PBASEADDR ($5002)
- SHMGETBLK ($4d00)
  This is only supported for "shared memory" files, which are the files 
  that lie in u:\shm.
- SHMSETBLK ($4d01)
  This is only supported for "shared memory" files, which are the files 
  that lie in u:\shm. <arg> is a pointer to a memory block reserved with 
  M(x)alloc() which represents the "shared memory". The block is marked 
  in such a manner that it is not released at the termination of a 
  process. The length is verified and used for the opened file as well 
  as entered in the directory. Invalid block addresses result in the 
  error code EIMBA or to a bus or address error. The implementation 
  ought to correspond to MiNT.
(...)


LONG Finstat( WORD handle)
--------------------------

This returns for a file <handle> opened for reading the minimum number 
of characters that can be read without waiting. If this number can not 
be specified exactly then 1L will be returned.

The kernel tries at first to execute this call as Fcntl(FIONREAD).
If this subfunction of dev_ioctl does not exist (i.e. the file driver 
returns EINVFN) then dev_stat is called instead. In this case one can 
only make the statement "Character is waiting" (return == 1) or 
"No character is waiting" (return == 0).
FAT files and shared memory return the actual file length minus the 
current position.
Pipes return the number of bytes present in the block.


LONG Foutstat( WORD handle )
----------------------------

This returns for a file <handle> opened for writing the minimum number 
of characters that can be written without waiting. If this number can not 
be specified exactly then 1L will be returned.

The kernel tries at first to execute this call as Fcntl(FIONWRITE).
If this subfunction of dev_ioctl does not exist (i.e. the file driver 
returns EINVFN) then dev_stat is called instead. In this case one can 
only make the statement "Character is pending" (return == 1) or "No 
character is pending" (return == 0).
FAT files return 1.
Shared memory returns the actual file length minus the current position.
Pipes return the number of bytes still free in the block.


LONG Fgetchar( WORD	handle, WORD mode )
---------------------------------------

This reads a single character from the opened file <handle>. Return 
value is a LONG, whose upper 24 bits however are generally zeros (for a 
normal file). With a terminal the upper bits too will be filled (with 
scancode etc.). A special return value is 0xff1a for EOF (END-OF-FILE).

For terminals and similar devices only the mode <mode> has the following 
meanings:

	CMODE_COOKED (1)	Key combinations Ctrl-C, Ctrl-S, Ctrl-Q are 
					evaluated (return the corresponding signals 
					to the caller) and do not reach the caller as 
					normal key codes.
	CMODE_RAW (0)		No evaluation of above key combinations.
	CMODE_ECHO (2)		Outputs the characters input immedately on the 
					screen.

The modes are as usual OR'd, i.e. CMODE_ECHO+CMODE_COOKED is permitted.


LONG Fputchar( WORD	handle, ULONG value, WORD mode )
----------------------------------------------------

This writes a single character to the opened file <handle>. Return value 
is a negative error code or the number of bytes written:

	1L	One byte (the lowest 8 bits of <value>) were written to the file.
	4L	The complete character <value> was written to the terminal file.
	0L	Write error (disk full or similar).

For terminals and similar devices only the mode <mode> has the following 
meanings:

	CMODE_COOKED (1)	Key combinations Ctrl-C, Ctrl-S, Ctrl-Q are 
					evaluated (return the corresponding signals  
					to the caller) and are not passed on to the 
					terminal.
	CMODE_RAW (0)		No evaluation of above key combinations.


LONG Fselect( WORD timeout, LONG *instat, LONG *outstat, LONG dummy )
---------------------------------------------------------------------

This waits for the specified time (timeout in ms, or 0 for "Indefinitely") 
to see whether characters are available at the input (instat) and/or 
output (outstat) file descriptor, which is specified as a bit vector.
Here "bit n set" means that one waits for the file with the handle <n>. 
An empty amount can be passed as a pointer to 0L or as a null-pointer.
At the return all bits are cleared from *instat and *outstat whose 
associated files make _NO_ characters available.
<dummy> ist always 0.
Return value is the number of set bits of <*instat> plus that from
<*outstat> or an error code. As a result one gets 0L at a timeout.


LONG Fmidipipe ( WORD pid, WORD in, WORD out )
----------------------------------------------

In MiNT this changes the MIDI handles of a process <pid>, i.e. the handles
-4 and -5, to <in> or <out>, and so is equivalent to the corresponding 
Fforce() calls.
It is not implemented in MagiC.



IX Character-oriented functions
===============================


LONG Cconin( void )
-------------------

This is implemented as

	Fgetchar( STDIN, CMODE_COOKED+CMODE_ECHO )


LONG Cconout( WORD c )
----------------------

This is implemented as

	Fputchar( STDOUT, (ULONG) val, CMODE_COOKED )

The following return values are possible with this:

	MiNT and MagiC >= 3.00:

		1L	Successful ouput to file
		4L	Successful output to terminal
		0L	Disk full
		< 0	Error 

	KAOS and MagiC < 3.00:

		1L	Successful output to file or terminal
		0L	Disk full
		< 0	Error 

	TOS

		(No sensible return value)


LONG Cauxin( void )
-------------------

This is implemented as

	Fgetchar( STDAUX, CMODE_RAW )


LONG Cauxout( WORD c )
----------------------

This is implemented as

	Fputchar( STAUX, (ULONG) val, CMODE_RAW )

Here the same applies as with Cconout().


LONG Cprnout( WORD c )
----------------------

This is implemented as

	Fputchar( STPRN, (ULONG) val, CMODE_RAW )

Here the same applies as with Cconout().


LONG Crawio( WORD c )
---------------------

This is implemented as

	if	(c != 0x00ff)
		return(Fputchar( STDOUT, (ULONG) c, CMODE_RAW ));
	else	{
		if	(Cconis())
			return(Crawcin());
		else	return(0L);
		}


LONG Crawcin( void )
--------------------

This is implemented as

	Fgetchar( STDIN, CMODE_RAW )


LONG Cnecin( void )
-------------------

This is implemented as

	Fgetchar( STDIN, CMODE_COOKED )


LONG Cconws( char *s )
----------------------

In KAOS, MagiC and MiNT this is implemented as

	Fwrite( STDOUT, strlen(s), s )

and hence is "cooked" (i.e. evaluates Ctrl-C etc.) if STDOUT is a terminal.
TOS 1.4 gives a return value 0L for "OK" and -1L for "Error".
Under other operating systems the function is apparently void, i.e. it 
gives no usable return value at all.


LONG Cconrs( char *buf )
------------------------

This reads a character string from STDIN in "cooked" mode (i.e. Ctrl-C 
etc. are evaluated) with echo (i.e. the input is visible on screen).
The (buffer length - 1) is passed in buf[0], where the buffer starts 
from buf+2.
The input is terminated with [Return] and stored from buf+2[] onwards.
If reading from the keyboard, then in MagiC edit commands such as the 
cursor keys, Backspace and Delete are available. TOS handles only 
Backspace and Ctrl-X; TOS versions before 1.4 fail with ASCII codes > 127.
Herewith the key codes of MagiC:

     Cursor up/down          Restore last input
     Cursor left/right       Move cursor one character
     ditto with Shift        Cursor to start/end of line
     ClrHome                 Cursor to start of line
     Insert                  Insert mode
     Shift-Insert            Overwrite mode
     Shift-ClrHome           Clear input
     Tab                     Line start/end alternately (toggle)
     Undo                    Undo last input
     Delete/Backspace        Delete character under/before cursor
     F1..F10                 Call environmental variables F1..F10

With normal files one reads in MagiC up to the first LF, where CR is 
skipped over. Under TOS this function returns undefined results for 
redirected standard input; in particular the input is echoed partly to 
the screen or STDOUT. In MiNT (at least in Version 1.12) the function is 
implemented incorrectly.
The number of characters actually read is returned in buf[1], where CR 
and/or LF are not counted.
Return value is E_OK or an error code.


LONG Cconis( void )
-------------------

This verifies the input status of STDIN. Return values are 0 for "Not 
ready to read" (i.e. "Busy") and -1L for "Ready to read".

Here "Ready to read" for terminals means that characters are present in 
the input buffer. While TOS, KAOS and MagiC < 3.00 handle the function 
as "cooked" (i.e. evaluate Ctrl-C etc. if appropriate), MagiC >= 3.00 
handles this function as "raw" for compatibility reasons to MiNT.

For normal files the operating systems hold different opinions:

- TOS always returns -1 for "OK", thus making the function unusable.
- Though MiNT verifies the device driver, with FAT file systems this is 
  powerless and always returns -1 there too.
  An ingenious concept :-(
- MagiC only returns -1 if the file is opened for reading and the 
  device driver gives its OK with fd->dev_stat(). The DFS-FAT driver 
  only returns "OK" when the read pointer of the file is not at the 
  file end.

The return of error codes is not possible. At errors, 0 for "Not ready"
is returned.


LONG Cconos( void )
-------------------

This verifies the output status of STDOUT. Return values are 0 for "Not 
ready to write" (i.e. "Busy") and -1L for "Ready to write".
The return of error codes is not possible. At errors, 0 for "Not ready"
is returned.
In MagiC this call is implemented as the device function dev_stat().


LONG Cprnos( void )
-------------------

As Cconos(), but for STDPRN.


LONG Cauxis( void )
-------------------

As Cconis(), but for STDAUX.


LONG Cauxos( void )
-------------------

As Cconos(), but for STDAUX
