Hi all,

During the new year holiday, I was trying to introduce per-site limiter
of memory allocation to memory debugger module in FreeType2. I think
it might be useful for the application programmers to reproduce the
out-of-memory error by specific scenario. If you're interested in,
please give me comment about the current design.

The patch is attached: mps20110107-ft2_limit-alloc-per-site.diff
--------------------------------------------------------------------
* What is this?
Current FreeType2 memory debugger provides 2 interfaces to restrict the
memory allocator; FT2_ALLOC_TOTAL_MAX (historical summation of allocation,
free() is not considered) and FT2_ALLOC_COUNT_MAX (how many times allocation
is requested). Their restriction is for whole of FT2 library, so it is
difficult to make an OOM error occur at specific site.

During the debug for Savannah bug#31923, I wanted to make OOM error in
ftc_sbit_copy_bitmap().

Attached patch introduces 2 interfaces to define the per-site limiter
of memory allocation; FT2_ALLOC_TOTAL_MAX_SITE and FT2_ALLOC_CUR_MAX_SITE.
FT2_ALLOC_TOTAL_MAX_SITE is a per-site version of FT2_ALLOC_TOTAL_MAX.
FT2_ALLOC_CUR_MAX_SITE is a modified version of FT2_TOTAL_MAX_SITE to
consider the effect of free().

* Basic syntax of the environmental variables to control per-site limiter
As FT2_DEBUG is a space-separated list, new interfaces are same.
A limiter for a specific site is described by a pair of site-specifier
and the max buffer size allocated by the site.
        <limiter> ::= <a_site>,<max_buffer_size>

        <site> ::= <pathname>:<line_number>

        <pathname> ::= free string
        <line_number> ::= 32-bit integer

        <max_buffer_size> ::= 32-bit integer

and FT2_ALLOC_{TOTAL,CUR}_MAX_SITE should be set as a space-separated
list of the limiters.

        <limiters> ::= <limiter> | <limiter> <limiters>

For example,
        FT2_ALLOC_CUR_MAX_SITE="/foo/bah/aaa.c:10,1000 /foo/bah/bbb.c:21,10000"

* More easier syntax is required?
The site specifier is embedded by existing memory debugger. You can the
summary report when you set FT2_DEBUG_MEMORY environment, like this:

FreeType Memory Dump: current=0 max=1360517 total=3047988 count=0
 block  block    sizes    sizes    sizes   source
 count   high      sum  highsum      max   location
-------------------------------------------------
     0   6879        0   385224       56 
/home/mpsuzuki/redhat/BUILD/freetype2-current/freetype2/src/base/ftobjs.c:302
     0   6878        0   385168       56 
/home/mpsuzuki/redhat/BUILD/freetype2-current/freetype2/src/cache/ftcsbits.c:57
     0   6878        0   357656       52 
/home/mpsuzuki/redhat/BUILD/freetype2-current/freetype2/src/base/ftglyph.c:290
     0   6878        0   220096       32 
/home/mpsuzuki/redhat/BUILD/freetype2-current/freetype2/src/cache/ftcimage.c:67
     0    430        0   123840      288 
/home/mpsuzuki/redhat/BUILD/freetype2-current/freetype2/src/cache/ftcsbits.c:232
...

Setting FT2_ALLOC_CUR_MAX_SITE with absolute pathname like
"/home/mpsuzuki/redhat/BUILD/freetype2-current/freetype2/src/base/ftobjs.c:302,1000
 ..."
is lengthy. I want to specify by basename like "ftobjs.c:302,1000 ...".
But FreeType2 is a cross-platform library assuming only C89 and we
should not expect the function like basename(). ft2demos has already it,
slightly modified version is written in another patch;
mps20110107-ft2_basename.diff. Here if libgen.h is available,
native basename() is used. Also raw slash in resource fork accessor
is replaced by new macro PLATFORM_DIR_SEPARATOR.

* Future issues
Some people may request a feature to define the limiter with
more fine-tuned scenario, like "per specific stackframe".
For example, if there is a generic function calling allocater
and the function is called by many places, the site specification
by the position where the allocator is invoked is not enough
to set fine-tuned timebomb. I was trying to add a feature to
define a limiter by the range of code, catching all allocation
from the range. The patch was unfinished, if you're interested
in, please refer the patch uploaded on Savannah bug#31923.

