shithub: freetype+ttf2subf

ref: cef95a09d7de5f0de7bdc280f0377579fb470d1e
dir: /config/unix/ftsys.c/

View raw version
/*******************************************************************
 *
 *  ftsys.c
 *
 *    Unix-specific system operations.
 *
 *  Copyright 1996-1998 by
 *  David Turner, Robert Wilhelm, and Werner Lemberg.
 *
 *  This file is part of the FreeType project, and may only be used
 *  modified and distributed under the terms of the FreeType project
 *  license, LICENSE.TXT.  By continuing to use, modify, or distribute 
 *  this file you indicate that you have read the license and
 *  understand and accept it fully.
 *
 *
 *  This implementation of the 'ftsys' component uses memory-mapped
 *  files, as well as the ANSI malloc/free functions..
 *
 *  IMPORTANT NOTE :
 *
 *    Porters, read carefully the comments in ftsys.h before trying
 *    to port this file to your system. It contains many essential
 *    remarks, and will ease your work greatly..
 *
 ******************************************************************/

#include "ftsys.h"
#include "ftobjs.h"
#include "ftstream.h"
#include "ftdebug.h"

/* Memory-mapping includes and definitions..                            */
/*                                                                      */
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif

#include <sys/mman.h>
#ifndef MAP_FILE
#define MAP_FILE  0x00
#endif

/*
 * The prototype for munmap() is not provided on SunOS.  This needs to
 * have a check added later to see if the GNU C library is being used.
 * If so, then this prototype is not needed.
 */
#if defined(__sun__) && !defined(SVR4) && !defined(__SVR4)
  extern int  munmap( caddr_t  addr, int  len );
#endif

#include <sys/stat.h>
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif


/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
/* parameter of the PTRACE and PERROR macros, used to print/log    */
/* messages during execution..                                     */
/*                                                                 */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_io




/* To ease porting, we use the macro SYS_STREAM to name the system-specific */
/* stream type. For example, it is a "FILE*" with the ANSI libc, it will be */
/* a file descriptor, i.e. an integer, when using the Unix system api, etc. */
 
/* we identify each memory-mapped file through its address in memory */
/* hence the following macro definition..                            */
 
#define  SYS_STREAM  void*


/**************************************************************************/
/*                                                                        */
/*                      I/O ACCESS AND MANAGEMENT                         */
/*                                                                        */
/*  We only define the "ANSI" resource class in this class. It is         */
/*  disk-based, and provides a MRU cache, in order to only keep the file  */
/*  descriptors of the 10 most recently used resource files.              */
/*                                                                        */
/*  it simply contains two lists. One contains the "cached" resources     */
/*  with a valid FILE* pointer, the second contains all other "flushed"   */
/*  resource objects.                                                     */
/*                                                                        */

/* The FT_MMapFile class derives from FT_ResourceRec - description :   */
/*                                                                     */
/* <Struct> FT_AnsiFileRec                                             */
/*                                                                     */
/* <Fields>                                                            */
/*                                                                     */
/* root ::                                                             */
/*    the root resource class fields.                                  */
/*                                                                     */
/* pathname ::                                                         */
/*    the file's pathname. Needed because we open and close font       */
/*    resources dynamically in order to limit the number of            */
/*    concurrently active mappings (this saves kernel resources).      */
/*                                                                     */
/* file_size ::                                                        */
/*    the size in bytes of the resource. This field should be set to   */
/*    -1 until the resource is first opened..                          */
/*                                                                     */

#include <stdio.h>

  typedef struct FT_MMapFileRec_
  {
    FT_ResourceRec  root;
    const char*     pathname;
    FT_Long         file_size;  /* file size in bytes */
    
  } FT_MMapFileRec, *FT_MMapFile;


/* We use the macro STREAM_Name as a convenience to return a given  */
/* ANSI resource's pathname. Its "stream" argument is a FT_Resource */
/* which is typecasted to the FT_AnsiFile class                     */
#define STREAM_Name(stream)  ((FT_MMapFile)stream->resource)->pathname

