diff --git a/qse/include/qse/cmn/fma.h b/qse/include/qse/cmn/fma.h index d2224e4e..e8e0c143 100644 --- a/qse/include/qse/cmn/fma.h +++ b/qse/include/qse/cmn/fma.h @@ -22,20 +22,21 @@ #define _QSE_CMN_FMA_H_ /** @file - * This file defines a fixed-size block memory allocator. As the block size - * is known in advance, it achieves block allocation with little overhead. + * This file defines a fixed-size block memory allocator. + * As the block size is known in advance, it achieves block allocation + * with little overhead. * *
  *  chunk head(cnkhead)   
- *   |                                              chunk
+ *   |
  *   |    +---------------------------------------------+
- *   +--> |     |   f1     |   f2      |      |         |
+ *   +--> |     |   f1     |   f2      |      |         | chunk #2
  *        +--|---------^------|----^--------------------+
  *           |         |      |    |
- *           |         +------+    +---+    +--------------+   chunk
+ *           |         +------+    +---+    +--------------+  
  *           |                         |    |              |
  *           |       +-----------------|----V--------------|-------+
- *           +--->   |     |         |   f3    |         |  f4     |
+ *           +--->   |     |         |   f3    |         |  f4     | chunk #1
  *                   +---------------------------------------^-----+
  *                                                           |
  *                                           free block head (freeblk)
@@ -44,8 +45,122 @@
  * The diagram above assumes that f1, f2, f3, and f4 are free blocks. 
  * The chaining order depends on the allocation and deallocation order.
  *
- * See #qse_fma_t for more information. Use #qse_xma_t for variable-size block
- * allocation.
+ * See an example below. Note that it omits error handling.
+ *
+ * @code
+ * #include 
+ * int main ()
+ * {
+ *   qse_fma_t* fma;
+ *   int* ptr1, * ptr2;
+ *
+ *   // create a memory allocator for integer blocks up to 50.
+ *   fma = qse_fma_open (QSE_NULL, 0, sizeof(int), 10, 5);
+ *
+ *   // allocate two integer blocks
+ *   ptr1 = (int*) qse_fma_alloc (fma, sizeof(int));
+ *   ptr2 = (int*) qse_fma_alloc (fma, sizeof(int));
+ *
+ *   *ptr1 = 20; *ptr2 = 99;
+ *
+ *   // free the two blocks.
+ *   qse_fma_free (fma, ptr1);
+ *   qse_fma_free (fma, ptr2);
+ *
+ *   // destroy the memory allocator
+ *   qse_fma_close (fma);
+ * }
+ * @endcode
+ *
+ * The following example shows how to use the fixed-size block
+ * allocator for a dynamic data structure allocating fixed-size nodes.
+ *
+ * @code
+ * #include 
+ * #include 
+ * #include 
+ * #include 
+ *
+ * static qse_rbt_walk_t walk (qse_rbt_t* rbt, qse_rbt_pair_t* pair, void* ctx)
+ * {
+ *   qse_printf (QSE_T("key = %lld, value = %lld\n"),
+ *       *(long*)QSE_RBT_KPTR(pair), *(long*)QSE_RBT_VPTR(pair));
+ *   return QSE_RBT_WALK_FORWARD;
+ * }
+ *
+ * int main ()
+ * {
+ *   qse_fma_t* fma;
+ *   qse_rbt_t rbt; 
+ *   qse_size_t blksize;
+ *   long x;
+ *
+ *   // prepare the fixed-size block allocator into the qse_mmgr_t interface
+ *   qse_mmgr_t mmgr = 
+ *   {
+ *      (qse_mmgr_alloc_t) qse_fma_alloc,
+ *      (qse_mmgr_realloc_t) qse_fma_realloc,
+ *      (qse_mmgr_free_t) qse_fma_free,
+ *      QSE_NULL
+ *   };
+ *
+ *   // the block size of a red-black tree is fixed to be:
+ *	//   key size + value size + internal node size.
+ *   blksize = sizeof(long) + sizeof(long) + sizeof(qse_rbt_pair_t);
+ *
+ *   // create a fixed-size block allocator which is created
+ *   // with the default memory allocator.
+ *   fma = qse_fma_open (QSE_MMGR_GETDFL(), 0, blksize, 10, 0);
+ *   if (fma == QSE_NULL)
+ *   {
+ *      qse_printf (QSE_T("cannot open a memory allocator\n"));
+ *      return -1;
+ *   }
+ *
+ *   // complete the qse_mmgr_t interface by providing the allocator.
+ *   mmgr.udd = fma;
+ *
+ *   // initializes the statically declared red-black tree.
+ *   // can not call qse_rbt_open() which allocates the qse_rbt_t object.
+ *   // as its size differs from the block size calculated above. 
+ *   if (qse_rbt_init (&rbt, &mmgr) == QSE_NULL)
+ *   {
+ *      qse_printf (QSE_T("cannot initialize a tree\n"));
+ *      qse_fma_close (fma);
+ *      return -1;
+ *   }
+ *
+ *   // perform more initializations for keys and values.
+ *   qse_rbt_setcopier (&rbt, QSE_RBT_KEY, QSE_RBT_COPIER_INLINE);
+ *   qse_rbt_setcopier (&rbt, QSE_RBT_VAL, QSE_RBT_COPIER_INLINE);
+ *   qse_rbt_setscale (&rbt, QSE_RBT_KEY, QSE_SIZEOF(long));
+ *   qse_rbt_setscale (&rbt, QSE_RBT_VAL, QSE_SIZEOF(long));
+ *
+ *   // insert numbers into the red-black tree
+ *   for (x = 10; x < 100; x++)
+ *   {
+ *      long y = x * x;
+ *      if (qse_rbt_insert (&rbt, &x, 1, &y, 1) == QSE_NULL) 
+ *      {
+ *         qse_printf (QSE_T("failed to insert. out of memory\n"));
+ *         break;
+ *      }
+ *   }
+ *
+ *   // print the tree contents 
+ *   qse_rbt_walk (&rbt, walk, QSE_NULL);
+ *
+ *   // finalize the tree.
+ *   qse_rbt_fini (&rbt);
+ *
+ *   // destroy the memory allocator.
+ *   qse_fma_close (fma);
+ *
+ *   return 0;
+ * }
+ * @endcode
+ *
+ * Use #qse_xma_t for variable-size block allocation.
  */
 
 #include 