Regards,
mpsuzuki
diff --git a/include/freetype/config/ftstdlib.h b/include/freetype/config/ftstdlib.h
index 30ec14e..db6b265 100644
--- a/include/freetype/config/ftstdlib.h
+++ b/include/freetype/config/ftstdlib.h
@@ -81,6 +81,7 @@
 #define ft_memmove  memmove
 #define ft_memset   memset
 #define ft_strcat   strcat
+#define ft_strchr   strchr
 #define ft_strcmp   strcmp
 #define ft_strcpy   strcpy
 #define ft_strlen   strlen
diff --git a/include/freetype/internal/fttrace.h b/include/freetype/internal/fttrace.h
index e9b383a..5d2decc 100644
--- a/include/freetype/internal/fttrace.h
+++ b/include/freetype/internal/fttrace.h
@@ -24,6 +24,7 @@ FT_TRACE_DEF( any )
   /* base components */
 FT_TRACE_DEF( calc )      /* calculations            (ftcalc.c)   */
 FT_TRACE_DEF( memory )    /* memory manager          (ftobjs.c)   */
+FT_TRACE_DEF( dbgmem )    /* memory debugger         (ftdbgmem.c) */
 FT_TRACE_DEF( stream )    /* stream manager          (ftstream.c) */
 FT_TRACE_DEF( io )        /* i/o interface           (ftsystem.c) */
 FT_TRACE_DEF( list )      /* list management         (ftlist.c)   */
diff --git a/src/base/ftdbgmem.c b/src/base/ftdbgmem.c
index 12fed04..bb04f68 100644
--- a/src/base/ftdbgmem.c
+++ b/src/base/ftdbgmem.c
@@ -25,6 +25,10 @@
 #include FT_TYPES_H
 
 
+#undef  FT_COMPONENT
+#define FT_COMPONENT  trace_dbgmem
+
+
 #ifdef FT_DEBUG_MEMORY
 
 #define  KEEPALIVE /* `Keep alive' means that freed blocks aren't released
@@ -505,6 +509,65 @@
   }
 
 
+  /*
+   * ft_mem_get_val_for_source( source, env_var_name )
+   *
+   * Get a numerical value from named environmental variable
+   * for the site specified by FT_MemSource.  For the syntax
+   * of the environmental variable, see docs/DEBUG.
+   *
+   */
+  static int
+  ft_mem_get_env_val_for_source( FT_MemSource  source,
+                                 const char*   env_var_name )
+  {
+    char  *file_name = (char*)source->file_name;
+    char  *c, *c0;
+
+
+    /* return if specified environment is unset */
+    c = c0 = getenv( env_var_name );
+    if ( !c )
+      return -1;
+
+    /* return if basename not found anymore */
+    while ( NULL != ( c = ft_strstr( c, file_name ) ) )
+    {
+      /* matched token is 1st or after separator space? */
+      if ( c != c0 && *(c-1) != ' ' )
+        goto NextToken;
+
+      /* check ':', a separator between pathname & line number */
+      c = c + ft_strlen( file_name );
+      if ( ':' != *c || !ft_isdigit( c[1] ) )
+        goto NextToken;
+      c++;
+
+      /* check the line number */
+      if ( atoi( c ) !=  source->line_no )
+        goto NextToken;
+
+      /* line number matched, skip digits */
+      while ( ft_isdigit( *c ) )
+        c++;
+
+      /* check ',', a separator between line number & value */
+      if ( ',' != *c || !ft_isdigit( c[1] ) )
+        goto NextToken;
+      c++;
+      return atoi( c );
+
+  NextToken:
+      c = ft_strchr( c, ' ' );
+      if ( !c ) /* no token anymore */
+        break;
+
+      c++;
+    }
+    return -1;
+  }
+
+
   static void
   ft_mem_table_set( FT_MemTable  table,
                     FT_Byte*     address,
@@ -676,17 +739,87 @@
   }
 
 