/* We use the macro STREAM_File as a convenience to extract the      */
/* system-specific stream handle from a given FreeType stream object */
#define STREAM_File(stream)  ((void*)stream->stream_id.pointer)



/***************************************************************************/
/*                                                                         */
/* <Function> MMapFile_Open                                                */
/*                                                                         */
/* <Description>                                                           */
/*    This function is used to open a system-stream for a given resource.  */
/*                                                                         */
/*    Note that it must update the target FreeType stream object with the  */
/*    system-stream handle and the resource's size.                        */
/*                                                                         */
/*    Also, the 'stream->base' field must be set to NULL for disk-based    */
/*    resource, and to the address in memory of the resource's first byte  */
/*    for a memory-based one.                                              */
/*                                                                         */
/* <Input>                                                                 */
/*   resource :: the source resource                                       */
/*   stream   :: the target stream object                                  */
/*                                                                         */
/* <Return>                                                                */
/*   Error code                                                            */
/*                                                                         */
/* <Note>                                                                  */
/*   This function simply opens and maps the resource's file pathname      */
/*                                                                         */
/*   The stream object IS NOT CREATED by this function, but by its caller. */
/*                                                                         */
/***************************************************************************/

  static
  FT_Error  MMapFile_Open( FT_MMapFile  resource,
                           FT_Stream    stream )
  {
    int          file;
    struct stat  stat_buf;
    
    /* open the file */
    file = open( resource->pathname, O_RDONLY );
    if (file < 0)
    {
      PERROR(( "UnixSys.MMapFile_Open : could not open '%s'\n",
               resource->pathname ));
      return FT_Err_Cannot_Open_Stream;
    }

    if (fstat( file, &stat_buf ) < 0)
    {
      PERROR(( "UnixSys.MMapFile_Open : could not 'fstat' file '%s'\n",
               resource->pathname ));
      goto Fail_Map;
    }
      
    if ( resource->file_size < 0 )
      resource->file_size = stat_buf.st_size;
      
    stream->resource          = (FT_Resource)resource;
    stream->system            = resource->root.driver->system;
    stream->size              = resource->file_size;
    stream->stream_id.pointer = mmap( NULL,
                                      resource->file_size,
                                      PROT_READ,
                                      MAP_FILE | MAP_PRIVATE,
                                      file,
                                      0 );

    if ( (long)stream->stream_id.pointer == -1 )
    {
      PERROR(( "UnixSys.MMapFile_Open : Could not map file '%s'\n",
               resource->pathname ));
      goto Fail_Map;
    }

    close(file);
    stream->base   = (FT_Byte*)stream->stream_id.pointer;
    stream->cursor = stream->base;
    
    PTRACE1(( "UnixSys.MMapFile_Open: opened '%s' (%d bytes) succesfully\n",
              resource->pathname, resource->file_size ));

    return FT_Err_Ok;
    
  Fail_Map:
    close(file);
    stream->resource          = NULL;
    stream->size              = 0;
    stream->stream_id.pointer = NULL;
    stream->base              = NULL;
    stream->cursor            = NULL;
    
    return FT_Err_Cannot_Open_Stream;
  }


/***************************************************************************/
/*                                                                         */
/* <Function> MMapFile_Close                                               */
/*                                                                         */
/* <Description> Closes a given stream                                     */
/*                                                                         */
/* <Input>                                                                 */
/*   stream   :: the target stream object                                  */
/*                                                                         */
/* <Return>                                                                */
/*   Error code                                                            */
/*                                                                         */
/* <Note>                                                                  */
/*   This function simply unmaps the resource..                            */
/*                                                                         */
/***************************************************************************/

  static
  FT_Error  MMapFile_Close( FT_Stream  stream )
  {
    PTRACE1(( "Closing file '%s'\n", STREAM_Name(stream) ));
    
    munmap ( (void*)stream->stream_id.pointer, stream->size );
        
    stream->resource          = NULL;
    stream->stream_id.pointer = NULL;
    stream->size              = 0;
    stream->base              = NULL;
    stream->cursor            = NULL;

    return FT_Err_Ok;
  }