@@ -73,27 +188,6 @@ struct qse_fma_blk_t
 
 /** @struct qse_fma_t
  * The qse_fma_t type defines a fixed-size block memory allocator.
- * See the example below. Note that it omits error handling.
- * @code
- *  qse_fma_t* fma;
- *  int* ptr1, * ptr2;
- *
- *  // create a memory allocator for integer blocks up to 50.
- *  fma = qse_fma_open (QSE_NULL, 0, sizeof(int), 10, 5);
- *
- *  // allocate two integer blocks
- *  ptr1 = (int*) qse_fma_alloc (fma);
- *  ptr2 = (int*) qse_fma_alloc (fma);
- *
- *  *ptr1 = 20; *ptr2 = 99;
- *
- *  // free the two blocks.
- *  qse_fma_free (fma, ptr1);
- *  qse_fma_free (fma, ptr2);
- *
- *  // destroy the memory allocator
- *  qse_fma_close (fma);
- * @endcode
  */
 typedef struct qse_fma_t qse_fma_t;
 struct qse_fma_t
@@ -122,9 +216,9 @@ QSE_DEFINE_COMMON_FUNCTIONS (fma)
 qse_fma_t* qse_fma_open (
 	qse_mmgr_t* mmgr,   /**< outer memory manager */
 	qse_size_t xtnsize, /**< extension size in bytes */
-	qse_size_t blksize, /**< block size in bytes */
+	qse_size_t blksize, /**< fixed block size in bytes */
 	qse_size_t maxblks, /**< maximum numbers of blocks in a chunk */
-	qse_size_t maxcnks  /**< maximum numbers of chunks */
+	qse_size_t maxcnks  /**< maximum numbers of chunks. 0 for no limit */
 );
 
 /**
@@ -135,14 +229,15 @@ void qse_fma_close (
 );
 
 /**
- * The qse_fma_init() function initializes an memory allocator.
+ * The qse_fma_init() function initializes an memory allocator statically 
+ * declared.
  */
 qse_fma_t* qse_fma_init (
 	qse_fma_t* fma,     /**< memory allocator */
 	qse_mmgr_t* mmgr,   /**< outer memory manager */
-	qse_size_t blksize, /**< block size in bytes */
+	qse_size_t blksize, /**< fixed block size in bytes */
 	qse_size_t maxblks, /**< maximum numbers of blocks in a chunk */
-	qse_size_t maxcnks  /**< maximum numbers of chunks */
+	qse_size_t maxcnks  /**< maximum numbers of chunks. 0 for no limit */
 );
 
 /**
@@ -153,15 +248,41 @@ void qse_fma_fini (
 );
 
 /**
- * The qse_fma_alloc() function allocates a block.
- * @return block pointer on success, QSE_NULL on failure
+ * The qse_fma_alloc() function allocates a block of the fixed block size
+ * specified during initialization regardless of the block size @a size 
+ * requested so long as it is not greater than the fixed size. The function
+ * fails if it is greater.
+ * 
+ * @return block pointer on success, #QSE_NULL on failure
  */
 void* qse_fma_alloc (
-	qse_fma_t* fma      /**< memory allocator */
+	qse_fma_t* fma,     /**< memory allocator */
+	qse_size_t size     /**< block size in bytes*/
 );
 
 /**
- * The qse_fma_alloc() function deallocates a block.
+ * The qse_fma_realloc() function is provided for consistency with other 
+ * generic memory allocator which provides a reallocation function.
+ * Block resizing is meaningless for #qse_fma_t as it deals with fixed-size
+ * blocks. 
+ *
+ * If the @a size requested is greater than the fixed block size of the memory
+ * allocator @a fma, the function fails; If the block @a blk is #QSE_NULL and 
+ * the @a size requested is not greater than the fixed block size of the memory
+ * allocator @a fma, it allocates a block of the fixed size; If the block 
+ * @a blk is not #QSE_NULL and the @a size requested is not greater than the
+ * fixed block size of the memory allocator @a fma, it returns the block @blk.
+ *
+ * @return block pointer on success, #QSE_NULL on failure
+ */
+void* qse_fma_realloc (
+	qse_fma_t* fma,     /**< memory allocator */
+	void*      blk,     /**< memory block */
+	qse_size_t size     /**< block size in bytes*/
+);
+
+/**
+ * The qse_fma_free() function deallocates a block.
  */
 void qse_fma_free (
 	qse_fma_t* fma,     /**< memory allocator */
diff --git a/qse/include/qse/cmn/mem.h b/qse/include/qse/cmn/mem.h
index 4a48fc66..953f6915 100644
--- a/qse/include/qse/cmn/mem.h
+++ b/qse/include/qse/cmn/mem.h
@@ -1,5 +1,5 @@
 /*
- * $Id: mem.h 287 2009-09-15 10:01:02Z hyunghwan.chung $
+ * $Id: mem.h 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -21,13 +21,21 @@
 #ifndef _QSE_CMN_MEM_H_
 #define _QSE_CMN_MEM_H_
 
+/** @file
+ * This file defines functions and macros for memory manipulation.
+ */
+
 #include 
 #include 
 
-/* gets a pointer to the default memory manager */
+/** 
+ * The QSE_MMGR_GETDFL() macro returns the default memory manager.
+ */
 #define QSE_MMGR_GETDFL()  (qse_mmgr)
 
-/* sets a pointer to the default memory manager */
+/**
+ * The QSE_MMGR_SETDFL() macro changes the default memory manager.
+ */
 #define QSE_MMGR_SETDFL(m) ((qse_mmgr)=(m))
 
 /* allocate a memory block */
@@ -46,163 +54,128 @@
 extern "C" {
 #endif
 
-/* 
- * NAME: holds a pointer to the default memory manager 
- *
- * DESCRIPTION:
- *  The QSE_MMGR_GETDFL() macro returns the default memory manager.
- *  You may use QSE_MMGR_SETDFL() to change the default memory manager.
+/** 
+ * The qse_mmgr global variable holds a pointer to the default memory 
+ * manager. Use QSE_MMGR_GETDFL() and QSE_MMGR_SETDFL() to manipulate it.
  */
 extern qse_mmgr_t* qse_mmgr;
 
-/*
- * NAME: copy a memory block
+/**
+ * The qse_memcpy() functions copies @a n bytes from the source memory block 
+ * @a src to the destinaion memory block @a dst. The memory blocks must not 
+ * overlap. Use qse_memmove() if they overlap.
  *
- * DESCRIPTION:
- *  The qse_memcpy() functions copies n bytes from the source memory block src 
- *  to the destinaion memory block dst. 
- *
- * RETURNS: the destination memory block dst.
- *
- * WARNING:
- *  The memory blocks should not overlap. Use the qse_memmove() function if
- *  they overlap.
+ * @return destination memory block @a dst.
  */
-
 void* qse_memcpy (
-	void* dst /* a pointer to the destination memory block */ , 
-	const void* src /* a pointer to the source memory block */ , 
-	qse_size_t n /* the number of bytes to copy */
+	void*       dst, /**< destination memory block */
+	const void* src, /**< source memory block */
+	qse_size_t  n    /**< number of bytes to copy */
 );
 
-/*
- * NAME: copy a memory block with more care 
+/**
+ * The qse_memmove() functions copies @a n bytes from the source memory block
+ * @a src to the destinaion memory block @a dst without corrupting overlapping
+ * zone.
  *
- * DESCRIPTION:
- *  The qse_memmove() functions copies n bytes from the source memory block src 
- *  to the destinaion memory block dst without corrupting overlapping zone.
- *
- * RETURNS: the destination memory block dst.
+ * @return destination memory block @a dst.
  */
 void* qse_memmove (
-	void* dst /* a pointer to the destination memory block */,
-	const void* src /* a pointer to the source memory block */,
-	qse_size_t n /* the number of bytes to copy */
+	void*       dst, /**< destination memory block */
+	const void* src, /**< source memory block */
+	qse_size_t  n    /**< number of bytes to copy */
 );
 
 /*
- * NAME: fill a memory block
+ * The qse_memset() function fills leading @a n bytes of the destination 
+ * memory block @a dst with the byte @a val.
  *
- * DESCRIPTION:
- *  The qse_memset() function fills leading n bytes of the destination 
- *  memory block dst with the byte val.
- * 
- * RETURNS: the destination memory block dst
+ * @return destination memory block @a dst.
  */
 void* qse_memset (
-	void* dst /* a pointer to the destination memory block */,
-	int val /* the byte to fill the memory block with */,
-	qse_size_t n /* the number of bytes to fill */
+	void*       dst, /**< destination memory block */
+	int         val, /**< value fill the memory block with */
+	qse_size_t   n   /**< number of bytes to fill */
 );
 
-/*
- * NAME: compare memory blocks
- * 
- * DESCRIPTION:
- *  The qse_memcmp() function compares leading n bytes of two memory blocks 
- *  s1 and s2.
+/**
+ * The qse_memcmp() function compares leading *a n bytes of two memory blocks 
+ * @a s1 and @a s2.
  *
- * RETURNS: 
- *  0 if two memory ares have the same leadning n bytes.
- *  a positive number if the first different byte of s1 is greater than that 
- *  of s2.
- *  a negative number if the first different byte of s1 is less than that of s2.
+ * @return
+ * 0 if two memory ares have the same leadning @a n bytes.
+ * positive number if the first different byte of s1 is greater than that of s2.
+ * negative number if the first different byte of s1 is less than that of s2.
  */
 int qse_memcmp (
-	const void* s1 /* a pointer to the first memory block to compare */, 
-	const void* s2 /* a pointer to the second memory block to compare */, 
-	qse_size_t n /* the number of bytes to compare */
+	const void* s1, /**< first memory block to compare */
+	const void* s2, /**< second memory block to compare */ 
+	qse_size_t  n   /**< the number of bytes to compare */
 );
 
-/*
- * NAME: find a byte forward in a memory block
- * 
- * DESCRIPTION:
- *  The qse_membyte() function scans the memory block s from the first byte
- *  up to the nth byte in search of the byte val. If it finds a match,
- *  it aborts scanning the memory block and returns the pointer to the matching
- *  location.
+/**
+ * The qse_membyte() function scans the memory block @a s from the first byte
+ * up to the nth byte in search of the byte @a val. If it finds a match,
+ * it aborts scanning the memory block and returns the pointer to the matching
+ * location.
  *
- * RETURNS:
- *  QSE_NULL if the byte val is not found.
- *  The pointer to the location in the memory block s matching the byte val
+ * @return
+ *  #QSE_NULL if the byte @a val is not found.
+ *  pointer to the location in the memory block @a s matching the byte @a val
  *  if a match is found.
  */
 void* qse_membyte (
-	const void* s /* a pointer to the memory block to scan */,
-	int val /* a byte to find */,
-	qse_size_t n /* the number of bytes to scan */ 
+	const void* s,     /**< memory block to scan */
+	int         val,   /**< byte to find */
+	qse_size_t  n      /**< number of bytes to scan */ 
 );
 
 /*
- * NAME: find a byte backward in a memory block
- * 
- * DESCRIPTION:
- *  The qse_memrbyte() function scans the memory block s from the nth byte
- *  backward to the first byte in search of the byte val. If it finds a match,
- *  it aborts scanning the memory block and returns the pointer to the matching 
- *  location.
+ * The qse_memrbyte() function scans the memory block @a s from the nth byte
+ * backward to the first byte in search of the byte @a val. If it finds a match,
+ * it aborts scanning the memory block and returns the pointer to the matching 
+ * location.
  *
- * RETURNS:
- *  QSE_NULL if the byte val is not found.
- *  The pointer to the location in the memory block s matching the byte val
+ * @return
+ *  #QSE_NULL if the byte val is not found.
+ *  pointer to the location in the memory block s matching the byte val
  *  if a match is found.
  */
 void* qse_memrbyte (
-	const void* s /* a pointer to the memory block to scan */,
-	int val /* a byte to find */,
-	qse_size_t n /* the number of bytes to scan */ 
+	const void* s,     /**< memory block to scan */
+	int         val,   /**< byte to find */
+	qse_size_t  n      /**< number of bytes to scan */ 
 );
 
-/*
- * NAME: find a block of bytes forward in a memory block
- * 
- * DESCRIPTION:
- *  The qse_memmem() functions scans the first hl bytes of the memory block hs
- *  in search of the byte block nd of the length nl bytes.
+/**
+ * The qse_memmem() functions scans the first @a hl bytes of the memory 
+ * block @a hs in search of the byte block @a nd of the length @a nl bytes.
  *
- * RETURNS:
- *  QSE_NULL if the byte val is not found.
- *  The pointer to the location in the memory block s matching the byte val
- *  if a match is found.
- *
- * RETURNS:
- *  QSE_NULL if no match is found.
- *  The pointer to the start of the matching location if a match is found.
+ * @return
+ *  #QSE_NULL if no match is found.
+ *  pointer to the start of the matching location if a match is found.
  */
 void* qse_memmem (
-	const void* hs /* a pointer to the memory block to scan */,
-	qse_size_t hl /* the number of bytes to scan */,
-	const void* nd /* a pointer to the byte block to find */,
-	qse_size_t nl /* the number of bytes in the block */
+	const void* hs,  /**< memory block to scan */
+	qse_size_t  hl,  /**< number of bytes to scan */
+	const void* nd,  /**< byte block to find */
+	qse_size_t  nl   /**< number of bytes in the block */
 );
 
 /*
- * NAME: find a block of bytes backward in a memory block
+ * The qse_memrmem() functions scans the first @a hl bytes of the memory
+ * block @a hs backward in search of the byte block @a nd of the length 
+ * @a nl bytes.
  *
- * DESCRIPTION:
- *  The qse_memrmem() functions scans the first hl bytes of the memory block hs
- *  backward in search of the byte block nd of the length nl bytes.
- *
- * RETURNS:
- *  QSE_NULL if no match is found.
- *  The pointer to the start of the matching location if a match is found.
+ * @return
+ * #QSE_NULL if no match is found.
+ * pointer to the start of the matching location if a match is found.
  */
 void* qse_memrmem (
-	const void* hs /* a pointer to the memory block to scan */,
-	qse_size_t hl /* the number of bytes to scan */,
-	const void* nd /* a pointer to the byte block to find */,
-	qse_size_t nl /* the number of bytes in the block */
+	const void* hs,  /**< memory block to scan */
+	qse_size_t  hl,  /**< number of bytes to scan */
+	const void* nd,  /**< byte block to find */
+	qse_size_t  nl   /**< number of bytes in the block */
 );
 
 #ifdef __cplusplus
diff --git a/qse/include/qse/cmn/opt.h b/qse/include/qse/cmn/opt.h
index 120ff821..e805b249 100644
--- a/qse/include/qse/cmn/opt.h
+++ b/qse/include/qse/cmn/opt.h
@@ -1,5 +1,5 @@
 /*
- * $Id: opt.h 287 2009-09-15 10:01:02Z hyunghwan.chung $
+ * $Id: opt.h 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -25,7 +25,7 @@
 #include 
 
 /** @file
- *  defines functions and data structures to process 
+ * This file defines functions and data structures to process 
  * command-line arguments. 
  */
 
diff --git a/qse/include/qse/cmn/stdio.h b/qse/include/qse/cmn/stdio.h
index 7255068d..35f0348b 100644
--- a/qse/include/qse/cmn/stdio.h
+++ b/qse/include/qse/cmn/stdio.h
@@ -22,8 +22,7 @@
 #define _QSE_CMN_STDIO_H_
 
 /** @file
- * #qse_char_t friendly stdio wrapper functions are defined in this file.
- *
+ * This file defines stdio wrapper functions for #qse_char_t.
  */
 
 #include 
@@ -89,6 +88,9 @@ QSE_FILE* qse_fopen (const qse_char_t* path, const qse_char_t* mode);
 QSE_FILE* qse_popen (const qse_char_t* cmd, const qse_char_t* mode);
 
 /**
+ * The qse_getline() function read a line from a file pointer @a fp
+ * until a new line character is met.
+ *
  * @return -2 on error, -1 on eof, length of data read on success 
  */
 qse_ssize_t qse_getline (qse_char_t **buf, qse_size_t *n, QSE_FILE *fp);
diff --git a/qse/include/qse/cmn/xma.h b/qse/include/qse/cmn/xma.h
index f9360e67..09c52906 100644
--- a/qse/include/qse/cmn/xma.h
+++ b/qse/include/qse/cmn/xma.h
@@ -27,7 +27,36 @@
  * larger memory chunk allocated with an outer memory allocator.
  * Typically, an outer memory allocator is a standard memory allocator
  * like malloc(). You can isolate memory blocks into a particular chunk.
- * See #qse_xma_t for an example.
+ *
+ * See the example below. Note it omits error handling.
+ *
+ * @code
+ * #include 
+ * #include 
+ * int main ()
+ * {
+ *   qse_xma_t* xma;
+ *   void* ptr1, * ptr2;
+ *
+ *   // create a new memory allocator obtaining a 100K byte zone 
+ *   // with the default memory allocator
+ *   xma = qse_xma_open (QSE_NULL, 0, 100000L); 
+ *
+ *   ptr1 = qse_xma_alloc (xma, 5000); // allocate a 5K block from the zone
+ *   ptr2 = qse_xma_alloc (xma, 1000); // allocate a 1K block from the zone
+ *   ptr1 = qse_xma_realloc (xma, ptr1, 6000); // resize the 5K block to 6K.
+ *
+ *   qse_xma_dump (xma, qse_printf); // dump memory blocks 
+ *
+ *   // the following two lines are not actually needed as the allocator
+ *   // is closed after them.
+ *   qse_xma_free (xma, ptr2); // dispose of the 1K block
+ *   qse_xma_free (xma, ptr1); // dispose of the 6K block
+ *
+ *   qse_xma_close (xma); //  destroy the memory allocator
+ *   return 0;
+ * }
+ * @endcode
  */
 #include 
 #include 
@@ -39,28 +68,6 @@
 /** @struct qse_xma_t
  * The qse_xma_t type defines a simple memory allocator over a memory zone.
  * It can obtain a relatively large zone of memory and manage it.
- *
- * @code
- *  qse_xma_t* xma;
- *  void* ptr1, * ptr2;
- *
- *  // create a new memory allocator obtaining a 100K byte zone 
- *  // with the default memory allocator
- *  xma = qse_xma_open (QSE_NULL, 0, 100000L); 
- *  
- *  ptr1 = qse_xma_alloc (xma, 5000); // allocate a 5K block from the zone
- *  ptr2 = qse_xma_alloc (xma, 1000); // allocate a 1K block from the zone
- *  ptr1 = qse_xma_realloc (xma, ptr1, 6000); // resize the 5K block to 6K.
- *
- *  qse_xma_dump (xma, qse_printf); // dump memory blocks 
- *
- *  // the following two lines are not actually needed as the allocator
- *  // is closed after them.
- *  qse_xma_free (xma, ptr2); // dispose of the 1K block
- *  qse_xma_free (xma, ptr1); // dispose of the 6K block
- *
- *  qse_xma_close (xma); //  destroy the memory allocator
- * @endcode
  */
 typedef struct qse_xma_t qse_xma_t;
 
diff --git a/qse/include/qse/macros.h b/qse/include/qse/macros.h
index 93af813e..179d3eaf 100644
--- a/qse/include/qse/macros.h
+++ b/qse/include/qse/macros.h
@@ -1,5 +1,5 @@
 /*
- * $Id: macros.h 338 2010-07-30 13:24:19Z hyunghwan.chung $
+ * $Id: macros.h 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -24,7 +24,7 @@
 #include 
 
 /** @file
- *  contains various useful macro definitions.
+ * This file contains various useful macro definitions.
  */
 
 #if defined(__STDC_VERSION__) && (__STDC_VERSION__>=199901L)
diff --git a/qse/include/qse/types.h b/qse/include/qse/types.h
index 7662d813..a0d5e12e 100644
--- a/qse/include/qse/types.h
+++ b/qse/include/qse/types.h
@@ -1,5 +1,5 @@
 /*
- * $Id: types.h 338 2010-07-30 13:24:19Z hyunghwan.chung $
+ * $Id: types.h 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -22,7 +22,7 @@
 #define _QSE_TYPES_H_
 
 /**@file
- *  defines various common basic types designed to be
+ * This file defines various common basic types designed to be
  * cross-platform. These types are preferred over native data types.
  */
 
diff --git a/qse/lib/cmn/fio.c b/qse/lib/cmn/fio.c
index f835ba50..45569cfb 100644
--- a/qse/lib/cmn/fio.c
+++ b/qse/lib/cmn/fio.c
@@ -1,5 +1,5 @@
 /*
- * $Id: fio.c 323 2010-04-05 12:50:01Z hyunghwan.chung $
+ * $Id: fio.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -81,6 +81,8 @@ qse_fio_t* qse_fio_init (
 {
 	qse_fio_hnd_t handle;
 
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_MEMSET (fio, 0, QSE_SIZEOF(*fio));
 	fio->mmgr = mmgr;
 
diff --git a/qse/lib/cmn/fma.c b/qse/lib/cmn/fma.c
index 6e5c7eb1..f17dc9ac 100644
--- a/qse/lib/cmn/fma.c
+++ b/qse/lib/cmn/fma.c
@@ -29,7 +29,7 @@ qse_fma_t* qse_fma_open (
 {
 	qse_fma_t* fma;
 
-	if (mmgr == QSE_NULL)
+	if (mmgr == QSE_NULL) 
 	{
 		mmgr = QSE_MMGR_GETDFL();
 
@@ -61,13 +61,14 @@ qse_fma_t* qse_fma_init (
 	qse_fma_t* fma, qse_mmgr_t* mmgr,
 	qse_size_t blksize, qse_size_t maxblks, qse_size_t maxcnks)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_MEMSET (fma, 0, QSE_SIZEOF(*fma));
 	fma->mmgr = mmgr;
 	
-	if (blksize <= QSE_SIZEOF(qse_fma_blk_t)) 
+	if (blksize < QSE_SIZEOF(qse_fma_blk_t)) 
 		blksize = QSE_SIZEOF(qse_fma_blk_t);
 	if (maxblks <= 0) maxblks = 1;
-	if (maxcnks <= 0) maxcnks = 1;
 
 	fma->blksize = blksize;
 	fma->maxblks = maxblks;
@@ -78,6 +79,7 @@ qse_fma_t* qse_fma_init (
 
 void qse_fma_fini (qse_fma_t* fma)
 {
+	/* destroys the chunks allocated */
 	while (fma->cnkhead)
 	{
 		qse_fma_cnk_t* next = fma->cnkhead->next;
@@ -93,7 +95,7 @@ static QSE_INLINE qse_fma_cnk_t* add_chunk (qse_fma_t* fma)
 	qse_size_t i;
 
 	/* check if there are too many chunks */
-	if (fma->numcnks >= fma->maxcnks) return QSE_NULL;
+	if (fma->maxcnks && fma->numcnks >= fma->maxcnks) return QSE_NULL;
 
 	/* allocate a chunk */
 	cnk = (qse_fma_cnk_t*) QSE_MMGR_ALLOC (fma->mmgr, 
@@ -118,10 +120,16 @@ static QSE_INLINE qse_fma_cnk_t* add_chunk (qse_fma_t* fma)
 	return cnk;
 }
 
-void* qse_fma_alloc (qse_fma_t* fma)
+void* qse_fma_alloc (qse_fma_t* fma, qse_size_t size)
 {
 	void* blk;
 
+	QSE_ASSERTX (size <= fma->blksize, 
+		"You must not request a block larger than the fixed size set in the allocator. Use a generic allocator instead"
+	);
+
+	if (size > fma->blksize) return QSE_NULL;
+
 	if ((blk = fma->freeblk) == QSE_NULL)
 	{
 		if (add_chunk (fma) == QSE_NULL) return QSE_NULL;
@@ -131,9 +139,23 @@ void* qse_fma_alloc (qse_fma_t* fma)
 	return blk;
 }
 
+void* qse_fma_realloc (qse_fma_t* fma, void* blk, qse_size_t size)
+{
+	if (blk)
+	{
+		QSE_ASSERTX (size <= fma->blksize, 
+			"A block can be enlarged with a fixed-size block allocator. Use a generic allocator instead"
+		);
+
+		if (size > fma->blksize) return QSE_NULL;
+		return blk;
+	}
+
+	return qse_fma_alloc (fma, size);
+}
+
 void qse_fma_free (qse_fma_t* fma, void* blk)
 {
 	((qse_fma_blk_t*)blk)->next = fma->freeblk;
 	fma->freeblk = blk;
 }
-
diff --git a/qse/lib/cmn/htb.c b/qse/lib/cmn/htb.c
index ff1fea38..9ba64617 100644
--- a/qse/lib/cmn/htb.c
+++ b/qse/lib/cmn/htb.c
@@ -1,5 +1,5 @@
 /*
- * $Id: htb.c 332 2010-07-13 11:25:24Z hyunghwan.chung $
+ * $Id: htb.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -248,11 +248,14 @@ void qse_htb_close (htb_t* htb)
 
 htb_t* qse_htb_init (htb_t* htb, mmgr_t* mmgr, size_t capa, int factor)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_ASSERTX (capa > 0,
 		"The initial capacity should be greater than 0. Otherwise, it is adjusted to 1 in the release mode");
 	QSE_ASSERTX (factor >= 0 && factor <= 100,
 		"The load factor should be between 0 and 100 inclusive. In the release mode, a value out of the range is adjusted to 100");
 
+
 	/* some initial adjustment */
 	if (capa <= 0) capa = 1;
 	if (factor > 100) factor = 100;
diff --git a/qse/lib/cmn/lda.c b/qse/lib/cmn/lda.c
index c8192224..6df8bdc1 100644
--- a/qse/lib/cmn/lda.c
+++ b/qse/lib/cmn/lda.c
@@ -1,5 +1,5 @@
 /*
- * $Id: lda.c 327 2010-05-10 13:15:55Z hyunghwan.chung $
+ * $Id: lda.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -108,10 +108,10 @@ lda_t* qse_lda_open (mmgr_t* mmgr, size_t ext, size_t capa)
 		if (mmgr == QSE_NULL) return QSE_NULL;
 	}
 
-        lda = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(lda_t) + ext);
-        if (lda == QSE_NULL) return QSE_NULL;
+	lda = QSE_MMGR_ALLOC (mmgr, QSE_SIZEOF(lda_t) + ext);
+	if (lda == QSE_NULL) return QSE_NULL;
 
-        if (qse_lda_init (lda, mmgr, capa) == QSE_NULL)
+	if (qse_lda_init (lda, mmgr, capa) == QSE_NULL)
 	{
 		QSE_MMGR_FREE (mmgr, lda);
 		return QSE_NULL;
@@ -128,6 +128,8 @@ void qse_lda_close (lda_t* lda)
 
 lda_t* qse_lda_init (lda_t* lda, mmgr_t* mmgr, size_t capa)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_MEMSET (lda, 0, QSE_SIZEOF(*lda));
 
 	lda->mmgr = mmgr;
diff --git a/qse/lib/cmn/pio.c b/qse/lib/cmn/pio.c
index 075152a7..58daa6fb 100644
--- a/qse/lib/cmn/pio.c
+++ b/qse/lib/cmn/pio.c
@@ -1,5 +1,5 @@
 /*
- * $Id: pio.c 316 2009-12-14 12:50:11Z hyunghwan.chung $
+ * $Id: pio.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -72,7 +72,6 @@ void qse_pio_close (qse_pio_t* pio)
 qse_pio_t* qse_pio_init (
 	qse_pio_t* pio, qse_mmgr_t* mmgr, const qse_char_t* cmd, int oflags)
 {
-
 	qse_pio_hnd_t handle[6] = 
 	{ 
 		QSE_PIO_HND_NIL, 
@@ -92,6 +91,8 @@ qse_pio_t* qse_pio_init (
 
 	int i, minidx = -1, maxidx = -1;
 
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 #ifdef _WIN32
 	SECURITY_ATTRIBUTES secattr; 
 	PROCESS_INFORMATION procinfo;
diff --git a/qse/lib/cmn/rbt.c b/qse/lib/cmn/rbt.c
index b0dffff6..db5e137e 100644
--- a/qse/lib/cmn/rbt.c
+++ b/qse/lib/cmn/rbt.c
@@ -192,6 +192,8 @@ void qse_rbt_close (rbt_t* rbt)
 
 rbt_t* qse_rbt_init (rbt_t* rbt, mmgr_t* mmgr)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	/* do not zero out the extension */
 	QSE_MEMSET (rbt, 0, SIZEOF(*rbt));
 	rbt->mmgr = mmgr;
diff --git a/qse/lib/cmn/rex.c b/qse/lib/cmn/rex.c
index ce8a26f5..9dcbad53 100644
--- a/qse/lib/cmn/rex.c
+++ b/qse/lib/cmn/rex.c
@@ -1,5 +1,5 @@
 /*
- * $Id: rex.c 328 2010-07-08 06:58:44Z hyunghwan.chung $
+ * $Id: rex.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  * 
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -118,6 +118,8 @@ struct cand_t
 
 qse_rex_t* qse_rex_init (qse_rex_t* rex, qse_mmgr_t* mmgr, qse_rex_node_t* code)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_MEMSET (rex, 0, QSE_SIZEOF(*rex));
 	rex->mmgr = mmgr;
 
diff --git a/qse/lib/cmn/sio.c b/qse/lib/cmn/sio.c
index 46b35814..7ec06bd7 100644
--- a/qse/lib/cmn/sio.c
+++ b/qse/lib/cmn/sio.c
@@ -1,5 +1,5 @@
 /*
- * $Id: sio.c 340 2010-08-01 13:13:38Z hyunghwan.chung $
+ * $Id: sio.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -178,6 +178,8 @@ qse_sio_t* qse_sio_init (
 {
 	int mode;
 
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_MEMSET (sio, 0, QSE_SIZEOF(*sio));
 	sio->mmgr = mmgr;
 
diff --git a/qse/lib/cmn/sll.c b/qse/lib/cmn/sll.c
index 0bf6685f..df480f23 100644
--- a/qse/lib/cmn/sll.c
+++ b/qse/lib/cmn/sll.c
@@ -1,5 +1,5 @@
 /*
- * $Id: sll.c 328 2010-07-08 06:58:44Z hyunghwan.chung $
+ * $Id: sll.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -124,6 +124,8 @@ void qse_sll_close (sll_t* sll)
 
 sll_t* qse_sll_init (sll_t* sll, mmgr_t* mmgr)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	/* do not zero out the extension */
 	QSE_MEMSET (sll, 0, SIZEOF(*sll));
 
diff --git a/qse/lib/cmn/str_dyn.c b/qse/lib/cmn/str_dyn.c
index a0fdcda3..ac049fae 100644
--- a/qse/lib/cmn/str_dyn.c
+++ b/qse/lib/cmn/str_dyn.c
@@ -1,5 +1,5 @@
 /*
- * $Id: str_dyn.c 297 2009-10-08 13:09:19Z hyunghwan.chung $
+ * $Id: str_dyn.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -57,6 +57,8 @@ void qse_str_close (qse_str_t* str)
 
 qse_str_t* qse_str_init (qse_str_t* str, qse_mmgr_t* mmgr, qse_size_t capa)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_MEMSET (str, 0, QSE_SIZEOF(qse_str_t));
 
 	str->mmgr = mmgr;
diff --git a/qse/lib/cmn/tio.c b/qse/lib/cmn/tio.c
index ceaa12d8..a4b4b5ce 100644
--- a/qse/lib/cmn/tio.c
+++ b/qse/lib/cmn/tio.c
@@ -1,5 +1,5 @@
 /*
- * $Id: tio.c 287 2009-09-15 10:01:02Z hyunghwan.chung $
+ * $Id: tio.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -58,6 +58,8 @@ int qse_tio_close (qse_tio_t* tio)
 
 qse_tio_t* qse_tio_init (qse_tio_t* tio, qse_mmgr_t* mmgr)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_MEMSET (tio, 0, QSE_SIZEOF(*tio));
 
 	tio->mmgr = mmgr;
diff --git a/qse/lib/cmn/xma.c b/qse/lib/cmn/xma.c
index c05594b8..fe1113c0 100644
--- a/qse/lib/cmn/xma.c
+++ b/qse/lib/cmn/xma.c
@@ -142,6 +142,8 @@ qse_xma_t* qse_xma_init (qse_xma_t* xma, qse_mmgr_t* mmgr, qse_size_t zonesize)
 	qse_xma_blk_t* free;
 	qse_size_t xfi;
 
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	/* round 'zonesize' to be the multiples of ALIGN */
 	zonesize = ((zonesize + ALIGN - 1) / ALIGN) * ALIGN;
 
diff --git a/qse/lib/cut/cut.c b/qse/lib/cut/cut.c
index 8abdc32a..330c371a 100644
--- a/qse/lib/cut/cut.c
+++ b/qse/lib/cut/cut.c
@@ -109,6 +109,8 @@ void qse_cut_close (qse_cut_t* cut)
 
 static qse_cut_t* qse_cut_init (qse_cut_t* cut, qse_mmgr_t* mmgr)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_MEMSET (cut, 0, QSE_SIZEOF(*cut));
 
 	cut->mmgr = mmgr;
diff --git a/qse/lib/sed/sed.c b/qse/lib/sed/sed.c
index d4d1f6f5..453d8244 100644
--- a/qse/lib/sed/sed.c
+++ b/qse/lib/sed/sed.c
@@ -1,5 +1,5 @@
 /*
- * $Id: sed.c 344 2010-08-17 13:15:14Z hyunghwan.chung $
+ * $Id: sed.c 348 2010-08-26 06:26:28Z hyunghwan.chung $
  *
     Copyright 2006-2009 Chung, Hyung-Hwan.
     This file is part of QSE.
@@ -75,6 +75,8 @@ void qse_sed_close (qse_sed_t* sed)
 
 static qse_sed_t* qse_sed_init (qse_sed_t* sed, qse_mmgr_t* mmgr)
 {
+	if (mmgr == QSE_NULL) mmgr = QSE_MMGR_GETDFL();
+
 	QSE_MEMSET (sed, 0, QSE_SIZEOF(*sed));
 	sed->mmgr = mmgr;
 	sed->errstr = qse_sed_dflerrstr;
diff --git a/qse/samples/cmn/fma.c b/qse/samples/cmn/fma.c
index 58c44562..67a343ab 100644
--- a/qse/samples/cmn/fma.c
+++ b/qse/samples/cmn/fma.c
@@ -1,4 +1,6 @@
 #include 
+#include 
+#include 
 #include 
 
 #define R(f) \
@@ -12,7 +14,7 @@ static int test1 ()
 	int i;
 	int* ptr[100];
 
-	qse_fma_t* fma = qse_fma_open (QSE_NULL, 0, sizeof(int), 10, 5);
+	qse_fma_t* fma = qse_fma_open (QSE_MMGR_GETDFL(), 0, sizeof(int), 10, 5);
 	if (fma == QSE_NULL) 
 	{
 		qse_printf (QSE_T("cannot open fma\n"));
@@ -21,7 +23,7 @@ static int test1 ()
 
 	for (i = 0; i < 100; i++)
 	{
-		ptr[i] = qse_fma_alloc (fma);
+		ptr[i] = qse_fma_alloc (fma, sizeof(int));
 		if (ptr[i]) 
 		{
 			qse_printf (QSE_T("%d %p\n"), i, ptr[i]);
@@ -50,7 +52,7 @@ static int test1 ()
 
 	for (i = 0; i < 100; i++)
 	{
-		ptr[i] = qse_fma_alloc (fma);
+		ptr[i] = qse_fma_alloc (fma, sizeof(int));
 		if (ptr[i]) 
 		{
 			qse_printf (QSE_T("%d %p\n"), i, ptr[i]);
@@ -63,8 +65,71 @@ static int test1 ()
 	return 0;
 }
 
+static qse_rbt_walk_t walk (qse_rbt_t* rbt, qse_rbt_pair_t* pair, void* ctx)
+{
+	qse_printf (QSE_T("key = %lld, value = %lld\n"),
+		*(long*)QSE_RBT_KPTR(pair), *(long*)QSE_RBT_VPTR(pair));
+	return QSE_RBT_WALK_FORWARD;
+}
+
+static int test2 ()
+{ 
+	qse_mmgr_t mmgr = 
+	{
+		(qse_mmgr_alloc_t) qse_fma_alloc,
+		(qse_mmgr_realloc_t) qse_fma_realloc,
+		(qse_mmgr_free_t) qse_fma_free,
+		QSE_NULL
+	};
+	qse_fma_t* fma;
+	qse_rbt_t rbt;
+	qse_size_t blksize;
+	long x;
+
+	           /* key */      /* value */      /* internal node */
+	blksize = sizeof(long) + sizeof(long) + sizeof(qse_rbt_pair_t);
+
+	fma = qse_fma_open (QSE_MMGR_GETDFL(), 0, blksize, 10, 0);
+	if (fma == QSE_NULL)
+	{
+		qse_printf (QSE_T("cannot open a memory allocator\n"));
+		return -1;
+	}
+
+	mmgr.udd = fma;
+	if (qse_rbt_init (&rbt, &mmgr) == QSE_NULL)
+	{
+		qse_printf (QSE_T("cannot initialize a tree\n"));
+		qse_fma_close (fma);
+		return -1;
+	}
+
+	qse_rbt_setcopier (&rbt, QSE_RBT_KEY, QSE_RBT_COPIER_INLINE);
+	qse_rbt_setcopier (&rbt, QSE_RBT_VAL, QSE_RBT_COPIER_INLINE);
+	qse_rbt_setscale (&rbt, QSE_RBT_KEY, QSE_SIZEOF(long));
+	qse_rbt_setscale (&rbt, QSE_RBT_VAL, QSE_SIZEOF(long));
+
+	for (x = 10; x < 100; x++)
+	{
+		long y = x * x;
+		if (qse_rbt_insert (&rbt, &x, 1, &y, 1) == QSE_NULL) 
+		{
+			qse_printf (QSE_T("failed to insert. out of memory\n"));
+			break;
+		}
+	}
+
+	qse_rbt_walk (&rbt, walk, QSE_NULL);
+
+	qse_rbt_fini (&rbt);
+	qse_fma_close (fma);
+
+	return 0;
+}
+
 int main ()
 {
 	R (test1);
+	R (test2);
 	return 0;
 }
diff --git a/qse/samples/cmn/rbt.c b/qse/samples/cmn/rbt.c
index fc7aef60..dbb85c56 100644
--- a/qse/samples/cmn/rbt.c
+++ b/qse/samples/cmn/rbt.c
@@ -102,7 +102,6 @@ qse_printf (QSE_T("deleting %d\n"), i);
 static int test2 ()
 {
 	qse_rbt_t* s1;
-	int i;
 
 	s1 = qse_rbt_open (QSE_MMGR_GETDFL(), 0);
 	if (s1 == QSE_NULL)