+  static FT_Bool
+  ft_mem_check_alloc_limiter_for_source( FT_MemSource  source,
+                                         FT_Long       size )
+  {
+    int      mem_limit_site_total = -1; /* negative means unlimited */
+    int      mem_limit_site_cur   = -1; /* negative means unlimited */
+    FT_Bool  exceeds_limit_site_total = FALSE;
+    FT_Bool  exceeds_limit_site_cur   = FALSE;
+    long     req_all = source->all_size + size;
+    long     req_cur = source->cur_size + size;
+#define FT_HAS_LIMITER( key ) \
+    ( mem_limit_ ## key ## _total >= 0 || mem_limit_ ## key ## _cur >= 0 )
+#define FT_HAS_MULTI_LIMITERS( key ) \
+    ( mem_limit_ ## key ## _total >= 0 && mem_limit_ ## key ## _cur >= 0 )
+#define FT_TRACE6_DEFINED_LIMIT( req, limit )    \
+    {                                            \
+      if ( limit >= 0 )                          \
+        FT_TRACE6(( "%ld =< %ld", req, limit )); \
+    }
+
+    mem_limit_site_total =
+      ft_mem_get_env_val_for_source( source,
+                                     "FT2_ALLOC_TOTAL_MAX_SITE" );
+    mem_limit_site_cur =
+      ft_mem_get_env_val_for_source( source,
+                                     "FT2_ALLOC_CUR_MAX_SITE" );
+    if ( FT_HAS_LIMITER( site ) )
+      FT_TRACE6(( "ft_mem_table_set() invoked by %s:%lu, limit:( ",
+                  source->file_name, source->line_no ));
+    FT_TRACE6_DEFINED_LIMIT( req_all, mem_limit_site_total );
+    if ( FT_HAS_MULTI_LIMITERS( site ) )
+      FT_TRACE6(( " && " ));
+    FT_TRACE6_DEFINED_LIMIT( req_cur, mem_limit_site_cur );
+    if ( FT_HAS_LIMITER( site ) )
+      FT_TRACE6((" )\n"));
+
+    if ( mem_limit_site_total >= 0 && mem_limit_site_total > req_all )
+      exceeds_limit_site_total = TRUE;
+
+    if ( mem_limit_site_cur >= 0 && mem_limit_site_cur > req_cur )
+      exceeds_limit_site_cur = TRUE;
+
+    if ( exceeds_limit_site_total || exceeds_limit_site_cur )
+    {
+      FT_TRACE6(( "ft_mem_table_set() returns NULL to %s:%lu,"
+                  " allocation request exceeds %s-limit (%lu > %lu)\n",
+                  source->file_name, source->line_no,
+                  ( exceeds_limit_site_total ? "site-total" :
+                                               "site-current" ),
+                  ( exceeds_limit_site_total ? req_all :
+                                               req_cur ),
+                  ( exceeds_limit_site_total ? mem_limit_site_total :
+                                               mem_limit_site_cur )
+                 ));
+      return FALSE;
+    }
+    return TRUE;
+
+#undef FT_HAS_LIMITER
+#undef FT_HAS_MULTI_LIMITERS
+#undef FT_TRACE6_DEFINED_LIMIT
+  }
+
+
   extern FT_Pointer
   ft_mem_debug_alloc( FT_Memory  memory,
                       FT_Long    size )
   {
-    FT_MemTable  table = (FT_MemTable)memory->user;
-    FT_Byte*     block;
+    FT_MemTable   table = (FT_MemTable)memory->user;
+    FT_MemSource  source = NULL;
+    FT_Byte*      block;
 
 
     if ( size <= 0 )
       ft_mem_debug_panic( "negative block size allocation (%ld)", size );
 
+    source = ft_mem_table_get_source( table );
+    if ( source )
+      if ( !ft_mem_check_alloc_limiter_for_source( source, size ) )
+        return NULL;
+
     /* return NULL if the maximum number of allocations was reached */
     if ( table->bound_count                           &&
          table->alloc_count >= table->alloc_count_max )
diff --git a/src/base/ftrfork.c b/src/base/ftrfork.c
index 6df2def..b01ecb9 100644
--- a/src/base/ftrfork.c
+++ b/src/base/ftrfork.c
@@ -25,6 +25,7 @@
 
 
 #include <ft2build.h>
+#include FT_CONFIG_CONFIG_H
 #include FT_INTERNAL_DEBUG_H
 #include FT_INTERNAL_STREAM_H
 #include FT_INTERNAL_RFORK_H
diff --git a/src/cache/ftccache.c b/src/cache/ftccache.c
index a5a915e..18af754 100644
--- a/src/cache/ftccache.c
+++ b/src/cache/ftccache.c
@@ -473,6 +473,29 @@
   }
 
 
+  FT_LOCAL_DEF( FT_Size )
+  ftc_get_list_length( FTC_Cache   cache,
+                       FT_PtrDist  hash )
+  {
+    FT_Size    len = 0;
+    FTC_Node*  bucket;
+    FTC_Node*  pnode;
+    FT_UFast   idx;
+    
+
+    idx = hash & cache->mask;
+    if ( idx < cache->p )
+      idx = hash & ( cache->mask * 2 + 1 );
+
+    bucket = cache->buckets + idx;
+    pnode = bucket;
+    for ( ; pnode && *pnode; pnode = &((*pnode)->link) )
+      len++;
+
+    return len;
+  }
+
+
 #ifndef FTC_INLINE
 
   FT_LOCAL_DEF( FT_Error )
diff --git a/src/cache/ftccache.h b/src/cache/ftccache.h
index 10830a9..176f766 100644
--- a/src/cache/ftccache.h
+++ b/src/cache/ftccache.h
@@ -196,6 +196,10 @@ FT_BEGIN_HEADER
   FTC_Cache_RemoveFaceID( FTC_Cache   cache,
                           FTC_FaceID  face_id );
 
+  FT_LOCAL( FT_Size )
+  ftc_get_list_length( FTC_Cache   cache,
+                       FT_PtrDist  hash );
+
 
 #ifdef FTC_INLINE
 
@@ -208,6 +212,12 @@ FT_BEGIN_HEADER
     FT_UFast              _idx;                                          \
                                                                          \
                                                                          \
+    FT_TRACE6(("FTC_CACHE_LOOKUP_CMP() lookup object for "));            \
+    FT_TRACE6(("hash=0x%08x in cache ", _hash ));                        \
+    FT_TRACE6(("mask=0x%08x p=0x%08x ", _cache->mask, _cache->p ));      \
+    FT_TRACE7(("list length=%d", ftc_get_list_length( _cache, _hash ) )); \
+    FT_TRACE6(("\n"));                                                   \
+                                                                         \
     error = FTC_Err_Ok;                                                  \
     node  = NULL;                                                        \
     _idx  = _hash & _cache->mask;                                        \
@@ -227,6 +237,8 @@ FT_BEGIN_HEADER
       _pnode = &_node->link;                                             \
     }                                                                    \
                                                                          \
+    FT_TRACE6(("(_bucket,_pnode)=(%p,%p)\n", _bucket, _pnode));          \
+                                                                         \
     if ( _node != *_bucket )                                             \
     {                                                                    \
       *_pnode     = _node->link;                                         \
diff --git a/src/cache/ftcmanag.c b/src/cache/ftcmanag.c
index 548ebe9..fcf1c43 100644
--- a/src/cache/ftcmanag.c
+++ b/src/cache/ftcmanag.c
@@ -622,6 +622,24 @@
   }
 
 
+  static int
+  ft_get_length_nodes_list( FTC_Node  node0 )
+  {
+    FTC_Node  node = node0;
+    int       len = 0;
+
+
+    while ( node )
+    {
+      len ++; 
+      node = node->link;
+      if ( node == node0 )
+        return len;
+    }
+    return len;
+  }
+
+
   FT_LOCAL_DEF( FT_UInt )
   FTC_Manager_FlushN( FTC_Manager  manager,
                       FT_UInt      count )
@@ -631,9 +649,17 @@
     FT_UInt   result;
 
 
+    FT_TRACE2(( "FTC_Manager_FlushN() tries to"
+                " free %d nodes from list length=%d\n",
+                count,
+                ft_get_length_nodes_list( manager->nodes_list ) ));
+
     /* try to remove `count' nodes from the list */
     if ( first == NULL )  /* empty list! */
+    {
+      FT_TRACE2(("FTC_Manager_FlushN() cannot change empty list\n" ));
       return 0;
+    }
 
     /* go to last node - it's a circular list */
     node = FTC_NODE__PREV(first);
@@ -654,6 +680,10 @@
 
       node = prev;
     }