/***************************************************************************/
/*                                                                         */
/* <Function> MMapFile_Seek                                                */
/*                                                                         */
/* <Description> Seek a stream to a given position                         */
/*                                                                         */
/* <Input>                                                                 */
/*   stream   :: the target stream object                                  */
/*   position :: offset in bytes from start of resource/stream             */
/*                                                                         */
/* <Return>                                                                */
/*   Error code                                                            */
/*                                                                         */
/* <Note>                                                                  */
/*   This function should never be called for memory-based resources..     */
/*                                                                         */
/***************************************************************************/

  static
  FT_Error  MMapFile_Seek( FT_Stream  stream,
                           FT_Long    position )
  {
    (void)stream;
    (void)position;
    return FT_Err_Invalid_Stream_Operation;
  }


/***************************************************************************/
/*                                                                         */
/* <Function> MMapFile_Skip                                                */
/*                                                                         */
/* <Description> Skip a given number of bytes in an MMap stream.           */
/*               Useful to skip pad bytes, for example.                    */
/*                                                                         */
/* <Input>                                                                 */
/*   stream   :: the target stream object                                  */
/*   count    :: number of bytes to skip in the stream                     */
/*                                                                         */
/* <Return>                                                                */
/*   Error code                                                            */
/*                                                                         */
/* <Note>                                                                  */
/*   This function should never be called for memory-based resources..     */
/*                                                                         */
/***************************************************************************/

  static
  FT_Error  MMapFile_Skip( FT_Stream  stream,
                           FT_Long    count )
  {
    (void)stream;
    (void)count;
    return FT_Err_Invalid_Stream_Operation;
  }                        

/***************************************************************************/
/*                                                                         */
/* <Function> MMapFile_Pos                                                 */
/*                                                                         */
/* <Description> Returns the current offset within an MMap stream's        */
/*               resource.                                                 */
/*                                                                         */
/* <Input>                                                                 */
/*   stream   :: the target stream object                                  */
/*                                                                         */
/* <Output>                                                                */
/*   position :: current offset. -1 in case of error                       */
/*                                                                         */
/* <Return>                                                                */
/*   Error code.                                                           */
/*                                                                         */
/* <Note>                                                                  */
/*   This function should never be called for memory-based resources..     */
/*                                                                         */
/***************************************************************************/

  static
  FT_Error  MMapFile_Pos( FT_Stream  stream,
                          FT_Long*   position )
  {
    (void)stream;
    (void)position;
    return FT_Err_Invalid_Stream_Operation;
  }

/***************************************************************************/
/*                                                                         */
/* <Function> MMapFile_Read                                                */
/*                                                                         */
/* <Description> Read a given number of bytes from an MMap stream into     */
/*               memory.                                                   */
/*                                                                         */
/* <Input>                                                                 */
/*   stream   :: the target stream object                                  */
/*   buffer   :: the target read buffer where data is copied               */
/*   size     :: number of bytes to read from the stream                   */
/*                                                                         */
/* <Output>                                                                */
/*   read_bytes :: the number of bytes effectively read from the stream    */
/*                 used in case of error (i.e. FT_Err_Invalid_Stream_Read) */
/*                 by some parts of the library..                          */
/* <Return>                                                                */
/*   Error code                                                            */
/*                                                                         */
/* <Note>                                                                  */
/*   This function should never be called for memory-based resources..     */
/*                                                                         */
/***************************************************************************/

  static
  FT_Error  MMapFile_Read( FT_Stream  stream,
                           FT_Byte*   buffer,
                           FT_Long    size,
                           FT_Long*   read_bytes )
  {
    (void)stream;
    (void)buffer;
    (void)size;
    (void)read_bytes;
    return FT_Err_Invalid_Stream_Operation;                      
  }

/* The following table is the "virtual method table" for the 'MMap  */
/* resource class', which methods are defined above. Its address is */
/* set in the 'interface' field of all resource objects created by  */
/* the function FT_Create_MMapFile (see below)                      */

  static
  FTRes_InterfaceRec  FT_MMapFile_Interface =
  {
    (FTRes_Open_Func)  MMapFile_Open,
    (FTRes_Close_Func) MMapFile_Close,
    (FTRes_Seek_Func)  MMapFile_Seek,
    (FTRes_Skip_Func)  MMapFile_Skip,
    (FTRes_Pos_Func)   MMapFile_Pos,
    (FTRes_Read_Func)  MMapFile_Read,
  };


 /************************************************************************/
 /*                                                                      */
 /* <Function>  FT_Create_Resource                                       */
 /*                                                                      */
 /* <Description>                                                        */
 /*    Create a new resource object for a given library. Note that this  */
 /*    function takes an ASCII 'pathname' as an argument.                */
 /*                                                                      */
 /* <Input>                                                              */
 /*     library  :: handle to target library object                      */
 /*     pathanme :: ASCII pathname of the font file                      */
 /*                                                                      */
 /* <Output>                                                             */
 /*     resource :: handle to new resource object                        */
 /*                                                                      */
 /* <Return>                                                             */
 /*     Error code. 0 means success                                      */
 /*                                                                      */
 /* <Note>                                                               */
 /*     When porting the library to exotic environments, where an        */
 /*     ASCII pathname isn't used to name files, developers should       */
 /*     invoke directly their own resource creation function which       */
 /*     must be placed in their port of the "ftsys" component.           */
 /*                                                                      */
 /*     See the porting guide for more information..                     */
 /*                                                                      */
  EXPORT_FUNC
  FT_Error  FT_Create_Resource( FT_Library    library,
                                const char*   pathname,
                                FT_Resource*  aresource )
  {
    FT_Int       len;
    FT_System    system;
    FT_MMapFile  resource;
    FT_Error     error;

    *aresource = NULL;
    
    if (!library)
    {
      PERROR(( "Unix.New_Resource : null library handle\n" ));
      return FT_Err_Invalid_Library_Handle;
    }

    system = library->system;

    if ( !pathname )
      goto Fail_Null;
      
    len = strlen(pathname);
    if (len == 0)
      goto Fail_Null;

    resource = NULL;
    
    if ( ALLOC( resource, sizeof(*resource) ) ||
         ALLOC( resource->pathname, len+1   ) )
      goto Fail_Memory;

    resource->root.library   = library;
    resource->root.interface = &FT_MMapFile_Interface;
    resource->root.flags     = FT_RESOURCE_TYPE_MEMORY_BASED;
    resource->file_size      = -1;
    strcpy( (char*)resource->pathname, pathname );

    PTRACE1(( "Create_MMapFile : MMap resource created for '%s'\n",
              pathname ));
    
    *aresource = (FT_Resource)resource;
    return FT_Err_Ok;

  Fail_Null:    
    PERROR(( "Create_MMapFile : null pathname !!\n" ));
    return FT_Err_Invalid_Argument;
    
  Fail_Memory:
    if (resource)
      FREE( resource->pathname );
    FREE( resource );
    PERROR(( "Create_MMapFile : error when creating resource !\n" ));
    return error;
  }

  