+    FT_TRACE2(( "FTC_Manager_FlushN() freed %d nodes,"
+                " list length=%d\n", 
+                result,
+                ft_get_length_nodes_list( manager->nodes_list ) ));
     return  result;
   }
 
diff --git a/src/cache/ftcsbits.c b/src/cache/ftcsbits.c
index 0386bdd..907868c 100644
--- a/src/cache/ftcsbits.c
+++ b/src/cache/ftcsbits.c
@@ -125,6 +125,11 @@
     sbit->buffer = 0;
 
     error = clazz->family_load_glyph( family, gindex, manager, &face );
+    FT_TRACE2(( "ftc_snode_load() got %s from "
+                "family_load_glyph() err=0x%02x%s\n",
+                 error ? "error" : "ok",
+                 error,
+                 error ? " fallback to BadGlyph" : "" ));
     if ( error )
       goto BadGlyph;
 
@@ -200,6 +205,8 @@
         *asize = 0;
     }
 
+    FT_TRACE2(( "ftc_snode_load() load glyph for gid=%d, err=0x%02x\n",
+                gindex, error));
     return error;
   }
 
@@ -333,6 +340,7 @@
     FT_Bool     result;
 
 
+    FT_TRACE2(( "ftc_snode_compare() work for gindex=%d\n", gindex ));
     result = FT_BOOL( gnode->family == gquery->family                    &&
                       (FT_UInt)( gindex - gnode->gindex ) < snode->count );
     if ( result )