/***************************************************************************/
/*                                                                         */
/* <Function> FT_Destroy_Resource                                          */
/*                                                                         */
/* <Description> Destroys an MMap resource object.                         */
/*               This function is never called directly by the font        */
/*               drivers. Only by the higher-level part of FreeType        */
/*               (called the HLib), or client applications                 */
/*                                                                         */
/* <Input>                                                                 */
/*   resource :: the MMap resource object                                  */
/*                                                                         */
/* <Note>                                                                  */
/*   This functions does not check that runs or streams are opened for     */
/*   the resource (for now, we assume developer intelligence. We'll most   */
/*   probably lower our standard later to ease debugging ;-)               */
/*                                                                         */
/***************************************************************************/
 
  EXPORT_FUNC
  FT_Error  FT_Destroy_Resource( FT_Resource  resource )
  {
    FT_System    system = resource->library->system;
    FT_MMapFile  res    = (FT_MMapFile)resource;
    
    if ( !res || res->root.interface != &FT_MMapFile_Interface )
    {
      PERROR(( 
        "Destroy_MMapFile : Trying to destroy an invalid resource !!\n" ));
      return FT_Err_Invalid_Resource_Handle;
    }
    
    PTRACE1(( "Destroy_MMapFile : destroying resource for '%s'\n",
              res->pathname ));

    FREE( res->pathname );
    FREE( res );

    return FT_Err_Ok;
  }

  
  
/**************************************************************************/
/*                                                                        */
/*                         MEMORY MANAGEMENT                              */
/*                                                                        */
/*                                                                        */
/*   This part copies the old FreeType 1.0 and 1.1 memory management      */
/*   scheme that was defined in the file "ttmemory.h". One can see that   */
/*                                                                        */
/*   - a set of macros is defined for the memory operations used          */
/*     by the engine ( MEM_Copy, MEM_Move, MEM_Set ). This comes from     */
/*     the fact that many compilers are able to inline these ops directly */
/*     within the compiled code, rather than generating a call to the     */
/*     C library. However, this obliges us to include the <string.h>      */
/*     header file.                                                       */
/*                                                                        */
/*     If you provide your own memory operations routine, you can get     */
/*     rid of the #include <string.h> below.                              */
/*                                                                        */
/*                                                                        */
/*   - the FT_Alloc function has several essential properties that        */
/*     MUST be retained by each port :                                    */
/*                                                                        */
/*      - it returns an error code, NOT the allocated block's base        */
/*        address                                                         */
/*                                                                        */
/*      - it takes the address of a target pointer, where the block's     */
/*        base address will be set. if the size is zero, its value        */
/*        will be NULL and the function returns successfully              */
/*                                                                        */
/*      - in case of error, the pointer's value is set to NULL and        */
/*        an error code is returned..                                     */
/*                                                                        */
/*      - the new allocated block MUST be zero-filled. This is a strong   */
/*        convetion the rest of the engine relies on                      */
/*                                                                        */
/*                                                                        */
/*                                                                        */
/*   - the FT_Free function has also its essentials :                     */
/*                                                                        */
/*      - it takes the address of a pointer which value is the block's    */
/*        base address. This is UNLIKE a standard "free" which takes the  */
/*        the block's base directly.                                      */
/*                                                                        */
/*      - it accepts succesfully the address of a pointer which value     */
/*        is NULL, in which case it simply returns.                       */
/*                                                                        */
/*      - the pointer is always set to NULL by the function               */
/*                                                                        */
/*                                                                        */
/*   - the MEM_Alloc, ALLOC and ALLOC_ARRAY macros are used by the        */
/*     library, and should NOT be modified by porters !!                  */
/*                                                                        */

/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
/* parameter of the PTRACE and PERROR macros, used to print/log    */
/* messages during execution..                                     */
/*                                                                 */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_memory


#include <stdlib.h>

/**************************************************************************/
/*                                                                        */
/* <Function> FT_Alloc                                                    */
/*                                                                        */
/* <Description>                                                          */
/*    Allocates a new bloc of memory. The returned area is always         */
/*    zero-filled, this is a strong convention in many FreeType parts     */
/*                                                                        */
/* <Input>                                                                */
/*    system    :: handle to a given 'system object' where allocation     */
/*                 occurs..                                               */
/*                                                                        */
/*    size      :: size in bytes of the block to allocate                 */
/*                                                                        */
/* <Output>                                                               */
/*    P         :: pointer to the fresh new block. It should be set       */
/*                 to NULL if 'size' is 0, of in case of error..          */
/*                                                                        */
/* <Return>                                                               */
/*    FreeType error code. 0 means success.                               */
/*                                                                        */
/**************************************************************************/

  BASE_FUNC
  FT_Error  FT_Alloc( FT_System  system,
                      long       size, 
                      void*     *P ) 
  {
  
    if (!P)
    {
      PERROR(( "FT_Alloc : invalid pointer address !!\n" ));
      return FT_Err_Invalid_Argument;
    }
    
    if ( size > 0 )
    {
      *P = malloc( size );
      if ( !*P )
      {
        PERROR(( "FT_Alloc : out of memory (%ld bytes requested) !!\n",
                 size ));

        return FT_Err_Out_Of_Memory;
      }

      system->total_alloc += size;

      /* ALWAYS ZERO-FILL THE BLOCK !!!!! */   
      MEM_Set( *P, 0, size );
    }
    else
      *P = NULL;

    PTRACE2(( "FT_Alloc : size = %ld, pointer = 0x%08lx, block = 0x%08lx\n",
              size, (long)P, (long)*P ));

    return FT_Err_Ok;
  }


/**************************************************************************/
/*                                                                        */
/* <Function> FT_Realloc                                                  */
/*                                                                        */
/* <Description>                                                          */
/*    Reallocates a block of memory pointed to by '*P' to 'Size'          */
/*    bytes from the hea^, possibly changing '*P'.                        */
/*                                                                        */
/* <Input>                                                                */
/*    system    :: handle to a given 'system object' where allocation     */
/*                 occurs..                                               */
/*                                                                        */
/*    size      :: size in bytes of the block to allocate                 */
/*                                                                        */
/* <InOut>                                                                */
/*    P         :: pointer to the fresh new block. It should be set       */
/*                 to NULL if 'size' is 0, of in case of error..          */
/*                                                                        */
/* <Return>                                                               */
/*    FreeType error code. 0 means success.                               */
/*                                                                        */

  BASE_FUNC
  int  FT_Realloc( FT_System  system,
                   long       size, 
                   void*     *P )
  {
    void*  Q;
    
    if (!P)
    {
      PERROR(( "FT_Realloc : invalid pointer address !!\n" ));
      return FT_Err_Invalid_Argument;
    }

    /* if the original pointer is NULL, call FT_Alloc */    
    if (!*P)
      return FT_Alloc( system, size, P );

    /* if the new block if zero-sized, clear the current one */    
    if (size <= 0)
      return FT_Free( system, P );
    
    Q = (void*)realloc( *P, size );
    if (!Q)
    {
      PERROR(( "FT_Realloc : reallocation failed\n" ));
      return FT_Err_Out_Of_Memory;
    }

    *P = Q;    
    return FT_Err_Ok;
  }


/**************************************************************************/
/*                                                                        */
/* <Function> FT_Free                                                     */
/*                                                                        */
/* <Description>                                                          */
/*    Releases a given block of memory allocated through FT_Alloc         */
/*                                                                        */
/* <Input>                                                                */
/*    system    :: handle to a given 'system object' where allocation     */
/*                 occured..                                              */
/*                                                                        */
/*    P         :: This is the _address_ of a _pointer_ which points to   */
/*                 the allocated block. It is always set to NULL on exit  */
/*                                                                        */
/* <Return>                                                               */
/*    FreeType error code. 0 means success.                               */
/*                                                                        */
/* <Note>                                                                 */
/*    If P or *P are NULL, this function should return successfuly. This  */
/*    is a strong convention within all of FreeType and its drivers..     */
/*                                                                        */

  BASE_FUNC
  FT_Error  FT_Free( FT_System  system,
                     void*     *P )
  {
    (void)system;  /* unused parameter. Gets rid of warnings */

    PTRACE2(( "FT_Free : freeing pointer 0x%08lx (block 0x%08lx)\n",
              (long)P, (P ? (long)*P : -1) ));

    if ( !P || !*P )
      return FT_Err_Ok;

    free( *P );
    *P = NULL;

    return FT_Err_Ok;
  }