@@ -397,6 +405,8 @@
       }
     }
 
+    FT_TRACE2(( "ftc_snode_compare() returns %s\n",
+                result ? "TRUE" : "FALSE" ));
     return result;
   }
 
diff --git a/builds/unix/configure.raw b/builds/unix/configure.raw
index cb10ef4..6e4c1c2 100644
--- a/builds/unix/configure.raw
+++ b/builds/unix/configure.raw
@@ -111,7 +111,7 @@ esac
 # checks for header files
 
 AC_HEADER_STDC
-AC_CHECK_HEADERS([fcntl.h unistd.h])
+AC_CHECK_HEADERS([fcntl.h unistd.h libgen.h])
 
 
 # checks for typedefs, structures, and compiler characteristics
diff --git a/builds/unix/ftconfig.in b/builds/unix/ftconfig.in
index 4c81187..3bb68fb 100644
--- a/builds/unix/ftconfig.in
+++ b/builds/unix/ftconfig.in
@@ -60,6 +60,7 @@ FT_BEGIN_HEADER
 #undef HAVE_UNISTD_H
 #undef HAVE_FCNTL_H
 #undef HAVE_STDINT_H
+#undef HAVE_LIBGEN_H
 
 
   /* There are systems (like the Texas Instruments 'C54x) where a `char' */
@@ -167,6 +168,26 @@ FT_BEGIN_HEADER
 #endif
 
 
+  /*************************************************************************/
+  /*                                                                       */
+  /* Pathname separator used by resource-fork accessor & ft_basename()     */
+  /*                                                                       */
+
+#ifdef PLATFORM_DIR_SEPARATOR
+  /* explicitly defined, do nothing */
+#elif defined( __DOS__ ) || defined( __OS2__ ) || defined( _WIN32 ) || \
+      defined( __SYMBIAN32__ )
+#define PLATFORM_DIR_SEPARATOR "\\"
+#elif defined( FT_MACINTOSH ) && !defined( __MACH__ )
+#define PLATFORM_DIR_SEPARATOR ":"
+#elif defined( __riscos__ ) || defined( VMS )
+#define PLATFORM_DIR_SEPARATOR "."
+#else
+#define PLATFORM_DIR_SEPARATOR "/"
+#endif
+
+
+
   /* Fix compiler warning with sgi compiler */
 #if defined( __sgi ) && !defined( __GNUC__ )
 #if defined( _COMPILER_VERSION ) && ( _COMPILER_VERSION >= 730 )
diff --git a/include/freetype/config/ftconfig.h b/include/freetype/config/ftconfig.h
index cbe30f2..cd0fa27 100644
--- a/include/freetype/config/ftconfig.h
+++ b/include/freetype/config/ftconfig.h
@@ -147,6 +147,25 @@ FT_BEGIN_HEADER
 
   /*************************************************************************/
   /*                                                                       */
+  /* Pathname separator used by resource-fork accessor & ft_basename()     */
+  /*                                                                       */
+
+#ifdef PLATFORM_DIR_SEPARATOR
+  /* explicitly defined, do nothing */
+#elif defined( __DOS__ ) || defined( __OS2__ ) || defined( _WIN32 ) || \
+      defined( __SYMBIAN32__ )
+#define PLATFORM_DIR_SEPARATOR "\\"
+#elif defined( FT_MACINTOSH ) && !defined( __MACH__ )
+#define PLATFORM_DIR_SEPARATOR ":"
+#elif defined( __riscos__ ) || defined( VMS )
+#define PLATFORM_DIR_SEPARATOR "."
+#else
+#define PLATFORM_DIR_SEPARATOR "/"
+#endif
+
+
+  /*************************************************************************/
+  /*                                                                       */
   /* <Section>                                                             */
   /*    basic_types                                                        */
   /*                                                                       */
diff --git a/include/freetype/internal/ftobjs.h b/include/freetype/internal/ftobjs.h
index 670eb78..4cffb13 100644
--- a/include/freetype/internal/ftobjs.h
+++ b/include/freetype/internal/ftobjs.h
@@ -108,6 +108,14 @@ FT_BEGIN_HEADER
 #define  ft_isalpha( x )  ( ft_isupper( x ) || ft_islower( x ) )
 #define  ft_isalnum( x )  ( ft_isdigit( x ) || ft_isalpha( x ) )
 
+#ifdef HAVE_LIBGEN_H
+#include <libgen.h>
+#define ft_basename( p )  basename( ( p ) )
+#else
+  FT_BASE( char* )
+  ft_basename( char* path );
+#endif
+
 
   /*************************************************************************/
   /*************************************************************************/
diff --git a/src/base/ftdbgmem.c b/src/base/ftdbgmem.c
index bb04f68..538c086 100644
--- a/src/base/ftdbgmem.c
+++ b/src/base/ftdbgmem.c
@@ -521,7 +521,7 @@
   ft_mem_get_env_val_for_source( FT_MemSource  source,
                                  const char*   env_var_name )
   {
-    char  *file_name = (char*)source->file_name;
+    char  *file_name = ft_basename( (char*)source->file_name );
     char  *c, *c0;
 
 
@@ -534,7 +534,12 @@
     while ( NULL != ( c = ft_strstr( c, file_name ) ) )
     {
       /* matched token is 1st or after separator space? */
-      if ( c != c0 && *(c-1) != ' ' )
+      if ( c != c0 && *(c-1) != ' ' &&
+#ifndef macintosh
+           *(c-1) != '/' && *(c-1) != '\\' )
+#else
+           *(c-1) != ':' )
+#endif
         goto NextToken;
 
       /* check ':', a separator between pathname & line number */
@@ -767,7 +772,8 @@
                                      "FT2_ALLOC_CUR_MAX_SITE" );
     if ( FT_HAS_LIMITER( site ) )
       FT_TRACE6(( "ft_mem_table_set() invoked by %s:%lu, limit:( ",
-                  source->file_name, source->line_no ));
+                  ft_basename( (char*)source->file_name ),
+                                source->line_no ));
     FT_TRACE6_DEFINED_LIMIT( req_all, mem_limit_site_total );
     if ( FT_HAS_MULTI_LIMITERS( site ) )
       FT_TRACE6(( " && " ));