/**************************************************************************/
/*                                                                        */
/*                       SYNCHRONIZATION MANAGEMENT                       */
/*                                                                        */
/*                                                                        */
/*   This section deals with mutexes. The library can be compiled to      */
/*   three distinct thread-support levels ( namely single-threaded,       */
/*   thread-safe and re-entrant modes ).                                  */
/*                                                                        */
/*   It protects its variables through the MUTEX_Lock and MUTEX_Release   */
/*   macros which are void in single-threaded mode.                       */
/*                                                                        */
/*                                                                        */
/*   It defines a type-less mutex reference type, "TMutex", that you're   */
/*   free to redefine for your system's needs..                           */
/*                                                                        */
/*   The default implementation of ftsys.c contains only dummy functions  */
/*   which always return succesfully. you NEED to specialize them in      */
/*   order to port ftsys.c in any multi-threaded environment...           */
/*                                                                        */

/* The macro FT_COMPONENT is used in trace mode. It is an implicit */
/* parameter of the PTRACE and PERROR macros, used to print/log    */
/* messages during execution..                                     */
/*                                                                 */
#undef  FT_COMPONENT
#define FT_COMPONENT  trace_sync

#ifdef FT_CONFIG_THREADS


  BASE_FUNC
  FT_Error  FT_Mutex_Create ( FT_System  system,
                              TMutex*    mutex )
  {
    (void)system;  /* unused parameter. Gets rid of warnings */
    
    mutex = (void*)-1;
    system->num_mutexes++;
    return FT_Err_Ok;
    /* Replace this line with your own mutex creation code */
  }


  BASE_FUNC
  void  FT_Mutex_Delete ( FT_System  system,
                          TMutex*    mutex )
  {
    (void)system; /* unused parameter. Gets rid of warnings */
    
    mutex = (void*)0;
    system->num_mutexes--;
    /* Replace this line with your own mutex destruction code */
  }

  BASE_FUNC
  void  FT_Mutex_Lock   ( FT_System  system,
                          TMutex*    mutex )
  {
    /* NOTE: It is legal to call this function with a NULL argument */
    /*       in which case an immediate return is appropriate.      */
    (void)system; /* unused parameter. Gets rid of warnings */
    
    if ( !mutex )
      return;

    ; /* Insert your own mutex locking code here */
  }


  void  FT_Mutex_Release( FT_System  system,
                          TMutex*  mutex )
  {
    /* NOTE: It is legal to call this function with a NULL argument */
    /*       in which case an immediate return is appropriate       */
    (void)system; /* unused parameter. Gets rid of warnings */
    
    if ( !mutex )
      return;
    ; /* Insert your own mutex release code here */
  }

#endif /* FT_CONFIG_THREADS */




  EXPORT_FUNC
  FT_Error  FT_New_System( FT_System*  system )
  {
    *system = (FT_System)malloc( sizeof(FT_SystemRec) );
    if ( !*system )
      return FT_Err_Out_Of_Memory;

    /* the ANSI function 'free' is unable to  return the number   */
    /* of released bytes. Hence, the 'current_alloc' field of the */
    /* system object cannot be used                               */
    
    (*system)->system_flags = FT_SYSTEM_FLAG_TOTAL_ALLOC |
                              FT_SYSTEM_FLAG_MUTEXES;
    (*system)->total_alloc = 0;
    (*system)->num_mutexes = 0;

    /* initialise i/o management (nothing) */
    
    /* initialise synchronisation (nothing) */
    
    /* initialise streams */

    return FT_Err_Ok;
  }



  EXPORT_FUNC
  FT_Error  FT_Done_System( FT_System  system )
  {
    /* finalise syncrhonisation (nothing) */
    
    /* finalise i/o management (nothing)  */
    
    /* finalise memory management         */
    free( system );

    return FT_Err_Ok;
  }