@@ -785,7 +791,8 @@
     {
       FT_TRACE6(( "ft_mem_table_set() returns NULL to %s:%lu,"
                   " allocation request exceeds %s-limit (%lu > %lu)\n",
-                  source->file_name, source->line_no,
+                  ft_basename( (char*)source->file_name ),
+                  source->line_no,
                   ( exceeds_limit_site_total ? "site-total" :
                                                "site-current" ),
                   ( exceeds_limit_site_total ? req_all :
diff --git a/src/base/ftobjs.c b/src/base/ftobjs.c
index 6b01f43..afe2995 100644
--- a/src/base/ftobjs.c
+++ b/src/base/ftobjs.c
@@ -1226,6 +1226,27 @@
   }
 
 
+#ifndef HAVE_LIBGEN_H
+  FT_BASE_DEF( char* )
+  ft_basename( char*  pathname )
+  {
+    char*  c;
+
+
+    c = pathname + ft_strlen( pathname );
+
+    /* skip trailing separator */
+    while ( pathname < c && *c == PLATFORM_DIR_SEPARATOR[0] )
+      c--;
+
+    while ( pathname < c && *(c-1) != PLATFORM_DIR_SEPARATOR[0] )
+      c--;
+
+    return c;
+  }
+#endif
+
+
 #ifdef FT_CONFIG_OPTION_MAC_FONTS
 
   /* The behavior here is very similar to that in base/ftmac.c, but it     */
diff --git a/src/base/ftrfork.c b/src/base/ftrfork.c
index b01ecb9..01be277 100644
--- a/src/base/ftrfork.c
+++ b/src/base/ftrfork.c
@@ -544,7 +544,8 @@
       return error;
 
     FT_MEM_COPY( newpath, base_file_name, base_file_len );
-    FT_MEM_COPY( newpath + base_file_len, "/rsrc", 6 );
+    FT_MEM_COPY( newpath + base_file_len,
+                 PLATFORM_DIR_SEPARATOR "rsrc", 6 );
 
     *result_file_name = newpath;
     *result_offset    = 0;
@@ -580,7 +581,9 @@
       return error;
 
     FT_MEM_COPY( newpath, base_file_name, base_file_len );
-    FT_MEM_COPY( newpath + base_file_len, "/..namedfork/rsrc", 18 );
+    FT_MEM_COPY( newpath + base_file_len,
+                 PLATFORM_DIR_SEPARATOR "..namedfork"
+                 PLATFORM_DIR_SEPARATOR "rsrc", 18 );
 
     *result_file_name = newpath;
     *result_offset    = 0;
@@ -605,7 +608,8 @@
     memory = library->memory;
 
     newpath = raccess_make_file_name( memory, base_file_name,
-                                      "resource.frk/" );
+                                      "resource.frk"
+                                      PLATFORM_DIR_SEPARATOR );
     if ( !newpath )
       return FT_Err_Out_Of_Memory;
 
@@ -631,7 +635,9 @@
 
     memory = library->memory;
 
-    newpath = raccess_make_file_name( memory, base_file_name, ".resource/" );
+    newpath = raccess_make_file_name( memory, base_file_name,
+                                      ".resource"
+                                      PLATFORM_DIR_SEPARATOR );
     if ( !newpath )
       return FT_Err_Out_Of_Memory;
 
@@ -690,7 +696,8 @@
     memory = library->memory;
 
     newpath = raccess_make_file_name( memory, base_file_name,
-                                      ".AppleDouble/" );
+                                      ".AppleDouble"
+                                      PLATFORM_DIR_SEPARATOR );
     if ( !newpath )
       return FT_Err_Out_Of_Memory;
 
@@ -815,7 +822,7 @@
     if ( FT_ALLOC( new_name, new_length + 1 ) )
       return NULL;
 
-    tmp = ft_strrchr( original_name, '/' );
+    tmp = ft_strrchr( original_name, PLATFORM_DIR_SEPARATOR[0] );
     if ( tmp )
     {
       ft_strncpy( new_name, original_name, tmp - original_name + 1 );
_______________________________________________
Freetype-devel mailing list
Freetype-devel@nongnu.org
http://lists.nongnu.org/mailman/listinfo/freetype-devel

Reply via email to