gnutls-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[SCM] GNU gnutls branch, master, updated. gnutls_2_11_4-4-gb7e3cf4


From: Nikos Mavrogiannopoulos
Subject: [SCM] GNU gnutls branch, master, updated. gnutls_2_11_4-4-gb7e3cf4
Date: Sat, 16 Oct 2010 13:52:36 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU gnutls".

http://git.savannah.gnu.org/cgit/gnutls.git/commit/?id=b7e3cf472340c1abb2aaa06768517ba3e8909d1d

The branch, master has been updated
       via  b7e3cf472340c1abb2aaa06768517ba3e8909d1d (commit)
       via  896d2321f3196c5ab373f4be3764c4da754322f8 (commit)
      from  b8e117f259e5fe0578d9986e75c0f46ca76ac317 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit b7e3cf472340c1abb2aaa06768517ba3e8909d1d
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Oct 16 15:49:30 2010 +0200

    Added tests/suite which contains tests to be executed during
    development time and will not be distributed (not included in make dist).
    Added "ecore" and a new mini-eagain to test EAGAIN behavior.

commit 896d2321f3196c5ab373f4be3764c4da754322f8
Author: Nikos Mavrogiannopoulos <address@hidden>
Date:   Sat Oct 16 15:41:32 2010 +0200

    updated .gitignore.

-----------------------------------------------------------------------

Summary of changes:
 .gitignore                                         |    9 +
 tests/Makefile.am                                  |    3 +
 tests/safe-renegotiation/Makefile.am               |    4 +-
 tests/suite/Makefile.am                            |   79 +
 tests/suite/README                                 |    2 +
 tests/suite/eagain                                 |   43 +
 tests/suite/ecore/eina_config.h                    |   52 +
 tests/suite/ecore/src/include/Eina.h               |  165 ++
 tests/suite/ecore/src/include/eina_accessor.h      |  148 ++
 tests/suite/ecore/src/include/eina_array.h         |  153 ++
 tests/suite/ecore/src/include/eina_benchmark.h     |   77 +
 tests/suite/ecore/src/include/eina_binshare.h      |  105 +
 tests/suite/ecore/src/include/eina_config.h        |   52 +
 tests/suite/ecore/src/include/eina_convert.h       |   80 +
 tests/suite/ecore/src/include/eina_counter.h       |   57 +
 tests/suite/ecore/src/include/eina_cpu.h           |   39 +
 tests/suite/ecore/src/include/eina_error.h         |   66 +
 tests/suite/ecore/src/include/eina_file.h          |   92 +
 tests/suite/ecore/src/include/eina_fp.h            |  111 +
 tests/suite/ecore/src/include/eina_hamster.h       |   44 +
 tests/suite/ecore/src/include/eina_hash.h          |  168 ++
 tests/suite/ecore/src/include/eina_inline_array.x  |  181 ++
 tests/suite/ecore/src/include/eina_inline_f16p16.x |   83 +
 tests/suite/ecore/src/include/eina_inline_f32p32.x |  110 +
 tests/suite/ecore/src/include/eina_inline_f8p24.x  |   82 +
 tests/suite/ecore/src/include/eina_inline_fp.x     |  153 ++
 tests/suite/ecore/src/include/eina_inline_hash.x   |   88 +
 tests/suite/ecore/src/include/eina_inline_list.x   |  145 ++
 tests/suite/ecore/src/include/eina_inline_log.x    |  197 ++
 .../suite/ecore/src/include/eina_inline_mempool.x  |  105 +
 tests/suite/ecore/src/include/eina_inline_rbtree.x |   50 +
 .../ecore/src/include/eina_inline_rectangle.x      |  254 ++
 tests/suite/ecore/src/include/eina_inline_str.x    |   76 +
 .../ecore/src/include/eina_inline_stringshare.x    |   91 +
 tests/suite/ecore/src/include/eina_inline_tiler.x  |  182 ++
 tests/suite/ecore/src/include/eina_inline_trash.x  |   90 +
 .../ecore/src/include/eina_inline_ustringshare.x   |   93 +
 tests/suite/ecore/src/include/eina_inlist.h        |  115 +
 tests/suite/ecore/src/include/eina_iterator.h      |  141 ++
 tests/suite/ecore/src/include/eina_lalloc.h        |   60 +
 tests/suite/ecore/src/include/eina_list.h          |  349 +++
 tests/suite/ecore/src/include/eina_log.h           |  387 +++
 tests/suite/ecore/src/include/eina_magic.h         |  153 ++
 tests/suite/ecore/src/include/eina_main.h          |   75 +
 tests/suite/ecore/src/include/eina_matrixsparse.h  |  120 +
 tests/suite/ecore/src/include/eina_mempool.h       |   77 +
 tests/suite/ecore/src/include/eina_module.h        |  150 ++
 tests/suite/ecore/src/include/eina_quadtree.h      |   53 +
 tests/suite/ecore/src/include/eina_rbtree.h        |  157 ++
 tests/suite/ecore/src/include/eina_rectangle.h     |  109 +
 tests/suite/ecore/src/include/eina_safety_checks.h |  234 ++
 tests/suite/ecore/src/include/eina_sched.h         |   26 +
 tests/suite/ecore/src/include/eina_str.h           |   73 +
 tests/suite/ecore/src/include/eina_strbuf.h        |  477 ++++
 tests/suite/ecore/src/include/eina_stringshare.h   |   93 +
 tests/suite/ecore/src/include/eina_tiler.h         |   86 +
 tests/suite/ecore/src/include/eina_trash.h         |  100 +
 tests/suite/ecore/src/include/eina_types.h         |  284 +++
 tests/suite/ecore/src/include/eina_unicode.h       |   67 +
 tests/suite/ecore/src/include/eina_ustrbuf.h       |  418 ++++
 tests/suite/ecore/src/include/eina_ustringshare.h  |   89 +
 tests/suite/ecore/src/lib/Ecore.h                  |  484 ++++
 tests/suite/ecore/src/lib/Ecore_Getopt.h           |  403 ++++
 tests/suite/ecore/src/lib/ecore.c                  |  418 ++++
 tests/suite/ecore/src/lib/ecore_anim.c             |  233 ++
 tests/suite/ecore/src/lib/ecore_app.c              |   77 +
 tests/suite/ecore/src/lib/ecore_events.c           |  659 ++++++
 tests/suite/ecore/src/lib/ecore_exe.c              | 1846 +++++++++++++++
 tests/suite/ecore/src/lib/ecore_getopt.c           | 1735 ++++++++++++++
 tests/suite/ecore/src/lib/ecore_glib.c             |  286 +++
 tests/suite/ecore/src/lib/ecore_idle_enterer.c     |  171 ++
 tests/suite/ecore/src/lib/ecore_idle_exiter.c      |  148 ++
 tests/suite/ecore/src/lib/ecore_idler.c            |  154 ++
 tests/suite/ecore/src/lib/ecore_job.c              |  106 +
 tests/suite/ecore/src/lib/ecore_main.c             | 1453 ++++++++++++
 tests/suite/ecore/src/lib/ecore_pipe.c             |  595 +++++
 tests/suite/ecore/src/lib/ecore_poll.c             |  442 ++++
 tests/suite/ecore/src/lib/ecore_private.h          |  208 ++
 tests/suite/ecore/src/lib/ecore_signal.c           |  620 +++++
 tests/suite/ecore/src/lib/ecore_thread.c           | 1226 ++++++++++
 tests/suite/ecore/src/lib/ecore_time.c             |  156 ++
 tests/suite/ecore/src/lib/ecore_timer.c            |  591 +++++
 tests/suite/ecore/src/lib/eina_accessor.c          |  267 +++
 tests/suite/ecore/src/lib/eina_array.c             |  727 ++++++
 tests/suite/ecore/src/lib/eina_benchmark.c         |  742 ++++++
 tests/suite/ecore/src/lib/eina_binshare.c          |  202 ++
 tests/suite/ecore/src/lib/eina_chained_mempool.c   |  351 +++
 tests/suite/ecore/src/lib/eina_convert.c           |  773 ++++++
 tests/suite/ecore/src/lib/eina_counter.c           |  505 ++++
 tests/suite/ecore/src/lib/eina_cpu.c               |  208 ++
 tests/suite/ecore/src/lib/eina_error.c             |  463 ++++
 tests/suite/ecore/src/lib/eina_file.c              |  544 +++++
 tests/suite/ecore/src/lib/eina_fp.c                |  532 +++++
 tests/suite/ecore/src/lib/eina_hamster.c           |  128 +
 tests/suite/ecore/src/lib/eina_hash.c              | 1933 +++++++++++++++
 tests/suite/ecore/src/lib/eina_inlist.c            |  693 ++++++
 tests/suite/ecore/src/lib/eina_iterator.c          |  260 ++
 tests/suite/ecore/src/lib/eina_lalloc.c            |  158 ++
 tests/suite/ecore/src/lib/eina_list.c              | 2184 +++++++++++++++++
 tests/suite/ecore/src/lib/eina_log.c               | 2483 ++++++++++++++++++++
 tests/suite/ecore/src/lib/eina_magic.c             |  487 ++++
 tests/suite/ecore/src/lib/eina_main.c              |  377 +++
 tests/suite/ecore/src/lib/eina_matrixsparse.c      | 1692 +++++++++++++
 tests/suite/ecore/src/lib/eina_mempool.c           |  399 ++++
 tests/suite/ecore/src/lib/eina_module.c            |  762 ++++++
 tests/suite/ecore/src/lib/eina_private.h           |  135 ++
 tests/suite/ecore/src/lib/eina_quadtree.c          |  916 ++++++++
 tests/suite/ecore/src/lib/eina_rbtree.c            |  592 +++++
 tests/suite/ecore/src/lib/eina_rectangle.c         |  693 ++++++
 tests/suite/ecore/src/lib/eina_safety_checks.c     |  114 +
 tests/suite/ecore/src/lib/eina_sched.c             |   95 +
 tests/suite/ecore/src/lib/eina_share_common.c      |  974 ++++++++
 tests/suite/ecore/src/lib/eina_share_common.h      |  103 +
 tests/suite/ecore/src/lib/eina_str.c               |  639 +++++
 tests/suite/ecore/src/lib/eina_strbuf.c            |  180 ++
 tests/suite/ecore/src/lib/eina_strbuf_common.c     |  862 +++++++
 tests/suite/ecore/src/lib/eina_strbuf_common.h     |  112 +
 tests/suite/ecore/src/lib/eina_strbuf_template_c.x |  216 ++
 tests/suite/ecore/src/lib/eina_stringshare.c       |  956 ++++++++
 tests/suite/ecore/src/lib/eina_tiler.c             | 1295 ++++++++++
 tests/suite/ecore/src/lib/eina_unicode.c           |  176 ++
 tests/suite/ecore/src/lib/eina_ustrbuf.c           |   89 +
 tests/suite/ecore/src/lib/eina_ustringshare.c      |  243 ++
 tests/suite/ecore/src/lib/eina_value.c             |   47 +
 tests/suite/mini-eagain2.c                         |  205 ++
 tests/{safe-renegotiation => suite}/params.dh      |    0
 tests/{safe-renegotiation => suite}/testsrn        |    0
 127 files changed, 44942 insertions(+), 3 deletions(-)
 create mode 100644 tests/suite/Makefile.am
 create mode 100644 tests/suite/README
 create mode 100755 tests/suite/eagain
 create mode 100644 tests/suite/ecore/eina_config.h
 create mode 100644 tests/suite/ecore/src/include/Eina.h
 create mode 100644 tests/suite/ecore/src/include/eina_accessor.h
 create mode 100644 tests/suite/ecore/src/include/eina_array.h
 create mode 100644 tests/suite/ecore/src/include/eina_benchmark.h
 create mode 100644 tests/suite/ecore/src/include/eina_binshare.h
 create mode 100644 tests/suite/ecore/src/include/eina_config.h
 create mode 100644 tests/suite/ecore/src/include/eina_convert.h
 create mode 100644 tests/suite/ecore/src/include/eina_counter.h
 create mode 100644 tests/suite/ecore/src/include/eina_cpu.h
 create mode 100644 tests/suite/ecore/src/include/eina_error.h
 create mode 100644 tests/suite/ecore/src/include/eina_file.h
 create mode 100644 tests/suite/ecore/src/include/eina_fp.h
 create mode 100644 tests/suite/ecore/src/include/eina_hamster.h
 create mode 100644 tests/suite/ecore/src/include/eina_hash.h
 create mode 100644 tests/suite/ecore/src/include/eina_inline_array.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_f16p16.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_f32p32.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_f8p24.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_fp.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_hash.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_list.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_log.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_mempool.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_rbtree.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_rectangle.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_str.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_stringshare.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_tiler.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_trash.x
 create mode 100644 tests/suite/ecore/src/include/eina_inline_ustringshare.x
 create mode 100644 tests/suite/ecore/src/include/eina_inlist.h
 create mode 100644 tests/suite/ecore/src/include/eina_iterator.h
 create mode 100644 tests/suite/ecore/src/include/eina_lalloc.h
 create mode 100644 tests/suite/ecore/src/include/eina_list.h
 create mode 100644 tests/suite/ecore/src/include/eina_log.h
 create mode 100644 tests/suite/ecore/src/include/eina_magic.h
 create mode 100644 tests/suite/ecore/src/include/eina_main.h
 create mode 100644 tests/suite/ecore/src/include/eina_matrixsparse.h
 create mode 100644 tests/suite/ecore/src/include/eina_mempool.h
 create mode 100644 tests/suite/ecore/src/include/eina_module.h
 create mode 100644 tests/suite/ecore/src/include/eina_quadtree.h
 create mode 100644 tests/suite/ecore/src/include/eina_rbtree.h
 create mode 100644 tests/suite/ecore/src/include/eina_rectangle.h
 create mode 100644 tests/suite/ecore/src/include/eina_safety_checks.h
 create mode 100644 tests/suite/ecore/src/include/eina_sched.h
 create mode 100644 tests/suite/ecore/src/include/eina_str.h
 create mode 100644 tests/suite/ecore/src/include/eina_strbuf.h
 create mode 100644 tests/suite/ecore/src/include/eina_stringshare.h
 create mode 100644 tests/suite/ecore/src/include/eina_tiler.h
 create mode 100644 tests/suite/ecore/src/include/eina_trash.h
 create mode 100644 tests/suite/ecore/src/include/eina_types.h
 create mode 100644 tests/suite/ecore/src/include/eina_unicode.h
 create mode 100644 tests/suite/ecore/src/include/eina_ustrbuf.h
 create mode 100644 tests/suite/ecore/src/include/eina_ustringshare.h
 create mode 100644 tests/suite/ecore/src/lib/Ecore.h
 create mode 100644 tests/suite/ecore/src/lib/Ecore_Getopt.h
 create mode 100644 tests/suite/ecore/src/lib/ecore.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_anim.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_app.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_events.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_exe.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_getopt.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_glib.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_idle_enterer.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_idle_exiter.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_idler.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_job.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_main.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_pipe.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_poll.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_private.h
 create mode 100644 tests/suite/ecore/src/lib/ecore_signal.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_thread.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_time.c
 create mode 100644 tests/suite/ecore/src/lib/ecore_timer.c
 create mode 100644 tests/suite/ecore/src/lib/eina_accessor.c
 create mode 100644 tests/suite/ecore/src/lib/eina_array.c
 create mode 100644 tests/suite/ecore/src/lib/eina_benchmark.c
 create mode 100644 tests/suite/ecore/src/lib/eina_binshare.c
 create mode 100644 tests/suite/ecore/src/lib/eina_chained_mempool.c
 create mode 100644 tests/suite/ecore/src/lib/eina_convert.c
 create mode 100644 tests/suite/ecore/src/lib/eina_counter.c
 create mode 100644 tests/suite/ecore/src/lib/eina_cpu.c
 create mode 100644 tests/suite/ecore/src/lib/eina_error.c
 create mode 100644 tests/suite/ecore/src/lib/eina_file.c
 create mode 100644 tests/suite/ecore/src/lib/eina_fp.c
 create mode 100644 tests/suite/ecore/src/lib/eina_hamster.c
 create mode 100644 tests/suite/ecore/src/lib/eina_hash.c
 create mode 100644 tests/suite/ecore/src/lib/eina_inlist.c
 create mode 100644 tests/suite/ecore/src/lib/eina_iterator.c
 create mode 100644 tests/suite/ecore/src/lib/eina_lalloc.c
 create mode 100644 tests/suite/ecore/src/lib/eina_list.c
 create mode 100644 tests/suite/ecore/src/lib/eina_log.c
 create mode 100644 tests/suite/ecore/src/lib/eina_magic.c
 create mode 100644 tests/suite/ecore/src/lib/eina_main.c
 create mode 100644 tests/suite/ecore/src/lib/eina_matrixsparse.c
 create mode 100644 tests/suite/ecore/src/lib/eina_mempool.c
 create mode 100644 tests/suite/ecore/src/lib/eina_module.c
 create mode 100644 tests/suite/ecore/src/lib/eina_private.h
 create mode 100644 tests/suite/ecore/src/lib/eina_quadtree.c
 create mode 100644 tests/suite/ecore/src/lib/eina_rbtree.c
 create mode 100644 tests/suite/ecore/src/lib/eina_rectangle.c
 create mode 100644 tests/suite/ecore/src/lib/eina_safety_checks.c
 create mode 100644 tests/suite/ecore/src/lib/eina_sched.c
 create mode 100644 tests/suite/ecore/src/lib/eina_share_common.c
 create mode 100644 tests/suite/ecore/src/lib/eina_share_common.h
 create mode 100644 tests/suite/ecore/src/lib/eina_str.c
 create mode 100644 tests/suite/ecore/src/lib/eina_strbuf.c
 create mode 100644 tests/suite/ecore/src/lib/eina_strbuf_common.c
 create mode 100644 tests/suite/ecore/src/lib/eina_strbuf_common.h
 create mode 100644 tests/suite/ecore/src/lib/eina_strbuf_template_c.x
 create mode 100644 tests/suite/ecore/src/lib/eina_stringshare.c
 create mode 100644 tests/suite/ecore/src/lib/eina_tiler.c
 create mode 100644 tests/suite/ecore/src/lib/eina_unicode.c
 create mode 100644 tests/suite/ecore/src/lib/eina_ustrbuf.c
 create mode 100644 tests/suite/ecore/src/lib/eina_ustringshare.c
 create mode 100644 tests/suite/ecore/src/lib/eina_value.c
 create mode 100644 tests/suite/mini-eagain2.c
 rename tests/{safe-renegotiation => suite}/params.dh (100%)
 rename tests/{safe-renegotiation => suite}/testsrn (100%)

diff --git a/.gitignore b/.gitignore
index 389a9df..07367b2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,6 +3,7 @@
 *~
 .deps
 .libs
+tags
 ABOUT-NLS
 INSTALL
 Makefile
@@ -26,6 +27,9 @@ doc/Makefile
 doc/Makefile.in
 doc/algorithms.texi
 doc/core.c.texi
+doc/gnutls.dvi
+doc/gnutls.html
+doc/gnutls.ps
 doc/credentials/Makefile
 doc/credentials/Makefile.in
 doc/credentials/openpgp/Makefile
@@ -263,6 +267,7 @@ lib/libgnutlsxx.la
 lib/libtool
 lib/minitasn1/Makefile
 lib/minitasn1/Makefile.in
+lib/minitasn1/libminitasn1.la
 lib/nettle/libcrypto.la
 lib/opencdk/Makefile
 lib/opencdk/Makefile.in
@@ -431,3 +436,7 @@ tests/x509paths/
 tests/x509self
 tests/x509sign-verify
 tests/x509signself
+tests/suite/eagain-cli
+tests/suite/libecore.la
+tests/certuniqueid
+tests/gendh
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 4a42a09..15d03a4 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -96,3 +96,6 @@ TESTS_ENVIRONMENT =                                           
\
        EXEEXT=$(EXEEXT)                                        \
        srcdir="$(srcdir)"                                      \
        $(VALGRIND)
+
+check-local:
+       [ -d suite ] && $(MAKE) -C suite check
diff --git a/tests/safe-renegotiation/Makefile.am 
b/tests/safe-renegotiation/Makefile.am
index e175c78..a76e437 100644
--- a/tests/safe-renegotiation/Makefile.am
+++ b/tests/safe-renegotiation/Makefile.am
@@ -31,7 +31,5 @@ check_PROGRAMS = $(ctests)
 TESTS = $(ctests)
 TESTS_ENVIRONMENT = $(VALGRIND)
 
-EXTRA_DIST = README params.dh
+EXTRA_DIST = README
 
-dist_check_SCRIPTS = testsrn
-#TESTS = testsrn
diff --git a/tests/suite/Makefile.am b/tests/suite/Makefile.am
new file mode 100644
index 0000000..184acbe
--- /dev/null
+++ b/tests/suite/Makefile.am
@@ -0,0 +1,79 @@
+## Process this file with automake to produce Makefile.in
+# Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software
+# Foundation, Inc.
+#
+# Author: Simon Josefsson
+#
+# This file is part of GnuTLS.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This file is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this file; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+EXTRA_DIST = params.dh
+
+AM_CFLAGS = $(WARN_CFLAGS)
+AM_CPPFLAGS = \
+       -I$(top_srcdir)/gl                      \
+       -I$(top_builddir)/gl                    \
+       -I$(top_srcdir)/lib/includes            \
+       -I$(top_builddir)/lib/includes          \
+       -I$(top_srcdir)/libextra/includes       \
+       -I$(top_builddir)/libextra/includes     \
+       -I$(top_srcdir)/lib                     \
+       -I$(top_srcdir)/doc/examples    \
+       -I$(top_srcdir)/tests/suite/ecore/src/include \
+       -I$(top_srcdir)/tests/suite/ecore/src/lib
+
+AM_LDFLAGS = -no-install
+LDADD = ../../lib/libgnutls.la \
+       ../../gl/libgnu.la \
+       ../libutils.la \
+       $(LTLIBGCRYPT)  \
+       $(LIBSOCKET) $(INET_NTOP_LIB) $(INET_PTON_LIB)
+
+noinst_LTLIBRARIES = libecore.la                                               
                                                                                
                                                                                
                   
+
+libecore_la_CPPFLAGS = -I$(top_srcdir)/tests/suite/ecore/ 
-I$(top_srcdir)/tests/suite/ecore/src/include \
+       -I$(top_srcdir)/tests/suite/ecore/src/lib -DHAVE_CONFIG_H -D__UNUSED__= 
-DVMAJ=1 \
+       -D VMIC=0 -DVMIN=0 -DVREV=0 -DEFL_HAVE_POSIX_THREADS=1 
-DEFL_HAVE_POSIX_THREADS_SPINLOCK=1 \
+       -DEFL_HAVE_THREADS=1 -DEINA_BUILD_CHAINED_POOL=1 
-DEINA_STATIC_BUILD_CHAINED_POOL=1 \
+       -DHAVE_CLOCK_GETTIME -DHAVE_GETTIMEOFDAY -DPACKAGE_LIB_DIR=\"/usr/lib\" 
-DMODULE_ARCH=\"unix\" \
+       -DSHARED_LIB_SUFFIX=\".so\"
+libecore_la_CFLAGS = -w
+libecore_la_SOURCES = ecore/src/lib/ecore_anim.c ecore/src/lib/ecore_app.c \
+       ecore/src/lib/ecore.c ecore/src/lib/ecore_events.c 
ecore/src/lib/ecore_exe.c \
+       ecore/src/lib/ecore_getopt.c ecore/src/lib/ecore_glib.c 
ecore/src/lib/ecore_idle_enterer.c \
+       ecore/src/lib/ecore_idle_exiter.c ecore/src/lib/ecore_idler.c 
ecore/src/lib/ecore_job.c \
+       ecore/src/lib/ecore_main.c ecore/src/lib/ecore_pipe.c 
ecore/src/lib/ecore_poll.c \
+       ecore/src/lib/ecore_signal.c ecore/src/lib/ecore_thread.c 
ecore/src/lib/ecore_time.c \
+       ecore/src/lib/ecore_timer.c ecore/src/lib/eina_accessor.c 
ecore/src/lib/eina_array.c \
+       ecore/src/lib/eina_benchmark.c ecore/src/lib/eina_binshare.c 
ecore/src/lib/eina_chained_mempool.c \
+       ecore/src/lib/eina_convert.c ecore/src/lib/eina_counter.c 
ecore/src/lib/eina_cpu.c ecore/src/lib/eina_error.c \
+       ecore/src/lib/eina_file.c ecore/src/lib/eina_fp.c 
ecore/src/lib/eina_hamster.c ecore/src/lib/eina_hash.c \
+       ecore/src/lib/eina_inlist.c ecore/src/lib/eina_iterator.c 
ecore/src/lib/eina_lalloc.c ecore/src/lib/eina_list.c \
+       ecore/src/lib/eina_log.c ecore/src/lib/eina_magic.c 
ecore/src/lib/eina_main.c ecore/src/lib/eina_matrixsparse.c \
+       ecore/src/lib/eina_mempool.c ecore/src/lib/eina_module.c 
ecore/src/lib/eina_quadtree.c ecore/src/lib/eina_rbtree.c \
+       ecore/src/lib/eina_rectangle.c ecore/src/lib/eina_safety_checks.c 
ecore/src/lib/eina_sched.c ecore/src/lib/eina_share_common.c \
+       ecore/src/lib/eina_strbuf.c ecore/src/lib/eina_strbuf_common.c 
ecore/src/lib/eina_str.c \
+       ecore/src/lib/eina_stringshare.c ecore/src/lib/eina_tiler.c 
ecore/src/lib/eina_unicode.c \
+       ecore/src/lib/eina_ustrbuf.c ecore/src/lib/eina_ustringshare.c 
ecore/src/lib/eina_value.c
+
+eagain_cli_LDADD = $(LDADD) libecore.la -lrt -lm
+eagain_cli_SOURCES = mini-eagain2.c
+
+noinst_PROGRAMS = eagain-cli
+
+dist_check_SCRIPTS = eagain #testsrn
+
+TESTS = eagain #testsrn
diff --git a/tests/suite/README b/tests/suite/README
new file mode 100644
index 0000000..ece7004
--- /dev/null
+++ b/tests/suite/README
@@ -0,0 +1,2 @@
+Here are tests that will not be distributed with a release. Only
+done during development.
diff --git a/tests/suite/eagain b/tests/suite/eagain
new file mode 100755
index 0000000..0acf21b
--- /dev/null
+++ b/tests/suite/eagain
@@ -0,0 +1,43 @@
+#!/bin/sh
+
+# Copyright (C) 2006, 2007, 2008, 2010 Free Software Foundation, Inc.
+#
+# Author: Simon Josefsson
+#
+# This file is part of GnuTLS.
+#
+# GnuTLS is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at
+# your option) any later version.
+#
+# GnuTLS is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GnuTLS; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+srcdir="${srcdir:-.}"
+SERV="${SERV:-../../src/gnutls-serv$EXEEXT} -q"
+PORT="${PORT:-4445}"
+
+
+$SERV -p $PORT --echo --priority "NORMAL:+ANON-DH" --dhparams 
$srcdir/params.dh >/dev/null 2>&1 &
+pid=$!
+
+sleep 2
+
+./eagain-cli
+if [ $? != 0 ];then
+       exit 1
+fi
+
+if [ "$pid" != "" ];then
+kill $pid
+wait
+fi
+
+exit 0
diff --git a/tests/suite/ecore/eina_config.h b/tests/suite/ecore/eina_config.h
new file mode 100644
index 0000000..f89327d
--- /dev/null
+++ b/tests/suite/ecore/eina_config.h
@@ -0,0 +1,52 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_CONFIG_H_
+#define EINA_CONFIG_H_
+
+#ifdef EINA_MAGIC_DEBUG
+# undef EINA_MAGIC_DEBUG
+#endif
+#define EINA_MAGIC_DEBUG
+
+#ifdef EINA_DEFAULT_MEMPOOL
+# undef EINA_DEFAULT_MEMPOOL
+#endif
+
+
+#ifdef EINA_SAFETY_CHECKS
+# undef EINA_SAFETY_CHECKS
+#endif
+#define EINA_SAFETY_CHECKS
+
+#ifdef EINA_HAVE_INTTYPES_H
+# undef EINA_HAVE_INTTYPES_H
+#endif
+#define EINA_HAVE_INTTYPES_H
+
+#ifdef EINA_HAVE_STDINT_H
+# undef EINA_HAVE_STDINT_H
+#endif
+#define EINA_HAVE_STDINT_H
+
+#ifdef EINA_SIZEOF_WCHAR_T
+# undef EINA_SIZEOF_WCHAR_T
+#endif
+#define EINA_SIZEOF_WCHAR_T 4
+
+#endif /* EINA_CONFIG_H_ */
diff --git a/tests/suite/ecore/src/include/Eina.h 
b/tests/suite/ecore/src/include/Eina.h
new file mode 100644
index 0000000..eb0263f
--- /dev/null
+++ b/tests/suite/ecore/src/include/Eina.h
@@ -0,0 +1,165 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008-2010 Enlightenment Developers:
+ *           Albin "Lutin" Tonnerre <address@hidden>
+ *           Alexandre "diaxen" Becoulet <address@hidden>
+ *           Andre Dieb <address@hidden>
+ *           Arnaud de Turckheim "quarium" <address@hidden>
+ *           Carsten Haitzler <address@hidden>
+ *           Cedric Bail <address@hidden>
+ *           Corey "atmos" Donohoe <address@hidden>
+ *           Fabiano Fidêncio <address@hidden>
+ *           Gustavo Chaves <address@hidden>
+ *           Gustavo Sverzut Barbieri <address@hidden>
+ *           Jorge Luis "turran" Zapata <address@hidden>
+ *           Peter "pfritz" Wehrfritz <address@hidden>
+ *           Raphael Kubo da Costa <address@hidden>
+ *           Tilman Sauerbeck <address@hidden>
+ *           Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ *           Tom Hacohen <address@hidden>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_H_
+#define EINA_H_
+
+/**
+ * @mainpage Eina
+ *
+ * @author Albin "Lutin" Tonnerre <albin.tonnerre@@gmail.com>
+ * @author Alexandre "diaxen" Becoulet <diaxen@@free.fr>
+ * @author Andre Dieb <andre.dieb@@gmail.com>
+ * @author Arnaud de Turckheim "quarium" <quarium@@gmail.com>
+ * @author Carsten Haitzler <raster@@rasterman.com>
+ * @author Cedric Bail <cedric.bail@@free.fr>
+ * @author Corey "atmos" Donohoe <atmos@@atmos.org>
+ * @author Fabiano Fidêncio <fidencio@@profusion.mobi>
+ * @author Gustavo Chaves <glima@@profusion.mobi>
+ * @author Gustavo Sverzut Barbieri <barbieri@@profusion.mobi>
+ * @author Jorge Luis "turran" Zapata <jorgeluis.zapata@@gmail.com>
+ * @author Peter "pfritz" Wehrfritz <peter.wehrfritz@@web.de>
+ * @author Raphael Kubo da Costa <kubo@@profusion.mobi>
+ * @author Tilman Sauerbeck <tilman@@code-monkey.de>
+ * @author Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ * @author Tom Hacohen <tom@@stosb.com>
+ * @date 2008-2010
+ *
+ * @section eina_intro_sec Introduction
+ *
+ * The Eina library is a library that implements an API for data types
+ * in an efficient way. It also provides some useful tools like
+ * openin shared libraries, errors management, type conversion,
+ * time accounting and memory pool.
+ *
+ * This library is cross-platform and can be compiled and used on
+ * Linux, BSD, Opensolaris and Windows (XP and CE).
+ *
+ * The data types that are available are (see @ref Eina_Data_Types_Group):
+ * @li @ref Eina_Array_Group standard array of @c void* data.
+ * @li @ref Eina_Hash_Group standard hash of @c void* data.
+ * @li @ref Eina_Inline_List_Group list with nodes inlined into user type.
+ * @li @ref Eina_List_Group standard list of @c void* data.
+ * @li @ref Eina_Matrixsparse_Group sparse matrix of @c void* data.
+ * @li @ref Eina_Rbtree_Group red-black tree with nodes inlined into user type.
+ * @li @ref Eina_String_Buffer_Group mutable string to prepend, insert or 
append strings to a buffer.
+ * @li @ref Eina_Stringshare_Group saves memory by sharing read-only string 
references.
+ * @li @ref Eina_Tiler_Group split, merge and navigates into 2D tiled regions.
+ * @li @ref Eina_Trash_Group container of unused but allocated data.
+ *
+ * The tools that are available are (see @ref Eina_Tools_Group):
+ * @li @ref Eina_Benchmark_Group helper to write benchmarks.
+ * @li @ref Eina_Convert_Group faster conversion from strings to integers, 
double, etc.
+ * @li @ref Eina_Counter_Group measures number of calls and their time.
+ * @li @ref Eina_Error_Group error identifiers.
+ * @li @ref Eina_File_Group simple file list and path split.
+ * @li @ref Eina_Lalloc_Group simple lazy allocator.
+ * @li @ref Eina_Log_Group full-featured logging system.
+ * @li @ref Eina_Magic_Group provides runtime type checking.
+ * @li @ref Eina_Memory_Pool_Group abstraction for various memory allocators.
+ * @li @ref Eina_Module_Group lists, loads and share modules using Eina_Module 
standard.
+ * @li @ref Eina_Rectangle_Group rectangle structure and standard manipulation 
methods.
+ * @li @ref Eina_Safety_Checks_Group extra checks that will report unexpected 
conditions and can be disabled at compile time.
+ * @li @ref Eina_String_Group a set of functions that manages C strings.
+ *
+ * @defgroup Eina_Data_Types_Group Data types.
+ *
+ * Eina provide easy to use and optimized data types and structures.
+ *
+ *
+ * @defgroup Eina_Containers_Group Containers
+ *
+ * Containers are data types that hold data and allow iteration over
+ * their elements with an @ref Eina_Iterator_Group, or eventually an
+ * @ref Eina_Accessor_Group.
+ *
+ *
+ * @defgroup Eina_Tools_Group Tools
+ *
+ * Eina tools aims to help application development, providing ways to
+ * make it safer, log errors, manage memory more efficiently and more.
+ */
+
+#include <dirent.h>
+
+#ifdef _WIN32
+# include <Evil.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "eina_config.h"
+#include "eina_types.h"
+#include "eina_main.h"
+#include "eina_fp.h"
+#include "eina_rectangle.h"
+#include "eina_inlist.h"
+#include "eina_file.h"
+#include "eina_list.h"
+#include "eina_hash.h"
+#include "eina_trash.h"
+#include "eina_lalloc.h"
+#include "eina_module.h"
+#include "eina_mempool.h"
+#include "eina_error.h"
+#include "eina_log.h"
+#include "eina_array.h"
+#include "eina_binshare.h"
+#include "eina_stringshare.h"
+#include "eina_ustringshare.h"
+#include "eina_magic.h"
+#include "eina_counter.h"
+#include "eina_rbtree.h"
+#include "eina_accessor.h"
+#include "eina_iterator.h"
+#include "eina_benchmark.h"
+#include "eina_convert.h"
+#include "eina_cpu.h"
+#include "eina_sched.h"
+#include "eina_tiler.h"
+#include "eina_hamster.h"
+#include "eina_matrixsparse.h"
+#include "eina_str.h"
+#include "eina_strbuf.h"
+#include "eina_ustrbuf.h"
+#include "eina_unicode.h"
+#include "eina_quadtree.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* EINA_H */
diff --git a/tests/suite/ecore/src/include/eina_accessor.h 
b/tests/suite/ecore/src/include/eina_accessor.h
new file mode 100644
index 0000000..4d2f92e
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_accessor.h
@@ -0,0 +1,148 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_ACCESSOR_H__
+#define EINA_ACCESSOR_H__
+
+#include "eina_config.h"
+
+#include "eina_types.h"
+#include "eina_magic.h"
+
+/**
+ * @addtogroup Eina_Content_Access_Group Content Access
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Accessor_Group Accessor Functions
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Accessor
+ * Type for accessors.
+ */
+typedef struct _Eina_Accessor Eina_Accessor;
+
+typedef Eina_Bool (*Eina_Accessor_Get_At_Callback)(Eina_Accessor *it,
+                                                   unsigned int index,
+                                                   void **data);
+typedef void *(*Eina_Accessor_Get_Container_Callback)(Eina_Accessor *it);
+typedef void (*Eina_Accessor_Free_Callback)(Eina_Accessor *it);
+typedef Eina_Bool (*Eina_Accessor_Lock_Callback)(Eina_Accessor *it);
+
+struct _Eina_Accessor
+{
+#define EINA_ACCESSOR_VERSION 1
+   int version;
+
+   Eina_Accessor_Get_At_Callback get_at               EINA_ARG_NONNULL(1, 3) 
EINA_WARN_UNUSED_RESULT;
+   Eina_Accessor_Get_Container_Callback get_container EINA_ARG_NONNULL(1) 
EINA_WARN_UNUSED_RESULT;
+   Eina_Accessor_Free_Callback free                   EINA_ARG_NONNULL(1);
+
+   Eina_Accessor_Lock_Callback lock   EINA_WARN_UNUSED_RESULT;
+   Eina_Accessor_Lock_Callback unlock EINA_WARN_UNUSED_RESULT;
+
+#define EINA_MAGIC_ACCESSOR 0x98761232
+   EINA_MAGIC
+};
+
+#define FUNC_ACCESSOR_GET_AT(Function) 
((Eina_Accessor_Get_At_Callback)Function)
+#define FUNC_ACCESSOR_GET_CONTAINER(Function) 
((Eina_Accessor_Get_Container_Callback)Function)
+#define FUNC_ACCESSOR_FREE(Function) ((Eina_Accessor_Free_Callback)Function)
+#define FUNC_ACCESSOR_LOCK(Function) ((Eina_Accessor_Lock_Callback)Function)
+
+EAPI void      eina_accessor_free(Eina_Accessor *accessor) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool eina_accessor_data_get(Eina_Accessor *accessor,
+                                      unsigned int position,
+                                      void **data) EINA_ARG_NONNULL(1);
+EAPI void *    eina_accessor_container_get(Eina_Accessor *accessor) 
EINA_ARG_NONNULL(1) EINA_PURE;
+EAPI void      eina_accessor_over(Eina_Accessor *accessor,
+                                  Eina_Each_Cb cb,
+                                  unsigned int start,
+                                  unsigned int end,
+                                  const void *fdata) EINA_ARG_NONNULL(1, 2);
+EAPI Eina_Bool eina_accessor_lock(Eina_Accessor *accessor) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool eina_accessor_unlock(Eina_Accessor *accessor) 
EINA_ARG_NONNULL(1);
+
+/**
+ * @def EINA_ACCESSOR_FOREACH
+ * @brief Macro to iterate over all elements easily.
+ *
+ * @param accessor The accessor to use.
+ * @param counter A counter used by eina_accessor_data_get() when
+ * iterating over the container.
+ * @param data Where to store * data, must be a pointer support getting
+ * its address since * eina_accessor_data_get() requires a pointer to
+ * pointer!
+ *
+ * This macro allows a convenient way to loop over all elements in an
+ * accessor, very similar to EINA_LIST_FOREACH().
+ *
+ * This macro can be used for freeing the data of a list, like in the
+ * following example. It has the same goal as the one documented in
+ * EINA_LIST_FOREACH(), but using accessors:
+ *
+ * @code
+ * Eina_List     *list;
+ * Eina_Accessor *accessor;
+ * unsigned int   i;
+ * char          *data;
+ *
+ * // list is already filled,
+ * // its elements are just duplicated strings
+ *
+ * accessor = eina_list_accessor_new(list);
+ * EINA_ACCESSOR_FOREACH(accessor, i, data)
+ *   free(data);
+ * eina_accessor_free(accessor);
+ * eina_list_free(list);
+ * @endcode
+ *
+ * @note if the datatype provides both iterators and accessors prefer
+ *    to use iterators to iterate over, as they're likely to be more
+ *    optimized for such task.
+ *
+ * @note this example is not optimal algorithm to release a list since
+ *    it will walk the list twice, but it serves as an example. For
+ *    optimized version use EINA_LIST_FREE()
+ *
+ * @warning unless explicitly stated in functions returning accessors,
+ *    do not modify the accessed object while you walk it, in this
+ *    example using lists, do not remove list nodes or you might
+ *    crash!  This is not a limitiation of accessors themselves,
+ *    rather in the accessors implementations to keep them as simple
+ *    and fast as possible.
+ */
+#define EINA_ACCESSOR_FOREACH(accessor, counter, data)                 \
+  for ((counter) = 0;                                                  \
+       eina_accessor_data_get((accessor), (counter), (void **)&(data)); \
+       (counter)++)
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_array.h 
b/tests/suite/ecore/src/include/eina_array.h
new file mode 100644
index 0000000..cb0d12a
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_array.h
@@ -0,0 +1,153 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_ARRAY_H_
+#define EINA_ARRAY_H_
+
+#include <stdlib.h>
+
+#include "eina_config.h"
+
+#include "eina_types.h"
+#include "eina_error.h"
+#include "eina_iterator.h"
+#include "eina_accessor.h"
+#include "eina_magic.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @addtogroup Eina_Containers_Group Containers
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Array_Group Array
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Array
+ * Type for a generic vector.
+ */
+typedef struct _Eina_Array Eina_Array;
+
+/**
+ * @typedef Eina_Array_Iterator
+ * Type for an iterator on arrays, used with #EINA_ARRAY_ITER_NEXT.
+ */
+typedef void **Eina_Array_Iterator;
+
+/**
+ * @struct _Eina_Array
+ * Type for an array of data.
+ */
+struct _Eina_Array
+{
+#define EINA_ARRAY_VERSION 1
+   int version; /**< Should match EINA_ARRAY_VERSION used when compiled your 
apps, provided for ABI compatibility */
+
+   void **data; /**< Pointer to a vector of pointer to payload */
+   unsigned int total; /**< Total number of slots in the vector */
+   unsigned int count; /**< Number of active slots in the vector */
+   unsigned int step; /**< How much must we grow the vector when it is full */
+   EINA_MAGIC
+};
+
+EAPI Eina_Array *               eina_array_new(unsigned int step) 
EINA_WARN_UNUSED_RESULT EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI void                       eina_array_free(Eina_Array *array) 
EINA_ARG_NONNULL(1);
+EAPI void                       eina_array_step_set(Eina_Array *array,
+                                                    unsigned int 
sizeof_eina_array,
+                                                    unsigned int step) 
EINA_ARG_NONNULL(1);
+EAPI void                       eina_array_clean(Eina_Array *array) 
EINA_ARG_NONNULL(1);
+EAPI void                       eina_array_flush(Eina_Array *array) 
EINA_ARG_NONNULL(1);
+EAPI Eina_Bool                  eina_array_remove(Eina_Array *array,
+                                                  Eina_Bool(*keep)(void *data, 
void *gdata),
+                                                  void *gdata) 
EINA_ARG_NONNULL(1, 2);
+static inline Eina_Bool         eina_array_push(Eina_Array *array,
+                                                const void *data) 
EINA_ARG_NONNULL(1, 2);
+static inline void *            eina_array_pop(Eina_Array *array) 
EINA_ARG_NONNULL(1);
+static inline void *            eina_array_data_get(const Eina_Array *array,
+                                                    unsigned int idx) 
EINA_ARG_NONNULL(1);
+static inline void              eina_array_data_set(const Eina_Array *array,
+                                                    unsigned int idx,
+                                                    const void *data) 
EINA_ARG_NONNULL(1, 3);
+static inline unsigned int      eina_array_count_get(const Eina_Array *array) 
EINA_ARG_NONNULL(1);
+EAPI Eina_Iterator *            eina_array_iterator_new(const Eina_Array 
*array) EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Accessor *            eina_array_accessor_new(const Eina_Array 
*array) EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+static inline Eina_Bool                eina_array_foreach(Eina_Array *array,
+                                                   Eina_Each_Cb cb,
+                                                   void *data);
+/**
+ * @def EINA_ARRAY_ITER_NEXT
+ * @brief Macro to iterate over an array easily.
+ *
+ * @param array The array to iterate over.
+ * @param index The integer number that is increased while itareting.
+ * @param item The data
+ * @param iterator The iterator
+ *
+ * This macro allows the iteration over @p array in an easy way. It
+ * iterates from the first element to the last one. @p index is an
+ * integer that increases from 0 to the number of elements. @p item is
+ * the data of each element of @p array, so it is a pointer to a type
+ * chosen by the user. @p iterator is of type #Eina_Array_Iterator.
+ *
+ * This macro can be used for freeing the data of an array, like in
+ * the following example:
+ *
+ * @code
+ * Eina_Array         *array;
+ * char               *item;
+ * Eina_Array_Iterator iterator;
+ * unsigned int        i;
+ *
+ * // array is already filled,
+ * // its elements are just duplicated strings,
+ * // EINA_ARRAY_ITER_NEXT will be used to free those strings
+ *
+ * EINA_ARRAY_ITER_NEXT(array, i, item, iterator)
+ *   free(item);
+ * @endcode
+ */
+#define EINA_ARRAY_ITER_NEXT(array, index, item, iterator)             \
+  for (index = 0, iterator = (array)->data;                            \
+       (index < eina_array_count_get(array)) && ((item = *((iterator)++))); \
+       ++(index))
+
+#include "eina_inline_array.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_benchmark.h 
b/tests/suite/ecore/src/include/eina_benchmark.h
new file mode 100644
index 0000000..e0faa72
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_benchmark.h
@@ -0,0 +1,77 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_BENCHMARK_H_
+#define EINA_BENCHMARK_H_
+
+#include "eina_array.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Benchmark_Group Benchmark
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Benchmark
+ * Type for a benchmark.
+ */
+typedef struct _Eina_Benchmark Eina_Benchmark;
+
+/**
+ * @typedef Eina_Benchmark_Specimens
+ * Type for a test function to be called when running a benchmark.
+ */
+typedef void (*Eina_Benchmark_Specimens)(int request);
+
+/**
+ * @def EINA_BENCHMARK
+ * @brief cast to an #Eina_Benchmark_Specimens.
+ *
+ * @param function The function to cast.
+ *
+ * This macro casts @p function to Eina_Benchmark_Specimens.
+ */
+#define EINA_BENCHMARK(function) ((Eina_Benchmark_Specimens)function)
+
+EAPI Eina_Benchmark * eina_benchmark_new(const char *name,
+                                         const char *run);
+EAPI void             eina_benchmark_free(Eina_Benchmark *bench);
+EAPI Eina_Bool        eina_benchmark_register(Eina_Benchmark *bench,
+                                              const char *name,
+                                              Eina_Benchmark_Specimens 
bench_cb,
+                                              int count_start,
+                                              int count_end,
+                                              int count_set);
+EAPI Eina_Array *     eina_benchmark_run(Eina_Benchmark *bench);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_BENCHMARK_H_ */
diff --git a/tests/suite/ecore/src/include/eina_binshare.h 
b/tests/suite/ecore/src/include/eina_binshare.h
new file mode 100644
index 0000000..e785ed0
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_binshare.h
@@ -0,0 +1,105 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Jorge Luis Zapata Muga, Cedric 
Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (C) 2008 Peter Wehrfritz
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a 
copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies of the Software and its Copyright notices. In addition publicly
+ *  documented acknowledgment must be given that this software has been used 
if no
+ *  source code of this software is made available publicly. This includes
+ *  acknowledgments in either Copyright notices, Manuals, Publicity and 
Marketing
+ *  documents or any documentation provided with any product containing this
+ *  software. This License does not apply to any software that links to the
+ *  libraries provided by this software (statically or dynamically), but only 
to
+ *  the software provided.
+ *
+ *  Please see the OLD-COPYING.PLAIN for a plain-english explanation of this 
notice
+ *  and it's intent.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef EINA_BINSHARE_H_
+#define EINA_BINSHARE_H_
+
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Binshare_Group Binary Share
+ *
+ * @{
+ */
+
+EAPI Eina_Bool    eina_binshare_init(void);
+EAPI Eina_Bool    eina_binshare_shutdown(void);
+EAPI const void * eina_binshare_add_length(const void *obj,
+                                          unsigned int olen) EINA_PURE 
EINA_WARN_UNUSED_RESULT;
+EAPI const void * eina_binshare_ref(const void *obj);
+EAPI void         eina_binshare_del(const void *obj);
+EAPI int          eina_binshare_length(const void *obj) 
EINA_WARN_UNUSED_RESULT;
+EAPI void         eina_binshare_dump(void);
+
+/**
+ * @brief Retrieve an instance of a blob for use in a program.
+ *
+ * @param   ptr The binary blob to retrieve an instance of.
+ * @return  A pointer to an instance of the string on success.
+ *          @c NULL on failure.
+ *
+ * This macro retrieves an instance of @p obj. If @p obj is
+ * @c NULL, then @c NULL is returned. If @p obj is already stored, it
+ * is just returned and its reference counter is increased. Otherwise
+ * it is added to the blobs to be searched and a duplicated blob
+ * of @p obj is returned.
+ *
+ * This macro essentially calls eina_binshare_add_length with ptr and 
sizeof(*ptr)
+ * as the parameters. It's useful for pointers to structures.
+ *
+ * @see eina_stringshare_add_length()
+ */
+#define eina_binshare_add(ptr) eina_binshare_add_length(ptr, sizeof(*ptr))
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_STRINGSHARE_H_ */
diff --git a/tests/suite/ecore/src/include/eina_config.h 
b/tests/suite/ecore/src/include/eina_config.h
new file mode 100644
index 0000000..f89327d
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_config.h
@@ -0,0 +1,52 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_CONFIG_H_
+#define EINA_CONFIG_H_
+
+#ifdef EINA_MAGIC_DEBUG
+# undef EINA_MAGIC_DEBUG
+#endif
+#define EINA_MAGIC_DEBUG
+
+#ifdef EINA_DEFAULT_MEMPOOL
+# undef EINA_DEFAULT_MEMPOOL
+#endif
+
+
+#ifdef EINA_SAFETY_CHECKS
+# undef EINA_SAFETY_CHECKS
+#endif
+#define EINA_SAFETY_CHECKS
+
+#ifdef EINA_HAVE_INTTYPES_H
+# undef EINA_HAVE_INTTYPES_H
+#endif
+#define EINA_HAVE_INTTYPES_H
+
+#ifdef EINA_HAVE_STDINT_H
+# undef EINA_HAVE_STDINT_H
+#endif
+#define EINA_HAVE_STDINT_H
+
+#ifdef EINA_SIZEOF_WCHAR_T
+# undef EINA_SIZEOF_WCHAR_T
+#endif
+#define EINA_SIZEOF_WCHAR_T 4
+
+#endif /* EINA_CONFIG_H_ */
diff --git a/tests/suite/ecore/src/include/eina_convert.h 
b/tests/suite/ecore/src/include/eina_convert.h
new file mode 100644
index 0000000..8cd6433
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_convert.h
@@ -0,0 +1,80 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric BAIL, Vincent Torri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_CONVERT_H_
+#define EINA_CONVERT_H_
+
+#include "eina_types.h"
+#include "eina_error.h"
+
+#include "eina_fp.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Convert_Group Convert
+ *
+ * @{
+ */
+
+/**
+ * @var EINA_ERROR_CONVERT_P_NOT_FOUND
+ * Error identifier corresponding to string not containing 'p'.
+ */
+EAPI extern Eina_Error EINA_ERROR_CONVERT_P_NOT_FOUND;
+
+/**
+ * @var EINA_ERROR_CONVERT_0X_NOT_FOUND
+ * Error identifier corresponding to string not containing '0x'.
+ */
+EAPI extern Eina_Error EINA_ERROR_CONVERT_0X_NOT_FOUND;
+
+/**
+ * @var EINA_ERROR_CONVERT_OUTRUN_STRING_LENGTH
+ * Error identifier corresponding to length of the string being too small.
+ */
+EAPI extern Eina_Error EINA_ERROR_CONVERT_OUTRUN_STRING_LENGTH;
+
+EAPI int       eina_convert_itoa(int n, char *s)  EINA_ARG_NONNULL(2);
+EAPI int       eina_convert_xtoa(unsigned int n, char *s) EINA_ARG_NONNULL(2);
+
+EAPI int       eina_convert_dtoa(double d, char *des) EINA_ARG_NONNULL(2);
+EAPI Eina_Bool eina_convert_atod(const char *src,
+                                 int length,
+                                 long long *m,
+                                 long *e) EINA_ARG_NONNULL(1,3,4);
+
+EAPI int       eina_convert_fptoa(Eina_F32p32 fp,
+                                  char *des) EINA_ARG_NONNULL(2);
+EAPI Eina_Bool eina_convert_atofp(const char *src,
+                                  int length,
+                                  Eina_F32p32 *fp) EINA_ARG_NONNULL(1,3);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_CONVERT_H_ */
diff --git a/tests/suite/ecore/src/include/eina_counter.h 
b/tests/suite/ecore/src/include/eina_counter.h
new file mode 100644
index 0000000..fc7b23f
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_counter.h
@@ -0,0 +1,57 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_COUNTER_H_
+#define EINA_COUNTER_H_
+
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Counter_Group Counter
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Counter
+ * Counter type.
+ */
+typedef struct _Eina_Counter Eina_Counter;
+
+EAPI Eina_Counter * eina_counter_new(const char *name) EINA_WARN_UNUSED_RESULT 
EINA_ARG_NONNULL(1);
+EAPI void           eina_counter_free(Eina_Counter *counter) 
EINA_ARG_NONNULL(1);
+EAPI void           eina_counter_start(Eina_Counter *counter) 
EINA_ARG_NONNULL(1);
+EAPI void           eina_counter_stop(Eina_Counter *counter,
+                                      int specimen) EINA_ARG_NONNULL(1);
+EAPI char *         eina_counter_dump(Eina_Counter *counter) 
EINA_ARG_NONNULL(1);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_COUNTER_H_ */
diff --git a/tests/suite/ecore/src/include/eina_cpu.h 
b/tests/suite/ecore/src/include/eina_cpu.h
new file mode 100644
index 0000000..ac32e1d
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_cpu.h
@@ -0,0 +1,39 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_CPU_H_
+#define EINA_CPU_H_
+
+#include "eina_types.h"
+
+typedef enum _Eina_Cpu_Features
+{
+   EINA_CPU_MMX = 0x00000001,
+   EINA_CPU_SSE = 0x00000002,
+   EINA_CPU_SSE2 = 0x00000004,
+   EINA_CPU_SSE3 = 0x00000008,
+   /* TODO 3DNow! */
+   EINA_CPU_ALTIVEC = 0x00000010,
+   EINA_CPU_VIS = 0x00000020,
+   EINA_CPU_NEON = 0x00000040,
+} Eina_Cpu_Features;
+
+EAPI Eina_Cpu_Features eina_cpu_features_get(void);
+EAPI int               eina_cpu_count(void);
+
+#endif /* EINA_CPU_H_ */
diff --git a/tests/suite/ecore/src/include/eina_error.h 
b/tests/suite/ecore/src/include/eina_error.h
new file mode 100644
index 0000000..8c74b66
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_error.h
@@ -0,0 +1,66 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_ERROR_H_
+#define EINA_ERROR_H_
+
+#include <stdarg.h>
+
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Error_Group Error
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Error
+ * Error type.
+ */
+typedef int Eina_Error;
+
+/**
+ * @var EINA_ERROR_OUT_OF_MEMORY
+ * Error identifier corresponding to a lack of memory.
+ */
+EAPI extern Eina_Error EINA_ERROR_OUT_OF_MEMORY;
+
+EAPI Eina_Error   eina_error_msg_register(const char *msg) EINA_ARG_NONNULL(1) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Error   eina_error_msg_static_register(const char *msg) 
EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool    eina_error_msg_modify(Eina_Error error,
+                                       const char *msg) EINA_ARG_NONNULL(2);
+EAPI Eina_Error   eina_error_get(void);
+EAPI void         eina_error_set(Eina_Error err);
+EAPI const char * eina_error_msg_get(Eina_Error error) EINA_PURE;
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_ERROR_H_ */
diff --git a/tests/suite/ecore/src/include/eina_file.h 
b/tests/suite/ecore/src/include/eina_file.h
new file mode 100644
index 0000000..4c3740f
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_file.h
@@ -0,0 +1,92 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_FILE_H_
+#define EINA_FILE_H_
+
+#include <limits.h>
+
+#include "eina_types.h"
+#include "eina_array.h"
+#include "eina_iterator.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_File_Group File
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_File_Direct_Info
+ * A typedef to #_Eina_File_Direct_Info.
+ */
+typedef struct _Eina_File_Direct_Info Eina_File_Direct_Info;
+
+/**
+ * @typedef Eina_File_Dir_List_Cb
+ * Type for a callback to be called when iterating over the files of a
+ * directory.
+ */
+typedef void (*Eina_File_Dir_List_Cb)(const char *name, const char *path, void 
*data);
+
+/**
+ * @struct _Eina_File_Direct_Info
+ * A structure to store informations of a path.
+ */
+struct _Eina_File_Direct_Info
+{
+   size_t path_length; /**< size of the whole path */
+   size_t name_length; /**< size of the filename/basename component */
+   size_t name_start; /**< where the filename/basename component starts */
+   char path[PATH_MAX]; /**< the path */
+   const struct dirent *dirent; /**< the dirent structure of the path */
+};
+
+/**
+ * @def EINA_FILE_DIR_LIST_CB
+ * @brief cast to an #Eina_File_Dir_List_Cb.
+ *
+ * @param function The function to cast.
+ *
+ * This macro casts @p function to Eina_File_Dir_List_Cb.
+ */
+#define EINA_FILE_DIR_LIST_CB(function) ((Eina_File_Dir_List_Cb)function)
+
+EAPI Eina_Bool       eina_file_dir_list(const char *dir,
+                                        Eina_Bool recursive,
+                                        Eina_File_Dir_List_Cb cb,
+                                        void *data) EINA_ARG_NONNULL(1, 3);
+EAPI Eina_Array *    eina_file_split(char *path) EINA_WARN_UNUSED_RESULT 
EINA_ARG_NONNULL(1) EINA_MALLOC;
+EAPI Eina_Iterator * eina_file_ls(const char *dir) EINA_WARN_UNUSED_RESULT 
EINA_ARG_NONNULL(1) EINA_MALLOC;
+EAPI Eina_Iterator * eina_file_direct_ls(const char *dir) 
EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_FILE_H_ */
diff --git a/tests/suite/ecore/src/include/eina_fp.h 
b/tests/suite/ecore/src/include/eina_fp.h
new file mode 100644
index 0000000..47dbaa4
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_fp.h
@@ -0,0 +1,111 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ * Copyright (C) 2009 Cedric BAIL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_FP_H_
+# define EINA_FP_H_
+
+#include "eina_types.h"
+
+#ifdef _MSC_VER
+typedef unsigned __int64 uint64_t;
+typedef signed __int64 int64_t;
+typedef signed int int32_t;
+#else
+# include <stdint.h>
+#endif
+
+#define EINA_F32P32_PI 0x00000003243f6a89
+
+typedef int64_t Eina_F32p32;
+typedef int32_t Eina_F16p16;
+typedef int32_t Eina_F8p24;
+
+static inline Eina_F32p32  eina_f32p32_int_from(int32_t v);
+static inline int32_t      eina_f32p32_int_to(Eina_F32p32 v);
+static inline Eina_F32p32  eina_f32p32_double_from(double v);
+static inline double       eina_f32p32_double_to(Eina_F32p32 v);
+
+static inline Eina_F32p32  eina_f32p32_add(Eina_F32p32 a,
+                                           Eina_F32p32 b);
+static inline Eina_F32p32  eina_f32p32_sub(Eina_F32p32 a,
+                                           Eina_F32p32 b);
+static inline Eina_F32p32  eina_f32p32_mul(Eina_F32p32 a,
+                                           Eina_F32p32 b);
+static inline Eina_F32p32  eina_f32p32_scale(Eina_F32p32 a,
+                                             int b);
+static inline Eina_F32p32  eina_f32p32_div(Eina_F32p32 a,
+                                           Eina_F32p32 b);
+static inline Eina_F32p32  eina_f32p32_sqrt(Eina_F32p32 a);
+static inline unsigned int eina_f32p32_fracc_get(Eina_F32p32 v);
+
+// dont use llabs - issues if not on 64bit
+#define eina_fp32p32_llabs(a) ((a < 0) ? -(a) : (a))
+
+EAPI Eina_F32p32           eina_f32p32_cos(Eina_F32p32 a);
+EAPI Eina_F32p32           eina_f32p32_sin(Eina_F32p32 a);
+
+static inline Eina_F16p16  eina_f16p16_int_from(int32_t v);
+static inline int32_t      eina_f16p16_int_to(Eina_F16p16 v);
+static inline Eina_F16p16  eina_f16p16_float_from(float v);
+static inline float        eina_f16p16_float_to(Eina_F16p16 v);
+
+static inline Eina_F16p16  eina_f16p16_add(Eina_F16p16 a,
+                                           Eina_F16p16 b);
+static inline Eina_F16p16  eina_f16p16_sub(Eina_F16p16 a,
+                                           Eina_F16p16 b);
+static inline Eina_F16p16  eina_f16p16_mul(Eina_F16p16 a,
+                                           Eina_F16p16 b);
+static inline Eina_F16p16  eina_f16p16_scale(Eina_F16p16 a,
+                                             int b);
+static inline Eina_F16p16  eina_f16p16_div(Eina_F16p16 a,
+                                           Eina_F16p16 b);
+static inline Eina_F16p16  eina_f16p16_sqrt(Eina_F16p16 a);
+static inline unsigned int eina_f16p16_fracc_get(Eina_F16p16 v);
+
+static inline Eina_F8p24   eina_f8p24_int_from(int32_t v);
+static inline int32_t      eina_f8p24_int_to(Eina_F8p24 v);
+static inline Eina_F8p24   eina_f8p24_float_from(float v);
+static inline float        eina_f8p24_float_to(Eina_F8p24 v);
+
+static inline Eina_F8p24   eina_f8p24_add(Eina_F8p24 a,
+                                          Eina_F8p24 b);
+static inline Eina_F8p24   eina_f8p24_sub(Eina_F8p24 a,
+                                          Eina_F8p24 b);
+static inline Eina_F8p24   eina_f8p24_mul(Eina_F8p24 a,
+                                          Eina_F8p24 b);
+static inline Eina_F8p24   eina_f8p24_scale(Eina_F8p24 a,
+                                            int b);
+static inline Eina_F8p24   eina_f8p24_div(Eina_F8p24 a,
+                                          Eina_F8p24 b);
+static inline Eina_F8p24   eina_f8p24_sqrt(Eina_F8p24 a);
+static inline unsigned int eina_f8p24_fracc_get(Eina_F8p24 v);
+
+static inline Eina_F32p32  eina_f16p16_to_f32p32(Eina_F16p16 a);
+static inline Eina_F32p32  eina_f8p24_to_f32p32(Eina_F8p24 a);
+static inline Eina_F16p16  eina_f32p32_to_f16p16(Eina_F32p32 a);
+static inline Eina_F16p16  eina_f8p24_to_f16p16(Eina_F8p24 a);
+static inline Eina_F8p24   eina_f32p32_to_f8p24(Eina_F32p32 a);
+static inline Eina_F8p24   eina_f16p16_to_f8p24(Eina_F16p16 a);
+
+#include "eina_inline_f32p32.x"
+#include "eina_inline_f16p16.x"
+#include "eina_inline_f8p24.x"
+#include "eina_inline_fp.x"
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_hamster.h 
b/tests/suite/ecore/src/include/eina_hamster.h
new file mode 100644
index 0000000..0818b15
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_hamster.h
@@ -0,0 +1,44 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_HAMSTER_H_
+#define EINA_HAMSTER_H_
+
+/**
+ * @addtogroup Eina_Core_Group Core
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Hamster_Group Hamster
+ *
+ * @{
+ */
+
+EAPI int eina_hamster_count(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_HAMSTER_H_ */
diff --git a/tests/suite/ecore/src/include/eina_hash.h 
b/tests/suite/ecore/src/include/eina_hash.h
new file mode 100644
index 0000000..0345133
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_hash.h
@@ -0,0 +1,168 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Gustavo Sverzut Barbieri,
+ *                         Vincent Torri, Jorge Luis Zapata Muga, Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_HASH_H_
+#define EINA_HASH_H_
+
+#include "eina_types.h"
+#include "eina_iterator.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @addtogroup Eina_Containers_Group Containers
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Hash_Group Hash Table
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Hash
+ * Type for a generic hash table.
+ */
+typedef struct _Eina_Hash Eina_Hash;
+
+typedef struct _Eina_Hash_Tuple Eina_Hash_Tuple;
+
+struct _Eina_Hash_Tuple
+{
+   const void *key; /**< The key */
+   void *data; /**< The data associated to the key */
+   unsigned int key_length; /**< The length of the key */
+};
+
+typedef unsigned int (*Eina_Key_Length)(const void *key);
+#define EINA_KEY_LENGTH(Function) ((Eina_Key_Length)Function)
+typedef int (*Eina_Key_Cmp)(const void *key1, int key1_length, const void 
*key2, int key2_length);
+#define EINA_KEY_CMP(Function) ((Eina_Key_Cmp)Function)
+typedef int (*Eina_Key_Hash)(const void *key, int key_length);
+#define EINA_KEY_HASH(Function) ((Eina_Key_Hash)Function)
+typedef Eina_Bool (*Eina_Hash_Foreach)(const Eina_Hash *hash, const void *key, 
void *data, void *fdata);
+
+EAPI Eina_Hash *     eina_hash_new(Eina_Key_Length key_length_cb,
+                                   Eina_Key_Cmp key_cmp_cb,
+                                   Eina_Key_Hash key_hash_cb,
+                                   Eina_Free_Cb data_free_cb,
+                                   int buckets_power_size) EINA_MALLOC 
EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(2, 3);
+EAPI Eina_Hash *     eina_hash_string_djb2_new(Eina_Free_Cb data_free_cb);
+EAPI Eina_Hash *     eina_hash_string_superfast_new(Eina_Free_Cb data_free_cb);
+EAPI Eina_Hash *     eina_hash_string_small_new(Eina_Free_Cb data_free_cb);
+EAPI Eina_Hash *     eina_hash_int32_new(Eina_Free_Cb data_free_cb);
+EAPI Eina_Hash *     eina_hash_int64_new(Eina_Free_Cb data_free_cb);
+EAPI Eina_Hash *     eina_hash_pointer_new(Eina_Free_Cb data_free_cb);
+EAPI Eina_Hash *     eina_hash_stringshared_new(Eina_Free_Cb data_free_cb);
+EAPI Eina_Bool       eina_hash_add(Eina_Hash *hash,
+                                   const void *key,
+                                   const void *data) EINA_ARG_NONNULL(1, 2, 3);
+EAPI Eina_Bool       eina_hash_direct_add(Eina_Hash *hash,
+                                          const void *key,
+                                          const void *data) 
EINA_ARG_NONNULL(1, 2, 3);
+EAPI Eina_Bool       eina_hash_del(Eina_Hash *hash,
+                                   const void *key,
+                                   const void *data) EINA_ARG_NONNULL(1);
+EAPI void *          eina_hash_find(const Eina_Hash *hash,
+                                    const void *key) EINA_ARG_NONNULL(1, 2);
+EAPI void *          eina_hash_modify(Eina_Hash *hash,
+                                      const void *key,
+                                      const void *data) EINA_ARG_NONNULL(1, 2, 
3);
+EAPI void *          eina_hash_set(Eina_Hash *hash,
+                                   const void *key,
+                                   const void *data) EINA_ARG_NONNULL(1, 2, 3);
+EAPI Eina_Bool       eina_hash_move(Eina_Hash *hash,
+                                    const void *old_key,
+                                    const void *new_key) EINA_ARG_NONNULL(1, 
2, 3);
+EAPI void            eina_hash_free(Eina_Hash *hash) EINA_ARG_NONNULL(1);
+EAPI void            eina_hash_free_buckets(Eina_Hash *hash) 
EINA_ARG_NONNULL(1);
+EAPI int             eina_hash_population(const Eina_Hash *hash) 
EINA_ARG_NONNULL(1);
+EAPI Eina_Bool       eina_hash_add_by_hash(Eina_Hash *hash,
+                                           const void *key,
+                                           int key_length,
+                                           int key_hash,
+                                           const void *data) 
EINA_ARG_NONNULL(1, 2, 5);
+EAPI Eina_Bool       eina_hash_direct_add_by_hash(Eina_Hash *hash,
+                                                  const void *key,
+                                                  int key_length,
+                                                  int key_hash,
+                                                  const void *data) 
EINA_ARG_NONNULL(1, 2, 5);
+EAPI Eina_Bool       eina_hash_del_by_key_hash(Eina_Hash *hash,
+                                               const void *key,
+                                               int key_length,
+                                               int key_hash) 
EINA_ARG_NONNULL(1, 2);
+EAPI Eina_Bool       eina_hash_del_by_key(Eina_Hash *hash,
+                                          const void *key) EINA_ARG_NONNULL(1, 
2);
+EAPI Eina_Bool       eina_hash_del_by_data(Eina_Hash *hash,
+                                           const void *data) 
EINA_ARG_NONNULL(1, 2);
+EAPI Eina_Bool       eina_hash_del_by_hash(Eina_Hash *hash,
+                                           const void *key,
+                                           int key_length,
+                                           int key_hash,
+                                           const void *data) 
EINA_ARG_NONNULL(1);
+EAPI void *          eina_hash_find_by_hash(const Eina_Hash *hash,
+                                            const void *key,
+                                            int key_length,
+                                            int key_hash) EINA_ARG_NONNULL(1, 
2);
+EAPI void *          eina_hash_modify_by_hash(Eina_Hash *hash,
+                                              const void *key,
+                                              int key_length,
+                                              int key_hash,
+                                              const void *data) 
EINA_ARG_NONNULL(1, 2, 5);
+EAPI Eina_Iterator * eina_hash_iterator_key_new(const Eina_Hash *hash) 
EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Iterator * eina_hash_iterator_data_new(const Eina_Hash *hash) 
EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Iterator * eina_hash_iterator_tuple_new(const Eina_Hash *hash) 
EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI void            eina_hash_foreach(const Eina_Hash *hash,
+                                       Eina_Hash_Foreach cb,
+                                       const void *fdata) EINA_ARG_NONNULL(1, 
2);
+/* Paul Hsieh (http://www.azillionmonkeys.com/qed/hash.html) hash function 
used by WebCore (http://webkit.org/blog/8/hashtables-part-2/) */
+EAPI int             eina_hash_superfast(const char *key,
+                                         int len) EINA_ARG_NONNULL(1);
+/* Hash function first reported by dan bernstein many years ago in comp.lang.c 
*/
+static inline int    eina_hash_djb2(const char *key,
+                                    int len) EINA_ARG_NONNULL(1);
+static inline int    eina_hash_djb2_len(const char *key,
+                                        int *plen) EINA_ARG_NONNULL(1, 2);
+/* Hash function from http://www.concentric.net/~Ttwang/tech/inthash.htm */
+static inline int    eina_hash_int32(const unsigned int *pkey,
+                                     int len) EINA_ARG_NONNULL(1);
+static inline int    eina_hash_int64(const unsigned long int *pkey,
+                                     int len) EINA_ARG_NONNULL(1);
+
+#include "eina_inline_hash.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /*EINA_HASH_H_*/
diff --git a/tests/suite/ecore/src/include/eina_inline_array.x 
b/tests/suite/ecore/src/include/eina_inline_array.x
new file mode 100644
index 0000000..883d728
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_array.x
@@ -0,0 +1,181 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLINE_ARRAY_X_
+#define EINA_INLINE_ARRAY_X_
+
+#include <stdio.h>
+
+/**
+ * @cond LOCAL
+ */
+
+EAPI Eina_Bool eina_array_grow(Eina_Array *array);
+
+/**
+ * @endcond
+ */
+
+/**
+ * @addtogroup Eina_Array_Group Array
+ *
+ * @brief These functions provide array management.
+ *
+ * @{
+ */
+
+/**
+ * @brief Append a data to an array.
+ *
+ * @param array The array.
+ * @param data The data to add.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function appends @p data to @p array. For performance
+ * reasons, there is no check of @p array. If it is @c NULL or
+ * invalid, the program may crash. If @p data is @c NULL, or if an
+ * allocation is necessary and fails, #EINA_FALSE is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, #EINA_TRUE is
+ * returned.
+ */
+
+static inline Eina_Bool
+eina_array_push(Eina_Array *array, const void *data)
+{
+   if (!data) return EINA_FALSE;
+
+   if (EINA_UNLIKELY((array->count + 1) > array->total))
+     if (!eina_array_grow(array))
+       return EINA_FALSE;
+
+   array->data[array->count++] = (void*) data;
+
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Remove the last data of an array.
+ *
+ * @param array The array.
+ * @return The retrieved data.
+ *
+ * This function removes the last data of @p array, decreases the count
+ * of @p array and returns the data. For performance reasons, there
+ * is no check of @p array. If it is @c NULL or invalid, the program
+ * may crash. If the count member is less or equal than 0, @c NULL is
+ * returned.
+ */
+static inline void *
+eina_array_pop(Eina_Array *array)
+{
+   void *ret = NULL;
+
+   if (array->count <= 0)
+     goto on_empty;
+
+   ret = array->data[--array->count];
+
+ on_empty:
+   return ret;
+}
+
+/**
+ * @brief Return the data at a given position in an array.
+ *
+ * @param array The array.
+ * @param idx The potition of the data to retrieve.
+ * @return The retrieved data.
+ *
+ * This function returns the data at the position @p idx in @p
+ * array. For performance reasons, there is no check of @p array or @p
+ * idx. If it is @c NULL or invalid, the program may crash.
+ */
+static inline void *
+eina_array_data_get(const Eina_Array *array, unsigned int idx)
+{
+   return array->data[idx];
+}
+
+/**
+ * @brief Set the data at a given position in an array.
+ *
+ * @param array The array.
+ * @param idx The potition of the data to set.
+ * @param data The data to set.
+ *
+ * This function sets the data at the position @p idx in @p
+ * array. For performance reasons, there is no check of @p array or @p
+ * idx. If it is @c NULL or invalid, the program may crash.
+ */
+static inline void
+eina_array_data_set(const Eina_Array *array, unsigned int idx, const void 
*data)
+{
+   array->data[idx] = (void*) data;
+}
+
+/**
+ * @brief Return the number of elements in an array.
+ *
+ * @param array The array.
+ * @return The number of elements.
+ *
+ * This function returns the number of elements in @p array. For
+ * performance reasons, there is no check of @p array. If it is
+ * @c NULL or invalid, the program may crash.
+ */
+static inline unsigned int
+eina_array_count_get(const Eina_Array *array)
+{
+   return array->count;
+}
+
+/**
+ * @brief Provide a safe way to iterate over an array
+ *
+ * @param array The array to iterate over.
+ * @param cb The callback to call for each item.
+ * @param fdata The user data to pass to the callback.
+ * @return EINA_TRUE if it successfully iterate all items of the array.
+ *
+ * This function provide a safe way to iterate over an array. @p cb should
+ * return EINA_TRUE as long as you want the function to continue iterating,
+ * by returning EINA_FALSE it will stop and return EINA_FALSE as a result.
+ */
+static inline Eina_Bool
+eina_array_foreach(Eina_Array *array, Eina_Each_Cb cb, void *fdata)
+{
+   void *data;
+   Eina_Array_Iterator iterator;
+   unsigned int i;
+   Eina_Bool ret = EINA_TRUE;
+
+   EINA_ARRAY_ITER_NEXT(array, i, data, iterator)
+     if (cb(array, data, fdata) != EINA_TRUE)
+       {
+         ret = EINA_FALSE;
+         break;
+       }
+
+   return ret;
+}
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_f16p16.x 
b/tests/suite/ecore/src/include/eina_inline_f16p16.x
new file mode 100644
index 0000000..e16d188
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_f16p16.x
@@ -0,0 +1,83 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ * Copyright (C) 2009 Cedric BAIL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLINE_F16P16_X_
+#define EINA_INLINE_F16P16_X_
+
+static inline Eina_F16p16
+eina_f16p16_add(Eina_F16p16 a, Eina_F16p16 b)
+{
+   return a + b;
+}
+
+static inline Eina_F16p16
+eina_f16p16_sub(Eina_F16p16 a, Eina_F16p16 b)
+{
+   return a - b;
+}
+
+static inline Eina_F16p16
+eina_f16p16_mul(Eina_F16p16 a, Eina_F16p16 b)
+{
+   return (Eina_F16p16)(((int64_t)a * (int64_t)b) >> 16);
+}
+
+static inline Eina_F16p16
+eina_f16p16_scale(Eina_F16p16 a, int b)
+{
+   return a * b;
+}
+
+static inline Eina_F16p16
+eina_f16p16_div(Eina_F16p16 a, Eina_F16p16 b)
+{
+   return (Eina_F16p16) ((((int64_t) a) << 16) / (int64_t) b);
+}
+
+static inline Eina_F16p16
+eina_f16p16_sqrt(Eina_F16p16 a)
+{
+   unsigned int root, remHi, remLo, testDiv, count;
+
+   root = 0; /* Clear root */
+   remHi = 0; /* Clear high part of partial remainder */
+   remLo = a; /* Get argument into low part of partial remainder */
+   count = (15 + (16 >> 1)); /* Load loop counter */
+   do {
+      remHi = (remHi << 2) | (remLo >> 30);
+      remLo <<= 2; /* get 2 bits of arg */
+      root <<= 1; /* Get ready for the next bit in the root */
+      testDiv = (root << 1) + 1; /* Test radical */
+      if (remHi >= testDiv)
+       {
+          remHi -= testDiv;
+          root++;
+       }
+   } while (count-- != 0);
+
+   return root;
+}
+
+static inline unsigned int
+eina_f16p16_fracc_get(Eina_F16p16 v)
+{
+   return (v & 0xffff);
+}
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_f32p32.x 
b/tests/suite/ecore/src/include/eina_inline_f32p32.x
new file mode 100644
index 0000000..73480de
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_f32p32.x
@@ -0,0 +1,110 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2009 Jorge Luis Zapata Muga, Cedric BAIL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLINE_F32P32_X_
+# define EINA_INLINE_F32P32_X_
+
+#include <stdlib.h>
+
+static inline Eina_F32p32
+eina_f32p32_add(Eina_F32p32 a, Eina_F32p32 b)
+{
+   return a + b;
+}
+
+static inline Eina_F32p32
+eina_f32p32_sub(Eina_F32p32 a, Eina_F32p32 b)
+{
+   return a - b;
+}
+
+static inline Eina_F32p32
+eina_f32p32_mul(Eina_F32p32 a, Eina_F32p32 b)
+{
+   /* Prevent overflow and do '(a * b) >> 32' */
+   /* Basically do: Eina_F16p16 * Eina_F16p16 = Eina_F32p32 */
+   Eina_F32p32 up;
+   Eina_F32p32 down;
+   Eina_F32p32 result;
+   uint64_t as, bs;
+   Eina_F32p32 sign;
+
+   sign = a ^ b;
+   as = eina_fp32p32_llabs(a);
+   bs = eina_fp32p32_llabs(b);
+
+   up = (as >> 16) * (bs >> 16);
+   down = (as & 0xFFFF) * (bs & 0xFFFF);
+
+   result = up + (down >> 32);
+
+   return sign < 0 ? - result : result;
+}
+
+static inline Eina_F32p32
+eina_f32p32_scale(Eina_F32p32 a, int b)
+{
+   return a * b;
+}
+
+static inline Eina_F32p32
+eina_f32p32_div(Eina_F32p32 a, Eina_F32p32 b)
+{
+   Eina_F32p32 sign;
+   Eina_F32p32 result;
+
+   sign = a ^ b;
+
+   if (b == 0)
+     return sign < 0 ? (Eina_F32p32) 0x8000000000000000ull : (Eina_F32p32) 
0x7FFFFFFFFFFFFFFFull;
+
+   result = (eina_f32p32_mul(eina_fp32p32_llabs(a),  (((uint64_t) 1 << 62) / 
((uint64_t)(eina_fp32p32_llabs(b)) >> 2))));
+
+   return sign < 0 ? - result : result;
+}
+
+static inline Eina_F32p32
+eina_f32p32_sqrt(Eina_F32p32 a)
+{
+   uint64_t root, remHi, remLo, testDiv, count;
+
+   root = 0; /* Clear root */
+   remHi = 0; /* Clear high part of partial remainder */
+   remLo = a; /* Get argument into low part of partial remainder */
+   count = (31 + (32 >> 1)); /* Load loop counter */
+   do {
+      remHi = (remHi << 2) | (remLo >> 30);
+      remLo <<= 2; /* get 2 bits of arg */
+      root <<= 1; /* Get ready for the next bit in the root */
+      testDiv = (root << 1) + 1; /* Test radical */
+      if (remHi >= testDiv) {
+        remHi -= testDiv;
+        root++;
+      }
+   } while (count-- != 0);
+
+   return root;
+}
+
+static inline unsigned int
+eina_f32p32_fracc_get(Eina_F32p32 v)
+{
+   return (unsigned int)v;
+}
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_f8p24.x 
b/tests/suite/ecore/src/include/eina_inline_f8p24.x
new file mode 100644
index 0000000..f80bf61
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_f8p24.x
@@ -0,0 +1,82 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ * Copyright (C) 2009 Cedric BAIL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLINE_F8P24_X_
+#define EINA_INLINE_F8P24_X_
+
+static inline Eina_F8p24
+eina_f8p24_add(Eina_F8p24 a, Eina_F8p24 b)
+{
+   return a + b;
+}
+
+static inline Eina_F8p24
+eina_f8p24_sub(Eina_F8p24 a, Eina_F8p24 b)
+{
+   return a - b;
+}
+
+static inline Eina_F8p24
+eina_f8p24_mul(Eina_F8p24 a, Eina_F8p24 b)
+{
+   return (Eina_F8p24)(((int64_t) a * (int64_t) b) >> 24);
+}
+
+static inline Eina_F8p24
+eina_f8p24_scale(Eina_F8p24 a, int b)
+{
+   return a * b;
+}
+
+static inline Eina_F8p24
+eina_f8p24_div(Eina_F8p24 a, Eina_F8p24 b)
+{
+   return (Eina_F8p24) ((((int64_t) a) << 24) / (int64_t) b);
+}
+
+static inline Eina_F8p24
+eina_f8p24_sqrt(Eina_F8p24 a)
+{
+   unsigned int root, remHi, remLo, testDiv, count;
+
+   root = 0; /* Clear root */
+   remHi = 0; /* Clear high part of partial remainder */
+   remLo = a; /* Get argument into low part of partial remainder */
+   count = (23 + (24 >> 1)); /* Load loop counter */
+   do {
+      remHi = (remHi << 2) | (remLo >> 30);
+      remLo <<= 2; /* get 2 bits of arg */
+      root <<= 1; /* Get ready for the next bit in the root */
+      testDiv = (root << 1) + 1; /* Test radical */
+      if (remHi >= testDiv)
+       {
+          remHi -= testDiv;
+          root++;
+       }
+   } while (count-- != 0);
+   return (root);
+}
+
+static inline unsigned int
+eina_f8p24_fracc_get(Eina_F8p24 v)
+{
+   return (v & 0xffffff);
+}
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_fp.x 
b/tests/suite/ecore/src/include/eina_inline_fp.x
new file mode 100644
index 0000000..de44123
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_fp.x
@@ -0,0 +1,153 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ * Copyright (C) 2009 Cedric BAIL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLINE_FP_X_
+# define EINA_INLINE_FP_X_
+
+static inline Eina_F32p32
+eina_f32p32_int_from(int32_t v)
+{
+   return (Eina_F32p32)(v) << 32;
+}
+
+static inline int32_t
+eina_f32p32_int_to(Eina_F32p32 v)
+{
+   return (int32_t)(v >> 32);
+}
+
+static inline Eina_F32p32
+eina_f32p32_double_from(double v)
+{
+   Eina_F32p32 r;
+   r = (Eina_F32p32)(v * 4294967296.0 + (v < 0 ? -0.5 : 0.5));
+   return r;
+}
+
+static inline double
+eina_f32p32_double_to(Eina_F32p32 v)
+{
+   double r;
+   r = v / 4294967296.0;
+   return r;
+}
+
+
+
+static inline Eina_F16p16
+eina_f16p16_int_from(int32_t v)
+{
+   return v << 16;
+}
+
+static inline int32_t
+eina_f16p16_int_to(Eina_F16p16 v)
+{
+   return v >> 16;
+}
+
+static inline Eina_F16p16
+eina_f16p16_float_from(float v)
+{
+   Eina_F16p16 r;
+
+   r = (Eina_F16p16)(v * 65536.0f + (v < 0 ? -0.5f : 0.5f));
+   return r;
+}
+
+static inline float
+eina_f16p16_float_to(Eina_F16p16 v)
+{
+   float r;
+
+   r = v / 65536.0f;
+   return r;
+}
+
+
+
+static inline Eina_F8p24
+eina_f8p24_int_from(int32_t v)
+{
+   return v << 24;
+}
+
+static inline int32_t
+eina_f8p24_int_to(Eina_F8p24 v)
+{
+   return v >> 24;
+}
+
+static inline Eina_F8p24
+eina_f8p24_float_from(float v)
+{
+   Eina_F8p24 r;
+
+   r = (Eina_F8p24)(v * 16777216.0f + (v < 0 ? -0.5f : 0.5f));
+   return r;
+}
+
+static inline float
+eina_f8p24_float_to(Eina_F8p24 v)
+{
+   float r;
+
+   r = v / 16777216.0f;
+   return r;
+}
+
+
+
+static inline Eina_F32p32
+eina_f16p16_to_f32p32(Eina_F16p16 a)
+{
+   return ((Eina_F32p32) a) << 16;
+}
+
+static inline Eina_F32p32
+eina_f8p24_to_f32p32(Eina_F8p24 a)
+{
+   return ((Eina_F32p32) a) << 8;
+}
+
+static inline Eina_F16p16
+eina_f32p32_to_f16p16(Eina_F32p32 a)
+{
+   return (Eina_F16p16) (a >> 16);
+}
+
+static inline Eina_F16p16
+eina_f8p24_to_f16p16(Eina_F8p24 a)
+{
+   return (Eina_F16p16) (a >> 8);
+}
+
+static inline Eina_F8p24
+eina_f32p32_to_f8p24(Eina_F32p32 a)
+{
+   return (Eina_F8p24) (a >> 8);
+}
+
+static inline Eina_F8p24
+eina_f16p16_to_f8p24(Eina_F16p16 a)
+{
+   return (Eina_F8p24) (a << 8);
+}
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_hash.x 
b/tests/suite/ecore/src/include/eina_inline_hash.x
new file mode 100644
index 0000000..8aa7bec
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_hash.x
@@ -0,0 +1,88 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLINE_HASH_X_
+#define EINA_INLINE_HASH_X_
+
+/*
+  djb2 hash algorithm was first reported by dan bernstein, and was the old
+  default hash function for evas.
+ */
+static inline int
+eina_hash_djb2(const char *key, int len)
+{
+   unsigned int hash_num = 5381;
+   const unsigned char *ptr;
+
+   if (!key) return 0;
+   for (ptr = (unsigned char *)key; len; ptr++, len--)
+     hash_num = ((hash_num << 5) + hash_num) ^ *ptr; /* hash * 33 ^ c */
+
+   return (int)hash_num;
+}
+
+static inline int
+eina_hash_djb2_len(const char *key, int *plen)
+{
+   unsigned int hash_num = 5381;
+   int len = 0;
+   const unsigned char *ptr;
+
+   if (!key) return 0;
+
+   for (ptr = (unsigned char *)key; *ptr; ptr++, len++)
+     hash_num = ((hash_num << 5) + hash_num) ^ *ptr; /* hash * 33 ^ c */
+
+   *plen = len + 1;
+
+   return (int)hash_num;
+}
+
+static inline int
+eina_hash_int32(const unsigned int *pkey, int len)
+{
+  unsigned int key = *pkey;
+
+  (void) len;
+
+  key = ~key + (key << 15);
+  key = key ^ (key >> 12);
+  key = key + (key << 2);
+  key = key ^ (key >> 4);
+  key = key * 2057;
+  key = key ^ (key >> 16);
+  return key;
+}
+
+static inline int
+eina_hash_int64(const unsigned long int *pkey, int len)
+{
+  unsigned long int key = *pkey;
+
+  (void) len;
+
+  key = (~key) + (key << 18);
+  key = key ^ (key >> 31);
+  key = key * 21;
+  key = key ^ (key >> 11);
+  key = key + (key << 6);
+  key = key ^ (key >> 22);
+  return (int) key;
+}
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_list.x 
b/tests/suite/ecore/src/include/eina_inline_list.x
new file mode 100644
index 0000000..8325370
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_list.x
@@ -0,0 +1,145 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Vincent Torri, Jorge Luis Zapata 
Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_LIST_INLINE_H_
+#define EINA_LIST_INLINE_H_
+
+/**
+ * @addtogroup Eina_List_Group List
+ *
+ * @brief These functions provide list management.
+ *
+ * @{
+ */
+
+/**
+ * @brief Get the last list node in the list.
+ *
+ * @param list The list to get the last list node from.
+ * @return The last list node in the list.
+ *
+ * This function returns the last list node in the list @p list. If
+ * @p list is @c NULL or empty, @c NULL is returned.
+ *
+ * This is a order-1 operation (it takes the same short time
+ * regardless of the length of the list).
+ */
+static inline Eina_List *
+eina_list_last(const Eina_List *list)
+{
+   if (!list) return NULL;
+   return list->accounting->last;
+}
+
+/**
+ * @brief Get the next list node after the specified list node.
+ *
+ * @param list The list node to get the next list node from
+ * @return The next list node on success, @c NULL otherwise.
+ *
+ * This function returns the next list node after the current one in
+ * @p list. It is equivalent to list->next. If @p list is @c NULL or
+ * if no next list node exists, it returns @c NULL.
+ */
+static inline Eina_List *
+eina_list_next(const Eina_List *list)
+{
+   if (!list) return NULL;
+   return list->next;
+}
+
+/**
+ * @brief Get the previous list node before the specified list node.
+ *
+ * @param list The list node to get the previous list node from.
+ * @return The previous list node o success, @c NULL otherwise.
+ * if no previous list node exists
+ *
+ * This function returns the previous list node before the current one
+ * in @p list. It is equivalent to list->prev. If @p list is @c NULL or
+ * if no previous list node exists, it returns @c NULL.
+ */
+static inline Eina_List *
+eina_list_prev(const Eina_List *list)
+{
+   if (!list) return NULL;
+   return list->prev;
+}
+
+/**
+ * @brief Get the list node data member.
+ *
+ * @param list The list node to get the data member of.
+ * @return The data member from the list node.
+ *
+ * This function returns the data member of the specified list node @p
+ * list. It is equivalent to list->data. If @p list is @c NULL, this
+ * function returns @c NULL.
+ */
+static inline void *
+eina_list_data_get(const Eina_List *list)
+{
+   if (!list) return NULL;
+   return list->data;
+}
+
+/**
+ * @brief Set the list node data member.
+ *
+ * @param list The list node to get the data member of.
+ * @param data The data member to the list node.
+ * @return The previous data value.
+ *
+ * This function set the data member @p data of the specified list node
+ * @p list. It returns the previous data of the node. If @p list is
+ * @c NULL, this function returns @c NULL.
+ */
+static inline void *
+eina_list_data_set(Eina_List *list, const void *data)
+{
+   void *tmp;
+   if (!list) return NULL;
+   tmp = list->data;
+   list->data = (void*) data;
+   return tmp;
+}
+
+/**
+ * @brief Get the count of the number of items in a list.
+ *
+ * @param list The list whose count to return.
+ * @return The number of members in the list.
+ *
+ * This function returns how many members @p list contains. If the
+ * list is @c NULL, 0 is returned.
+ *
+ * NB: This is an order-1 operation and takes the same time regardless
+ * of the length of the list.
+ */
+static inline unsigned int
+eina_list_count(const Eina_List *list)
+{
+   if (!list) return 0;
+   return list->accounting->count;
+}
+
+/**
+ * @}
+ */
+
+#endif /* EINA_LIST_INLINE_H_ */
diff --git a/tests/suite/ecore/src/include/eina_inline_log.x 
b/tests/suite/ecore/src/include/eina_inline_log.x
new file mode 100644
index 0000000..4cdd7d8
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_log.x
@@ -0,0 +1,197 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Gustavo Sverzut Barbieri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_LOG_INLINE_H_
+#define EINA_LOG_INLINE_H_
+
+/**
+ * @addtogroup Eina_Log_Group Log
+ *
+ * @{
+ */
+
+/**
+ * Checks whenever the given level should be printed out.
+ *
+ * This is useful to enable certain blocks of code just when given
+ * level is to be used.
+ *
+ * @code
+ * #include <Eina.h>
+ *
+ * void my_func(void *data)
+ * {
+ *    if (eina_log_level_check(EINA_LOG_LEVEL_WARN))
+ *       expensive_debugging_code(data);
+ *
+ *    my_func_code(data);
+ * }
+ * @endcode
+ *
+ * @return #EINA_TRUE if level is equal or smaller than the current global
+ *         logging level.
+ */
+static inline Eina_Bool
+eina_log_level_check(int level)
+{
+   return eina_log_level_get() <= level;
+}
+
+/**
+ * Checks whenever the given level should be printed out.
+ *
+ * This is useful to enable certain blocks of code just when given
+ * level is to be used.
+ *
+ * @code
+ * #include <Eina.h>
+ *
+ * extern int _my_log_dom;
+ *
+ * void my_func(void *data)
+ * {
+ *    if (eina_log_domain_level_check(_my_log_dom, EINA_LOG_LEVEL_WARN))
+ *       expensive_debugging_code(data);
+ *
+ *    my_func_code(data);
+ * }
+ * @endcode
+ *
+ * @return #EINA_TRUE if level is equal or smaller than the current
+ *         domain logging level.
+ */
+static inline Eina_Bool
+eina_log_domain_level_check(int domain, int level)
+{
+   int dom_level = eina_log_domain_registered_level_get(domain);
+   if (EINA_UNLIKELY(dom_level == EINA_LOG_LEVEL_UNKNOWN))
+     return EINA_FALSE;
+   return dom_level <= level;
+}
+
+/**
+ * Function to format the level as a 3 character (+1 null byte) string.
+ *
+ * This function converts the given level to a known string name (CRI,
+ * ERR, WRN, INF or DBG) or a zero-padded 3-character string. In any
+ * case the last byte will contain a trailing null byte.
+ *
+ * If extreme level values are used (greater than 999 and smaller than
+ * -99), then the value will just consider the less significant
+ * part. This is so uncommon that users should handle this in their
+ * code.
+ *
+ * @param level what level value to use.
+ * @param name where to write the actual value.
+ *
+ * @return pointer to @p name.
+ */
+static inline const char *
+eina_log_level_name_get(int level, char name[4])
+{
+#define BCPY(A, B, C) \
+   do { name[0] = A; name[1] = B; name[2] = C; } while (0)
+
+   if (EINA_UNLIKELY(level < 0))
+     {
+       name[0] = '-';
+       name[1] = '0' + (-level / 10) % 10;
+       name[2] = '0' + (-level % 10);
+     }
+   else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
+     {
+       name[0] = '0' + (level / 100) % 10;
+       name[1] = '0' + (level / 10) % 10;
+       name[2] = '0' + level % 10;
+     }
+   else if (level == 0)
+     BCPY('C', 'R', 'I');
+   else if (level == 1)
+     BCPY('E', 'R', 'R');
+   else if (level == 2)
+     BCPY('W', 'R', 'N');
+   else if (level == 3)
+     BCPY('I', 'N', 'F');
+   else if (level == 4)
+     BCPY('D', 'B', 'G');
+   else
+     BCPY('?', '?', '?');
+
+   name[3] = '\0';
+
+   return name;
+}
+
+/**
+ * Function to get recommended color value for level.
+ *
+ * This function will not check if colors are enabled or not before
+ * returning the level color. If you desire such check, use
+ * eina_log_level_color_if_enabled_get().
+ *
+ * @param level what level value to use.
+ *
+ * @return pointer to null byte terminated ANSI color string to be
+ *         used in virtual terminals supporting VT100 color codes.
+ *
+ * @see eina_log_level_color_if_enabled_get()
+ */
+static inline const char *
+eina_log_level_color_get(int level)
+{
+   if (level <= 0)
+     return EINA_COLOR_LIGHTRED;
+   else if (level == 1)
+     return EINA_COLOR_RED;
+   else if (level == 2)
+     return EINA_COLOR_YELLOW;
+   else if (level == 3)
+     return EINA_COLOR_GREEN;
+   else if (level == 4)
+     return EINA_COLOR_LIGHTBLUE;
+   else
+     return EINA_COLOR_BLUE;
+}
+
+/**
+ * Function to get recommended color value for level, if colors are
+ * enabled.
+ *
+ * This function will check if colors are enabled or not before
+ * returning the level color. If colors are disabled, then empty
+ * string is returned.
+ *
+ * @param level what level value to use.
+ *
+ * @return pointer to null byte terminated ANSI color string to be
+ *         used in virtual terminals supporting VT100 color codes. If
+ *         colors are disabled, the empty string is returned.
+ */
+static inline const char *
+eina_log_level_color_if_enabled_get(int level)
+{
+   if (eina_log_color_disable_get())
+     return "";
+   return eina_log_level_color_get(level);
+}
+
+/**
+ * @}
+ */
+
+#endif /* EINA_LOG_INLINE_H_ */
diff --git a/tests/suite/ecore/src/include/eina_inline_mempool.x 
b/tests/suite/ecore/src/include/eina_inline_mempool.x
new file mode 100644
index 0000000..3f44b90
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_mempool.x
@@ -0,0 +1,105 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLINE_MEMPOOL_X_
+#define EINA_INLINE_MEMPOOL_X_
+
+/**
+ * @addtogroup Eina_Memory_Pool_Group Memory Pool
+ *
+ * @{
+ */
+
+/* Memory Pool */
+struct _Eina_Mempool_Backend
+{
+   const char *name;
+   void *(*init)(const char *context, const char *options, va_list args);
+   void (*free)(void *data, void *element);
+   void *(*alloc)(void *data, unsigned int size);
+   void *(*realloc)(void *data, void *element, unsigned int size);
+   void (*garbage_collect)(void *data);
+   void (*statistics)(void *data);
+   void (*shutdown)(void *data);
+};
+
+struct _Eina_Mempool
+{
+   Eina_Mempool_Backend backend;
+   void *backend_data;
+};
+
+/**
+ * @brief Re-allocate a amount memory by the given mempool.
+ *
+ * @param mp The mempool.
+ * @param element The element to re-allocate.
+ * @param size The size in bytes to re-allocate.
+ * @return The newly re-allocated data.
+ *
+ * This function re-allocates @p element with @p size bytes, using the
+ * mempool @p mp and returns the allocated data. If not used anymore,
+ * the data must be freed with eina_mempool_free(). No check is done
+ * on @p mp, so it must be a valid mempool.
+ */
+static inline void *
+eina_mempool_realloc(Eina_Mempool *mp, void *element, unsigned int size)
+{
+   return mp->backend.realloc(mp->backend_data, element, size);
+}
+
+/**
+ * @brief Allocate a amount memory by the given mempool.
+ *
+ * @param mp The mempool.
+ * @param size The size in bytes to allocate.
+ * @return The newly allocated data.
+ *
+ * This function allocates @p size bytes, using the mempool @p mp and
+ * returns the allocated data. If not used anymore, the data must be
+ * freed with eina_mempool_free(). No check is done on @p mp, so it
+ * must be a valid mempool.
+ */
+static inline void *
+eina_mempool_malloc(Eina_Mempool *mp, unsigned int size)
+{
+   return mp->backend.alloc(mp->backend_data, size);
+}
+
+/**
+ * @brief Free the allocated ressources by the given mempool.
+ *
+ * @param mp The mempool.
+ * @param element The data to free.
+ *
+ * This function frees @p element allocated by @p mp. @p element must
+ * have been obtained by eina_mempool_malloc() or
+ * eina_mempool_realloc(). No check is done on @p mp, so it must be a
+ * valid mempool.
+ */
+static inline void
+eina_mempool_free(Eina_Mempool *mp, void *element)
+{
+   mp->backend.free(mp->backend_data, element);
+}
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_rbtree.x 
b/tests/suite/ecore/src/include/eina_inline_rbtree.x
new file mode 100644
index 0000000..954774b
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_rbtree.x
@@ -0,0 +1,50 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Cedric BAIL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_RBTREE_INLINE_H_
+#define EINA_RBTREE_INLINE_H_
+
+/**
+ * @addtogroup Eina_Rbtree_Group Red-Black tree
+ *
+ * @brief These functions provide Red-Black trees management.
+ *
+ * @{
+ */
+
+static inline Eina_Rbtree *
+eina_rbtree_inline_lookup(const Eina_Rbtree *root, const void *key, int 
length, Eina_Rbtree_Cmp_Key_Cb cmp, const void *data)
+{
+   int result;
+
+   while (root)
+     {
+        result = cmp(root, key, length, (void*) data);
+        if (result == 0) return (Eina_Rbtree*) root;
+
+        root = root->son[result < 0 ? 0 : 1];
+     }
+
+   return NULL;
+}
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_rectangle.x 
b/tests/suite/ecore/src/include/eina_inline_rectangle.x
new file mode 100644
index 0000000..29ad24b
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_rectangle.x
@@ -0,0 +1,254 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLINE_RECTANGLE_H__
+#define EINA_INLINE_RECTANGLE_H__
+
+/**
+ * @addtogroup Eina_Rectangle_Group Rectangle
+ *
+ * @brief These functions provide rectangle management.
+ *
+ * @{
+ */
+
+/**
+ * @brief Check if the given spans intersect.
+ *
+ * @param c1 The column of the first span.
+ * @param l1 The length of the first span.
+ * @param c2 The column of the second span.
+ * @param l2 The length of the second span.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function returns #EINA_TRUE if the  given spans intersect,
+ * #EINA_FALSE otherwise.
+ */
+static inline int
+eina_spans_intersect(int c1, int l1, int c2, int l2)
+{
+       return (!(((c2 + l2) <= c1) || (c2 >= (c1 + l1))));
+}
+
+/**
+ * @brief Check if the given rectangle is empty.
+ *
+ * @param r The rectangle to check.
+ * @return #EINA_TRUE if the rectangle is empty, #EINA_FALSE otherwise.
+ *
+ * This function returns #EINA_TRUE if @p r is empty, #EINA_FALSE
+ * otherwise. No check is done on @p r, so it must be a valid
+ * rectangle.
+ */
+static inline Eina_Bool
+eina_rectangle_is_empty(const Eina_Rectangle *r)
+{
+       return ((r->w < 1) || (r->h < 1)) ? EINA_TRUE : EINA_FALSE;
+}
+
+/**
+ * @brief Set the coordinates and size of the given rectangle.
+ *
+ * @param r The rectangle.
+ * @param x The top-left x coordinate of the rectangle.
+ * @param y The top-left y coordinate of the rectangle.
+ * @param w The width of the rectangle.
+ * @param h The height of the rectangle.
+ *
+ * This function sets its top-left x coordinate to @p x, its top-left
+ * y coordinate to @p y, its width to @p w and its height to @p h. No
+ * check is done on @p r, so it must be a valid rectangle.
+ */
+static inline void
+eina_rectangle_coords_from(Eina_Rectangle *r, int x, int y, int w, int h)
+{
+       r->x = x;
+       r->y = y;
+       r->w = w;
+       r->h = h;
+}
+
+/**
+ * @brief Check if the given rectangles intersect.
+ *
+ * @param r1 The first rectangle.
+ * @param r2 The second rectangle.
+ * @return #EINA_TRUE if the rectangles intersect, #EINA_FALSE otherwise.
+ *
+ * This function returns #EINA_TRUE if @p r1 and @p r2 intersect,
+ * #EINA_FALSE otherwise. No check is done on @p r1 and @p r2, so they
+ * must be valid rectangles.
+ */
+static inline Eina_Bool
+eina_rectangles_intersect(const Eina_Rectangle *r1, const Eina_Rectangle *r2)
+{
+       return (eina_spans_intersect(r1->x, r1->w, r2->x, r2->w) && 
eina_spans_intersect(r1->y, r1->h, r2->y, r2->h)) ? EINA_TRUE : EINA_FALSE;
+}
+
+/**
+ * @brief Check if the given x-coordinate is in the rectangle .
+ *
+ * @param r The rectangle.
+ * @param x The x coordinate.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function returns #EINA_TRUE if @p x is in @p r with respect to
+ * the horizontal direction, #EINA_FALSE otherwise. No check is done
+ * on @p r, so it must be a valid rectangle.
+ */
+static inline Eina_Bool
+eina_rectangle_xcoord_inside(const Eina_Rectangle *r, int x)
+{
+       return ((x >= r->x) && (x < (r->x + r->w))) ? EINA_TRUE : EINA_FALSE;
+}
+
+/**
+ * @brief Check if the given y-coordinate is in the rectangle .
+ *
+ * @param r The rectangle.
+ * @param y The y coordinate.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function returns #EINA_TRUE if @p y is in @p r with respect to
+ * the vertical direction, #EINA_FALSE otherwise. No check is done
+ * on @p r, so it must be a valid rectangle.
+ */
+static inline Eina_Bool
+eina_rectangle_ycoord_inside(const Eina_Rectangle *r, int y)
+{
+       return ((y >= r->y) && (y < (r->y + r->h))) ? EINA_TRUE : EINA_FALSE;
+}
+
+/**
+ * @brief Check if the given point is in the rectangle .
+ *
+ * @param r The rectangle.
+ * @param x The x coordinate of the point.
+ * @param y The y coordinate of the point.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function returns #EINA_TRUE if the point of coordinate (@p x,
+ * @p y) is in @p r, #EINA_FALSE otherwise. No check is done on @p r,
+ * so it must be a valid rectangle.
+ */
+static inline Eina_Bool
+eina_rectangle_coords_inside(const Eina_Rectangle *r, int x, int y)
+{
+       return (eina_rectangle_xcoord_inside(r, x) && 
eina_rectangle_ycoord_inside(r, y)) ? EINA_TRUE : EINA_FALSE;
+}
+
+/**
+ * @brief Get the union of two rectangles.
+ *
+ * @param dst The first rectangle.
+ * @param src The second rectangle.
+ *
+ * This function get the union of the rectangles @p dst and @p src. The
+ * result is stored in @p dst. No check is done on @p dst or @p src,
+ * so they must be valid rectangles.
+ */
+static inline void
+eina_rectangle_union(Eina_Rectangle *dst, const Eina_Rectangle *src)
+{
+       /* left */
+       if (dst->x > src->x)
+       {
+               dst->w += dst->x - src->x;
+               dst->x = src->x;
+       }
+       /* right */
+       if ((dst->x + dst->w) < (src->x + src->w))
+               dst->w = src->x + src->w;
+       /* top */
+       if (dst->y > src->y)
+       {
+               dst->h += dst->y - src->y;
+               dst->y = src->y;
+       }
+       /* bottom */
+       if ((dst->y + dst->h) < (src->y + src->h))
+               dst->h = src->y + src->h;
+}
+
+/**
+ * @brief Get the intersection of two rectangles.
+ *
+ * @param dst The first rectangle.
+ * @param src The second rectangle.
+ * @return #EINA_TRUE if the rectangles intersect, #EINA_FALSE
+ * otherwise.
+ *
+ * This function get the intersection of the rectangles @p dst and
+ * @p src. The result is stored in @p dst. No check is done on @p dst
+ * or @p src, so they must be valid rectangles.
+ */
+static inline Eina_Bool
+eina_rectangle_intersection(Eina_Rectangle *dst, const Eina_Rectangle *src)
+{
+       if (!(eina_rectangles_intersect(dst, src)))
+               return EINA_FALSE;
+
+       /* left */
+       if (dst->x < src->x)
+       {
+               dst->w += dst->x - src->x;
+               dst->x = src->x;
+               if (dst->w < 0)
+                       dst->w = 0;
+       }
+       /* right */
+       if ((dst->x + dst->w) > (src->x + src->w))
+               dst->w = src->x + src->w - dst->x;
+       /* top */
+       if (dst->y < src->y)
+       {
+               dst->h += dst->y - src->y;
+               dst->y = src->y;
+               if (dst->h < 0)
+                       dst->h = 0;
+       }
+       /* bottom */
+       if ((dst->y + dst->h) > (src->y + src->h))
+               dst->h = src->y + src->h - dst->y;
+
+       return EINA_TRUE;
+}
+
+static inline void
+eina_rectangle_rescale_in(const Eina_Rectangle *out, const Eina_Rectangle *in, 
Eina_Rectangle *res)
+{
+       res->x = in->x - out->x;
+       res->y = in->y - out->y;
+       res->w = in->w;
+       res->h = in->h;
+}
+
+static inline void
+eina_rectangle_rescale_out(const Eina_Rectangle *out, const Eina_Rectangle 
*in, Eina_Rectangle *res)
+{
+       res->x = out->x + in->x;
+       res->y = out->y + in->y;
+       res->w = out->w;
+       res->h = out->h;
+}
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_str.x 
b/tests/suite/ecore/src/include/eina_inline_str.x
new file mode 100644
index 0000000..2daeb85
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_str.x
@@ -0,0 +1,76 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Gustavo Sverzut Barbieri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_STR_INLINE_H_
+#define EINA_STR_INLINE_H_
+
+/**
+ * @addtogroup Eina_String_Group String
+ *
+ * @{
+ */
+
+/**
+ * @brief Count up to a given amount of bytes of the given string.
+ *
+ * @param str The string pointer.
+ * @param maxlen The maximum length to allow.
+ * @return the string size or (size_t)-1 if greater than @a maxlen.
+ *
+ * This function returns the size of @p str, up to @p maxlen
+ * characters. It avoid needless iterations after that size. @p str
+ * must be a valid pointer and MUST not be @c NULL, otherwise this
+ * function will crash. This function returns the string size, or
+ * (size_t)-1 if the size is greater than @a maxlen.
+ */
+static inline size_t
+eina_strlen_bounded(const char *str, size_t maxlen)
+{
+   const char *itr, *str_maxend = str + maxlen;
+   for (itr = str; *itr != '\0'; itr++)
+     if (itr == str_maxend) return (size_t)-1;
+   return itr - str;
+}
+
+/**
+ * @brief Join two strings of known length.
+ *
+ * @param dst The buffer to store the result.
+ * @param size Size (in byte) of the buffer.
+ * @param sep The separator character to use.
+ * @param a First string to use, before @p sep.
+ * @param b Second string to use, after @p sep.
+ * @return The number of characters printed.
+ *
+ * This function is similar to eina_str_join_len(), but will compute
+ * the length of @p a  and @p b using strlen().
+ *
+ * @see eina_str_join_len()
+ * @see eina_str_join_static()
+ */
+static inline size_t
+eina_str_join(char *dst, size_t size, char sep, const char *a, const char *b)
+{
+   return eina_str_join_len(dst, size, sep, a, strlen(a), b, strlen(b));
+}
+
+/**
+ * @}
+ */
+
+#endif /* EINA_STR_INLINE_H_ */
diff --git a/tests/suite/ecore/src/include/eina_inline_stringshare.x 
b/tests/suite/ecore/src/include/eina_inline_stringshare.x
new file mode 100644
index 0000000..bfd7677
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_stringshare.x
@@ -0,0 +1,91 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Gustavo Sverzut Barbieri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_STRINGSHARE_INLINE_H_
+#define EINA_STRINGSHARE_INLINE_H_
+
+#include <string.h>
+#include "eina_stringshare.h"
+/**
+ * @addtogroup Eina_Stringshare_Group Stringshare
+ *
+ * @{
+ */
+
+/**
+ * Replace the previously stringshared pointer with new content.
+ *
+ * The string pointed by @a p_str should be previously stringshared or
+ * @c NULL and it will be eina_stringshare_del(). The new string will
+ * be passed to eina_stringshare_add() and then assigned to @c *p_str.
+ *
+ * @param p_str pointer to the stringhare to be replaced. Must not be
+ *        @c NULL, but @c *p_str may be @c NULL as it is a valid
+ *        stringshare handle.
+ * @param news new string to be stringshared, may be @c NULL.
+ *
+ * @return #EINA_TRUE if the strings were different and thus replaced,
+ *         #EINA_FALSE if the strings were the same after shared.
+ */
+static inline Eina_Bool
+eina_stringshare_replace(const char **p_str, const char *news)
+{
+   if (*p_str == news) return EINA_FALSE;
+
+   news = eina_stringshare_add(news);
+   eina_stringshare_del(*p_str);
+   if (*p_str == news)
+     return EINA_FALSE;
+   *p_str = news;
+   return EINA_TRUE;
+}
+
+/**
+ * Replace the previously stringshared pointer with a new content.
+ *
+ * The string pointed by @a p_str should be previously stringshared or
+ * @c NULL and it will be eina_stringshare_del(). The new string will
+ * be passed to eina_stringshare_add_length() and then assigned to @c *p_str.
+ *
+ * @param p_str pointer to the stringhare to be replaced. Must not be
+ *        @c NULL, but @c *p_str may be @c NULL as it is a valid
+ *        stringshare handle.
+ * @param news new string to be stringshared, may be @c NULL.
+ * @param slen The string size (<= strlen(str)).
+ *
+ * @return #EINA_TRUE if the strings were different and thus replaced,
+ *         #EINA_FALSE if the strings were the same after shared.
+ */
+static inline Eina_Bool
+eina_stringshare_replace_length(const char **p_str, const char *news, unsigned 
int slen)
+{
+   if (*p_str == news) return EINA_FALSE;
+
+   news = eina_stringshare_add_length(news, slen);
+   eina_stringshare_del(*p_str);
+   if (*p_str == news)
+     return EINA_FALSE;
+   *p_str = news;
+   return EINA_TRUE;
+}
+
+/**
+ * @}
+ */
+
+#endif /* EINA_STRINGSHARE_INLINE_H_ */
diff --git a/tests/suite/ecore/src/include/eina_inline_tiler.x 
b/tests/suite/ecore/src/include/eina_inline_tiler.x
new file mode 100644
index 0000000..ffc34c1
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_tiler.x
@@ -0,0 +1,182 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2009 Rafael Antognolli
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_TILER_INLINE_H_
+#define EINA_TILER_INLINE_H_
+
+#include "eina_safety_checks.h"
+
+/**
+ * @cond LOCAL
+ * This struct should not be accessed directly, it is used by
+ * eina_tile_grid_slicer functions to maintain context and fill "info"
+ * member with correct values for given iteration.
+ */
+struct _Eina_Tile_Grid_Slicer
+{
+   unsigned long col1, col2, row1, row2; // initial and final col,row
+   int tile_w, tile_h; // tile width, height
+   int x_rel, y_rel; // starting x,y coordinates of the first col,row
+   int w1_rel, h1_rel; // width,height of the first col,row
+   int w2_rel, h2_rel; // width,height of the last col,row
+   struct Eina_Tile_Grid_Info info; // info about the current tile
+   Eina_Bool first;
+};
+
+/**
+ * @endcond
+ */
+
+/**
+ * @brief Iterates over the tiles set by eina_tile_grid_slicer_setup().
+ *
+ * @param   slc Pointer to an Eina_Tile_Grid_Slicer struct.
+ * @param   rect Pointer to a struct Eina_Tile_Grid_Info *.
+ * @return  @c EINA_TRUE if the current rect is valid.
+ *          @c EINA_FALSE if there is no more rects to iterate over (and
+ *            thus the current one isn't valid).
+ *
+ * This functions iterates over each Eina_Tile_Grid_Info *rect of the grid.
+ * eina_tile_grid_slicer_setup() must be called first, and *rect is only valid
+ * if this function returns EINA_TRUE. Its content shouldn't be modified.
+ */
+static inline Eina_Bool
+eina_tile_grid_slicer_next(Eina_Tile_Grid_Slicer *slc, const 
Eina_Tile_Grid_Info **rect)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(slc, 0);
+
+   if (slc->first)
+     {
+       slc->first = 0;
+       *rect = &slc->info;
+       return EINA_TRUE;
+     }
+
+   slc->info.col++;
+
+   if (slc->info.col > slc->col2)
+     {
+       slc->info.row++;
+       if (slc->info.row > slc->row2)
+         return EINA_FALSE;
+       else if (slc->info.row < slc->row2)
+         slc->info.rect.h = slc->tile_h;
+       else
+         slc->info.rect.h = slc->h2_rel;
+       slc->info.rect.y = 0;
+       slc->info.col = slc->col1;
+       slc->info.rect.x = slc->x_rel;
+       slc->info.rect.w = slc->w1_rel;
+     }
+   else
+     {
+       slc->info.rect.x = 0;
+       if (slc->info.col < slc->col2)
+         slc->info.rect.w = slc->tile_w;
+       else
+         slc->info.rect.w = slc->w2_rel;
+     }
+
+   if (slc->info.rect.w == slc->tile_w && slc->info.rect.h == slc->tile_h)
+     slc->info.full = EINA_TRUE;
+   else
+     slc->info.full = EINA_FALSE;
+
+   *rect = &slc->info;
+
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Setup an Eina_Tile_Grid_Slicer struct.
+ *
+ * @param   slc Pointer to an Eina_Tile_Grid_Slicer struct.
+ * @param   x X axis coordinate.
+ * @param   y Y axis coordinate.
+ * @param   w width.
+ * @param   h height.
+ * @param   tile_w tile width.
+ * @param   tile_h tile height.
+ * @return  A pointer to the Eina_Iterator.
+ *          @c NULL on failure.
+ *
+ * This function splits the rectangle given as argument into tiles of size
+ * tile_w X tile_h, and returns an iterator to them. The geometry of each
+ * tile can be accessed with eina_tile_grid_slicer_next, where rect
+ * will be a pointer to a struct Eina_Tile_Grid_Info.
+ */
+static inline Eina_Bool
+eina_tile_grid_slicer_setup(Eina_Tile_Grid_Slicer *slc, int x, int y, int w, 
int h, int tile_w, int tile_h)
+{
+   int tx1, tx2, ty1, ty2;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(slc, 0);
+
+   tx1 = x;
+   ty1 = y;
+   tx2 = x + w - 1;
+   ty2 = y + h - 1;
+
+   if (x < 0 || y < 0 || w <= 0 || h <= 0 || tile_w <= 0 || tile_h <= 0)
+     {
+       slc->first = 0;
+       slc->col1 = slc->row1 = 0;
+       slc->col2 = slc->row2 = 0;
+       slc->info.col = slc->col1;
+       slc->info.row = slc->row1;
+       return EINA_TRUE;
+     }
+
+   slc->col1 = tx1 / tile_w;
+   slc->row1 = ty1 / tile_h;
+   slc->col2 = (tx2 - 0) / tile_w;
+   slc->row2 = (ty2 - 0) / tile_h;
+   slc->x_rel = tx1 % tile_w;
+   slc->y_rel = ty1 % tile_h;
+   slc->w1_rel = tile_w - slc->x_rel;
+   slc->h1_rel = tile_h - slc->y_rel;
+   slc->w2_rel = tx2 % tile_w + 1;
+   slc->h2_rel = ty2 % tile_h + 1;
+
+   slc->tile_w = tile_w;
+   slc->tile_h = tile_h;
+
+   slc->first = 1;
+   slc->info.col = slc->col1;
+   slc->info.row = slc->row1;
+   slc->info.rect.x = slc->x_rel;
+   slc->info.rect.y = slc->y_rel;
+
+   if (slc->info.col == slc->col2)
+     slc->w1_rel = slc->w2_rel - slc->x_rel;
+
+   if (slc->info.row == slc->row2)
+     slc->h1_rel = slc->h2_rel - slc->y_rel;
+
+   slc->info.rect.w = slc->w1_rel;
+   slc->info.rect.h = slc->h1_rel;
+
+   if (slc->info.rect.w == slc->tile_w && slc->info.rect.h == slc->tile_h)
+     slc->info.full = EINA_TRUE;
+   else
+     slc->info.full = EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_trash.x 
b/tests/suite/ecore/src/include/eina_inline_trash.x
new file mode 100644
index 0000000..4a50611
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_trash.x
@@ -0,0 +1,90 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLINE_TRASH_X__
+#define EINA_INLINE_TRASH_X__
+
+/**
+ * @brief Initialize a trash before using it.
+ *
+ * @param trash The trash.
+ *
+ * This function just set to zero the trash to correctly
+ * initialize it.
+ *
+ * @note You can just set *trash to NULL and you will have
+ * the same result.
+ */
+static inline void
+eina_trash_init(Eina_Trash **trash)
+{
+   *trash = NULL;
+}
+
+/**
+ * @brief Push an unused pointer in the trash instead of freeing it.
+ *
+ * @param trash A pointer to an Eina_Trash.
+ * @param data An unused pointer big enougth to put a (void*).
+ *
+ * Instead of freeing a pointer and put pressure on malloc/free
+ * you can push it in a trash for a later use. This function just
+ * provide a fast way to push a now unused pointer into a trash.
+ *
+ * @note Do never use the pointer after insertion or bad things will
+ * happens.
+ *
+ * @note This trash will not resize, nor do anything with the size of
+ * the region pointed by @p data, so it's your duty to manage the size.
+ */
+static inline void
+eina_trash_push(Eina_Trash **trash, void *data)
+{
+   Eina_Trash *tmp;
+
+   tmp = (Eina_Trash *)data;
+   tmp->next = *trash;
+   *trash = tmp;
+}
+
+/**
+ * @brief Pop an available pointer from the trash if possible.
+ *
+ * @param trash A pointer to an Eina_Trash.
+ *
+ * Instead of calling malloc, and putting pressure on malloc/free
+ * you can recycle the content of the trash, if it's not empty.
+ *
+ * @note This trash will not resize, nor do anything with the size of
+ * the region pointed by pointer inside the trash, so it's your duty
+ * to manage the size of the returned pointer.
+ */
+static inline void*
+eina_trash_pop(Eina_Trash **trash)
+{
+   void *tmp;
+
+   tmp = *trash;
+
+   if (*trash)
+     *trash = (*trash)->next;
+
+   return tmp;
+}
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_inline_ustringshare.x 
b/tests/suite/ecore/src/include/eina_inline_ustringshare.x
new file mode 100644
index 0000000..ace6fdc
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inline_ustringshare.x
@@ -0,0 +1,93 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Gustavo Sverzut Barbieri
+                           Tom Hacohen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_USTRINGSHARE_INLINE_H_
+#define EINA_USTRINGSHARE_INLINE_H_
+
+#include "eina_unicode.h"
+#include "eina_ustringshare.h"
+
+/**
+ * @addtogroup Eina_UStringshare_Group Unicode Stringshare
+ *
+ * @{
+ */
+
+/**
+ * Replace the previously stringshared pointer with new content.
+ *
+ * The string pointed by @a p_str should be previously stringshared or
+ * @c NULL and it will be eina_ustringshare_del(). The new string will
+ * be passed to eina_ustringshare_add() and then assigned to @c *p_str.
+ *
+ * @param p_str pointer to the stringhare to be replaced. Must not be
+ *        @c NULL, but @c *p_str may be @c NULL as it is a valid
+ *        stringshare handle.
+ * @param news new string to be stringshared, may be @c NULL.
+ *
+ * @return #EINA_TRUE if the strings were different and thus replaced,
+ *         #EINA_FALSE if the strings were the same after shared.
+ */
+static inline Eina_Bool
+eina_ustringshare_replace(const Eina_Unicode **p_str, const Eina_Unicode *news)
+{
+   if (*p_str == news) return EINA_FALSE;
+
+   news = eina_ustringshare_add(news);
+   eina_ustringshare_del(*p_str);
+   if (*p_str == news)
+     return EINA_FALSE;
+   *p_str = news;
+   return EINA_TRUE;
+}
+
+/**
+ * Replace the previously stringshared pointer with a new content.
+ *
+ * The string pointed by @a p_str should be previously stringshared or
+ * @c NULL and it will be eina_ustringshare_del(). The new string will
+ * be passed to eina_ustringshare_add_length() and then assigned to @c *p_str.
+ *
+ * @param p_str pointer to the stringhare to be replaced. Must not be
+ *        @c NULL, but @c *p_str may be @c NULL as it is a valid
+ *        stringshare handle.
+ * @param news new string to be stringshared, may be @c NULL.
+ * @param slen The string size (<= strlen(str)).
+ *
+ * @return #EINA_TRUE if the strings were different and thus replaced,
+ *         #EINA_FALSE if the strings were the same after shared.
+ */
+static inline Eina_Bool
+eina_ustringshare_replace_length(const Eina_Unicode **p_str, const 
Eina_Unicode *news, unsigned int slen)
+{
+   if (*p_str == news) return EINA_FALSE;
+
+   news = eina_ustringshare_add_length(news, slen);
+   eina_ustringshare_del(*p_str);
+   if (*p_str == news)
+     return EINA_FALSE;
+   *p_str = news;
+   return EINA_TRUE;
+}
+
+/**
+ * @}
+ */
+
+#endif /* EINA_USTRINGSHARE_INLINE_H_ */
diff --git a/tests/suite/ecore/src/include/eina_inlist.h 
b/tests/suite/ecore/src/include/eina_inlist.h
new file mode 100644
index 0000000..34ee0ed
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_inlist.h
@@ -0,0 +1,115 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Vincent Torri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_INLIST_H_
+#define EINA_INLIST_H_
+
+#include "eina_types.h"
+#include "eina_iterator.h"
+#include "eina_accessor.h"
+#include <stddef.h>
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @addtogroup Eina_Containers_Group Containers
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Inline_List_Group Inline List
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Inlist
+ * Inlined list type.
+ */
+typedef struct _Eina_Inlist Eina_Inlist;
+
+/**
+ * @struct _Eina_Inlist
+ * Inlined list type.
+ */
+struct _Eina_Inlist
+{
+   Eina_Inlist *next; /**< next node */
+   Eina_Inlist *prev; /**< previous node */
+   Eina_Inlist *last; /**< last node */
+};
+
+#define EINA_INLIST Eina_Inlist __in_list
+#define EINA_INLIST_GET(Inlist) (& ((Inlist)->__in_list))
+#define EINA_INLIST_CONTAINER_GET(ptr, \
+                                  type) ((type *)((char *)ptr - \
+                                                  offsetof(type, __in_list)))
+
+EAPI Eina_Inlist *  eina_inlist_append(Eina_Inlist *in_list,
+                                       Eina_Inlist *in_item) 
EINA_ARG_NONNULL(2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Inlist *  eina_inlist_prepend(Eina_Inlist *in_list,
+                                        Eina_Inlist *in_item) 
EINA_ARG_NONNULL(2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Inlist *  eina_inlist_append_relative(Eina_Inlist *in_list,
+                                                Eina_Inlist *in_item,
+                                                Eina_Inlist *in_relative) 
EINA_ARG_NONNULL(2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Inlist *  eina_inlist_prepend_relative(Eina_Inlist *in_list,
+                                                 Eina_Inlist *in_item,
+                                                 Eina_Inlist *in_relative) 
EINA_ARG_NONNULL(2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Inlist *  eina_inlist_remove(Eina_Inlist *in_list,
+                                       Eina_Inlist *in_item) 
EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Inlist *  eina_inlist_find(Eina_Inlist *in_list,
+                                     Eina_Inlist *in_item) EINA_ARG_NONNULL(2) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Inlist *  eina_inlist_promote(Eina_Inlist *list,
+                                        Eina_Inlist *item) EINA_ARG_NONNULL(1, 
2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Inlist *  eina_inlist_demote(Eina_Inlist *list,
+                                       Eina_Inlist *item) EINA_ARG_NONNULL(1, 
2) EINA_WARN_UNUSED_RESULT;
+EAPI unsigned int   eina_inlist_count(const Eina_Inlist *list) 
EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Iterator *eina_inlist_iterator_new(const Eina_Inlist *in_list) 
EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Accessor *eina_inlist_accessor_new(const Eina_Inlist *in_list) 
EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+
+/* This two macros are helpers for the _FOREACH ones, don't use them */
+#define _EINA_INLIST_OFFSET(ref) ((char *)&(ref)->__in_list - (char *)(ref))
+#define _EINA_INLIST_CONTAINER(ref, ptr) (void *)((char *)(ptr) - \
+                                                  _EINA_INLIST_OFFSET(ref))
+
+#define EINA_INLIST_FOREACH(list, l) \
+   for (l = NULL, l = (list ? _EINA_INLIST_CONTAINER(l, list) : NULL); l; \
+        l = (EINA_INLIST_GET(l)->next ? _EINA_INLIST_CONTAINER(l, 
EINA_INLIST_GET(l)->next) : NULL))
+#define EINA_INLIST_REVERSE_FOREACH(list, l) \
+   for (l = NULL, l = (list ? _EINA_INLIST_CONTAINER(l, list->last) : NULL); \
+        l; l = (EINA_INLIST_GET(l)->prev ? _EINA_INLIST_CONTAINER(l, 
EINA_INLIST_GET(l)->prev) : NULL))
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /*EINA_INLIST_H_*/
diff --git a/tests/suite/ecore/src/include/eina_iterator.h 
b/tests/suite/ecore/src/include/eina_iterator.h
new file mode 100644
index 0000000..15188be
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_iterator.h
@@ -0,0 +1,141 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_ITERATOR_H__
+#define EINA_ITERATOR_H__
+
+#include "eina_config.h"
+
+#include "eina_types.h"
+#include "eina_magic.h"
+
+/**
+ * @addtogroup Eina_Content_Access_Group Content Access
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Iterator_Group Iterator Functions
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Iterator
+ * Type for iterators.
+ */
+typedef struct _Eina_Iterator Eina_Iterator;
+
+typedef Eina_Bool (*Eina_Iterator_Next_Callback)(Eina_Iterator *it, void 
**data);
+typedef void *(*Eina_Iterator_Get_Container_Callback)(Eina_Iterator *it);
+typedef void (*Eina_Iterator_Free_Callback)(Eina_Iterator *it);
+typedef Eina_Bool (*Eina_Iterator_Lock_Callback)(Eina_Iterator *it);
+
+struct _Eina_Iterator
+{
+#define EINA_ITERATOR_VERSION 1
+   int version;
+
+   Eina_Iterator_Next_Callback next                   EINA_ARG_NONNULL(1, 2) 
EINA_WARN_UNUSED_RESULT;
+   Eina_Iterator_Get_Container_Callback get_container EINA_ARG_NONNULL(1) 
EINA_WARN_UNUSED_RESULT;
+   Eina_Iterator_Free_Callback free                   EINA_ARG_NONNULL(1);
+
+   Eina_Iterator_Lock_Callback lock   EINA_WARN_UNUSED_RESULT;
+   Eina_Iterator_Lock_Callback unlock EINA_WARN_UNUSED_RESULT;
+
+#define EINA_MAGIC_ITERATOR 0x98761233
+   EINA_MAGIC
+};
+
+
+#define FUNC_ITERATOR_NEXT(Function) ((Eina_Iterator_Next_Callback)Function)
+#define FUNC_ITERATOR_GET_CONTAINER(Function) (( \
+                                                  
Eina_Iterator_Get_Container_Callback) \
+                                               Function)
+#define FUNC_ITERATOR_FREE(Function) ((Eina_Iterator_Free_Callback)Function)
+#define FUNC_ITERATOR_LOCK(Function) ((Eina_Iterator_Lock_Callback)Function)
+
+EAPI void      eina_iterator_free           (Eina_Iterator *iterator) 
EINA_ARG_NONNULL(1);
+
+EAPI void *    eina_iterator_container_get (Eina_Iterator *iterator) 
EINA_ARG_NONNULL(1) EINA_PURE;
+EAPI Eina_Bool eina_iterator_next      (Eina_Iterator *iterator,
+                                        void **data) EINA_ARG_NONNULL(1, 2) 
EINA_WARN_UNUSED_RESULT;
+
+EAPI void      eina_iterator_foreach        (Eina_Iterator *iterator,
+                                             Eina_Each_Cb callback,
+                                             const void *fdata) 
EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Bool eina_iterator_lock(Eina_Iterator *iterator) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool eina_iterator_unlock(Eina_Iterator *iterator) 
EINA_ARG_NONNULL(1);
+
+/**
+ * @def EINA_ITERATOR_FOREACH
+ * @brief Macro to iterate over all elements easily.
+ *
+ * @param itr The iterator to use.
+ * @param data Where to store * data, must be a pointer support getting
+ *        its address since * eina_iterator_next() requires a pointer
+ *        to pointer!
+ *
+ * This macro is a convenient way to use iterators, very similar to
+ * EINA_LIST_FOREACH().
+ *
+ * This macro can be used for freeing the data of a list, like in the
+ * following example. It has the same goal as the one documented in
+ * EINA_LIST_FOREACH(), but using iterators:
+ *
+ * @code
+ * Eina_List     *list;
+ * Eina_Iterator *itr;
+ * char          *data;
+ *
+ * // list is already filled,
+ * // its elements are just duplicated strings
+ *
+ * itr = eina_list_iterator_new(list);
+ * EINA_ITERATOR_FOREACH(itr, data)
+ *   free(data);
+ * eina_iterator_free(itr);
+ * eina_list_free(list);
+ * @endcode
+ *
+ * @note this example is not optimal algorithm to release a list since
+ *    it will walk the list twice, but it serves as an example. For
+ *    optimized version use EINA_LIST_FREE()
+ *
+ * @warning unless explicitly stated in functions returning iterators,
+ *    do not modify the iterated object while you walk it, in this
+ *    example using lists, do not remove list nodes or you might
+ *    crash!  This is not a limitiation of iterators themselves,
+ *    rather in the iterators implementations to keep them as simple
+ *    and fast as possible.
+ */
+#define EINA_ITERATOR_FOREACH(itr, \
+                              data) while (eina_iterator_next((itr), \
+                                                              (void 
**)&(data)))
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_lalloc.h 
b/tests/suite/ecore/src/include/eina_lalloc.h
new file mode 100644
index 0000000..d41a9ed
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_lalloc.h
@@ -0,0 +1,60 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_LALLOC_H_
+#define EINA_LALLOC_H_
+
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Lalloc_Group Lazy allocator
+ *
+ * @{
+ */
+
+typedef Eina_Bool (*Eina_Lalloc_Alloc)(void *user_data, int num);
+#define EINA_LALLOC_ALLOC(function) ((Eina_Lalloc_Alloc)function)
+typedef void (*Eina_Lalloc_Free)(void *user_data);
+#define EINA_LALLOC_FREE(function) ((Eina_Lalloc_Free)function)
+
+typedef struct _Eina_Lalloc Eina_Lalloc;
+
+EAPI Eina_Lalloc *eina_lalloc_new(void *data,
+                                  Eina_Lalloc_Alloc alloc_cb,
+                                  Eina_Lalloc_Free free_cb,
+                                  int num_init) EINA_ARG_NONNULL(2, 3);
+EAPI void         eina_lalloc_free(Eina_Lalloc *a) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool    eina_lalloc_elements_add(Eina_Lalloc *a,
+                                           int num) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool    eina_lalloc_element_add(Eina_Lalloc *a) EINA_ARG_NONNULL(1);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_LALLOC_H_ */
diff --git a/tests/suite/ecore/src/include/eina_list.h 
b/tests/suite/ecore/src/include/eina_list.h
new file mode 100644
index 0000000..835422d
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_list.h
@@ -0,0 +1,349 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Vincent Torri, Jorge Luis Zapata 
Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_LIST_H_
+#define EINA_LIST_H_
+
+#include <stdlib.h>
+
+#include "eina_config.h"
+
+#include "eina_types.h"
+#include "eina_iterator.h"
+#include "eina_accessor.h"
+#include "eina_magic.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @addtogroup Eina_Containers_Group Containers
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_List_Group List
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_List
+ * Type for a generic double linked list.
+ */
+typedef struct _Eina_List Eina_List;
+
+typedef struct _Eina_List_Accounting Eina_List_Accounting;
+
+/**
+ * @struct _Eina_List
+ * Type for a generic double linked list.
+ */
+struct _Eina_List
+{
+   void *data; /**< Pointer to list element payload */
+   Eina_List *next; /**< Next member in the list */
+   Eina_List *prev; /**< Previous member in the list */
+   Eina_List_Accounting *accounting; /**< Private list accounting info - don't 
touch */
+
+   EINA_MAGIC
+};
+
+struct _Eina_List_Accounting
+{
+   Eina_List *last;
+   unsigned int count;
+   EINA_MAGIC
+};
+
+EAPI Eina_List *               eina_list_append (Eina_List *list, const void 
*data) EINA_ARG_NONNULL(2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_prepend (Eina_List *list, const void 
*data) EINA_ARG_NONNULL(2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_append_relative (Eina_List *list, 
const void *data, const void *relative) EINA_ARG_NONNULL(2) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_append_relative_list (Eina_List 
*list, const void *data, Eina_List *relative) EINA_ARG_NONNULL(2) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_prepend_relative (Eina_List *list, 
const void *data, const void *relative) EINA_ARG_NONNULL(2) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_prepend_relative_list (Eina_List 
*list, const void *data, Eina_List *relative) EINA_ARG_NONNULL(2) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_sorted_insert(Eina_List *list, 
Eina_Compare_Cb func, const void *data) EINA_ARG_NONNULL(2,                     
3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_remove (Eina_List *list, const void 
*data) EINA_ARG_NONNULL(2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_remove_list (Eina_List *list, 
Eina_List *remove_list) EINA_ARG_NONNULL(   2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_promote_list (Eina_List *list, 
Eina_List *move_list) EINA_ARG_NONNULL(   2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_demote_list (Eina_List *list, 
Eina_List *move_list);
+EAPI void *                    eina_list_data_find(const Eina_List *list, 
const void *data) EINA_PURE EINA_ARG_NONNULL(2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_data_find_list (const Eina_List 
*list, const void *data) EINA_PURE EINA_ARG_NONNULL(2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_free (Eina_List *list);
+EAPI void *                    eina_list_nth(const Eina_List *list, unsigned 
int n) EINA_PURE EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_nth_list (const Eina_List *list, 
unsigned int n) EINA_PURE EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_reverse (Eina_List *list) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_reverse_clone(const Eina_List *list) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_clone(const Eina_List *list) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_sort (Eina_List *list, unsigned int 
size, Eina_Compare_Cb func) EINA_ARG_NONNULL(3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_merge (Eina_List *left, Eina_List 
*right) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_sorted_merge(Eina_List *left, 
Eina_List *right, Eina_Compare_Cb func) EINA_ARG_NONNULL(3) 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_List *               eina_list_split_list(Eina_List *list, Eina_List 
*relative, Eina_List **right) EINA_WARN_UNUSED_RESULT;
+
+
+EAPI Eina_List *               eina_list_search_sorted_near_list(const 
Eina_List *list, Eina_Compare_Cb func, const void *data, int *result_cmp);
+EAPI Eina_List *               eina_list_search_sorted_list(const Eina_List 
*list, Eina_Compare_Cb func, const void *data);
+EAPI void *                    eina_list_search_sorted(const Eina_List *list, 
Eina_Compare_Cb func, const void *data);
+EAPI Eina_List *               eina_list_search_unsorted_list(const Eina_List 
*list, Eina_Compare_Cb func, const void *data);
+EAPI void *                    eina_list_search_unsorted(const Eina_List 
*list, Eina_Compare_Cb func, const void *data);
+
+static inline Eina_List *               eina_list_last (const Eina_List *list) 
EINA_PURE EINA_WARN_UNUSED_RESULT;
+static inline Eina_List *               eina_list_next (const Eina_List *list) 
EINA_PURE EINA_WARN_UNUSED_RESULT;
+static inline Eina_List *               eina_list_prev (const Eina_List *list) 
EINA_PURE EINA_WARN_UNUSED_RESULT;
+static inline void *                    eina_list_data_get(const Eina_List 
*list) EINA_PURE EINA_WARN_UNUSED_RESULT;
+static inline unsigned int              eina_list_count(const Eina_List *list) 
EINA_PURE;
+
+EAPI Eina_Iterator *               eina_list_iterator_new(const Eina_List 
*list) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Iterator *               eina_list_iterator_reversed_new(const 
Eina_List *list) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Accessor *               eina_list_accessor_new(const Eina_List 
*list) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @def EINA_LIST_FOREACH
+ * @brief Macro to iterate over a list.
+ *
+ * @param list The list to iterate over.
+ * @param l A list that is used as an iterator and points to the current node.
+ * @param data Current item's data.
+ *
+ * This macro iterates over @p list from the first element to
+ * the last. @p data is the data related to the current element.
+ * @p l is an #Eina_List used as the list iterator.
+ *
+ * It can be used to free list data, as in the following example:
+ *
+ * @code
+ * Eina_List *list;
+ * Eina_List *l;
+ * char      *data;
+ *
+ * // list is already filled,
+ * // its elements are just duplicated strings,
+ * // EINA_LIST_FOREACH will be used to free those strings
+ *
+ * EINA_LIST_FOREACH(list, l, data)
+ *   free(data);
+ * eina_list_free(list);
+ * @endcode
+ *
+ * @note This is not the optimal way to release memory allocated to
+ *       a list, since it iterates over the list twice.
+ *       For an optimized algorithm, use EINA_LIST_FREE().
+ *
+ * @warning Be careful when deleting list nodes.
+ *          If you remove the current node and continue iterating,
+ *          the code will fail because the macro will not be able
+ *          to get the next node. Notice that it's OK to remove any
+ *          node if you stop the loop after that.
+ *          For destructive operations such as this, consider
+ *          using EINA_LIST_FOREACH_SAFE().
+ */
+#define EINA_LIST_FOREACH(list, l, data)       \
+  for (l = list,                               \
+        data = eina_list_data_get(l);          \
+       l;                                      \
+       l = eina_list_next(l),                  \
+        data = eina_list_data_get(l))
+
+/**
+ * @def EINA_LIST_REVERSE_FOREACH
+ * @brief Macro to iterate over a list in the reverse order.
+ *
+ * @param list The list to iterate over.
+ * @param l A list that is used as an iterator and points to the current node.
+ * @param data Current item's data.
+ *
+ * This macro works like EINA_LIST_FOREACH, but iterates from the
+ * last element of a list to the first.
+ * @p data is the data related to the current element, while @p l
+ * is an #Eina_List that is used as the list iterator.
+ *
+ * It can be used to free list data, as in the following example:
+ *
+ * @code
+ * Eina_List *list;
+ * Eina_List *l;
+ * char      *data;
+ *
+ * // list is already filled,
+ * // its elements are just duplicated strings,
+ * // EINA_LIST_REVERSE_FOREACH will be used to free those strings
+ *
+ * EINA_LIST_REVERSE_FOREACH(list, l, data)
+ *   free(data);
+ * eina_list_free(list);
+ * @endcode
+ *
+ * @note This is not the optimal way to release memory allocated to
+ *       a list, since it iterates over the list twice.
+ *       For an optimized algorithm, use EINA_LIST_FREE().
+ *
+ * @warning Be careful when deleting list nodes.
+ *          If you remove the current node and continue iterating,
+ *          the code will fail because the macro will not be able
+ *          to get the next node. Notice that it's OK to remove any
+ *          node if you stop the loop after that.
+ *          For destructive operations such as this, consider
+ *          using EINA_LIST_REVERSE_FOREACH_SAFE().
+ */
+#define EINA_LIST_REVERSE_FOREACH(list, l, data)       \
+  for (l = eina_list_last(list),                       \
+        data = eina_list_data_get(l);                  \
+       l;                                              \
+       l = eina_list_prev(l),                          \
+        data = eina_list_data_get(l))
+
+/**
+ * @def EINA_LIST_FOREACH_SAFE
+ * @brief Macro to iterate over a list with support for node deletion.
+ *
+ * @param list The list to iterate over.
+ * @param l A list that is used as an iterator and points to the current node.
+ * @param l_next A list that is used as an iterator and points to the next 
node.
+ * @param data Current item's data.
+ *
+ * This macro iterates over @p list from the first element to
+ * the last. @p data is the data related to the current element.
+ * @p l is an #Eina_List used as the list iterator.
+ *
+ * Since this macro stores a pointer to the next list node in @p l_next,
+ * deleting the current node and continuing looping is safe.
+ *
+ * This macro can be used to free list nodes, as in the following example:
+ *
+ * @code
+ * Eina_List *list;
+ * Eina_List *l;
+ * Eina_List *l_next;
+ * char      *data;
+ *
+ * // list is already filled,
+ * // its elements are just duplicated strings,
+ * // EINA_LIST_FOREACH_SAFE will be used to free elements that match "key".
+ *
+ * EINA_LIST_FOREACH_SAFE(list, l, l_next, data)
+ *   if (strcmp(data, "key") == 0) {
+ *      free(data);
+ *      list = eina_list_remove_list(list, l);
+ *   }
+ * @endcode
+ */
+#define EINA_LIST_FOREACH_SAFE(list, l, l_next, data)  \
+  for (l = list,                                       \
+        l_next = eina_list_next(l),                    \
+        data = eina_list_data_get(l);                  \
+       l;                                              \
+       l = l_next,                                     \
+        l_next = eina_list_next(l),                    \
+        data = eina_list_data_get(l))
+
+/**
+ * @def EINA_LIST_REVERSE_FOREACH_SAFE
+ * @brief Macro to iterate over a list in the reverse order with support
+ *        for deletion.
+ *
+ * @param list The list to iterate over.
+ * @param l A list that is used as an iterator and points to the current node.
+ * @param l_prev A list that is used as an iterator and points to the previous 
node.
+ * @param data Current item's data.
+ *
+ * This macro works like EINA_LIST_FOREACH_SAFE, but iterates from the
+ * last element of a list to the first.
+ * @p data is the data related to the current element, while @p l
+ * is an #Eina_List that is used as the list iterator.
+ *
+ * Since this macro stores a pointer to the previous list node in @p l_prev,
+ * deleting the current node and continuing looping is safe.
+ *
+ * This macro can be used to free list nodes, as in the following example:
+ *
+ * @code
+ * Eina_List *list;
+ * Eina_List *l;
+ * Eina_List *l_prev;
+ * char       *data;
+ *
+ * // list is already filled,
+ * // its elements are just duplicated strings,
+ * // EINA_LIST_REVERSE_FOREACH_SAFE will be used to free elements that match 
"key".
+ *
+ * EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, data)
+ *   if (strcmp(data, "key") == 0) {
+ *      free(data);
+ *      list = eina_list_remove_list(list, l);
+ *   }
+ * @endcode
+ */
+#define EINA_LIST_REVERSE_FOREACH_SAFE(list, l, l_prev, data)  \
+  for (l = eina_list_last(list),                               \
+        l_prev = eina_list_prev(l),                            \
+        data = eina_list_data_get(l);                          \
+       l;                                                      \
+       l = l_prev,                                             \
+        l_prev = eina_list_prev(l),                            \
+        data = eina_list_data_get(l))
+
+/**
+ * @def EINA_LIST_FREE
+ * @brief Macro to remove each list node while having access to each node's 
data.
+ *
+ * @param list The list that will be cleared.
+ * @param data Current node's data.
+ *
+ * This macro will call #eina_list_remove_list for each list node, and store
+ * the data contained in the current node in @p data.
+ *
+ * If you do not need to release node data, it is easier to call 
#eina_list_free().
+ *
+ * @code
+ * Eina_List *list;
+ * char      *data;
+ *
+ * // list is already filled,
+ * // its elements are just duplicated strings,
+ *
+ * EINA_LIST_FREE(list, data)
+ *   free(data);
+ * @endcode
+ *
+ * @see eina_list_free()
+ */
+#define EINA_LIST_FREE(list, data)                     \
+  for (data = eina_list_data_get(list);                        \
+       list;                                           \
+       list = eina_list_remove_list(list, list),       \
+        data = eina_list_data_get(list))
+
+#include "eina_inline_list.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_LIST_H_ */
diff --git a/tests/suite/ecore/src/include/eina_log.h 
b/tests/suite/ecore/src/include/eina_log.h
new file mode 100644
index 0000000..d0fd159
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_log.h
@@ -0,0 +1,387 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_LOG_H_
+#define EINA_LOG_H_
+
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "eina_types.h"
+
+#define EINA_COLOR_LIGHTRED  "\033[31;1m"
+#define EINA_COLOR_RED       "\033[31m"
+#define EINA_COLOR_LIGHTBLUE "\033[34;1m"
+#define EINA_COLOR_BLUE      "\033[34m"
+#define EINA_COLOR_GREEN     "\033[32;1m"
+#define EINA_COLOR_YELLOW    "\033[33;1m"
+#define EINA_COLOR_ORANGE    "\033[0;33m"
+#define EINA_COLOR_WHITE     "\033[37;1m"
+#define EINA_COLOR_LIGHTCYAN "\033[36;1m"
+#define EINA_COLOR_CYAN      "\033[36m"
+#define EINA_COLOR_RESET     "\033[0m"
+#define EINA_COLOR_HIGH      "\033[1m"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Log_Group Log
+ *
+ * @{
+ */
+
+/**
+ * EINA_LOG_DOMAIN_GLOBAL is the general purpose log domain to be
+ * used, it is always registered and available everywhere.
+ */
+EAPI extern int EINA_LOG_DOMAIN_GLOBAL;
+
+#ifndef EINA_LOG_DOMAIN_DEFAULT
+
+/**
+ * @def EINA_LOG_DOMAIN_DEFAULT
+ * This macro defines the domain to use with the macros EINA_LOG_DOM_DBG(),
+ * EINA_LOG_DOM_INFO(), EINA_LOG_DOM_WARN(), EINA_LOG_DOM_ERR() and
+ * EINA_LOG_DOM_CRIT().
+ *
+ * If not defined prior to the inclusion of this header, then it
+ * defaults to #EINA_LOG_DOMAIN_GLOBAL.
+ *
+ * @note One may like to redefine this in its code to avoid typing too
+ *       much. In this case the recommended way is:
+ *
+ * @code
+ * #include <Eina.h>
+ * #undef EINA_LOG_DOMAIN_DEFAULT
+ * #define EINA_LOG_DOMAIN_DEFAULT _log_dom
+ * static int _log_dom = -1;
+ *
+ * int main(void)
+ * {
+ *    eina_init();
+ *    _log_dom = eina_log_domain_register("mydom", EINA_COLOR_CYAN);
+ *    EINA_LOG_ERR("using my own domain");
+ *    return 0;
+ * }
+ * @endcode
+ *
+ * @warning If one defines the domain prior to inclusion of this
+ *          header, the defined log domain symbol must be defined
+ *          prior as well, otherwise the inlined functions defined by
+ *          Eina will fail to find the symbol, causing build failure.
+ *
+ * @code
+ * #define EINA_LOG_DOMAIN_DEFAULT _log_dom
+ * static int _log_dom = -1; // must come before inclusion of Eina.h!
+ * #include <Eina.h>
+ *
+ * int main(void)
+ * {
+ *    eina_init();
+ *    _log_dom = eina_log_domain_register("mydom", EINA_COLOR_CYAN);
+ *    EINA_LOG_ERR("using my own domain");
+ *    return 0;
+ * }
+ * @endcode
+ *
+ */
+# define EINA_LOG_DOMAIN_DEFAULT EINA_LOG_DOMAIN_GLOBAL
+
+#endif /* EINA_LOG_DOMAIN_DEFAULT */
+
+
+/**
+ * @def EINA_LOG(DOM, LEVEL, fmt, ...)
+ * Logs a message on the specified domain, level and format.
+ *
+ * @note if @c EINA_LOG_LEVEL_MAXIMUM is defined, then messages larger
+ *       than this value will be ignored regardless of current domain
+ *       level, the eina_log_print() is not even called! Most
+ *       compilers will just detect the two integers make the branch
+ *       impossible and remove the branch and function call all
+ *       together. Take this as optimization tip and possible remove
+ *       debug messages from binaries to be deployed, saving on hot
+ *       paths. Never define @c EINA_LOG_LEVEL_MAXIMUM on public
+ *       header files.
+ */
+#ifdef EINA_LOG_LEVEL_MAXIMUM
+#define EINA_LOG(DOM, LEVEL, fmt, ...)                                  \
+  do {                                                                  \
+     if (LEVEL <= EINA_LOG_LEVEL_MAXIMUM) {                            \
+       eina_log_print(DOM, LEVEL, __FILE__, __FUNCTION__, __LINE__,    \
+                      fmt, ## __VA_ARGS__); }                          \
+  } while (0)
+#else
+#define EINA_LOG(DOM, LEVEL, fmt, ...)         \
+  eina_log_print(DOM,                          \
+                LEVEL,                         \
+                __FILE__,                      \
+                __FUNCTION__,                  \
+                __LINE__,                      \
+                fmt,                           \
+                ## __VA_ARGS__)
+#endif
+
+/**
+ * @def EINA_LOG_DOM_CRIT(DOM, fmt, ...)
+ * Logs a message with level CRITICAL on the specified domain and format.
+ */
+#define EINA_LOG_DOM_CRIT(DOM, fmt, ...) \
+   EINA_LOG(DOM, EINA_LOG_LEVEL_CRITICAL, fmt, ## __VA_ARGS__)
+
+/**
+ * @def EINA_LOG_DOM_ERR(DOM, fmt, ...)
+ * Logs a message with level ERROR on the specified domain and format.
+ */
+#define EINA_LOG_DOM_ERR(DOM, fmt, ...) \
+   EINA_LOG(DOM, EINA_LOG_LEVEL_ERR, fmt, ## __VA_ARGS__)
+
+/**
+ * @def EINA_LOG_DOM_INFO(DOM, fmt, ...)
+ * Logs a message with level INFO on the specified domain and format.
+ */
+#define EINA_LOG_DOM_INFO(DOM, fmt, ...) \
+   EINA_LOG(DOM, EINA_LOG_LEVEL_INFO, fmt, ## __VA_ARGS__)
+
+/**
+ * @def EINA_LOG_DOM_DBG(DOM, fmt, ...)
+ * Logs a message with level DEBUG on the specified domain and format.
+ */
+#define EINA_LOG_DOM_DBG(DOM, fmt, ...) \
+   EINA_LOG(DOM, EINA_LOG_LEVEL_DBG, fmt, ## __VA_ARGS__)
+
+/**
+ * @def EINA_LOG_DOM_WARN(DOM, fmt, ...)
+ * Logs a message with level WARN on the specified domain and format.
+ */
+#define EINA_LOG_DOM_WARN(DOM, fmt, ...) \
+   EINA_LOG(DOM, EINA_LOG_LEVEL_WARN, fmt, ## __VA_ARGS__)
+
+/**
+ * @def EINA_LOG_CRIT(fmt, ...)
+ * Logs a message with level CRITICAL on the default domain with the specified
+ * format.
+ */
+#define EINA_LOG_CRIT(fmt, ...)             \
+   EINA_LOG(EINA_LOG_DOMAIN_DEFAULT, \
+            EINA_LOG_LEVEL_CRITICAL, \
+            fmt,                    \
+            ## __VA_ARGS__)
+
+/**
+ * @def EINA_LOG_ERR(fmt, ...)
+ * Logs a message with level ERROR on the default domain with the specified
+ * format.
+ */
+#define EINA_LOG_ERR(fmt, ...) \
+   EINA_LOG(EINA_LOG_DOMAIN_DEFAULT, EINA_LOG_LEVEL_ERR, fmt, ## __VA_ARGS__)
+
+/**
+ * @def EINA_LOG_INFO(fmt, ...)
+ * Logs a message with level INFO on the default domain with the specified
+ * format.
+ */
+#define EINA_LOG_INFO(fmt, ...) \
+   EINA_LOG(EINA_LOG_DOMAIN_DEFAULT, EINA_LOG_LEVEL_INFO, fmt, ## __VA_ARGS__)
+
+/**
+ * @def EINA_LOG_WARN(fmt, ...)
+ * Logs a message with level WARN on the default domain with the specified
+ * format.
+ */
+#define EINA_LOG_WARN(fmt, ...) \
+   EINA_LOG(EINA_LOG_DOMAIN_DEFAULT, EINA_LOG_LEVEL_WARN, fmt, ## __VA_ARGS__)
+
+/**
+ * @def EINA_LOG_DBG(fmt, ...)
+ * Logs a message with level DEBUG on the default domain with the specified
+ * format.
+ */
+#define EINA_LOG_DBG(fmt, ...) \
+   EINA_LOG(EINA_LOG_DOMAIN_DEFAULT, EINA_LOG_LEVEL_DBG, fmt, ## __VA_ARGS__)
+
+/**
+ * @typedef Eina_Log_Domain
+ * The domain used for logging.
+ */
+typedef struct _Eina_Log_Domain Eina_Log_Domain;
+
+/**
+ * @struct _Eina_Log_Domain
+ * The domain used for logging.
+ */
+struct _Eina_Log_Domain
+{
+   int level; /**< Max level to log */
+   const char *domain_str; /**< Formatted string with color to print */
+   const char *name; /**< Domain name */
+   size_t namelen; /**< strlen(name) */
+
+   /* Private */
+   Eina_Bool deleted : 1; /**< Flags deletion of domain, a free slot */
+};
+
+EAPI void eina_log_threads_enable(void);
+
+/**
+ * @enum _Eina_Log_Level
+ * List of available logging levels.
+ */
+typedef enum _Eina_Log_Level
+{
+   EINA_LOG_LEVEL_CRITICAL, /**< Critical log level */
+   EINA_LOG_LEVEL_ERR, /**< Error log level */
+   EINA_LOG_LEVEL_WARN, /**< Warning log level */
+   EINA_LOG_LEVEL_INFO, /**< Information log level */
+   EINA_LOG_LEVEL_DBG, /**< Debug log level */
+   EINA_LOG_LEVELS, /**< Count of default log levels */
+   EINA_LOG_LEVEL_UNKNOWN = (-2147483647 - 1) /**< Unknown level */
+} Eina_Log_Level;
+
+/**
+ * @typedef Eina_Log_Print_Cb
+ * Type for print callbacks.
+ */
+typedef void (*Eina_Log_Print_Cb)(const Eina_Log_Domain *d,
+                                  Eina_Log_Level level,
+                                  const char *file, const char *fnc, int line,
+                                  const char *fmt, void *data, va_list args);
+
+/*
+ * Customization
+ */
+EAPI void
+eina_log_print_cb_set(Eina_Log_Print_Cb cb, void *data) EINA_ARG_NONNULL(1);
+
+EAPI void
+eina_log_level_set(int level);
+EAPI int
+eina_log_level_get(void) EINA_WARN_UNUSED_RESULT;
+
+static inline Eina_Bool
+eina_log_level_check(int level);
+
+EAPI Eina_Bool
+eina_log_main_thread_check(void) EINA_CONST EINA_WARN_UNUSED_RESULT;
+
+EAPI void
+eina_log_color_disable_set(Eina_Bool disabled);
+EAPI Eina_Bool
+eina_log_color_disable_get(void) EINA_WARN_UNUSED_RESULT;
+EAPI void
+eina_log_file_disable_set(Eina_Bool disabled);
+EAPI Eina_Bool
+eina_log_file_disable_get(void) EINA_WARN_UNUSED_RESULT;
+EAPI void
+eina_log_function_disable_set(Eina_Bool disabled);
+EAPI Eina_Bool
+eina_log_function_disable_get(void) EINA_WARN_UNUSED_RESULT;
+EAPI void
+eina_log_abort_on_critical_set(Eina_Bool abort_on_critical);
+EAPI Eina_Bool
+eina_log_abort_on_critical_get(void) EINA_WARN_UNUSED_RESULT;
+EAPI void
+eina_log_abort_on_critical_level_set(int critical_level);
+EAPI int
+eina_log_abort_on_critical_level_get(void) EINA_WARN_UNUSED_RESULT;
+
+EAPI void
+eina_log_domain_level_set(const char *domain_name, int level) 
EINA_ARG_NONNULL(1);
+EAPI int
+eina_log_domain_level_get(const char *domain_name) EINA_WARN_UNUSED_RESULT 
EINA_ARG_NONNULL(1);
+EAPI int
+eina_log_domain_registered_level_get(int domain) EINA_WARN_UNUSED_RESULT;
+static inline Eina_Bool
+eina_log_domain_level_check(int domain, int level);
+
+
+/*
+ * Logging domains
+ */
+EAPI int
+eina_log_domain_register(const char *name, const char *color) 
EINA_ARG_NONNULL(1);
+EAPI void
+eina_log_domain_unregister(int domain);
+
+/*
+ * Logging functions.
+ */
+EAPI void
+eina_log_print(int domain,
+               Eina_Log_Level level,
+               const char *file,
+               const char *function,
+               int line,
+               const char *fmt,
+               ...) EINA_ARG_NONNULL(3, 4, 6) EINA_PRINTF(6, 7) 
EINA_NOINSTRUMENT;
+EAPI void
+eina_log_vprint(int domain,
+                Eina_Log_Level level,
+                const char *file,
+                const char *fnc,
+                int line,
+                const char *fmt,
+                va_list args) EINA_ARG_NONNULL(3, 4, 6) EINA_NOINSTRUMENT;
+
+
+/*
+ * Logging methods (change how logging is done).
+ */
+EAPI void
+eina_log_print_cb_stdout(const Eina_Log_Domain *d,
+                         Eina_Log_Level level,
+                         const char *file,
+                         const char *fnc,
+                         int line,
+                         const char *fmt,
+                         void *data,
+                         va_list args);
+EAPI void
+eina_log_print_cb_stderr(const Eina_Log_Domain *d,
+                         Eina_Log_Level level,
+                         const char *file,
+                         const char *fnc,
+                         int line,
+                         const char *fmt,
+                         void *data,
+                         va_list args);
+EAPI void
+eina_log_print_cb_file(const Eina_Log_Domain *d,
+                       Eina_Log_Level level,
+                       const char *file,
+                       const char *fnc,
+                       int line,
+                       const char *fmt,
+                       void *data,
+                       va_list args);
+
+#include "eina_inline_log.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_LOG_H_ */
diff --git a/tests/suite/ecore/src/include/eina_magic.h 
b/tests/suite/ecore/src/include/eina_magic.h
new file mode 100644
index 0000000..dd1a9f3
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_magic.h
@@ -0,0 +1,153 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_MAGIC_H_
+#define EINA_MAGIC_H_
+
+
+#include "eina_config.h"
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Magic_Group Magic
+ *
+ * @{
+ */
+
+typedef unsigned int Eina_Magic;
+
+/**
+ * @typedef Eina_Magic
+ * An abstract type for a magic number.
+ */
+EAPI const char *eina_magic_string_get(Eina_Magic magic) EINA_PURE 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool   eina_magic_string_set(Eina_Magic magic,
+                                       const char *magic_name) 
EINA_ARG_NONNULL(2);
+EAPI Eina_Bool   eina_magic_string_static_set(Eina_Magic magic,
+                                              const char *magic_name) 
EINA_ARG_NONNULL(2);
+
+/**
+ * @def EINA_MAGIC_NONE
+ * Random value for specifying that a structure using the magic
+ * feature has already been freed. It is used by eina_magic_fail().
+ *
+ * If the magic feature of Eina is disabled, #EINA_MAGIC_NONE is just
+ * @c 0.
+ */
+#define EINA_MAGIC_NONE            0x1234fedc
+
+#ifdef EINA_MAGIC_DEBUG
+
+/**
+ * @def EINA_MAGIC
+ * Declaration of a variable of type #Eina_Magic. To put in a structure
+ * when one wants to use the magic feature of Eina with the functions
+ * of that structure, like that:
+ *
+ * @code
+ * struct Foo
+ * {
+ *    int i;
+ *
+ *    EINA_MAGIC
+ * };
+ * @endcode
+ *
+ * If the magic feature of Eina is disabled, #EINA_MAGIC does nothing.
+ */
+#define EINA_MAGIC      Eina_Magic __magic;
+
+/**
+ * @def EINA_MAGIC_SET(d, m)
+ * Set the magic number of @p d to @p m. @p d must be a valid pointer
+ * to a structure holding an Eina magic number declaration. Use
+ * #EINA_MAGIC to add such declaration.
+ *
+ * If the magic feature of Eina is disabled, #EINA_MAGIC_CHECK is just
+ * the value @c 0.
+ */
+#define EINA_MAGIC_SET(d, m)       (d)->__magic = (m)
+
+/**
+ * @def EINA_MAGIC_CHECK(d, m)
+ * Test if @p d is @c NULL or not, and if not @c NULL, if
+ * @p d->__eina_magic is equal to @p m. @p d must be a structure that
+ * holds an Eina magic number declaration. Use #EINA_MAGIC to add such
+ * declaration.
+ *
+ * If the magic feature of Eina is disabled, #EINA_MAGIC_CHECK is just
+ * the value @c 1.
+ */
+#define EINA_MAGIC_CHECK(d, m)     ((d) && ((d)->__magic == (m)))
+
+/**
+ * @def EINA_MAGIC_FAIL(d, m)
+ * Call eina_magic_fail() with the parameters @p d, @p d->__magic, @p
+ * m, __FILE__, __FUNCTION__ and __LINE__. @p d must be a structure that
+ * holds an Eina magic number declaration. Use #EINA_MAGIC to add such
+ * declaration.
+ *
+ * If the magic feature of Eina is disabled, #EINA_MAGIC_FAIL does
+ * nothing.
+ */
+#define EINA_MAGIC_FAIL(d, m)                  \
+  eina_magic_fail((void *)(d),                 \
+                 (d) ? (d)->__magic : 0,       \
+                 (m),                          \
+                 __FILE__,                     \
+                 __FUNCTION__,                 \
+                 __LINE__);
+
+EAPI void eina_magic_fail(void *d, Eina_Magic m, Eina_Magic req_m,
+                          const char *file, const char *fnc,
+                          int line) EINA_ARG_NONNULL(4, 5);
+
+#else
+
+/**
+ * @cond LOCAL
+ */
+
+#define EINA_MAGIC
+#define EINA_MAGIC_SET(d, m)       ((void)0)
+#define EINA_MAGIC_CHECK(d, m)     (1)
+#define EINA_MAGIC_FAIL(d, m)      ((void)0)
+
+#define eina_magic_fail(d, m, req_m, file, fnx, line) ((void)0)
+
+/**
+ * @endcond
+ */
+
+#endif
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_MAGIC_H_ */
diff --git a/tests/suite/ecore/src/include/eina_main.h 
b/tests/suite/ecore/src/include/eina_main.h
new file mode 100644
index 0000000..db80042
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_main.h
@@ -0,0 +1,75 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_MAIN_H_
+#define EINA_MAIN_H_
+
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Core_Group Core
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Main_Group Main
+ *
+ * @{
+ */
+
+/**
+ * @def EINA_VERSION_MAJOR
+ * @brief Major version of Eina
+ */
+#define EINA_VERSION_MAJOR 1
+
+/**
+ * @def EINA_VERSION_MINOR
+ * @brief Minor version of Eina
+ */
+#define EINA_VERSION_MINOR 0
+
+/**
+ * @typedef Eina_Version
+ * The version of Eina.
+ */
+typedef struct _Eina_Version
+{
+   int major;    /**< Major component of the version */
+   int minor;    /**< Minor component of the version */
+   int micro;    /**< Micro component of the version */
+   int revision; /**< Revision component of the version */
+} Eina_Version;
+
+EAPI extern Eina_Version *eina_version;
+
+EAPI int eina_init(void);
+EAPI int eina_shutdown(void);
+EAPI int eina_threads_init(void);
+EAPI int eina_threads_shutdown(void);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_MAIN_H_ */
diff --git a/tests/suite/ecore/src/include/eina_matrixsparse.h 
b/tests/suite/ecore/src/include/eina_matrixsparse.h
new file mode 100644
index 0000000..cbf29cc
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_matrixsparse.h
@@ -0,0 +1,120 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2009 Gustavo Sverzut Barbieri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_MATRIXSPARSE_H_
+#define EINA_MATRIXSPARSE_H_
+
+#include <stdlib.h>
+
+#include "eina_config.h"
+
+#include "eina_types.h"
+#include "eina_iterator.h"
+#include "eina_accessor.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @addtogroup Eina_Containers_Group Containers
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Matrixsparse_Group Sparse Matrix
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Matrixsparse
+ * Type for a generic sparse matrix.
+ */
+typedef struct _Eina_Matrixsparse Eina_Matrixsparse;
+
+/**
+ * @typedef Eina_Matrixsparse_Row
+ * Type for a generic sparse matrix row, opaque for users.
+ */
+typedef struct _Eina_Matrixsparse_Row Eina_Matrixsparse_Row;
+
+/**
+ * @typedef Eina_Matrixsparse_Cell
+ * Type for a generic sparse matrix cell, opaque for users.
+ */
+typedef struct _Eina_Matrixsparse_Cell Eina_Matrixsparse_Cell;
+
+typedef struct _Eina_Matrixsparse_Item_Cell Eina_Matrixsparse_Item_Cell;
+typedef struct _Eina_Matrixsparse_Item_Row Eina_Matrixsparse_Item_Row;
+
+
+/* constructors and destructors */
+EAPI Eina_Matrixsparse *eina_matrixsparse_new(unsigned long rows,
+                                              unsigned long cols,
+                                              void (*free_func)(void 
*user_data,
+                                                                void 
*cell_data),
+                                              const void *user_data);
+EAPI void               eina_matrixsparse_free(Eina_Matrixsparse *m);
+
+/* size manipulation */
+EAPI void               eina_matrixsparse_size_get(const Eina_Matrixsparse *m,
+                                                   unsigned long *rows,
+                                                   unsigned long *cols);
+EAPI Eina_Bool          eina_matrixsparse_size_set(Eina_Matrixsparse *m,
+                                                   unsigned long rows,
+                                                   unsigned long cols);
+
+/* data getting */
+EAPI Eina_Bool          eina_matrixsparse_cell_idx_get(const Eina_Matrixsparse 
*m, unsigned long row, unsigned long col, Eina_Matrixsparse_Cell **cell);
+EAPI void *             eina_matrixsparse_cell_data_get(const 
Eina_Matrixsparse_Cell *cell);
+EAPI void *             eina_matrixsparse_data_idx_get(const Eina_Matrixsparse 
*m, unsigned long row, unsigned long col);
+EAPI Eina_Bool          eina_matrixsparse_cell_position_get(const 
Eina_Matrixsparse_Cell *cell, unsigned long *row, unsigned long *col);
+
+/* data setting */
+EAPI Eina_Bool eina_matrixsparse_cell_data_replace(Eina_Matrixsparse_Cell 
*cell, const void *data, void **p_old);
+EAPI Eina_Bool eina_matrixsparse_cell_data_set(Eina_Matrixsparse_Cell *cell, 
const void *data);
+EAPI Eina_Bool eina_matrixsparse_data_idx_replace(Eina_Matrixsparse *m, 
unsigned long row, unsigned long col, const void *data, void **p_old);
+EAPI Eina_Bool eina_matrixsparse_data_idx_set(Eina_Matrixsparse *m, unsigned 
long row, unsigned long col, const void *data);
+
+/* data deleting */
+EAPI Eina_Bool      eina_matrixsparse_row_idx_clear(Eina_Matrixsparse *m, 
unsigned long row);
+EAPI Eina_Bool      eina_matrixsparse_column_idx_clear(Eina_Matrixsparse *m, 
unsigned long col);
+EAPI Eina_Bool      eina_matrixsparse_cell_idx_clear(Eina_Matrixsparse *m, 
unsigned long row, unsigned long col);
+EAPI Eina_Bool      eina_matrixsparse_cell_clear(Eina_Matrixsparse_Cell *cell);
+
+/* iterators */
+EAPI Eina_Iterator *eina_matrixsparse_iterator_new(const Eina_Matrixsparse *m);
+EAPI Eina_Iterator *eina_matrixsparse_iterator_complete_new(const 
Eina_Matrixsparse *m);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_MATRIXSPARSE_H_ */
diff --git a/tests/suite/ecore/src/include/eina_mempool.h 
b/tests/suite/ecore/src/include/eina_mempool.h
new file mode 100644
index 0000000..cc19e94
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_mempool.h
@@ -0,0 +1,77 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_MEMPOOL_H_
+#define EINA_MEMPOOL_H_
+
+#include "eina_types.h"
+#include "eina_error.h"
+#include "eina_module.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Memory_Pool_Group Memory Pool
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Mempool
+ * Mempool type.
+ */
+typedef struct _Eina_Mempool Eina_Mempool;
+
+/**
+ * @typedef Eina_Mempool_Backend
+ * Mempool backend type.
+ */
+typedef struct _Eina_Mempool_Backend Eina_Mempool_Backend;
+
+EAPI extern Eina_Error EINA_ERROR_NOT_MEMPOOL_MODULE;
+
+EAPI Eina_Mempool *                     eina_mempool_add(const char 
*module,const char *context,const char *options,...) EINA_MALLOC 
EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+EAPI void                               eina_mempool_del(Eina_Mempool *mp) 
EINA_ARG_NONNULL(1);
+
+static inline void *                    eina_mempool_realloc(Eina_Mempool 
*mp,void *element,unsigned int size) EINA_ARG_NONNULL(1) 
EINA_WARN_UNUSED_RESULT;
+static inline void *                    eina_mempool_malloc(Eina_Mempool 
*mp,unsigned int size) EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+static inline void                      eina_mempool_free(Eina_Mempool 
*mp,void *element) EINA_ARG_NONNULL(1);
+
+EAPI void                               eina_mempool_gc(Eina_Mempool *mp) 
EINA_ARG_NONNULL(1);
+EAPI void                               eina_mempool_statistics(Eina_Mempool 
*mp) EINA_ARG_NONNULL(1);
+
+EAPI Eina_Bool                          
eina_mempool_register(Eina_Mempool_Backend *be) EINA_ARG_NONNULL(1);
+EAPI void                               
eina_mempool_unregister(Eina_Mempool_Backend *be) EINA_ARG_NONNULL(1);
+
+EAPI unsigned int                       eina_mempool_alignof(unsigned int 
size);
+
+#include "eina_inline_mempool.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_MEMPOOL_H_ */
diff --git a/tests/suite/ecore/src/include/eina_module.h 
b/tests/suite/ecore/src/include/eina_module.h
new file mode 100644
index 0000000..6618381
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_module.h
@@ -0,0 +1,150 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_MODULE_H_
+#define EINA_MODULE_H_
+
+#include "eina_types.h"
+#include "eina_array.h"
+#include "eina_error.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Module_Group Module
+ *
+ * Eina module provides some helpers over POSIX dlopen(). It is not
+ * meant to replace, abstract or make a "portable" version of the
+ * POSIX, but enhance its usage by defining some good practices.
+ *
+ * Modules are created with eina_module_new() and later loaded with
+ * eina_module_load(). Loads are reference counted and there must be
+ * the same number of eina_module_unload() in order to have it to call
+ * dlclose(). This makes simple to have different users for the same
+ * module.
+ *
+ * The loaded shared objects may have two visible functions that will
+ * be called and might provide initialization and shutdown
+ * proceedures. The symbols are @c __eina_module_init and
+ * @c __eina_module_shutdown and will be defined by the macros
+ * EINA_MODULE_INIT() and EINA_MODULE_SHUTDOWN().
+ *
+ * There are some helpers to automatically create modules based on
+ * directory listing. See eina_module_arch_list_get(),
+ * eina_module_list_get() and eina_module_find().
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Module
+ * Dynamic module loader handle.
+ */
+typedef struct _Eina_Module Eina_Module;
+
+typedef Eina_Bool (*Eina_Module_Cb)(Eina_Module *m, void *data);
+
+/**
+ * @typedef Eina_Module_Init
+ * If a function with such signature is exported by module as
+ * __eina_module_init, it will be called on the first load after
+ * dlopen() and if #EINA_FALSE is returned, load will fail, #EINA_TRUE
+ * means the module was successfully initialized.
+ * @see Eina_Module_Shutdown
+ */
+typedef Eina_Bool (*Eina_Module_Init)(void);
+
+/**
+ * @typedef Eina_Module_Shutdown
+ * If a function with such signature is exported by module as
+ * __eina_module_shutdown, it will be called before calling dlclose()
+ * @see Eina_Module_Init
+ */
+typedef void (*Eina_Module_Shutdown)(void);
+
+/**
+ * @def EINA_MODULE_INIT
+ * declares the given function as the module initializer (__eina_module_init).
+ * It must be of signature #Eina_Module_Init
+ */
+#define EINA_MODULE_INIT(f) EAPI Eina_Module_Init __eina_module_init = &f
+
+/**
+ * @def EINA_MODULE_SHUTDOWN
+ * declares the given function as the module shutdownializer
+ * (__eina_module_shutdown).  It must be of signature
+ * #Eina_Module_Shutdown
+ */
+#define EINA_MODULE_SHUTDOWN(f) EAPI Eina_Module_Shutdown 
__eina_module_shutdown = &f
+
+/**
+ * @var EINA_ERROR_WRONG_MODULE
+ * Error identifier corresponding to a wrong module.
+ */
+extern EAPI Eina_Error EINA_ERROR_WRONG_MODULE;
+
+/**
+ * @var EINA_ERROR_MODULE_INIT_FAILED
+ * Error identifier corresponding to a failure during the initialisation of a 
module.
+ */
+extern EAPI Eina_Error EINA_ERROR_MODULE_INIT_FAILED;
+
+EAPI Eina_Module *
+eina_module_new(const char *file) EINA_MALLOC EINA_WARN_UNUSED_RESULT 
EINA_ARG_NONNULL(1);
+EAPI Eina_Bool
+eina_module_free(Eina_Module *m) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool
+eina_module_load(Eina_Module *module) EINA_ARG_NONNULL(1);
+EAPI Eina_Bool
+eina_module_unload(Eina_Module *m) EINA_ARG_NONNULL(1);
+EAPI void *
+eina_module_symbol_get(const Eina_Module *module, const char *symbol) 
EINA_PURE EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI const char *
+eina_module_file_get(const Eina_Module *m) EINA_PURE EINA_WARN_UNUSED_RESULT 
EINA_ARG_NONNULL(1);
+
+EAPI char *
+eina_module_symbol_path_get(const void *symbol, const char *sub_dir) EINA_PURE 
EINA_MALLOC EINA_ARG_NONNULL(1, 2);
+EAPI char *
+eina_module_environment_path_get(const char *env, const char *sub_dir) 
EINA_PURE EINA_MALLOC EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Array *
+eina_module_arch_list_get(Eina_Array *array, const char *path, const char 
*arch);
+EAPI Eina_Array *
+eina_module_list_get(Eina_Array *array, const char *path, Eina_Bool recursive, 
Eina_Module_Cb cb, void *data) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI void
+eina_module_list_load(Eina_Array *list) EINA_ARG_NONNULL(1);
+EAPI void
+eina_module_list_unload(Eina_Array *list) EINA_ARG_NONNULL(1);
+EAPI void
+eina_module_list_free(Eina_Array *list) EINA_ARG_NONNULL(1);
+EAPI Eina_Module *
+eina_module_find(const Eina_Array *array, const char *module) 
EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /*EINA_MODULE_H_*/
diff --git a/tests/suite/ecore/src/include/eina_quadtree.h 
b/tests/suite/ecore/src/include/eina_quadtree.h
new file mode 100644
index 0000000..ad24c3e
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_quadtree.h
@@ -0,0 +1,53 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2010 Cedric BAIL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_QUADTREE_H_
+#define EINA_QUADTREE_H_
+
+#include "eina_config.h"
+
+#include "eina_inlist.h"
+
+typedef struct _Eina_QuadTree Eina_QuadTree;
+typedef struct _Eina_QuadTree_Item Eina_QuadTree_Item;
+
+typedef enum {
+   EINA_QUAD_LEFT,
+   EINA_QUAD_RIGHT,
+   EINA_QUAD_BOTH
+} Eina_Quad_Direction;
+
+typedef Eina_Quad_Direction (*Eina_Quad_Callback)(const void *object, size_t 
middle);
+
+EAPI Eina_QuadTree *     eina_quadtree_new(size_t w, size_t h, 
Eina_Quad_Callback vertical, Eina_Quad_Callback horizontal);
+EAPI void                eina_quadtree_free(Eina_QuadTree *q);
+EAPI void                eina_quadtree_resize(Eina_QuadTree *q, size_t w, 
size_t h);
+
+EAPI void                eina_quadtree_cycle(Eina_QuadTree *q);
+EAPI void                eina_quadtree_increase(Eina_QuadTree_Item *object);
+
+EAPI Eina_QuadTree_Item *eina_quadtree_add(Eina_QuadTree *q, const void 
*object);
+EAPI Eina_Bool           eina_quadtree_del(Eina_QuadTree_Item *object);
+EAPI Eina_Bool           eina_quadtree_change(Eina_QuadTree_Item *object);
+EAPI Eina_Bool           eina_quadtree_hide(Eina_QuadTree_Item *object);
+EAPI Eina_Bool           eina_quadtree_show(Eina_QuadTree_Item *object);
+
+EAPI Eina_Inlist *       eina_quadtree_collide(Eina_QuadTree *q, int x, int y, 
int w, int h);
+EAPI void *              eina_quadtree_object(Eina_Inlist *list);
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_rbtree.h 
b/tests/suite/ecore/src/include/eina_rbtree.h
new file mode 100644
index 0000000..026db41
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_rbtree.h
@@ -0,0 +1,157 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_RBTREE_H__
+#define EINA_RBTREE_H__
+
+#include <stdlib.h>
+
+#include "eina_types.h"
+#include "eina_error.h"
+#include "eina_iterator.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @addtogroup Eina_Containers_Group Containers
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Rbtree_Group Red-Black tree
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Rbtree_Color
+ * node color.
+ */
+typedef enum {
+   EINA_RBTREE_RED,
+   EINA_RBTREE_BLACK
+} Eina_Rbtree_Color;
+
+/**
+ * @typedef Eina_Rbtree_Direction
+ * walk direction.
+ */
+typedef enum {
+   EINA_RBTREE_LEFT = 0,
+   EINA_RBTREE_RIGHT = 1
+} Eina_Rbtree_Direction;
+
+/**
+ * @typedef Eina_Rbtree
+ * Type for a Red-Black tree node. It should be inlined into user's type.
+ */
+typedef struct _Eina_Rbtree Eina_Rbtree;
+struct _Eina_Rbtree
+{
+   Eina_Rbtree *son[2];
+
+   Eina_Rbtree_Color color : 1;
+};
+
+/**
+ * @def EINA_RBTREE
+ * recommended way to declare the inlined Eina_Rbtree in your type.
+ *
+ * @code
+ * struct my_type {
+ *    EINA_RBTREE;
+ *    int my_value;
+ *    char *my_name;
+ * };
+ * @endcode
+ *
+ * @see EINA_RBTREE_GET()
+ */
+#define EINA_RBTREE Eina_Rbtree __rbtree
+
+/**
+ * @def EINA_RBTREE_GET
+ * access the inlined node if it was created with #EINA_RBTREE.
+ */
+#define EINA_RBTREE_GET(Rbtree) & ((Rbtree)->__rbtree)
+
+/**
+ * @typedef Eina_Rbtree_Cmp_Node_Cb
+ * Function used compare two nodes and see which direction to navigate.
+ */
+typedef Eina_Rbtree_Direction (*Eina_Rbtree_Cmp_Node_Cb)(const Eina_Rbtree 
*left, const Eina_Rbtree *right, void *data);
+
+/**
+ * @def EINA_RBTREE_CMP_NODE_CB
+ * Cast using #Eina_Rbtree_Cmp_Node_Cb
+ */
+#define EINA_RBTREE_CMP_NODE_CB(Function) ((Eina_Rbtree_Cmp_Node_Cb)Function)
+
+/**
+ * @typedef Eina_Rbtree_Cmp_Key_Cb
+ * Function used compare node with a given key of specified length.
+ */
+typedef int (*Eina_Rbtree_Cmp_Key_Cb)(const Eina_Rbtree *node, const void 
*key, int length, void *data);
+/**
+ * @def EINA_RBTREE_CMP_KEY_CB
+ * Cast using #Eina_Rbtree_Cmp_Key_Cb
+ */
+#define EINA_RBTREE_CMP_KEY_CB(Function) ((Eina_Rbtree_Cmp_Key_Cb)Function)
+
+/**
+ * @typedef Eina_Rbtree_Free_Cb
+ * Function used free a node.
+ */
+typedef void (*Eina_Rbtree_Free_Cb)(Eina_Rbtree *node, void *data);
+/**
+ * @def EINA_RBTREE_FREE_CB
+ * Cast using #Eina_Rbtree_Free_Cb
+ */
+#define EINA_RBTREE_FREE_CB(Function) ((Eina_Rbtree_Free_Cb)Function)
+
+EAPI Eina_Rbtree *              eina_rbtree_inline_insert(Eina_Rbtree 
*root,Eina_Rbtree *node,Eina_Rbtree_Cmp_Node_Cb cmp,const void *data) 
EINA_ARG_NONNULL(2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Rbtree *              eina_rbtree_inline_remove(Eina_Rbtree 
*root,Eina_Rbtree *node,Eina_Rbtree_Cmp_Node_Cb cmp,const void *data) 
EINA_ARG_NONNULL(2, 3) EINA_WARN_UNUSED_RESULT;
+EAPI void                       eina_rbtree_delete(Eina_Rbtree 
*root,Eina_Rbtree_Free_Cb func,void *data) EINA_ARG_NONNULL(2);
+
+static inline Eina_Rbtree *     eina_rbtree_inline_lookup(const Eina_Rbtree 
*root,const void *key,int length,Eina_Rbtree_Cmp_Key_Cb cmp,const void *data) 
EINA_PURE EINA_ARG_NONNULL(2, 4) EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Iterator *            eina_rbtree_iterator_prefix(const Eina_Rbtree 
*root) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Iterator *            eina_rbtree_iterator_infix(const Eina_Rbtree 
*root) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Iterator *            eina_rbtree_iterator_postfix(const Eina_Rbtree 
*root) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+
+#include "eina_inline_rbtree.x"
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_rectangle.h 
b/tests/suite/ecore/src/include/eina_rectangle.h
new file mode 100644
index 0000000..a9daf66
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_rectangle.h
@@ -0,0 +1,109 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful, 
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_RECTANGLE_H_
+#define EINA_RECTANGLE_H_
+
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Rectangle_Group Rectangle
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Rectangle
+ * Simple rectangle structure.
+ */
+typedef struct _Eina_Rectangle
+{
+  int x; /**< top-left x co-ordinate of rectangle */
+  int y; /**< top-left y co-ordinate of rectangle */
+  int w; /**< width of rectangle */
+  int h; /**< height of rectangle */
+} Eina_Rectangle;
+
+/**
+ * @typedef Eina_Rectangle_Pool
+ * Type for an opaque pool of rectangle.
+ */
+typedef struct _Eina_Rectangle_Pool Eina_Rectangle_Pool;
+
+static inline int eina_spans_intersect(int c1, int l1, int c2, int l2) 
EINA_WARN_UNUSED_RESULT;
+static inline Eina_Bool eina_rectangle_is_empty(const Eina_Rectangle *r) 
EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+static inline void eina_rectangle_coords_from(Eina_Rectangle *r, int x, int y, 
int w, int h) EINA_ARG_NONNULL(1);
+static inline Eina_Bool eina_rectangles_intersect(const Eina_Rectangle *r1, 
const Eina_Rectangle *r2) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+static inline Eina_Bool eina_rectangle_xcoord_inside(const Eina_Rectangle *r, 
int x) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+static inline Eina_Bool eina_rectangle_ycoord_inside(const Eina_Rectangle *r, 
int y) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+static inline Eina_Bool eina_rectangle_coords_inside(const Eina_Rectangle *r, 
int x, int y) EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+static inline void eina_rectangle_union(Eina_Rectangle *dst, const 
Eina_Rectangle *src) EINA_ARG_NONNULL(1, 2);
+static inline Eina_Bool eina_rectangle_intersection(Eina_Rectangle *dst, const 
Eina_Rectangle *src) EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+static inline void eina_rectangle_rescale_in(const Eina_Rectangle *out, const 
Eina_Rectangle *in, Eina_Rectangle *res) EINA_ARG_NONNULL(1, 2, 3);
+static inline void eina_rectangle_rescale_out(const Eina_Rectangle *out, const 
Eina_Rectangle *in, Eina_Rectangle *res) EINA_ARG_NONNULL(1, 2, 3);
+
+EAPI Eina_Rectangle_Pool * eina_rectangle_pool_new(int w, int h) EINA_MALLOC 
EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Rectangle_Pool * eina_rectangle_pool_get(Eina_Rectangle *rect) 
EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+EAPI Eina_Bool eina_rectangle_pool_geometry_get(Eina_Rectangle_Pool *pool, int 
*w, int *h) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI void * eina_rectangle_pool_data_get(Eina_Rectangle_Pool *pool) 
EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+EAPI void eina_rectangle_pool_data_set(Eina_Rectangle_Pool *pool, const void 
*data) EINA_ARG_NONNULL(1);
+EAPI void eina_rectangle_pool_free(Eina_Rectangle_Pool *pool) 
EINA_ARG_NONNULL(1);
+EAPI int eina_rectangle_pool_count(Eina_Rectangle_Pool *pool) 
EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Rectangle * eina_rectangle_pool_request(Eina_Rectangle_Pool *pool, 
int w, int h) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+EAPI void eina_rectangle_pool_release(Eina_Rectangle *rect) 
EINA_ARG_NONNULL(1);
+
+/**
+ * @def EINA_RECTANGLE_SET
+ * @brief Macro to set the values of a #Eina_Rectangle.
+ *
+ * @param Rectangle The rectangle to set the values.
+ * @param X The X coordinate of the top left corner of the rectangle.
+ * @param Y The Y coordinate of the top left corner of the rectangle.
+ * @param W The width of the rectangle.
+ * @param H The height of the rectangle.
+ *
+ * This macro set the values of @p Rectangle. (@p X, @p Y) is the
+ * coordinates of the top left corner of @p Rectangle, @p W is its
+ * width and @p H is its height.
+ */
+#define EINA_RECTANGLE_SET(Rectangle, X, Y, W, H) \
+                          (Rectangle)->x = X;     \
+                          (Rectangle)->y = Y;     \
+                          (Rectangle)->w = W;     \
+                          (Rectangle)->h = H;
+
+EAPI Eina_Rectangle *eina_rectangle_new(int x, int y, int w, int h) 
EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI void            eina_rectangle_free(Eina_Rectangle *rect) 
EINA_ARG_NONNULL(1);
+
+#include "eina_inline_rectangle.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /*_EINA_RECTANGLE_H_*/
diff --git a/tests/suite/ecore/src/include/eina_safety_checks.h 
b/tests/suite/ecore/src/include/eina_safety_checks.h
new file mode 100644
index 0000000..29ebba0
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_safety_checks.h
@@ -0,0 +1,234 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Gustavo Sverzut Barbieri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_SAFETY_CHECKS_H_
+#define EINA_SAFETY_CHECKS_H_
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Safety_Checks_Group Safety Checks
+ *
+ * @warning @c eina_safety_checks.h should only be included by source
+ *          files, after all other includes and before the source file
+ *          specific includes. By source file specific includes we
+ *          mean those that define the functions that are being
+ *          checked. The reason for such complexity is the trick to
+ *          avoid compiler optimizations. If compilers are told that
+ *          some given function will never receive @c NULL
+ *          (EINA_ARG_NONNULL(), then compiler will emit a warning if
+ *          it detects so (good!) but will remove any checks for that
+ *          condition as it believes it will never happen, removing
+ *          all safety checks! By including @c eina_safety_checks.h it
+ *          will redefine EINA_ARG_NONNULL() to void and compiler
+ *          warning will not be emitted, but checks will be there. The
+ *          files already processed with the old macro
+ *          EINA_ARG_NONNULL() will still work and emit the warnings.
+ *
+ *
+ * @code
+ *
+ * // all these files will emit warning from EINA_ARG_NONNULL()
+ * #include <Evas.h>  // third party headers
+ * #include <Ecore.h>
+ * #include <eina_error.h> // eina own header
+ *
+ * #include <eina_safety_checks.h>
+ * // all these files below will NOT emit warning from EINA_ARG_NONNULL(),
+ * // but this is required to have the functions defined there to be checked
+ * // for NULL pointers
+ * #include "my_functions1.h"
+ * #include "my_functions2.h"
+ *
+ * @endcode
+ *
+ * @{
+ */
+
+
+#include "eina_config.h"
+#include "eina_error.h"
+
+/**
+ * @var EINA_ERROR_SAFETY_FAILED
+ * Error identifier corresponding to safety check failure.
+ */
+EAPI extern Eina_Error EINA_ERROR_SAFETY_FAILED;
+
+#ifdef EINA_SAFETY_CHECKS
+
+#include "eina_log.h"
+
+#define EINA_SAFETY_ON_NULL_RETURN(exp)                                 \
+  do                                                                    \
+    {                                                                   \
+       if (EINA_UNLIKELY((exp) == NULL))                                \
+        {                                                              \
+           eina_error_set(EINA_ERROR_SAFETY_FAILED);                   \
+           EINA_LOG_ERR("%s", "safety check failed: " # exp " == NULL"); \
+           return;                                                     \
+        }                                                              \
+    }                                                                   \
+  while (0)
+
+#define EINA_SAFETY_ON_NULL_RETURN_VAL(exp, val)                        \
+  do                                                                    \
+    {                                                                   \
+       if (EINA_UNLIKELY((exp) == NULL))                                \
+        {                                                              \
+           eina_error_set(EINA_ERROR_SAFETY_FAILED);                   \
+           EINA_LOG_ERR("%s", "safety check failed: " # exp " == NULL"); \
+           return (val);                                               \
+        }                                                              \
+    }                                                                   \
+  while (0)
+
+#define EINA_SAFETY_ON_NULL_GOTO(exp, label)                            \
+  do                                                                    \
+    {                                                                   \
+       if (EINA_UNLIKELY((exp) == NULL))                                \
+        {                                                              \
+           eina_error_set(EINA_ERROR_SAFETY_FAILED);                   \
+           EINA_LOG_ERR("%s", "safety check failed: " # exp " == NULL"); \
+           goto label;                                                 \
+        }                                                              \
+    }                                                                   \
+  while (0)
+
+#define EINA_SAFETY_ON_TRUE_RETURN(exp)                                 \
+  do                                                                    \
+    {                                                                   \
+       if (EINA_UNLIKELY(exp))                                          \
+        {                                                              \
+           eina_error_set(EINA_ERROR_SAFETY_FAILED);                   \
+           EINA_LOG_ERR("%s", "safety check failed: " # exp " is true"); \
+           return;                                                     \
+        }                                                              \
+    }                                                                   \
+  while (0)
+
+#define EINA_SAFETY_ON_TRUE_RETURN_VAL(exp, val)                        \
+  do                                                                    \
+    {                                                                  \
+       if (EINA_UNLIKELY(exp))                                         \
+        {                                                              \
+           eina_error_set(EINA_ERROR_SAFETY_FAILED);                   \
+           EINA_LOG_ERR("%s", "safety check failed: " # exp " is true"); \
+           return val;                                                 \
+        }                                                              \
+    }                                                                   \
+  while (0)
+
+#define EINA_SAFETY_ON_TRUE_GOTO(exp, label)                            \
+  do                                                                    \
+    {                                                                   \
+       if (EINA_UNLIKELY(exp))                                          \
+        {                                                              \
+           eina_error_set(EINA_ERROR_SAFETY_FAILED);                   \
+           EINA_LOG_ERR("%s", "safety check failed: " # exp " is true"); \
+           goto label;                                                 \
+        }                                                              \
+    }                                                                   \
+  while (0)
+
+#define EINA_SAFETY_ON_FALSE_RETURN(exp)                                \
+  do                                                                    \
+    {                                                                   \
+       if (EINA_UNLIKELY(!(exp)))                                       \
+        {                                                              \
+           eina_error_set(EINA_ERROR_SAFETY_FAILED);                   \
+           EINA_LOG_ERR("%s", "safety check failed: " # exp " is false"); \
+           return;                                                     \
+        }                                                              \
+    }                                                                   \
+  while (0)
+
+#define EINA_SAFETY_ON_FALSE_RETURN_VAL(exp, val)                       \
+  do                                                                    \
+    {                                                                   \
+       if (EINA_UNLIKELY(!(exp)))                                       \
+        {                                                              \
+           eina_error_set(EINA_ERROR_SAFETY_FAILED);                   \
+           EINA_LOG_ERR("%s", "safety check failed: " # exp " is false"); \
+           return val;                                                 \
+        }                                                              \
+    }                                                                   \
+  while (0)
+
+#define EINA_SAFETY_ON_FALSE_GOTO(exp, label)                           \
+  do                                                                    \
+    {                                                                   \
+       if (EINA_UNLIKELY(!(exp)))                                       \
+        {                                                              \
+           eina_error_set(EINA_ERROR_SAFETY_FAILED);                   \
+           EINA_LOG_ERR("%s", "safety check failed: " # exp " is false"); \
+           goto label;                                                 \
+        }                                                              \
+    }                                                                   \
+  while (0)
+
+#ifdef EINA_ARG_NONNULL
+/* make EINA_ARG_NONNULL void so GCC does not optimize safety checks */
+#undef EINA_ARG_NONNULL
+#define EINA_ARG_NONNULL(idx, ...)
+#endif
+
+
+#else /* no safety checks */
+
+#define EINA_SAFETY_ON_NULL_RETURN(exp)                \
+  do { (void)(!(exp)); } while (0)
+
+#define EINA_SAFETY_ON_NULL_RETURN_VAL(exp, val)               \
+  do { if (0 && !(exp)) { (void)val; } } while (0)
+
+#define EINA_SAFETY_ON_NULL_GOTO(exp, label)                   \
+  do { if (0 && (exp) == NULL) { goto label; } } while (0)
+
+#define EINA_SAFETY_ON_TRUE_RETURN(exp)                \
+  do { (void)(exp); } while (0)
+
+#define EINA_SAFETY_ON_TRUE_RETURN_VAL(exp, val)       \
+  do { if (0 && (exp)) { (void)val; } } while (0)
+
+#define EINA_SAFETY_ON_TRUE_GOTO(exp, label)           \
+  do { if (0 && (exp)) { goto label; } } while (0)
+
+#define EINA_SAFETY_ON_FALSE_RETURN(exp)       \
+  do { (void)(!(exp)); } while (0)
+
+#define EINA_SAFETY_ON_FALSE_RETURN_VAL(exp, val)      \
+  do { if (0 && !(exp)) { (void)val; } } while (0)
+
+#define EINA_SAFETY_ON_FALSE_GOTO(exp, label)          \
+  do { if (0 && !(exp)) { goto label; } } while (0)
+
+#endif /* safety checks macros */
+#endif /* EINA_SAFETY_CHECKS_H_ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/include/eina_sched.h 
b/tests/suite/ecore/src/include/eina_sched.h
new file mode 100644
index 0000000..607b9f5
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_sched.h
@@ -0,0 +1,26 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2010 ProFUSION embedded systems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_SCHED_H_
+#define EINA_SCHED_H_
+
+#include "eina_types.h"
+
+EAPI void eina_sched_prio_drop(void);
+
+#endif /* EINA_SCHED_H_ */
diff --git a/tests/suite/ecore/src/include/eina_str.h 
b/tests/suite/ecore/src/include/eina_str.h
new file mode 100644
index 0000000..1d12615
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_str.h
@@ -0,0 +1,73 @@
+#ifndef _EINA_STR_H
+#define _EINA_STR_H
+
+#include <stddef.h>
+#include <string.h>
+
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Tools_Group Tools
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_String_Group String
+ *
+ * @{
+ */
+
+/* strlcpy implementation for libc's lacking it */
+EAPI size_t      eina_strlcpy(char *dst, const char *src, size_t siz) 
EINA_ARG_NONNULL(1, 2);
+EAPI size_t      eina_strlcat(char *dst, const char *src, size_t siz) 
EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Bool   eina_str_has_prefix(const char *str, const char *prefix) 
EINA_PURE EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool   eina_str_has_suffix(const char *str, const char *suffix) 
EINA_PURE EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+EAPI Eina_Bool   eina_str_has_extension(const char *str, const char *ext) 
EINA_PURE    EINA_ARG_NONNULL(1, 2) EINA_WARN_UNUSED_RESULT;
+
+EAPI char **     eina_str_split(const char *string, const char *delimiter, int 
max_tokens) EINA_ARG_NONNULL(1, 2) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+EAPI char **     eina_str_split_full(const char *string, const char 
*delimiter, int max_tokens, unsigned int *elements) EINA_ARG_NONNULL(1, 2, 4) 
EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+
+EAPI size_t      eina_str_join_len(char *dst, size_t size, char sep, const 
char *a, size_t a_len, const char *b, size_t b_len) EINA_ARG_NONNULL(1, 4, 6);
+
+EAPI char *      eina_str_convert(const char *enc_from, const char *enc_to, 
const char *text) EINA_WARN_UNUSED_RESULT EINA_MALLOC EINA_ARG_NONNULL(1, 2, 3);
+
+EAPI char *      eina_str_escape(const char *str) EINA_WARN_UNUSED_RESULT 
EINA_MALLOC EINA_ARG_NONNULL(1);
+
+EAPI void        eina_str_tolower(char **str);
+EAPI void        eina_str_toupper(char **str);
+
+static inline size_t eina_str_join(char *dst, size_t size, char sep, const 
char *a, const char *b) EINA_ARG_NONNULL(1, 4, 5);
+
+/**
+ * @def eina_str_join_static(dst, sep, a, b)
+ * @brief Join two static strings and store the result in a static buffer.
+ *
+ * @param dst The buffer to store the result.
+ * @param sep The separator character to use.
+ * @param a First string to use, before @p sep.
+ * @param b Second string to use, after @p sep.
+ * @return The number of characters printed.
+ *
+ * This function is similar to eina_str_join_len(), but will assume
+ * string sizes are know using sizeof(X).
+ *
+ * @see eina_str_join()
+ * @see eina_str_join_static()
+ */
+#define eina_str_join_static(dst, sep, a, b) eina_str_join_len(dst, 
sizeof(dst), sep, a, (sizeof(a) > 0) ? sizeof(a) - 1 : 0, b, (sizeof(b) > 0) ? 
sizeof(b) - 1 : 0)
+
+static inline size_t eina_strlen_bounded(const char *str, size_t maxlen) 
EINA_PURE EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+#include "eina_inline_str.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_STR_H */
diff --git a/tests/suite/ecore/src/include/eina_strbuf.h 
b/tests/suite/ecore/src/include/eina_strbuf.h
new file mode 100644
index 0000000..4424eb4
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_strbuf.h
@@ -0,0 +1,477 @@
+#ifndef EINA_STRBUF_H
+#define EINA_STRBUF_H
+
+#include <stddef.h>
+#include <stdarg.h>
+
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_String_Buffer_Group String Buffer
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Strbuf
+ * Type for a string buffer.
+ */
+typedef struct _Eina_Strbuf Eina_Strbuf;
+
+/**
+ * @brief Create a new string buffer.
+ *
+ * @return Newly allocated string buffer instance.
+ *
+ * This function creates a new string buffer. On error, @c NULL is
+ * returned and Eina error is set to #EINA_ERROR_OUT_OF_MEMORY. To
+ * free the resources, use eina_strbuf_free().
+ *
+ * @see eina_strbuf_free()
+ * @see eina_strbuf_append()
+ * @see eina_strbuf_string_get()
+ */
+EAPI Eina_Strbuf *eina_strbuf_new(void) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @brief Free a string buffer.
+ *
+ * @param buf The string buffer to free.
+ *
+ * This function frees the memory of @p buf. @p buf must have been
+ * created by eina_strbuf_new().
+ */
+EAPI void         eina_strbuf_free(Eina_Strbuf *buf) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Reset a string buffer.
+ *
+ * @param buf The string buffer to reset.
+ *
+ * This function reset @p buf: the buffer len is set to 0, and the
+ * string is set to '\\0'. No memory is free'd.
+ */
+EAPI void         eina_strbuf_reset(Eina_Strbuf *buf) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Append a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends @p str to @p buf. It computes the length of
+ * @p str, so is slightly slower than eina_strbuf_append_length(). If
+ * the length is known beforehand, consider using that variant. If
+ * @p buf can't append it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ *
+ * @see eina_strbuf_append()
+ * @see eina_strbuf_append_length()
+ */
+EAPI Eina_Bool    eina_strbuf_append(Eina_Strbuf *buf, const char *str) 
EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Append an escaped string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends the escaped string @p str to @p buf. If @p
+ * str can not be appended, #EINA_FALSE is returned, otherwise,
+ * #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool    eina_strbuf_append_escaped(Eina_Strbuf *buf, const char 
*str) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Append a string to a buffer, reallocating as necessary,
+ * limited by the given length.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @param maxlen The maximum number of characters to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends at most @p maxlen characters of @p str to
+ * @p buf. It can't appends more than the length of @p str. It
+ * computes the length of @p str, so is slightly slower than
+ * eina_strbuf_append_length(). If the length is known beforehand,
+ * consider using that variant (@p maxlen should then be checked so
+ * that it is greater than the size of @p str). If @p str can not be
+ * appended, #EINA_FALSE is returned, otherwise, #EINA_TRUE is
+ * returned.
+ *
+ * @see eina_strbuf_append()
+ * @see eina_strbuf_append_length()
+ */
+EAPI Eina_Bool    eina_strbuf_append_n(Eina_Strbuf *buf, const char *str, 
size_t maxlen) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Append a string of exact length to a buffer, reallocating as 
necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @param length The exact length to use.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends @p str to @p buf. @p str must be of size at
+ * most @p length. It is slightly faster than eina_strbuf_append() as
+ * it does not compute the size of @p str. It is useful when dealing
+ * with strings of known size, such as eina_strngshare. If @p buf
+ * can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ *
+ * @see eina_stringshare_length()
+ * @see eina_strbuf_append()
+ * @see eina_strbuf_append_n()
+ */
+EAPI Eina_Bool    eina_strbuf_append_length(Eina_Strbuf *buf, const char *str, 
size_t length) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Append a character to a string buffer, reallocating as
+ * necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param c The char to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p c to @p buf. If it can not insert it,
+ * #EINA_FALSE is returned, otherwise #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool    eina_strbuf_append_char(Eina_Strbuf *buf, char c) 
EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Append a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param fmt The string to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * @see eina_strbuf_append()
+ */
+EAPI Eina_Bool    eina_strbuf_append_printf(Eina_Strbuf *buf, const char *fmt, 
...) EINA_ARG_NONNULL(1, 2) EINA_PRINTF(2, 3);
+
+/**
+ * @brief Append a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param fmt The string to append.
+ * @param args The variable arguments.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * @see eina_strbuf_append()
+ */
+EAPI Eina_Bool    eina_strbuf_append_vprintf(Eina_Strbuf *buf, const char 
*fmt, va_list args) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Insert a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to insert.
+ * @param str The string to insert.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p str to @p buf at position @p pos. It
+ * computes the length of @p str, so is slightly slower than
+ * eina_strbuf_insert_length(). If  the length is known beforehand,
+ * consider using that variant. If @p buf can't insert it, #EINA_FALSE
+ * is returned, otherwise #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool    eina_strbuf_insert(Eina_Strbuf *buf, const char *str, size_t 
pos) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Insert an escaped string to a buffer, reallocating as
+ * necessary.
+ *
+ * @param buf The string buffer to insert to.
+ * @param str The string to insert.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts the escaped string @p str to @p buf at
+ * position @p pos. If @p buf can't insert @p str, #EINA_FALSE is
+ * returned, otherwise #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool    eina_strbuf_insert_escaped(Eina_Strbuf *buf, const char 
*str, size_t pos) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Insert a string to a buffer, reallocating as necessary. Limited by 
maxlen.
+ *
+ * @param buf The string buffer to insert to.
+ * @param str The string to insert.
+ * @param maxlen The maximum number of chars to insert.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p str ot @p buf at position @p pos, with at
+ * most @p maxlen bytes. The number of inserted characters can not be
+ * greater than the length of @p str. It computes the length of
+ * @p str, so is slightly slower than eina_strbuf_insert_length(). If the
+ * length is known beforehand, consider using that variant (@p maxlen
+ * should then be checked so that it is greater than the size of
+ * @p str). If @p str can not be inserted, #EINA_FALSE is returned,
+ * otherwise, #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool    eina_strbuf_insert_n(Eina_Strbuf *buf, const char *str, 
size_t maxlen, size_t pos) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Insert a string of exact length to a buffer, reallocating as 
necessary.
+ *
+ * @param buf The string buffer to insert to.
+ * @param str The string to insert.
+ * @param length The exact length to use.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p str to @p buf. @p str must be of size at
+ * most @p length. It is slightly faster than eina_strbuf_insert() as
+ * it does not compute the size of @p str. It is useful when dealing
+ * with strings of known size, such as eina_strngshare. If @p buf
+ * can't insert it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ *
+ * @see eina_stringshare_length()
+ * @see eina_strbuf_insert()
+ * @see eina_strbuf_insert_n()
+ */
+EAPI Eina_Bool    eina_strbuf_insert_length(Eina_Strbuf *buf, const char *str, 
size_t length, size_t pos) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Insert a character to a string buffer, reallocating as
+ * necessary.
+ *
+ * @param buf The string buffer to insert to.
+ * @param c The char to insert.
+ * @param pos The position to insert the char.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p c to @p buf at position @p pos. If @p buf
+ * can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+EAPI Eina_Bool    eina_strbuf_insert_char(Eina_Strbuf *buf, char c, size_t 
pos) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Insert a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to insert.
+ * @param fmt The string to insert.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ */
+EAPI Eina_Bool    eina_strbuf_insert_printf(Eina_Strbuf *buf, const char *fmt, 
size_t pos, ...) EINA_ARG_NONNULL(1, 2) EINA_PRINTF(2, 4);
+
+/**
+ * @brief Insert a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to insert.
+ * @param fmt The string to insert.
+ * @param pos The position to insert the string.
+ * @param args The variable arguments.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ */
+EAPI Eina_Bool    eina_strbuf_insert_vprintf(Eina_Strbuf *buf, const char 
*fmt, size_t pos, va_list args) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @def eina_strbuf_prepend(buf, str)
+ * @brief Prepend the given string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param str The string to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_strbuf_insert() at position 0.If @p buf
+ * can't prepend it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+#define eina_strbuf_prepend(buf, str) eina_strbuf_insert(buf, str, 0)
+
+/**
+ * @def eina_strbuf_prepend_escaped(buf, str)
+ * @brief Prepend the given escaped string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param str The string to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_strbuf_insert_escaped() at position 0. If
+ * @p buf can't prepend it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ */
+#define eina_strbuf_prepend_escaped(buf, str) eina_strbuf_insert_escaped(buf, 
str, 0)
+
+/**
+ * @def eina_strbuf_prepend_n(buf, str)
+ * @brief Prepend the given escaped string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param str The string to prepend.
+ * @param maxlen The maximum number of chars to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_strbuf_insert_n() at position 0. If
+ * @p buf can't prepend it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ */
+#define eina_strbuf_prepend_n(buf, str, maxlen) eina_strbuf_insert_n(buf, str, 
maxlen, 0)
+
+/**
+ * @def eina_strbuf_prepend_length(buf, str)
+ * @brief Prepend the given escaped string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param str The string to prepend.
+ * @param length The exact length to use.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_strbuf_insert_length() at position 0. If
+ * @p buf can't prepend it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ */
+#define eina_strbuf_prepend_length(buf, str, length) 
eina_strbuf_insert_length( buf, str, length, 0)
+
+/**
+ * @def eina_strbuf_prepend_char(buf, str)
+ * @brief Prepend the given character to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param c The character to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_strbuf_insert_char() at position 0. If
+ * @p buf can't prepend it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ */
+#define eina_strbuf_prepend_char(buf, c) eina_strbuf_insert_char(buf, c, 0)
+
+/**
+ * @def eina_strbuf_prepend_printf(buf, fmt, ...)
+ * @brief Prepend the given string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param fmt The string to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_strbuf_insert_printf() at position 0.If @p buf
+ * can't prepend it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+#define eina_strbuf_prepend_printf(buf, fmt, ...) 
eina_strbuf_insert_printf(buf, fmt, 0, ## __VA_ARGS__)
+
+/**
+ * @def eina_strbuf_prepend_vprintf(buf, fmt, args)
+ * @brief Prepend the given string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param fmt The string to prepend.
+ * @param args The variable arguments.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_strbuf_insert_vprintf() at position 0.If @p buf
+ * can't prepend it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+#define eina_strbuf_prepend_vprintf(buf, fmt, args) 
eina_strbuf_insert_vprintf(buf, fmt, 0, args)
+
+/**
+ * @brief Remove a slice of the given string buffer.
+ *
+ * @param buf The string buffer to remove a slice.
+ * @param start The initial (inclusive) slice position to start
+ *        removing, in bytes.
+ * @param end The final (non-inclusive) slice position to finish
+ *        removing, in bytes.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function removes a slice of @p buf, starting at @p start
+ * (inclusive) and ending at @p end (non-inclusive). Both values are
+ * in bytes. It returns #EINA_FALSE on failure, #EINA_TRUE otherwise.
+ */
+
+EAPI Eina_Bool eina_strbuf_remove(Eina_Strbuf *buf, size_t start, size_t end) 
EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Retrieve a pointer to the contents of a string buffer
+ *
+ * @param buf The string buffer.
+ * @return The current string in the string buffer.
+ *
+ * This function returns the string contained in @p buf. The returned
+ * value must not be modified and will no longer be valid if @p buf is
+ * modified. In other words, any eina_strbuf_append() or similar will
+ * make that pointer invalid.
+ *
+ * @see eina_strbuf_string_steal()
+ */
+EAPI const char *eina_strbuf_string_get(const Eina_Strbuf *buf) 
EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @brief Steal the contents of a string buffer.
+ *
+ * @param buf The string buffer to steal.
+ * @return The current string in the string buffer.
+ *
+ * This function returns the string contained in @p buf. @p buf is
+ * then initialized and does not own the returned string anymore. The
+ * caller must release the memory of the returned string by calling
+ * free().
+ *
+ * @see eina_strbuf_string_get()
+ */
+EAPI char *eina_strbuf_string_steal(Eina_Strbuf *buf) EINA_MALLOC 
EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Free the contents of a string buffer but not the buffer.
+ *
+ * @param buf The string buffer to free the string of.
+ *
+ * This function frees the string contained in @p buf without freeing
+ * @p buf.
+ */
+EAPI void eina_strbuf_string_free(Eina_Strbuf *buf) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Retrieve the length of the string buffer content.
+ *
+ * @param buf The string buffer.
+ * @return The current length of the string, in bytes.
+ *
+ * This function returns the length of @p buf.
+ */
+EAPI size_t eina_strbuf_length_get(const Eina_Strbuf *buf) EINA_ARG_NONNULL(1) 
EINA_WARN_UNUSED_RESULT;
+
+EAPI Eina_Bool eina_strbuf_replace(Eina_Strbuf *buf, const char *str, const 
char *with, unsigned int n) EINA_ARG_NONNULL(1, 2, 3);
+
+/**
+ * @def eina_strbuf_replace_first(buf, str, with)
+ * @brief Prepend the given character to the given buffer
+ *
+ * @param buf The string buffer to work with.
+ * @param str The string to replace.
+ * @param with The replaceing string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_strbuf_replace() with the n-th occurrence
+ * equal to @c 1. If @p buf can't replace it, #EINA_FALSE is returned,
+ * otherwise #EINA_TRUE is returned.
+ */
+#define eina_strbuf_replace_first(buf, str, with) eina_strbuf_replace(buf, 
str, with, 1)
+
+EAPI int eina_strbuf_replace_all(Eina_Strbuf *buf, const char *str, const char 
*with) EINA_ARG_NONNULL(1, 2, 3);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_STRBUF_H */
diff --git a/tests/suite/ecore/src/include/eina_stringshare.h 
b/tests/suite/ecore/src/include/eina_stringshare.h
new file mode 100644
index 0000000..4df5b40
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_stringshare.h
@@ -0,0 +1,93 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Jorge Luis Zapata Muga, Cedric 
Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (C) 2008 Peter Wehrfritz
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a 
copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies of the Software and its Copyright notices. In addition publicly
+ *  documented acknowledgment must be given that this software has been used 
if no
+ *  source code of this software is made available publicly. This includes
+ *  acknowledgments in either Copyright notices, Manuals, Publicity and 
Marketing
+ *  documents or any documentation provided with any product containing this
+ *  software. This License does not apply to any software that links to the
+ *  libraries provided by this software (statically or dynamically), but only 
to
+ *  the software provided.
+ *
+ *  Please see the OLD-COPYING.PLAIN for a plain-english explanation of this 
notice
+ *  and it's intent.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef EINA_STRINGSHARE_H_
+#define EINA_STRINGSHARE_H_
+
+#include <stdarg.h>
+
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Stringshare_Group Stringshare
+ *
+ * @{
+ */
+
+EAPI const char *       eina_stringshare_add_length(const char *str, unsigned 
int slen) EINA_WARN_UNUSED_RESULT;
+EAPI const char *       eina_stringshare_add(const char *str) 
EINA_WARN_UNUSED_RESULT;
+EAPI const char *       eina_stringshare_printf(const char *fmt, ...) 
EINA_WARN_UNUSED_RESULT EINA_PRINTF(1, 2);
+EAPI const char *       eina_stringshare_vprintf(const char *fmt, va_list 
args) EINA_WARN_UNUSED_RESULT;
+EAPI const char *       eina_stringshare_nprintf(unsigned int len, const char 
*fmt, ...) EINA_WARN_UNUSED_RESULT EINA_PRINTF(2, 3);
+EAPI const char *       eina_stringshare_ref(const char *str);
+EAPI void               eina_stringshare_del(const char *str);
+EAPI int                eina_stringshare_strlen(const char *str) EINA_PURE 
EINA_WARN_UNUSED_RESULT;
+EAPI void               eina_stringshare_dump(void);
+
+static inline Eina_Bool eina_stringshare_replace(const char **p_str, const 
char *news) EINA_ARG_NONNULL(1);
+static inline Eina_Bool eina_stringshare_replace_length(const char **p_str, 
const char *news, unsigned int slen) EINA_ARG_NONNULL(1);
+
+#include "eina_inline_stringshare.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_STRINGSHARE_H_ */
diff --git a/tests/suite/ecore/src/include/eina_tiler.h 
b/tests/suite/ecore/src/include/eina_tiler.h
new file mode 100644
index 0000000..19762a5
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_tiler.h
@@ -0,0 +1,86 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_TILER_H_
+#define EINA_TILER_H_
+
+#include "eina_types.h"
+#include "eina_iterator.h"
+#include "eina_rectangle.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Tiler_Group Tiler
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Tiler
+ * Tiler type.
+ */
+typedef struct _Eina_Tiler Eina_Tiler;
+
+/**
+ * @typedef Eina_Tile_Grid_Info
+ * Grid type of a tiler.
+ */
+typedef struct Eina_Tile_Grid_Info Eina_Tile_Grid_Info;
+
+/**
+ * @struct Eina_Tile_Grid_Info
+ * Grid type of a tiler.
+ */
+struct Eina_Tile_Grid_Info
+{
+   unsigned long col; /**< column of the tiler grid */
+   unsigned long row; /**< row of the tiler grid*/
+   Eina_Rectangle rect; /**< rectangle of the tiler grid*/
+   Eina_Bool full; /**< whether the grid is full or not */
+};
+
+typedef struct _Eina_Tile_Grid_Slicer Eina_Tile_Grid_Slicer;
+
+EAPI Eina_Tiler *   eina_tiler_new(int w, int h);
+EAPI void           eina_tiler_free(Eina_Tiler *t);
+EAPI void           eina_tiler_tile_size_set(Eina_Tiler *t, int w, int h);
+EAPI Eina_Bool      eina_tiler_rect_add(Eina_Tiler *t, const Eina_Rectangle 
*r);
+EAPI void           eina_tiler_rect_del(Eina_Tiler *t, const Eina_Rectangle 
*r);
+EAPI void           eina_tiler_clear(Eina_Tiler *t);
+EAPI Eina_Iterator *eina_tiler_iterator_new(const Eina_Tiler *t);
+EAPI Eina_Iterator *eina_tile_grid_slicer_iterator_new(int x, int y, int w, 
int h, int tile_w, int tile_h);
+static inline Eina_Bool eina_tile_grid_slicer_next(Eina_Tile_Grid_Slicer *slc, 
const Eina_Tile_Grid_Info **rect);
+static inline Eina_Bool eina_tile_grid_slicer_setup(Eina_Tile_Grid_Slicer 
*slc, int x, int y, int w, int h, int tile_w, int tile_h);
+
+#include "eina_inline_tiler.x"
+
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_TILER_H_ */
diff --git a/tests/suite/ecore/src/include/eina_trash.h 
b/tests/suite/ecore/src/include/eina_trash.h
new file mode 100644
index 0000000..0d165f1
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_trash.h
@@ -0,0 +1,100 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Vincent Torri, Jorge Luis Zapata 
Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_TRASH_H__
+#define EINA_TRASH_H__
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @addtogroup Eina_Containers_Group Containers
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Trash_Group Trash
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Trash
+ * Type for a generic container of unused allocated pointer.
+ */
+typedef struct _Eina_Trash Eina_Trash;
+
+/**
+ * @struct _Eina_Trash
+ * Type for a generic container of unused allocated pointer.
+ */
+struct _Eina_Trash
+{
+   Eina_Trash *next; /**< next item in trash. */
+};
+
+static inline void  eina_trash_init(Eina_Trash **trash) EINA_ARG_NONNULL(1);
+static inline void  eina_trash_push(Eina_Trash **trash, void *data) 
EINA_ARG_NONNULL(1);
+static inline void *eina_trash_pop(Eina_Trash **trash) EINA_ARG_NONNULL(1) 
EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @def EINA_TRASH_CLEAN
+ * @brief Macro to remove all pointer from the trash.
+ *
+ * @param trash The trash to clean.
+ * @param data The pointer extracted from the trash.
+ *
+ * This macro allow the cleaning of @p trash in an easy way. It will
+ * remove all pointers from @p trash until it's empty.
+ *
+ * This macro can be used for freeing the data in the trash, like in
+ * the following example:
+ *
+ * @code
+ * Eina_Trash *trash = NULL;
+ * char *data;
+ *
+ * // trash is filled with pointer to some duped strings.
+ *
+ * EINA_TRASH_CLEAN(&trash, data)
+ *   free(data);
+ * @endcode
+ *
+ * @note this macro is useful when you implement some memory pool.
+ */
+#define EINA_TRASH_CLEAN(trash, data) while ((data = eina_trash_pop(trash))
+
+#include "eina_inline_trash.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_TRASH_H_ */
diff --git a/tests/suite/ecore/src/include/eina_types.h 
b/tests/suite/ecore/src/include/eina_types.h
new file mode 100644
index 0000000..c94983f
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_types.h
@@ -0,0 +1,284 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Carsten Haitzler, Vincent Torri, Jorge Luis Zapata 
Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_TYPES_H_
+#define EINA_TYPES_H_
+
+/**
+ * @addtogroup Eina_Core_Group Core
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Types_Group Types
+ *
+ * @{
+ */
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_EINA_BUILD
+#  ifdef DLL_EXPORT
+#   define EAPI __declspec(dllexport)
+#  else
+#   define EAPI
+#  endif /* ! DLL_EXPORT */
+# else
+#  define EAPI __declspec(dllimport)
+# endif /* ! EFL_EINA_BUILD */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif
+
+#include "eina_config.h"
+
+#ifdef EINA_WARN_UNUSED_RESULT
+# undef EINA_WARN_UNUSED_RESULT
+#endif
+#ifdef EINA_ARG_NONNULL
+# undef EINA_ARG_NONNULL
+#endif
+#ifdef EINA_DEPRECATED
+# undef EINA_DEPRECATED
+#endif
+#ifdef EINA_MALLOC
+# undef EINA_MALLOC
+#endif
+#ifdef EINA_PURE
+# undef EINA_PURE
+#endif
+#ifdef EINA_PRINTF
+# undef EINA_PRINTF
+#endif
+#ifdef EINA_SCANF
+# undef EINA_SCANF
+#endif
+#ifdef EINA_FORMAT
+# undef EINA_FORMAT
+#endif
+#ifdef EINA_CONST
+# undef EINA_CONST
+#endif
+#ifdef EINA_NOINSTRUMENT
+# undef EINA_NOINSTRUMENT
+#endif
+#ifdef EINA_UNLIKELY
+# undef EINA_UNLIKELY
+#endif
+#ifdef EINA_LIKELY
+# undef EINA_LIKELY
+#endif
+
+
+#ifdef __GNUC__
+# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#  define EINA_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
+# else
+#  define EINA_WARN_UNUSED_RESULT
+# endif
+
+# if (!defined(EINA_SAFETY_CHECKS)) && (__GNUC__ > 3 || (__GNUC__ == 3 && 
__GNUC_MINOR__ >= 3))
+#  define EINA_ARG_NONNULL(idx, ...) __attribute__ ((nonnull(idx, ## 
__VA_ARGS__)))
+# else
+#  define EINA_ARG_NONNULL(idx, ...)
+# endif
+
+# if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
+#  define EINA_DEPRECATED __attribute__ ((__deprecated__))
+# else
+#  define EINA_DEPRECATED
+# endif
+
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
+#  define EINA_MALLOC __attribute__ ((malloc))
+#  define EINA_PURE __attribute__ ((pure))
+# else
+#  define EINA_MALLOC
+#  define EINA_PURE
+# endif
+
+# if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
+#  define EINA_PRINTF(fmt, arg)  __attribute__((format (printf, fmt, arg)))
+#  define EINA_SCANF(fmt, arg)  __attribute__((format (scanf, fmt, arg)))
+#  define EINA_FORMAT(fmt) __attribute__((format_arg(fmt)))
+#  define EINA_CONST __attribute__((const))
+#  define EINA_NOINSTRUMENT __attribute__((no_instrument_function))
+#  define EINA_UNLIKELY(exp) __builtin_expect((exp), 0)
+#  define EINA_LIKELY(exp) __builtin_expect((exp), 1)
+# else
+#  define EINA_PRINTF(fmt, arg)
+#  define EINA_SCANF(fmt, arg)
+#  define EINA_FORMAT(fmt)
+#  define EINA_CONST
+#  define EINA_NOINSTRUMENT
+#  define EINA_UNLIKELY(exp) exp
+#  define EINA_LIKELY(exp) exp
+# endif
+
+#elif defined(_WIN32)
+# define EINA_WARN_UNUSED_RESULT
+# define EINA_ARG_NONNULL(idx, ...)
+# if defined(_MSC_VER) && _MSC_VER >= 1300
+#  define EINA_DEPRECATED __declspec(deprecated)
+# else
+#  define EINA_DEPRECATED
+# endif
+# define EINA_MALLOC
+# define EINA_PURE
+# define EINA_PRINTF(fmt, arg)
+# define EINA_SCANF(fmt, arg)
+# define EINA_FORMAT(fmt)
+# define EINA_CONST
+# define EINA_NOINSTRUMENT
+# define EINA_UNLIKELY(exp) exp
+# define EINA_LIKELY(exp) exp
+
+#elif defined(__SUNPRO_C)
+# define EINA_WARN_UNUSED_RESULT
+# define EINA_ARG_NONNULL(...)
+# define EINA_DEPRECATED
+# if __SUNPRO_C >= 0x590
+#  define EINA_MALLOC __attribute__ ((malloc))
+#  define EINA_PURE __attribute__ ((pure))
+# else
+#  define EINA_MALLOC
+#  define EINA_PURE
+# endif
+# define EINA_PRINTF(fmt, arg)
+# define EINA_SCANF(fmt, arg)
+# define EINA_FORMAT(fmt)
+# if __SUNPRO_C >= 0x590
+#  define EINA_CONST __attribute__ ((const))
+# else
+#  define EINA_CONST
+# endif
+# define EINA_NOINSTRUMENT
+# define EINA_UNLIKELY(exp) exp
+# define EINA_LIKELY(exp) exp
+
+#else /* ! __GNUC__ && ! _WIN32 && ! __SUNPRO_C */
+
+/**
+ * @def EINA_WARN_UNUSED_RESULT
+ * Used to warn when the returned value of the function is not used.
+ */
+# define EINA_WARN_UNUSED_RESULT
+
+/**
+ * @def EINA_ARG_NONNULL
+ * Used to warn when the specified arguments of the function are @c NULL.
+ */
+# define EINA_ARG_NONNULL(idx, ...)
+
+/**
+ * @def EINA_DEPRECATED
+ * Used to warn when the function is considered as deprecated.
+ */
+# define EINA_DEPRECATED
+# define EINA_MALLOC
+# define EINA_PURE
+# define EINA_PRINTF(fmt, arg)
+# define EINA_SCANF(fmt, arg)
+# define EINA_FORMAT(fmt)
+# define EINA_CONST
+# define EINA_NOINSTRUMENT
+# define EINA_UNLIKELY(exp) exp
+# define EINA_LIKELY(exp) exp
+#endif /* ! __GNUC__ && ! _WIN32 && ! __SUNPRO_C */
+
+
+/**
+ * @typedef Eina_Bool
+ * Type to mimic a boolean.
+ *
+ * @note it differs from stdbool.h as this is defined as an unsigned
+ *       char to make it usable by bitfields (Eina_Bool name:1) and
+ *       also take as few bytes as possible.
+ */
+typedef unsigned char Eina_Bool;
+
+/**
+ * @def EINA_FALSE
+ * boolean value FALSE (numerical value 0)
+ */
+#define EINA_FALSE ((Eina_Bool)0)
+
+/**
+ * @def EINA_TRUE
+ * boolean value TRUE (numerical value 1)
+ */
+#define EINA_TRUE ((Eina_Bool)1)
+
+EAPI extern const unsigned int eina_prime_table[];
+
+/**
+ * @typedef Eina_Compare_Cb
+ * Function used in functions using sorting. It compares @p data1 and
+ * @p data2. If @p data1 is 'less' than @p data2, -1 must be returned,
+ * if it is 'greater', 1 must be returned, and if they are equal, 0
+ * must be returned.
+ */
+typedef int (*Eina_Compare_Cb)(const void *data1, const void *data2);
+
+/**
+ * @def EINA_COMPARE_CB
+ * Macro to cast to Eina_Compare_Cb.
+ */
+#define EINA_COMPARE_CB(function) ((Eina_Compare_Cb)function)
+
+typedef Eina_Bool (*Eina_Each_Cb)(const void *container, void *data, void 
*fdata);
+
+/**
+ * @def EINA_EACH_CB
+ * Macro to cast to Eina_Each.
+ */
+#define EINA_EACH_CB(Function) ((Eina_Each_Cb)Function)
+
+/**
+ * @typedef Eina_Free_Cb
+ * A callback type used to free data when iterating over a container.
+ */
+typedef void (*Eina_Free_Cb)(void *data);
+
+/**
+ * @def EINA_FREE_CB
+ * Macro to cast to Eina_Free_Cb.
+ */
+#define EINA_FREE_CB(Function) ((Eina_Free_Cb)Function)
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_TYPES_H_ */
diff --git a/tests/suite/ecore/src/include/eina_unicode.h 
b/tests/suite/ecore/src/include/eina_unicode.h
new file mode 100644
index 0000000..06a2af1
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_unicode.h
@@ -0,0 +1,67 @@
+#ifndef EINA_UNICODE_H
+#define EINA_UNICODE_H
+
+#include <stdlib.h>
+
+#include "eina_config.h"
+#include "eina_types.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+/**
+ * @addtogroup Eina_Unicode_String Unicode String
+ *
+ * @brief These functions provide basic unicode string handling
+ *
+ * Eina_Unicode is a type that holds unicode codepoints.
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Unicode
+ * A type that holds Unicode codepoints.
+ */
+#if EINA_SIZEOF_WCHAR_T >= 4
+# include <wchar.h>
+typedef wchar_t Eina_Unicode;
+#elif defined(EINA_HAVE_INTTYPES_H)
+# include <inttypes.h>
+typedef uint32_t Eina_Unicode;
+#elif defined(EINA_HAVE_STDINT_H)
+# include <stdint.h>
+typedef uint32_t Eina_Unicode;
+#else
+/* Hope that int is big enough */
+typedef unsigned int Eina_Unicode;
+#endif
+
+EAPI extern const Eina_Unicode *EINA_UNICODE_EMPTY_STRING;
+
+EAPI size_t eina_unicode_strlen(const Eina_Unicode *ustr) EINA_ARG_NONNULL(1) 
EINA_WARN_UNUSED_RESULT EINA_PURE;
+EAPI size_t eina_unicode_strnlen(const Eina_Unicode *ustr, int n) 
EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT EINA_PURE;
+
+
+EAPI Eina_Unicode *eina_unicode_strdup(const Eina_Unicode *text) 
EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1) EINA_MALLOC;
+
+EAPI int           eina_unicode_strcmp(const Eina_Unicode *a, const 
Eina_Unicode *b) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2) EINA_PURE;
+
+EAPI Eina_Unicode *eina_unicode_strcpy(Eina_Unicode *dest, const Eina_Unicode 
*source) EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Unicode *eina_unicode_strstr(const Eina_Unicode *haystack, const 
Eina_Unicode *needle) EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1, 2) EINA_PURE;
+
+EAPI Eina_Unicode *eina_unicode_strncpy(Eina_Unicode *dest, const Eina_Unicode 
*source, size_t n) EINA_ARG_NONNULL(1, 2);
+
+EAPI Eina_Unicode *eina_unicode_escape(const Eina_Unicode *str) 
EINA_ARG_NONNULL(1) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @}
+ */
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/include/eina_ustrbuf.h 
b/tests/suite/ecore/src/include/eina_ustrbuf.h
new file mode 100644
index 0000000..e042b5d
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_ustrbuf.h
@@ -0,0 +1,418 @@
+#ifndef EINA_USTRBUF_H
+#define EINA_USTRBUF_H
+
+#include <stddef.h>
+
+#include "eina_types.h"
+#include "eina_unicode.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Unicode_String_Buffer_Group Unicode String Buffer
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_UStrbuf
+ * Type for a string buffer.
+ */
+typedef struct _Eina_Strbuf Eina_UStrbuf;
+
+/**
+ * @brief Create a new string buffer.
+ *
+ * @return Newly allocated string buffer instance.
+ *
+ * This function creates a new string buffer. On error, @c NULL is
+ * returned and Eina error is set to #EINA_ERROR_OUT_OF_MEMORY. To
+ * free the resources, use eina_ustrbuf_free().
+ *
+ * @see eina_ustrbuf_free()
+ * @see eina_ustrbuf_append()
+ * @see eina_ustrbuf_string_get()
+ */
+EAPI Eina_UStrbuf *eina_ustrbuf_new(void) EINA_MALLOC EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @brief Free a string buffer.
+ *
+ * @param buf The string buffer to free.
+ *
+ * This function frees the memory of @p buf. @p buf must have been
+ * created by eina_ustrbuf_new().
+ */
+EAPI void          eina_ustrbuf_free(Eina_UStrbuf *buf) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Reset a string buffer.
+ *
+ * @param buf The string buffer to reset.
+ *
+ * This function reset @p buf: the buffer len is set to 0, and the
+ * string is set to '\\0'. No memory is free'd.
+ */
+EAPI void          eina_ustrbuf_reset(Eina_UStrbuf *buf) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Append a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends @p str to @p buf. It computes the length of
+ * @p str, so is slightly slower than eina_ustrbuf_append_length(). If
+ * the length is known beforehand, consider using that variant. If
+ * @p buf can't append it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ *
+ * @see eina_ustrbuf_append()
+ * @see eina_ustrbuf_append_length()
+ */
+EAPI Eina_Bool     eina_ustrbuf_append(Eina_UStrbuf *buf, const Eina_Unicode 
*str) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Append an escaped string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends the escaped string @p str to @p buf. If @p
+ * str can not be appended, #EINA_FALSE is returned, otherwise,
+ * #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool     eina_ustrbuf_append_escaped(Eina_UStrbuf *buf, const 
Eina_Unicode *str) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Append a string to a buffer, reallocating as necessary,
+ * limited by the given length.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @param maxlen The maximum number of characters to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends at most @p maxlen characters of @p str to
+ * @p buf. It can't appends more than the length of @p str. It
+ * computes the length of @p str, so is slightly slower than
+ * eina_ustrbuf_append_length(). If the length is known beforehand,
+ * consider using that variant (@p maxlen should then be checked so
+ * that it is greater than the size of @p str). If @p str can not be
+ * appended, #EINA_FALSE is returned, otherwise, #EINA_TRUE is
+ * returned.
+ *
+ * @see eina_ustrbuf_append()
+ * @see eina_ustrbuf_append_length()
+ */
+EAPI Eina_Bool     eina_ustrbuf_append_n(Eina_UStrbuf *buf, const Eina_Unicode 
*str, size_t maxlen) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Append a string of exact length to a buffer, reallocating as 
necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @param length The exact length to use.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends @p str to @p buf. @p str must be of size at
+ * most @p length. It is slightly faster than eina_ustrbuf_append() as
+ * it does not compute the size of @p str. It is useful when dealing
+ * with strings of known size, such as eina_strngshare. If @p buf
+ * can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ *
+ * @see eina_stringshare_length()
+ * @see eina_ustrbuf_append()
+ * @see eina_ustrbuf_append_n()
+ */
+EAPI Eina_Bool     eina_ustrbuf_append_length(Eina_UStrbuf *buf, const 
Eina_Unicode *str, size_t length) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Append a character to a string buffer, reallocating as
+ * necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param c The char to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p c to @p buf. If it can not insert it,
+ * #EINA_FALSE is returned, otherwise #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool     eina_ustrbuf_append_char(Eina_UStrbuf *buf, Eina_Unicode c) 
EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Insert a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to insert.
+ * @param str The string to insert.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p str to @p buf at position @p pos. It
+ * computes the length of @p str, so is slightly slower than
+ * eina_ustrbuf_insert_length(). If  the length is known beforehand,
+ * consider using that variant. If @p buf can't insert it, #EINA_FALSE
+ * is returned, otherwise #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool     eina_ustrbuf_insert(Eina_UStrbuf *buf, const Eina_Unicode 
*str, size_t pos) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Insert an escaped string to a buffer, reallocating as
+ * necessary.
+ *
+ * @param buf The string buffer to insert to.
+ * @param str The string to insert.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts the escaped string @p str to @p buf at
+ * position @p pos. If @p buf can't insert @p str, #EINA_FALSE is
+ * returned, otherwise #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool     eina_ustrbuf_insert_escaped(Eina_UStrbuf *buf, const 
Eina_Unicode *str, size_t pos) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Insert a string to a buffer, reallocating as necessary. Limited by 
maxlen.
+ *
+ * @param buf The string buffer to insert to.
+ * @param str The string to insert.
+ * @param maxlen The maximum number of chars to insert.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p str ot @p buf at position @p pos, with at
+ * most @p maxlen bytes. The number of inserted characters can not be
+ * greater than the length of @p str. It computes the length of
+ * @p str, so is slightly slower than eina_ustrbuf_insert_length(). If the
+ * length is known beforehand, consider using that variant (@p maxlen
+ * should then be checked so that it is greater than the size of
+ * @p str). If @p str can not be inserted, #EINA_FALSE is returned,
+ * otherwise, #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool     eina_ustrbuf_insert_n(Eina_UStrbuf *buf, const Eina_Unicode 
*str, size_t maxlen, size_t pos) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Insert a string of exact length to a buffer, reallocating as 
necessary.
+ *
+ * @param buf The string buffer to insert to.
+ * @param str The string to insert.
+ * @param length The exact length to use.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p str to @p buf. @p str must be of size at
+ * most @p length. It is slightly faster than eina_ustrbuf_insert() as
+ * it does not compute the size of @p str. It is useful when dealing
+ * with strings of known size, such as eina_strngshare. If @p buf
+ * can't insert it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ *
+ * @see eina_stringshare_length()
+ * @see eina_ustrbuf_insert()
+ * @see eina_ustrbuf_insert_n()
+ */
+EAPI Eina_Bool     eina_ustrbuf_insert_length(Eina_UStrbuf *buf, const 
Eina_Unicode *str, size_t length, size_t pos) EINA_ARG_NONNULL(1, 2);
+
+/**
+ * @brief Insert a character to a string buffer, reallocating as
+ * necessary.
+ *
+ * @param buf The string buffer to insert to.
+ * @param c The char to insert.
+ * @param pos The position to insert the char.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p c to @p buf at position @p pos. If @p buf
+ * can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+EAPI Eina_Bool     eina_ustrbuf_insert_char(Eina_UStrbuf *buf, Eina_Unicode c, 
size_t pos) EINA_ARG_NONNULL(1);
+
+/**
+ * @def eina_ustrbuf_prepend(buf, str)
+ * @brief Prepend the given string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param str The string to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_ustrbuf_insert() at position 0.If @p buf
+ * can't prepend it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+#define eina_ustrbuf_prepend(buf, str) eina_ustrbuf_insert(buf, str, 0)
+
+/**
+ * @def eina_ustrbuf_prepend_escaped(buf, str)
+ * @brief Prepend the given escaped string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param str The string to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_ustrbuf_insert_escaped() at position 0. If
+ * @p buf can't prepend it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ */
+#define eina_ustrbuf_prepend_escaped(buf, str) 
eina_ustrbuf_insert_escaped(buf, str, 0)
+
+/**
+ * @def eina_ustrbuf_prepend_n(buf, str)
+ * @brief Prepend the given escaped string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param str The string to prepend.
+ * @param maxlen The maximum number of Eina_Unicode *s to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_ustrbuf_insert_n() at position 0. If
+ * @p buf can't prepend it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ */
+#define eina_ustrbuf_prepend_n(buf, str, maxlen) eina_ustrbuf_insert_n(buf, 
str, maxlen, 0)
+
+/**
+ * @def eina_ustrbuf_prepend_length(buf, str)
+ * @brief Prepend the given escaped string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param str The string to prepend.
+ * @param length The exact length to use.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_ustrbuf_insert_length() at position 0. If
+ * @p buf can't prepend it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ */
+#define eina_ustrbuf_prepend_length(buf, str, length) 
eina_ustrbuf_insert_length(buf, str, length, 0)
+
+/**
+ * @def eina_ustrbuf_prepend_Eina_Unicode *(buf, str)
+ * @brief Prepend the given Eina_Unicode *acter to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param c The Eina_Unicode *acter to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_ustrbuf_insert_Eina_Unicode *() at position 0. If
+ * @p buf can't prepend it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ */
+#define eina_ustrbuf_prepend_Eina_Unicode *(buf, 
c)eina_ustrbuf_insert_Eina_Unicode * (buf, c, 0)
+
+/**
+ * @def eina_ustrbuf_prepend_printf(buf, fmt, ...)
+ * @brief Prepend the given string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param fmt The string to prepend.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_ustrbuf_insert_printf() at position 0.If @p buf
+ * can't prepend it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+#define eina_ustrbuf_prepend_printf(buf, fmt, ...) 
eina_ustrbuf_insert_printf(buf, fmt, 0, ## __VA_ARGS__)
+
+/**
+ * @def eina_ustrbuf_prepend_vprintf(buf, fmt, args)
+ * @brief Prepend the given string to the given buffer
+ *
+ * @param buf The string buffer to prepend to.
+ * @param fmt The string to prepend.
+ * @param args The variable arguments.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This macro is calling eina_ustrbuf_insert_vprintf() at position 0.If @p buf
+ * can't prepend it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+#define eina_ustrbuf_prepend_vprintf(buf, fmt, args) 
eina_ustrbuf_insert_vprintf(buf, fmt, 0, args)
+
+/**
+ * @brief Remove a slice of the given string buffer.
+ *
+ * @param buf The string buffer to remove a slice.
+ * @param start The initial (inclusive) slice position to start
+ *        removing, in bytes.
+ * @param end The final (non-inclusive) slice position to finish
+ *        removing, in bytes.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function removes a slice of @p buf, starting at @p start
+ * (inclusive) and ending at @p end (non-inclusive). Both values are
+ * in bytes. It returns #EINA_FALSE on failure, #EINA_TRUE otherwise.
+ */
+EAPI Eina_Bool
+eina_ustrbuf_remove(Eina_UStrbuf *buf, size_t start, size_t end) 
EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Retrieve a pointer to the contents of a string buffer
+ *
+ * @param buf The string buffer.
+ * @return The current string in the string buffer.
+ *
+ * This function returns the string contained in @p buf. The returned
+ * value must not be modified and will no longer be valid if @p buf is
+ * modified. In other words, any eina_ustrbuf_append() or similar will
+ * make that pointer invalid.
+ *
+ * @see eina_ustrbuf_string_steal()
+ */
+EAPI const Eina_Unicode *
+eina_ustrbuf_string_get(const Eina_UStrbuf *buf) EINA_ARG_NONNULL(1) 
EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @brief Steal the contents of a string buffer.
+ *
+ * @param buf The string buffer to steal.
+ * @return The current string in the string buffer.
+ *
+ * This function returns the string contained in @p buf. @p buf is
+ * then initialized and does not own the returned string anymore. The
+ * caller must release the memory of the returned string by calling
+ * free().
+ *
+ * @see eina_ustrbuf_string_get()
+ */
+EAPI Eina_Unicode *
+eina_ustrbuf_string_steal(Eina_UStrbuf *buf) EINA_MALLOC 
EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Free the contents of a string buffer but not the buffer.
+ *
+ * @param buf The string buffer to free the string of.
+ *
+ * This function frees the string contained in @p buf without freeing
+ * @p buf.
+ */
+EAPI void
+eina_ustrbuf_string_free(Eina_UStrbuf *buf) EINA_ARG_NONNULL(1);
+
+/**
+ * @brief Retrieve the length of the string buffer content.
+ *
+ * @param buf The string buffer.
+ * @return The current length of the string, in bytes.
+ *
+ * This function returns the length of @p buf.
+ */
+EAPI size_t
+eina_ustrbuf_length_get(const Eina_UStrbuf *buf) EINA_ARG_NONNULL(1) 
EINA_WARN_UNUSED_RESULT;
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_STRBUF_H */
diff --git a/tests/suite/ecore/src/include/eina_ustringshare.h 
b/tests/suite/ecore/src/include/eina_ustringshare.h
new file mode 100644
index 0000000..ac8c889
--- /dev/null
+++ b/tests/suite/ecore/src/include/eina_ustringshare.h
@@ -0,0 +1,89 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Jorge Luis Zapata Muga, Cedric 
Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (C) 2008 Peter Wehrfritz
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a 
copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies of the Software and its Copyright notices. In addition publicly
+ *  documented acknowledgment must be given that this software has been used 
if no
+ *  source code of this software is made available publicly. This includes
+ *  acknowledgments in either Copyright notices, Manuals, Publicity and 
Marketing
+ *  documents or any documentation provided with any product containing this
+ *  software. This License does not apply to any software that links to the
+ *  libraries provided by this software (statically or dynamically), but only 
to
+ *  the software provided.
+ *
+ *  Please see the OLD-COPYING.PLAIN for a plain-english explanation of this 
notice
+ *  and it's intent.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef EINA_USTRINGSHARE_H_
+#define EINA_USTRINGSHARE_H_
+
+#include "eina_types.h"
+#include "eina_unicode.h"
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_UStringshare_Group Unicode Stringshare
+ *
+ * @{
+ */
+
+EAPI const Eina_Unicode *eina_ustringshare_add_length(const Eina_Unicode *str, 
unsigned int slen) EINA_WARN_UNUSED_RESULT;
+EAPI const Eina_Unicode *eina_ustringshare_add(const Eina_Unicode *str) 
EINA_WARN_UNUSED_RESULT;
+EAPI const Eina_Unicode *eina_ustringshare_ref(const Eina_Unicode *str);
+EAPI void                eina_ustringshare_del(const Eina_Unicode *str);
+EAPI int                 eina_ustringshare_strlen(const Eina_Unicode *str) 
EINA_PURE EINA_WARN_UNUSED_RESULT;
+EAPI void                eina_ustringshare_dump(void);
+
+static inline Eina_Bool  eina_ustringshare_replace(const Eina_Unicode **p_str, 
const Eina_Unicode *news) EINA_ARG_NONNULL(1);
+static inline Eina_Bool  eina_ustringshare_replace_length(const Eina_Unicode 
**p_str, const Eina_Unicode *news, unsigned int slen) EINA_ARG_NONNULL(1);
+
+#include "eina_inline_ustringshare.x"
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+#endif /* EINA_STRINGSHARE_H_ */
diff --git a/tests/suite/ecore/src/lib/Ecore.h 
b/tests/suite/ecore/src/lib/Ecore.h
new file mode 100644
index 0000000..a70fa21
--- /dev/null
+++ b/tests/suite/ecore/src/lib/Ecore.h
@@ -0,0 +1,484 @@
+#ifndef _ECORE_H
+#define _ECORE_H
+
+#ifdef _MSC_VER
+# include <Evil.h>
+#endif
+
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_BUILD
+#  ifdef DLL_EXPORT
+#   define EAPI __declspec(dllexport)
+#  else
+#   define EAPI
+#  endif /* ! DLL_EXPORT */
+# else
+#  define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_BUILD */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+/**
+ * @file Ecore.h
+ * @brief The file that provides the program utility, main loop and timer
+ *        functions.
+ *
+ * This header provides the Ecore event handling loop.  For more
+ * details, see @ref Ecore_Main_Loop_Group.
+ *
+ * For the main loop to be of any use, you need to be able to add events
+ * and event handlers.  Events for file descriptor events are covered in
+ * @ref Ecore_FD_Handler_Group.
+ *
+ * Time functions are covered in @ref Ecore_Time_Group.
+ *
+ * There is also provision for callbacks for when the loop enters or
+ * exits an idle state. See @ref Idle_Group for more information.
+ *
+ * Functions are also provided for spawning child processes using fork.
+ * See @ref Ecore_Exe_Basic_Group and @ref Ecore_Exe_Signal_Group for
+ * more details.
+ */
+
+#ifdef _WIN32
+# include <winsock2.h>
+#elif (defined (__FreeBSD__) && (__FreeBSD_version >= 420001)) || defined 
(__OpenBSD__)
+# include <sys/select.h>
+# include <signal.h>
+#else
+# include <sys/time.h>
+# include <signal.h>
+#endif
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ECORE_VERSION_MAJOR 1
+#define ECORE_VERSION_MINOR 0
+
+   typedef struct _Ecore_Version
+     {
+        int major;
+        int minor;
+        int micro;
+        int revision;
+     } Ecore_Version;
+   
+   EAPI extern Ecore_Version *ecore_version;
+
+#define ECORE_CALLBACK_CANCEL EINA_FALSE /**< Return value to remove a 
callback */
+#define ECORE_CALLBACK_RENEW EINA_TRUE  /**< Return value to keep a callback */
+
+#define ECORE_CALLBACK_PASS_ON EINA_TRUE /**< Return value to pass event to 
next handler */
+#define ECORE_CALLBACK_DONE EINA_FALSE /**< Return value to stop event 
handling */
+
+#define ECORE_EVENT_NONE            0
+#define ECORE_EVENT_SIGNAL_USER     1 /**< User signal event */
+#define ECORE_EVENT_SIGNAL_HUP      2 /**< Hup signal event */
+#define ECORE_EVENT_SIGNAL_EXIT     3 /**< Exit signal event */
+#define ECORE_EVENT_SIGNAL_POWER    4 /**< Power signal event */
+#define ECORE_EVENT_SIGNAL_REALTIME 5 /**< Realtime signal event */
+#define ECORE_EVENT_COUNT           6
+
+#define ECORE_EXE_PRIORITY_INHERIT 9999
+   
+   EAPI extern int ECORE_EXE_EVENT_ADD; /**< A child process has been added */
+   EAPI extern int ECORE_EXE_EVENT_DEL; /**< A child process has been deleted 
(it exited, naming consistent with the rest of ecore). */
+   EAPI extern int ECORE_EXE_EVENT_DATA; /**< Data from a child process. */
+   EAPI extern int ECORE_EXE_EVENT_ERROR; /**< Errors from a child process. */
+
+   enum _Ecore_Fd_Handler_Flags
+     {
+        ECORE_FD_READ = 1, /**< Fd Read mask */
+        ECORE_FD_WRITE = 2, /**< Fd Write mask */
+        ECORE_FD_ERROR = 4 /**< Fd Error mask */
+     };
+   typedef enum _Ecore_Fd_Handler_Flags Ecore_Fd_Handler_Flags;
+
+   enum _Ecore_Exe_Flags /* flags for executing a child with its stdin and/or 
stdout piped back */
+     {
+        ECORE_EXE_PIPE_READ = 1, /**< Exe Pipe Read mask */
+        ECORE_EXE_PIPE_WRITE = 2, /**< Exe Pipe Write mask */
+        ECORE_EXE_PIPE_ERROR = 4, /**< Exe Pipe error mask */
+        ECORE_EXE_PIPE_READ_LINE_BUFFERED = 8, /**< Reads are buffered until a 
newline and delivered 1 event per line */
+        ECORE_EXE_PIPE_ERROR_LINE_BUFFERED = 16, /**< Errors are buffered 
until a newline and delivered 1 event per line */
+        ECORE_EXE_PIPE_AUTO = 32, /**< stdout and stderr are buffered 
automatically */
+        ECORE_EXE_RESPAWN = 64, /**< FIXME: Exe is restarted if it dies */
+        ECORE_EXE_USE_SH = 128, /**< Use /bin/sh to run the command. */
+        ECORE_EXE_NOT_LEADER = 256 /**< Do not use setsid() to have the 
executed process be its own session leader */
+     };
+   typedef enum _Ecore_Exe_Flags Ecore_Exe_Flags;
+
+   enum _Ecore_Exe_Win32_Priority
+     {
+       ECORE_EXE_WIN32_PRIORITY_IDLE, /**< Idle priority, for monitoring the 
system */
+       ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL, /**< Below default priority */
+       ECORE_EXE_WIN32_PRIORITY_NORMAL, /**< Default priority */
+       ECORE_EXE_WIN32_PRIORITY_ABOVE_NORMAL, /**< Above default priority */
+       ECORE_EXE_WIN32_PRIORITY_HIGH, /**< High priority, use with care as 
other threads in the system will not get processor time */
+       ECORE_EXE_WIN32_PRIORITY_REALTIME /**< Realtime priority, should be 
almost never used as it can interrupt system threads that manage mouse input, 
keyboard input, and background disk flushing */
+     };
+   typedef enum _Ecore_Exe_Win32_Priority Ecore_Exe_Win32_Priority;
+
+   enum _Ecore_Poller_Type /* Poller types */
+     {
+        ECORE_POLLER_CORE = 0 /**< The core poller interval */
+     };
+   typedef enum _Ecore_Poller_Type Ecore_Poller_Type;
+
+   typedef struct _Ecore_Exe                   Ecore_Exe; /**< A handle for 
spawned processes */
+   typedef struct _Ecore_Timer                 Ecore_Timer; /**< A handle for 
timers */
+   typedef struct _Ecore_Idler                 Ecore_Idler; /**< A handle for 
idlers */
+   typedef struct _Ecore_Idle_Enterer          Ecore_Idle_Enterer; /**< A 
handle for idle enterers */
+   typedef struct _Ecore_Idle_Exiter           Ecore_Idle_Exiter; /**< A 
handle for idle exiters */
+   typedef struct _Ecore_Fd_Handler            Ecore_Fd_Handler; /**< A handle 
for Fd handlers */
+   typedef struct _Ecore_Win32_Handler         Ecore_Win32_Handler; /**< A 
handle for HANDLE handlers on Windows */
+   typedef struct _Ecore_Event_Handler         Ecore_Event_Handler; /**< A 
handle for an event handler */
+   typedef struct _Ecore_Event_Filter          Ecore_Event_Filter; /**< A 
handle for an event filter */
+   typedef struct _Ecore_Event                 Ecore_Event; /**< A handle for 
an event */
+   typedef struct _Ecore_Animator              Ecore_Animator; /**< A handle 
for animators */
+   typedef struct _Ecore_Pipe                  Ecore_Pipe; /**< A handle for 
pipes */
+   typedef struct _Ecore_Poller                Ecore_Poller; /**< A handle for 
pollers */
+   typedef struct _Ecore_Event_Signal_User     Ecore_Event_Signal_User; /**< 
User signal event */
+   typedef struct _Ecore_Event_Signal_Hup      Ecore_Event_Signal_Hup; /**< 
Hup signal event */
+   typedef struct _Ecore_Event_Signal_Exit     Ecore_Event_Signal_Exit; /**< 
Exit signal event */
+   typedef struct _Ecore_Event_Signal_Power    Ecore_Event_Signal_Power; /**< 
Power signal event */
+   typedef struct _Ecore_Event_Signal_Realtime Ecore_Event_Signal_Realtime; 
/**< Realtime signal event */
+   typedef struct _Ecore_Exe_Event_Add         Ecore_Exe_Event_Add; /**< 
Spawned Exe add event */
+   typedef struct _Ecore_Exe_Event_Del         Ecore_Exe_Event_Del; /**< 
Spawned Exe exit event */
+   typedef struct _Ecore_Exe_Event_Data_Line   Ecore_Exe_Event_Data_Line; /**< 
Lines from a child process */
+   typedef struct _Ecore_Exe_Event_Data        Ecore_Exe_Event_Data; /**< Data 
from a child process */
+   typedef struct _Ecore_Thread                Ecore_Thread;
+
+   /**
+    * @typedef Ecore_Data_Cb Ecore_Data_Cb
+    * A callback which is used to return data to the main function
+    */
+   typedef void *(*Ecore_Data_Cb) (void *data);
+   /**
+    * @typedef Ecore_Filter_Cb
+    * A callback used for filtering events from the main loop.
+    */
+   typedef Eina_Bool (*Ecore_Filter_Cb) (void *data, void *loop_data, int 
type, void *event);
+   /**
+    * @typedef Ecore_Eselect_Function Ecore_Eselect_Function
+    * A function which can be used to replace select() in the main loop
+    */
+   typedef int (*Ecore_Select_Function)(int nfds, fd_set *readfds, fd_set 
*writefds, fd_set *exceptfds, struct timeval *timeout);
+   /**
+    * @typedef Ecore_End_Cb Ecore_End_Cb
+    * This is the callback which is called at the end of a function, usually 
for cleanup purposes.
+    */
+   typedef void (*Ecore_End_Cb) (void *user_data, void *func_data);
+   /**
+    * @typedef Ecore_Pipe_Cb Ecore_Pipe_Cb
+    * The callback that data written to the pipe is sent to.
+    */
+   typedef void (*Ecore_Pipe_Cb) (void *data, void *buffer, unsigned int 
nbyte);
+   /**
+    * @typedef Ecore_Exe_Cb Ecore_Exe_Cb
+    * A callback to run with the associated @ref Ecore_Exe, usually for 
cleanup purposes.
+    */
+   typedef void (*Ecore_Exe_Cb)(void *data, const Ecore_Exe *exe);
+   /**
+    * @typedef Ecore_Event_Handler_Cb Ecore_Event_Handler_Cb
+    * A callback used by the main loop to handle events of a specified type.
+    */
+   typedef Eina_Bool (*Ecore_Event_Handler_Cb) (void *data, int type, void 
*event);
+   /**
+    * @typedef Ecore_Thread_Heavy_Cb Ecore_Thread_Heavy_Cb
+    * A callback used to run cpu intensive or blocking I/O operations.
+    */
+   typedef void (*Ecore_Thread_Heavy_Cb) (Ecore_Thread *thread, void *data);
+   /**
+    * @typedef Ecore_Thread_Notify_Cb Ecore_Thread_Notify_Cb
+    * A callback used by the main loop to receive data sent by an @ref 
Ecore_Thread.
+    */
+   typedef void (*Ecore_Thread_Notify_Cb) (Ecore_Thread *thread, void 
*msg_data, void *data);
+   /**
+    * @typedef Ecore_Task_Cb Ecore_Task_Cb
+    * A callback run for a task (timer, idler, poller, animater, etc)
+    */
+   typedef Eina_Bool (*Ecore_Task_Cb) (void *data);
+   /**
+    * @typedef Ecore_Cb Ecore_Cb
+    * A generic callback called as a hook when a certain point in execution is 
reached.
+    */
+   typedef void (*Ecore_Cb) (void *data);
+   /**
+    * @typedef Ecore_Fd_Cb Ecore_Fd_Cb
+    * A callback used by an @ref Ecore_Fd_Handler.
+    */
+   typedef Eina_Bool (*Ecore_Fd_Cb) (void *data, Ecore_Fd_Handler *fd_handler);
+   /**
+    * @typedef Ecore_Fd_Prep_Cb Ecore_Fd_Prep_Cb
+    * A callback used by an @ref Ecore_Fd_Handler.
+    */
+   typedef void (*Ecore_Fd_Prep_Cb) (void *data, Ecore_Fd_Handler *fd_handler);
+   /**
+    * @typedef Ecore_Fd_Win32_Cb Ecore_Fd_Win32_Cb
+    * A callback used by an @ref Ecore_Win32_Handler.
+    */
+   typedef Eina_Bool (*Ecore_Fd_Win32_Cb) (void *data, Ecore_Win32_Handler 
*wh);
+
+
+   typedef struct _Ecore_Job Ecore_Job; /**< A job handle */
+
+   struct _Ecore_Event_Signal_User /** User signal event */
+     {
+        int   number; /**< The signal number. Either 1 or 2 */
+        void *ext_data; /**< Extension data - not used */
+
+#ifndef _WIN32
+        siginfo_t data; /**< Signal info */
+#endif
+     };
+
+   struct _Ecore_Event_Signal_Hup /** Hup signal event */
+     {
+        void *ext_data; /**< Extension data - not used */
+
+#ifndef _WIN32
+        siginfo_t data; /**< Signal info */
+#endif
+     };
+
+   struct _Ecore_Event_Signal_Exit /** Exit request event */
+     {
+        unsigned int   interrupt : 1; /**< Set if the exit request was an 
interrupt  signal*/
+        unsigned int   quit      : 1; /**< set if the exit request was a quit 
signal */
+        unsigned int   terminate : 1; /**< Set if the exit request was a 
terminate singal */
+        void          *ext_data; /**< Extension data - not used */
+
+#ifndef _WIN32
+        siginfo_t data; /**< Signal info */
+#endif
+     };
+
+   struct _Ecore_Event_Signal_Power /** Power event */
+     {
+        void *ext_data; /**< Extension data - not used */
+
+#ifndef _WIN32
+        siginfo_t data; /**< Signal info */
+#endif
+     };
+
+   struct _Ecore_Event_Signal_Realtime /** Realtime event */
+     {
+        int num; /**< The realtime signal's number */
+
+#ifndef _WIN32
+        siginfo_t data; /**< Signal info */
+#endif
+     };
+
+   struct _Ecore_Exe_Event_Add /** Process add event */
+     {
+        Ecore_Exe *exe; /**< The handle to the added process */
+        void      *ext_data; /**< Extension data - not used */
+     };
+
+   struct _Ecore_Exe_Event_Del /** Process exit event */
+     {
+        pid_t         pid; /**< The process ID of the process that exited */
+        int           exit_code; /**< The exit code of the process */
+        Ecore_Exe    *exe; /**< The handle to the exited process, or NULL if 
not found */
+        int           exit_signal; /** < The signal that caused the process to 
exit */
+        unsigned int  exited    : 1; /** < set to 1 if the process exited of 
its own accord */
+        unsigned int  signalled : 1; /** < set to 1 id the process exited due 
to uncaught signal */
+        void         *ext_data; /**< Extension data - not used */
+#ifndef _WIN32
+        siginfo_t     data; /**< Signal info */
+#endif
+     };
+
+   struct _Ecore_Exe_Event_Data_Line /**< Lines from a child process */
+      {
+         char *line;
+         int   size;
+      };
+
+   struct _Ecore_Exe_Event_Data /** Data from a child process event */
+     {
+        Ecore_Exe *exe; /**< The handle to the process */
+        void *data; /**< the raw binary data from the child process that was 
received */
+        int   size; /**< the size of this data in bytes */
+        Ecore_Exe_Event_Data_Line *lines; /**< an array of line data if line 
buffered, the last one has it's line member set to NULL */
+     };
+
+   EAPI int  ecore_init(void);
+   EAPI int  ecore_shutdown(void);
+
+   EAPI void ecore_app_args_set(int argc, const char **argv);
+   EAPI void ecore_app_args_get(int *argc, char ***argv);
+   EAPI void ecore_app_restart(void);
+
+   EAPI Ecore_Event_Handler *ecore_event_handler_add(int type, 
Ecore_Event_Handler_Cb func, const void *data);
+   EAPI void                *ecore_event_handler_del(Ecore_Event_Handler 
*event_handler);
+   EAPI Ecore_Event         *ecore_event_add(int type, void *ev, Ecore_End_Cb 
func_free, void *data);
+   EAPI void                *ecore_event_del(Ecore_Event *event);
+   EAPI int                  ecore_event_type_new(void);
+   EAPI Ecore_Event_Filter  *ecore_event_filter_add(Ecore_Data_Cb func_start, 
Ecore_Filter_Cb func_filter, Ecore_End_Cb func_end, const void *data);
+   EAPI void                *ecore_event_filter_del(Ecore_Event_Filter *ef);
+   EAPI int                  ecore_event_current_type_get(void);
+   EAPI void                *ecore_event_current_event_get(void);
+
+
+   EAPI void        ecore_exe_run_priority_set(int pri);
+   EAPI int         ecore_exe_run_priority_get(void);
+   EAPI Ecore_Exe  *ecore_exe_run(const char *exe_cmd, const void *data);
+   EAPI Ecore_Exe  *ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags 
flags, const void *data);
+   EAPI void        ecore_exe_callback_pre_free_set(Ecore_Exe *exe, 
Ecore_Exe_Cb func);
+   EAPI Eina_Bool   ecore_exe_send(Ecore_Exe *exe, const void *data, int size);
+   EAPI void        ecore_exe_close_stdin(Ecore_Exe *exe);
+   EAPI void        ecore_exe_auto_limits_set(Ecore_Exe *exe, int start_bytes, 
int end_bytes, int start_lines, int end_lines);
+   EAPI Ecore_Exe_Event_Data *ecore_exe_event_data_get(Ecore_Exe *exe, 
Ecore_Exe_Flags flags);
+   EAPI void        ecore_exe_event_data_free(Ecore_Exe_Event_Data *data);
+   EAPI void       *ecore_exe_free(Ecore_Exe *exe);
+   EAPI pid_t       ecore_exe_pid_get(const Ecore_Exe *exe);
+   EAPI void        ecore_exe_tag_set(Ecore_Exe *exe, const char *tag);
+   EAPI const char *ecore_exe_tag_get(const Ecore_Exe *exe);
+   EAPI const char *ecore_exe_cmd_get(const Ecore_Exe *exe);
+   EAPI void       *ecore_exe_data_get(const Ecore_Exe *exe);
+   EAPI Ecore_Exe_Flags ecore_exe_flags_get(const Ecore_Exe *exe);
+   EAPI void        ecore_exe_pause(Ecore_Exe *exe);
+   EAPI void        ecore_exe_continue(Ecore_Exe *exe);
+   EAPI void        ecore_exe_interrupt(Ecore_Exe *exe);
+   EAPI void        ecore_exe_quit(Ecore_Exe *exe);
+   EAPI void        ecore_exe_terminate(Ecore_Exe *exe);
+   EAPI void        ecore_exe_kill(Ecore_Exe *exe);
+   EAPI void        ecore_exe_signal(Ecore_Exe *exe, int num);
+   EAPI void        ecore_exe_hup(Ecore_Exe *exe);
+
+   EAPI Ecore_Idler *ecore_idler_add(Ecore_Task_Cb func, const void *data);
+   EAPI void        *ecore_idler_del(Ecore_Idler *idler);
+
+   EAPI Ecore_Idle_Enterer *ecore_idle_enterer_add(Ecore_Task_Cb func, const 
void *data);
+   EAPI Ecore_Idle_Enterer *ecore_idle_enterer_before_add(Ecore_Task_Cb func, 
const void *data);
+   EAPI void               *ecore_idle_enterer_del(Ecore_Idle_Enterer 
*idle_enterer);
+
+   EAPI Ecore_Idle_Exiter *ecore_idle_exiter_add(Ecore_Task_Cb func, const 
void *data);
+   EAPI void              *ecore_idle_exiter_del(Ecore_Idle_Exiter 
*idle_exiter);
+
+   EAPI void              ecore_main_loop_iterate(void);
+
+   EAPI void              
ecore_main_loop_select_func_set(Ecore_Select_Function func);
+   EAPI void             *ecore_main_loop_select_func_get(void);
+
+   EAPI Eina_Bool         ecore_main_loop_glib_integrate(void);
+   EAPI void              ecore_main_loop_glib_always_integrate_disable(void);
+       
+   EAPI void              ecore_main_loop_begin(void);
+   EAPI void              ecore_main_loop_quit(void);
+   EAPI Ecore_Fd_Handler *ecore_main_fd_handler_add(int fd, 
Ecore_Fd_Handler_Flags flags, Ecore_Fd_Cb func, const void *data,
+                                                    Ecore_Fd_Cb buf_func, 
const void *buf_data);
+   EAPI void              
ecore_main_fd_handler_prepare_callback_set(Ecore_Fd_Handler *fd_handler, 
Ecore_Fd_Prep_Cb func, const void *data);
+   EAPI void             *ecore_main_fd_handler_del(Ecore_Fd_Handler 
*fd_handler);
+   EAPI int               ecore_main_fd_handler_fd_get(Ecore_Fd_Handler 
*fd_handler);
+   EAPI Eina_Bool         ecore_main_fd_handler_active_get(Ecore_Fd_Handler 
*fd_handler, Ecore_Fd_Handler_Flags flags);
+   EAPI void              ecore_main_fd_handler_active_set(Ecore_Fd_Handler 
*fd_handler, Ecore_Fd_Handler_Flags flags);
+
+   EAPI Ecore_Win32_Handler *ecore_main_win32_handler_add(void *h, 
Ecore_Fd_Win32_Cb func, const void *data);
+   EAPI void                *ecore_main_win32_handler_del(Ecore_Win32_Handler 
*win32_handler);
+
+   EAPI Ecore_Pipe  *ecore_pipe_add(Ecore_Pipe_Cb handler, const void *data);
+   EAPI void        *ecore_pipe_del(Ecore_Pipe *p);
+   EAPI Eina_Bool    ecore_pipe_write(Ecore_Pipe *p, const void *buffer, 
unsigned int nbytes);
+   EAPI void         ecore_pipe_write_close(Ecore_Pipe *p);
+   EAPI void         ecore_pipe_read_close(Ecore_Pipe *p);
+
+
+
+   EAPI Ecore_Thread *ecore_thread_run(Ecore_Cb,
+                                       Ecore_Cb,
+                                       Ecore_Cb,
+                                       const void *data);
+   EAPI Ecore_Thread *ecore_thread_feedback_run(Ecore_Thread_Heavy_Cb,
+                                                Ecore_Thread_Notify_Cb,
+                                                Ecore_Cb,
+                                                Ecore_Cb,
+                                                const void *data,
+                                                Eina_Bool try_no_queue);
+   EAPI Eina_Bool     ecore_thread_cancel(Ecore_Thread *thread);
+   EAPI Eina_Bool     ecore_thread_check(Ecore_Thread *thread);
+   EAPI Eina_Bool     ecore_thread_feedback(Ecore_Thread *thread, const void 
*msg_data);
+   EAPI int           ecore_thread_active_get(void);
+   EAPI int           ecore_thread_pending_get(void);
+   EAPI int           ecore_thread_pending_feedback_get(void);
+   EAPI int           ecore_thread_pending_total_get(void);
+   EAPI int           ecore_thread_max_get(void);
+   EAPI void          ecore_thread_max_set(int num);
+   EAPI void          ecore_thread_max_reset(void);
+   EAPI int           ecore_thread_available_get(void);
+
+   EAPI Eina_Bool     ecore_thread_local_data_add(Ecore_Thread *thread, const 
char *key, void *value, Eina_Free_Cb cb, Eina_Bool direct);
+   EAPI void         *ecore_thread_local_data_set(Ecore_Thread *thread, const 
char *key, void *value, Eina_Free_Cb cb);
+   EAPI void   *ecore_thread_local_data_find(Ecore_Thread *thread, const char 
*key);
+   EAPI Eina_Bool     ecore_thread_local_data_del(Ecore_Thread *thread, const 
char *key);
+
+   EAPI Eina_Bool     ecore_thread_global_data_add(const char *key, void 
*value, Eina_Free_Cb cb, Eina_Bool direct);
+   EAPI void         *ecore_thread_global_data_set(const char *key, void 
*value, Eina_Free_Cb cb);
+   EAPI void   *ecore_thread_global_data_find(const char *key);
+   EAPI Eina_Bool     ecore_thread_global_data_del(const char *key);
+   EAPI void   *ecore_thread_global_data_wait(const char *key, double seconds);
+
+
+
+
+   EAPI double ecore_time_get(void);
+   EAPI double ecore_time_unix_get(void);
+   EAPI double ecore_loop_time_get(void);
+
+   EAPI Ecore_Timer *ecore_timer_add(double in, Ecore_Task_Cb func, const void 
*data);
+   EAPI Ecore_Timer *ecore_timer_loop_add(double in, Ecore_Task_Cb func, const 
void *data);
+   EAPI void        *ecore_timer_del(Ecore_Timer *timer);
+   EAPI void         ecore_timer_interval_set(Ecore_Timer *timer, double in);
+   EAPI double       ecore_timer_interval_get(Ecore_Timer *timer);
+   EAPI void         ecore_timer_freeze(Ecore_Timer *timer);
+   EAPI void         ecore_timer_thaw(Ecore_Timer *timer);
+   EAPI void         ecore_timer_delay(Ecore_Timer *timer, double add);
+   EAPI double       ecore_timer_pending_get(Ecore_Timer *timer);
+
+   EAPI double       ecore_timer_precision_get(void);
+   EAPI void         ecore_timer_precision_set(double precision);
+
+   EAPI Ecore_Animator *ecore_animator_add(Ecore_Task_Cb func, const void 
*data);
+   EAPI void           *ecore_animator_del(Ecore_Animator *animator);
+   EAPI void            ecore_animator_freeze(Ecore_Animator *animator);
+   EAPI void            ecore_animator_thaw(Ecore_Animator *animator);
+   EAPI void            ecore_animator_frametime_set(double frametime);
+   EAPI double          ecore_animator_frametime_get(void);
+
+   EAPI void          ecore_poller_poll_interval_set(Ecore_Poller_Type type, 
double poll_time);
+   EAPI double        ecore_poller_poll_interval_get(Ecore_Poller_Type type);
+   EAPI Eina_Bool     ecore_poller_poller_interval_set(Ecore_Poller *poller, 
int interval);
+   EAPI int           ecore_poller_poller_interval_get(Ecore_Poller *poller);
+   EAPI Ecore_Poller *ecore_poller_add(Ecore_Poller_Type type, int interval, 
Ecore_Task_Cb func, const void *data);
+   EAPI void         *ecore_poller_del(Ecore_Poller *poller);
+
+   EAPI Ecore_Job *ecore_job_add(Ecore_Cb func, const void *data);
+   EAPI void      *ecore_job_del(Ecore_Job *job);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/tests/suite/ecore/src/lib/Ecore_Getopt.h 
b/tests/suite/ecore/src/lib/Ecore_Getopt.h
new file mode 100644
index 0000000..18a8459
--- /dev/null
+++ b/tests/suite/ecore/src/lib/Ecore_Getopt.h
@@ -0,0 +1,403 @@
+#ifndef _ECORE_GETOPT_H
+#define _ECORE_GETOPT_H
+
+#include <stdio.h>
+#include <Eina.h>
+
+#ifdef EAPI
+# undef EAPI
+#endif
+
+#ifdef _WIN32
+# ifdef EFL_ECORE_BUILD
+#  ifdef DLL_EXPORT
+#   define EAPI __declspec(dllexport)
+#  else
+#   define EAPI
+#  endif /* ! DLL_EXPORT */
+# else
+#  define EAPI __declspec(dllimport)
+# endif /* ! EFL_ECORE_BUILD */
+#else
+# ifdef __GNUC__
+#  if __GNUC__ >= 4
+#   define EAPI __attribute__ ((visibility("default")))
+#  else
+#   define EAPI
+#  endif
+# else
+#  define EAPI
+# endif
+#endif /* ! _WIN32 */
+
+/**
+ * @file Ecore_Getopt.h
+ * @brief Contains powerful getopt replacement.
+ *
+ * This replacement handles both short (-X) or long options (--ABC)
+ * options, with various actions supported, like storing one value and
+ * already converting to required type, counting number of
+ * occurrences, setting true or false values, show help, license,
+ * copyright and even support user-defined callbacks.
+ *
+ * It is provided a set of C Pre Processor macros so definition is
+ * straightforward.
+ *
+ * Values will be stored elsewhere indicated by an array of pointers
+ * to values, it is given in separate to parser description so you can
+ * use multiple values with the same parser.
+ */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+  typedef enum {
+    ECORE_GETOPT_ACTION_STORE,
+    ECORE_GETOPT_ACTION_STORE_CONST,
+    ECORE_GETOPT_ACTION_STORE_TRUE,
+    ECORE_GETOPT_ACTION_STORE_FALSE,
+    ECORE_GETOPT_ACTION_CHOICE,
+    ECORE_GETOPT_ACTION_APPEND,
+    ECORE_GETOPT_ACTION_COUNT,
+    ECORE_GETOPT_ACTION_CALLBACK,
+    ECORE_GETOPT_ACTION_HELP,
+    ECORE_GETOPT_ACTION_VERSION,
+    ECORE_GETOPT_ACTION_COPYRIGHT,
+    ECORE_GETOPT_ACTION_LICENSE
+  } Ecore_Getopt_Action;
+
+  typedef enum {
+    ECORE_GETOPT_TYPE_STR,
+    ECORE_GETOPT_TYPE_BOOL,
+    ECORE_GETOPT_TYPE_SHORT,
+    ECORE_GETOPT_TYPE_INT,
+    ECORE_GETOPT_TYPE_LONG,
+    ECORE_GETOPT_TYPE_USHORT,
+    ECORE_GETOPT_TYPE_UINT,
+    ECORE_GETOPT_TYPE_ULONG,
+    ECORE_GETOPT_TYPE_DOUBLE
+  } Ecore_Getopt_Type;
+
+  typedef enum {
+    ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO = 0,
+    ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES = 1,
+    ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL = 3
+  } Ecore_Getopt_Desc_Arg_Requirement;
+
+  typedef union _Ecore_Getopt_Value             Ecore_Getopt_Value;
+
+  typedef struct _Ecore_Getopt_Desc_Store       Ecore_Getopt_Desc_Store;
+  typedef struct _Ecore_Getopt_Desc_Callback    Ecore_Getopt_Desc_Callback;
+  typedef struct _Ecore_Getopt_Desc             Ecore_Getopt_Desc;
+  typedef struct _Ecore_Getopt                  Ecore_Getopt;
+
+  union _Ecore_Getopt_Value
+  {
+     char **strp;
+     unsigned char *boolp;
+     short *shortp;
+     int *intp;
+     long *longp;
+     unsigned short *ushortp;
+     unsigned int *uintp;
+     unsigned long *ulongp;
+     double *doublep;
+     Eina_List **listp;
+     void **ptrp;
+  };
+
+  struct _Ecore_Getopt_Desc_Store
+  {
+     Ecore_Getopt_Type type;           /**< type of data being handled */
+     Ecore_Getopt_Desc_Arg_Requirement arg_req;
+     union
+     {
+        const char *strv;
+        unsigned char boolv;
+        short shortv;
+        int intv;
+        long longv;
+        unsigned short ushortv;
+        unsigned int uintv;
+        unsigned long ulongv;
+        double doublev;
+     } def;
+  };
+
+  struct _Ecore_Getopt_Desc_Callback
+  {
+     unsigned char (*func)(const Ecore_Getopt *parser, const Ecore_Getopt_Desc 
*desc, const char *str, void *data, Ecore_Getopt_Value *storage);
+     const void *data;
+     Ecore_Getopt_Desc_Arg_Requirement arg_req;
+     const char *def;
+  };
+
+  struct _Ecore_Getopt_Desc
+  {
+     char shortname;       /**< used with a single dash */
+     const char *longname; /**< used with double dashes */
+     const char *help;     /**< used by --help/ecore_getopt_help() */
+     const char *metavar;  /**< used by ecore_getopt_help() with nargs > 0 */
+
+     Ecore_Getopt_Action action; /**< define how to handle it */
+     union
+     {
+        const Ecore_Getopt_Desc_Store store;
+        const void *store_const;
+        const char *const *choices; /* NULL terminated. */
+        const Ecore_Getopt_Type append_type;
+        const Ecore_Getopt_Desc_Callback callback;
+        const void *dummy;
+     } action_param;
+  };
+
+  struct _Ecore_Getopt
+  {
+     const char *prog; /**< to be used when ecore_app_args_get() fails */
+     const char *usage; /**< usage example, %prog is replaced */
+     const char *version; /**< if exists, --version will work */
+     const char *copyright; /**< if exists, --copyright will work */
+     const char *license; /**< if exists, --license will work */
+     const char *description; /**< long description, possible multiline */
+     unsigned char strict : 1; /**< fail on errors */
+     const Ecore_Getopt_Desc descs[]; /* NULL terminated. */
+  };
+
+#define ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, type, 
arg_requirement, default_value) \
+  {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_STORE,        \
+       {.store = {type, arg_requirement, default_value}}}
+
+#define ECORE_GETOPT_STORE(shortname, longname, help, type)             \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, NULL, type,        \
+                          ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES, {})
+
+#define ECORE_GETOPT_STORE_STR(shortname, longname, help)               \
+  ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_STR)
+#define ECORE_GETOPT_STORE_BOOL(shortname, longname, help)              \
+  ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_BOOL)
+#define ECORE_GETOPT_STORE_SHORT(shortname, longname, help)             \
+  ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_SHORT)
+#define ECORE_GETOPT_STORE_INT(shortname, longname, help)               \
+  ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_INT)
+#define ECORE_GETOPT_STORE_LONG(shortname, longname, help)              \
+  ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_LONG)
+#define ECORE_GETOPT_STORE_USHORT(shortname, longname, help)            \
+  ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_USHORT)
+#define ECORE_GETOPT_STORE_UINT(shortname, longname, help)              \
+  ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_UINT)
+#define ECORE_GETOPT_STORE_ULONG(shortname, longname, help)             \
+  ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_ULONG)
+#define ECORE_GETOPT_STORE_DOUBLE(shortname, longname, help)            \
+  ECORE_GETOPT_STORE(shortname, longname, help, ECORE_GETOPT_TYPE_DOUBLE)
+
+
+#define ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, type) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar, type,        \
+                          ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES, {})
+
+#define ECORE_GETOPT_STORE_METAVAR_STR(shortname, longname, help, metavar) \
+  ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, 
ECORE_GETOPT_TYPE_STR)
+#define ECORE_GETOPT_STORE_METAVAR_BOOL(shortname, longname, help, metavar) \
+  ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, 
ECORE_GETOPT_TYPE_BOOL)
+#define ECORE_GETOPT_STORE_METAVAR_SHORT(shortname, longname, help, metavar) \
+  ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, 
ECORE_GETOPT_TYPE_SHORT)
+#define ECORE_GETOPT_STORE_METAVAR_INT(shortname, longname, help, metavar) \
+  ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, 
ECORE_GETOPT_TYPE_INT)
+#define ECORE_GETOPT_STORE_METAVAR_LONG(shortname, longname, help, metavar) \
+  ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, 
ECORE_GETOPT_TYPE_LONG)
+#define ECORE_GETOPT_STORE_METAVAR_USHORT(shortname, longname, help, metavar) \
+  ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, 
ECORE_GETOPT_TYPE_USHORT)
+#define ECORE_GETOPT_STORE_METAVAR_UINT(shortname, longname, help, metavar) \
+  ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, 
ECORE_GETOPT_TYPE_UINT)
+#define ECORE_GETOPT_STORE_METAVAR_ULONG(shortname, longname, help, metavar) \
+  ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, 
ECORE_GETOPT_TYPE_ULONG)
+#define ECORE_GETOPT_STORE_METAVAR_DOUBLE(shortname, longname, help, metavar) \
+  ECORE_GETOPT_STORE_METAVAR(shortname, longname, help, metavar, 
ECORE_GETOPT_TYPE_DOUBLE)
+
+
+#define ECORE_GETOPT_STORE_DEF(shortname, longname, help, type, default_value) 
\
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, NULL, type,               
\
+                          ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL,          
\
+                          default_value)
+
+#define ECORE_GETOPT_STORE_DEF_STR(shortname, longname, help, default_value) \
+  ECORE_GETOPT_STORE_DEF(shortname, longname, help,                          \
+                         ECORE_GETOPT_TYPE_STR,                              \
+                         {.strv = default_value})
+#define ECORE_GETOPT_STORE_DEF_BOOL(shortname, longname, help, default_value) \
+  ECORE_GETOPT_STORE_DEF(shortname, longname, help,                           \
+                         ECORE_GETOPT_TYPE_BOOL,                              \
+                         {.boolv = default_value})
+#define ECORE_GETOPT_STORE_DEF_SHORT(shortname, longname, help, default_value) 
\
+  ECORE_GETOPT_STORE_DEF(shortname, longname, help,                            
\
+                         ECORE_GETOPT_TYPE_SHORT,                              
\
+                         {.shortv = default_value})
+#define ECORE_GETOPT_STORE_DEF_INT(shortname, longname, help, default_value) \
+  ECORE_GETOPT_STORE_DEF(shortname, longname, help,                          \
+                         ECORE_GETOPT_TYPE_INT,                              \
+                         {.intv = default_value})
+#define ECORE_GETOPT_STORE_DEF_LONG(shortname, longname, help, default_value) \
+  ECORE_GETOPT_STORE_DEF(shortname, longname, help,                           \
+                         ECORE_GETOPT_TYPE_LONG,                              \
+                         {.longv = default_value})
+#define ECORE_GETOPT_STORE_DEF_USHORT(shortname, longname, help, 
default_value) \
+  ECORE_GETOPT_STORE_DEF(shortname, longname, help,                            
 \
+                         ECORE_GETOPT_TYPE_USHORT,                             
 \
+                         {.ushortv = default_value})
+#define ECORE_GETOPT_STORE_DEF_UINT(shortname, longname, help, default_value) \
+  ECORE_GETOPT_STORE_DEF(shortname, longname, help,                           \
+                         ECORE_GETOPT_TYPE_UINT,                              \
+                         {.uintv = default_value})
+#define ECORE_GETOPT_STORE_DEF_ULONG(shortname, longname, help, default_value) 
\
+  ECORE_GETOPT_STORE_DEF(shortname, longname, help,                            
\
+                         ECORE_GETOPT_TYPE_ULONG,                              
\
+                         {.ulongv = default_value})
+#define ECORE_GETOPT_STORE_DEF_DOUBLE(shortname, longname, help, 
default_value) \
+  ECORE_GETOPT_STORE_DEF(shortname, longname, help,                            
 \
+                         ECORE_GETOPT_TYPE_DOUBLE,                             
 \
+                         {.doublev = default_value})
+
+#define ECORE_GETOPT_STORE_FULL_STR(shortname, longname, help, metavar, 
arg_requirement, default_value) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar,                  
                         \
+                          ECORE_GETOPT_TYPE_STR,                               
                         \
+                          arg_requirement,                                     
                          \
+                          {.strv = default_value})
+#define ECORE_GETOPT_STORE_FULL_BOOL(shortname, longname, help, metavar, 
arg_requirement, default_value) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar,                  
                          \
+                          ECORE_GETOPT_TYPE_BOOL,                              
                          \
+                          arg_requirement,                                     
                          \
+                          {.boolv = default_value})
+#define ECORE_GETOPT_STORE_FULL_SHORT(shortname, longname, help, metavar, 
arg_requirement, default_value) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar,                  
                           \
+                          ECORE_GETOPT_TYPE_SHORT,                             
                           \
+                          arg_requirement,                                     
                           \
+                          {.shortv = default_value})
+#define ECORE_GETOPT_STORE_FULL_INT(shortname, longname, help, metavar, 
arg_requirement, default_value) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar,                  
                         \
+                          ECORE_GETOPT_TYPE_INT,                               
                         \
+                          arg_requirement,                                     
                         \
+                          {.intv = default_value})
+#define ECORE_GETOPT_STORE_FULL_LONG(shortname, longname, help, metavar, 
arg_requirement, default_value) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar,                  
                          \
+                          ECORE_GETOPT_TYPE_LONG,                              
                          \
+                          arg_requirement,                                     
                          \
+                          {.longv = default_value})
+#define ECORE_GETOPT_STORE_FULL_USHORT(shortname, longname, help, metavar, 
arg_requirement, default_value) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar,                  
                            \
+                          ECORE_GETOPT_TYPE_USHORT,                            
                            \
+                          arg_requirement,                                     
                            \
+                          {.ushortv = default_value})
+#define ECORE_GETOPT_STORE_FULL_UINT(shortname, longname, help, metavar, 
arg_requirement, default_value) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar,                  
                          \
+                          ECORE_GETOPT_TYPE_UINT,                              
                          \
+                          arg_requirement,                                     
                          \
+                          {.uintv = default_value})
+#define ECORE_GETOPT_STORE_FULL_ULONG(shortname, longname, help, metavar, 
arg_requirement, default_value) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar,                  
                           \
+                          ECORE_GETOPT_TYPE_ULONG,                             
                           \
+                          arg_requirement,                                     
                           \
+                          {.ulongv = default_value})
+#define ECORE_GETOPT_STORE_FULL_DOUBLE(shortname, longname, help, metavar, 
arg_requirement, default_value) \
+  ECORE_GETOPT_STORE_FULL(shortname, longname, help, metavar,                  
                            \
+                          ECORE_GETOPT_TYPE_DOUBLE,                            
                            \
+                          arg_requirement,                                     
                            \
+                          {.doublev = default_value})
+
+#define ECORE_GETOPT_STORE_CONST(shortname, longname, help, value)   \
+  {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_STORE_CONST, \
+       {.store_const = value}}
+#define ECORE_GETOPT_STORE_TRUE(shortname, longname, help)          \
+  {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_STORE_TRUE, \
+       {.dummy = NULL}}
+#define ECORE_GETOPT_STORE_FALSE(shortname, longname, help)          \
+  {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_STORE_FALSE, \
+       {.dummy = NULL}}
+
+#define ECORE_GETOPT_CHOICE(shortname, longname, help, choices_array) \
+  {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_CHOICE,       \
+       {.choices = choices_array}}
+#define ECORE_GETOPT_CHOICE_METAVAR(shortname, longname, help, metavar, 
choices_array) \
+  {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_CHOICE,             
        \
+       {.choices = choices_array}}
+
+
+#define ECORE_GETOPT_APPEND(shortname, longname, help, sub_type) \
+  {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_APPEND,  \
+       {.append_type = sub_type}}
+#define ECORE_GETOPT_APPEND_METAVAR(shortname, longname, help, metavar, type) \
+  {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_APPEND,            \
+       {.append_type = type}}
+
+#define ECORE_GETOPT_COUNT(shortname, longname, help)          \
+  {shortname, longname, help, NULL, ECORE_GETOPT_ACTION_COUNT, \
+       {.dummy = NULL}}
+
+#define ECORE_GETOPT_CALLBACK_FULL(shortname, longname, help, metavar, 
callback_func, callback_data, argument_requirement, default_value) \
+  {shortname, longname, help, metavar, ECORE_GETOPT_ACTION_CALLBACK,           
                                                           \
+       {.callback = {callback_func, callback_data,                             
                                                           \
+                     argument_requirement, default_value}}}
+#define ECORE_GETOPT_CALLBACK_NOARGS(shortname, longname, help, callback_func, 
callback_data) \
+  ECORE_GETOPT_CALLBACK_FULL(shortname, longname, help, NULL,                  
               \
+                             callback_func, callback_data,                     
               \
+                             ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO,             
               \
+                             NULL)
+#define ECORE_GETOPT_CALLBACK_ARGS(shortname, longname, help, metavar, 
callback_func, callback_data) \
+  ECORE_GETOPT_CALLBACK_FULL(shortname, longname, help, metavar,               
                      \
+                             callback_func, callback_data,                     
                      \
+                             ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES,            
                      \
+                             NULL)
+
+#define ECORE_GETOPT_HELP(shortname, longname)      \
+  {shortname, longname, "show this message.", NULL, \
+       ECORE_GETOPT_ACTION_HELP,                    \
+       {.dummy = NULL}}
+
+#define ECORE_GETOPT_VERSION(shortname, longname)      \
+  {shortname, longname, "show program version.", NULL, \
+       ECORE_GETOPT_ACTION_VERSION,                    \
+       {.dummy = NULL}}
+
+#define ECORE_GETOPT_COPYRIGHT(shortname, longname) \
+  {shortname, longname, "show copyright.", NULL,    \
+       ECORE_GETOPT_ACTION_COPYRIGHT,               \
+       {.dummy = NULL}}
+
+#define ECORE_GETOPT_LICENSE(shortname, longname) \
+  {shortname, longname, "show license.", NULL,    \
+       ECORE_GETOPT_ACTION_LICENSE,               \
+       {.dummy = NULL}}
+
+#define ECORE_GETOPT_SENTINEL {0, NULL, NULL, NULL, 0, {.dummy = NULL}}
+
+#define ECORE_GETOPT_VALUE_STR(val)      {.strp = &(val)}
+#define ECORE_GETOPT_VALUE_BOOL(val)     {.boolp = &(val)}
+#define ECORE_GETOPT_VALUE_SHORT(val)    {.shortp = &(val)}
+#define ECORE_GETOPT_VALUE_INT(val)      {.intp = &(val)}
+#define ECORE_GETOPT_VALUE_LONG(val)     {.longp = &(val)}
+#define ECORE_GETOPT_VALUE_USHORT(val)   {.ushortp = &(val)}
+#define ECORE_GETOPT_VALUE_UINT(val)     {.uintp = &(val)}
+#define ECORE_GETOPT_VALUE_ULONG(val)    {.ulongp = &(val)}
+#define ECORE_GETOPT_VALUE_DOUBLE(val)   {.doublep = &(val)}
+#define ECORE_GETOPT_VALUE_PTR(val)      {.ptrp = &(val)}
+#define ECORE_GETOPT_VALUE_PTR_CAST(val) {.ptrp = (void **)&(val)}
+#define ECORE_GETOPT_VALUE_LIST(val)     {.listp = &(val)}
+#define ECORE_GETOPT_VALUE_NONE          {.ptrp = NULL}
+
+  EAPI void ecore_getopt_help(FILE *fp, const Ecore_Getopt *info);
+
+  EAPI unsigned char ecore_getopt_parser_has_duplicates(const Ecore_Getopt 
*parser);
+  EAPI int ecore_getopt_parse(const Ecore_Getopt *parser, Ecore_Getopt_Value 
*values, int argc, char **argv);
+
+  EAPI Eina_List *ecore_getopt_list_free(Eina_List *list);
+
+  /* helper functions to be used with ECORE_GETOPT_CALLBACK_*() */
+  EAPI unsigned char ecore_getopt_callback_geometry_parse(const Ecore_Getopt 
*parser, const Ecore_Getopt_Desc *desc, const char *str, void *data, 
Ecore_Getopt_Value *storage);
+  EAPI unsigned char ecore_getopt_callback_size_parse(const Ecore_Getopt 
*parser, const Ecore_Getopt_Desc *desc, const char *str, void *data, 
Ecore_Getopt_Value *storage);
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _ECORE_GETOPT_H */
diff --git a/tests/suite/ecore/src/lib/ecore.c 
b/tests/suite/ecore/src/lib/ecore.c
new file mode 100644
index 0000000..5b0789c
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore.c
@@ -0,0 +1,418 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#ifdef HAVE_LANGINFO_H
+# include <langinfo.h>
+#endif
+
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+#include <Eina.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#if HAVE_MALLINFO
+#include <malloc.h>
+
+static Ecore_Version _version = { VERS_MAJ, VERS_MIN, VERS_MIC, VERS_REV };
+EAPI Ecore_Version *ecore_version = &_version;
+
+#define KEEP_MAX(Global, Local)                        \
+   if (Global < (Local))                        \
+     Global = Local;
+
+static Eina_Bool _ecore_memory_statistic(void *data);
+static int _ecore_memory_max_total = 0;
+static int _ecore_memory_max_free = 0;
+static pid_t _ecore_memory_pid = 0;
+#endif
+
+static const char *_ecore_magic_string_get(Ecore_Magic m);
+static int _ecore_init_count = 0;
+int _ecore_log_dom = -1;
+int _ecore_fps_debug = 0;
+
+/** OpenBSD does not define CODESET
+ * FIXME ??
+ */
+
+#ifndef CODESET
+# define CODESET "INVALID"
+#endif
+
+/**
+ * Set up connections, signal handlers, sockets etc.
+ * @return 1 or greater on success, 0 otherwise
+ *
+ * This function sets up all singal handlers and the basic event loop. If it
+ * succeeds, 1 will be returned, otherwise 0 will be returned.
+ *
+ * @code
+ * #include <Ecore.h>
+ *
+ * int main(int argc, char **argv)
+ * {
+ *   if (!ecore_init())
+ *   {
+ *     printf("ERROR: Cannot init Ecore!\n");
+ *     return -1;
+ *   }
+ *   ecore_main_loop_begin();
+ *   ecore_shutdown();
+ * }
+ * @endcode
+ */
+EAPI int
+ecore_init(void)
+{
+   if (++_ecore_init_count != 1)
+     return _ecore_init_count;
+
+#ifdef HAVE_LOCALE_H
+   setlocale(LC_CTYPE, "");
+#endif
+   /*
+     if (strcmp(nl_langinfo(CODESET), "UTF-8"))
+     {
+        WRN("Not a utf8 locale!");
+     }
+   */
+#ifdef HAVE_EVIL
+   if (!evil_init())
+     return --_ecore_init_count;
+#endif
+   if (!eina_init())
+     goto shutdown_evil;
+   _ecore_log_dom = eina_log_domain_register("Ecore",ECORE_DEFAULT_LOG_COLOR);
+   if (_ecore_log_dom < 0) {
+     EINA_LOG_ERR("Ecore was unable to create a log domain.");
+     goto shutdown_log_dom;
+   }
+   if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
+   if (_ecore_fps_debug) _ecore_fps_debug_init();
+   _ecore_main_loop_init();
+   _ecore_signal_init();
+   _ecore_exe_init();
+   _ecore_thread_init();
+   _ecore_glib_init();
+   _ecore_job_init();
+   _ecore_time_init();
+
+#if HAVE_MALLINFO
+   if (getenv("ECORE_MEM_STAT"))
+     {
+        _ecore_memory_pid = getpid();
+        ecore_animator_add(_ecore_memory_statistic, NULL);
+     }
+#endif
+
+#if defined(GLIB_INTEGRATION_ALWAYS)
+   if (_ecore_glib_always_integrate) ecore_main_loop_glib_integrate();
+#endif
+   
+   return _ecore_init_count;
+
+ shutdown_log_dom:
+   eina_shutdown();
+ shutdown_evil:
+#ifdef HAVE_EVIL
+   evil_shutdown();
+#endif
+   return --_ecore_init_count;
+}
+
+/**
+ * Shut down connections, signal handlers sockets etc.
+ *
+ * This function shuts down all things set up in ecore_init() and cleans up all
+ * event queues, handlers, filters, timers, idlers, idle enterers/exiters
+ * etc. set up after ecore_init() was called.
+ *
+ * Do not call this function from any callback that may be called from the main
+ * loop, as the main loop will then fall over and not function properly.
+ */
+EAPI int
+ecore_shutdown(void)
+{
+   if (--_ecore_init_count != 0)
+     return _ecore_init_count;
+
+   if (_ecore_fps_debug) _ecore_fps_debug_shutdown();
+   _ecore_poller_shutdown();
+   _ecore_animator_shutdown();
+   _ecore_glib_shutdown();
+   _ecore_job_shutdown();
+   _ecore_thread_shutdown();
+   _ecore_exe_shutdown();
+   _ecore_idle_enterer_shutdown();
+   _ecore_idle_exiter_shutdown();
+   _ecore_idler_shutdown();
+   _ecore_timer_shutdown();
+   _ecore_event_shutdown();
+   _ecore_main_shutdown();
+   _ecore_signal_shutdown();
+   _ecore_main_loop_shutdown();
+
+#if HAVE_MALLINFO
+   if (getenv("ECORE_MEM_STAT"))
+     {
+        _ecore_memory_statistic(NULL);
+
+        ERR("[%i] Memory MAX total: %i, free: %i",
+            _ecore_memory_pid,
+            _ecore_memory_max_total,
+            _ecore_memory_max_free);
+     }
+#endif
+
+   eina_log_domain_unregister(_ecore_log_dom);
+   _ecore_log_dom = -1;
+   eina_shutdown();
+#ifdef HAVE_EVIL
+   evil_shutdown();
+#endif
+
+   return _ecore_init_count;
+}
+
+EAPI void
+ecore_print_warning(const char *function, const char *sparam)
+{
+   WRN("***** Developer Warning ***** :\n"
+       "\tThis program is calling:\n\n"
+       "\t%s();\n\n"
+       "\tWith the parameter:\n\n"
+       "\t%s\n\n"
+       "\tbeing NULL. Please fix your program.", function, sparam);
+   if (getenv("ECORE_ERROR_ABORT")) abort();
+}
+
+EAPI void
+_ecore_magic_fail(const void *d, Ecore_Magic m, Ecore_Magic req_m, const char 
*fname)
+{
+   ERR("\n"
+       "*** ECORE ERROR: Ecore Magic Check Failed!!!\n"
+       "*** IN FUNCTION: %s()", fname);
+   if (!d)
+     ERR("  Input handle pointer is NULL!");
+   else if (m == ECORE_MAGIC_NONE)
+     ERR("  Input handle has already been freed!");
+   else if (m != req_m)
+     ERR("  Input handle is wrong type\n"
+         "    Expected: %08x - %s\n"
+         "    Supplied: %08x - %s",
+         (unsigned int)req_m, _ecore_magic_string_get(req_m),
+         (unsigned int)m, _ecore_magic_string_get(m));
+     ERR("*** NAUGHTY PROGRAMMER!!!\n"
+         "*** SPANK SPANK SPANK!!!\n"
+         "*** Now go fix your code. Tut tut tut!");
+   if (getenv("ECORE_ERROR_ABORT")) abort();
+}
+
+static const char *
+_ecore_magic_string_get(Ecore_Magic m)
+{
+   switch (m)
+     {
+      case ECORE_MAGIC_NONE:
+        return "None (Freed Object)";
+        break;
+      case ECORE_MAGIC_EXE:
+        return "Ecore_Exe (Executable)";
+        break;
+      case ECORE_MAGIC_TIMER:
+        return "Ecore_Timer (Timer)";
+        break;
+      case ECORE_MAGIC_IDLER:
+        return "Ecore_Idler (Idler)";
+        break;
+      case ECORE_MAGIC_IDLE_ENTERER:
+        return "Ecore_Idle_Enterer (Idler Enterer)";
+        break;
+      case ECORE_MAGIC_IDLE_EXITER:
+        return "Ecore_Idle_Exiter (Idler Exiter)";
+        break;
+      case ECORE_MAGIC_FD_HANDLER:
+        return "Ecore_Fd_Handler (Fd Handler)";
+        break;
+      case ECORE_MAGIC_WIN32_HANDLER:
+        return "Ecore_Win32_Handler (Win32 Handler)";
+        break;
+      case ECORE_MAGIC_EVENT_HANDLER:
+        return "Ecore_Event_Handler (Event Handler)";
+        break;
+      case ECORE_MAGIC_EVENT:
+        return "Ecore_Event (Event)";
+        break;
+      default:
+        return "<UNKNOWN>";
+     };
+}
+
+/* fps debug calls - for debugging how much time your app actually spends */
+/* "running" (and the inverse being time spent running)... this does not */
+/* account for other apps and multitasking... */
+
+static int _ecore_fps_debug_init_count = 0;
+static int _ecore_fps_debug_fd = -1;
+unsigned int *_ecore_fps_runtime_mmap = NULL;
+
+void
+_ecore_fps_debug_init(void)
+{
+   char  buf[4096];
+   const char *tmp;
+   int   pid;
+
+   _ecore_fps_debug_init_count++;
+   if (_ecore_fps_debug_init_count > 1) return;
+
+#ifndef HAVE_EVIL
+   tmp = "/tmp";
+#else
+   tmp = (char *)evil_tmpdir_get ();
+#endif /* HAVE_EVIL */
+   pid = (int)getpid();
+   snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
+   _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
+   if (_ecore_fps_debug_fd < 0)
+     {
+        unlink(buf);
+        _ecore_fps_debug_fd = open(buf, O_CREAT | O_TRUNC | O_RDWR, 0644);
+     }
+   if (_ecore_fps_debug_fd >= 0)
+     {
+        unsigned int zero = 0;
+        char *buf = (char *)&zero;
+        ssize_t todo = sizeof(unsigned int);
+
+        while (todo > 0)
+          {
+             ssize_t r = write(_ecore_fps_debug_fd, buf, todo);
+             if (r > 0)
+               {
+                  todo -= r;
+                  buf += r;
+               }
+             else if ((r < 0) && (errno == EINTR))
+               continue;
+             else
+               {
+                  ERR("could not write to file '%s' fd %d: %s",
+                      tmp, _ecore_fps_debug_fd, strerror(errno));
+                  close(_ecore_fps_debug_fd);
+                  _ecore_fps_debug_fd = -1;
+                  return;
+               }
+          }
+        _ecore_fps_runtime_mmap = mmap(NULL, sizeof(unsigned int),
+                                       PROT_READ | PROT_WRITE,
+                                       MAP_SHARED,
+                                       _ecore_fps_debug_fd, 0);
+        if (_ecore_fps_runtime_mmap == MAP_FAILED)
+          _ecore_fps_runtime_mmap = NULL;
+     }
+}
+
+void
+_ecore_fps_debug_shutdown(void)
+{
+   _ecore_fps_debug_init_count--;
+   if (_ecore_fps_debug_init_count > 0) return;
+   if (_ecore_fps_debug_fd >= 0)
+     {
+        char buf[4096];
+        const char *tmp;
+        int   pid;
+
+#ifndef HAVE_EVIL
+   tmp = "/tmp";
+#else
+   tmp = (char *)evil_tmpdir_get ();
+#endif /* HAVE_EVIL */
+   pid = (int)getpid();
+        snprintf(buf, sizeof(buf), "%s/.ecore_fps_debug-%i", tmp, pid);
+        unlink(buf);
+        if (_ecore_fps_runtime_mmap)
+          {
+             munmap(_ecore_fps_runtime_mmap, sizeof(int));
+             _ecore_fps_runtime_mmap = NULL;
+          }
+        close(_ecore_fps_debug_fd);
+        _ecore_fps_debug_fd = -1;
+     }
+}
+
+void
+_ecore_fps_debug_runtime_add(double t)
+{
+   if ((_ecore_fps_debug_fd >= 0) &&
+       (_ecore_fps_runtime_mmap))
+     {
+        unsigned int tm;
+
+        tm = (unsigned int)(t * 1000000.0);
+        /* i know its not 100% theoretically guaranteed, but i'd say a write */
+        /* of an int could be considered atomic for all practical purposes */
+        /* oh and since this is cumulative, 1 second = 1,000,000 ticks, so */
+        /* this can run for about 4294 seconds becore looping. if you are */
+        /* doing performance testing in one run for over an hour... well */
+        /* time to restart or handle a loop condition :) */
+        *(_ecore_fps_runtime_mmap) += tm;
+     }
+}
+
+#if HAVE_MALLINFO
+static Eina_Bool
+_ecore_memory_statistic(__UNUSED__ void *data)
+{
+   struct mallinfo mi;
+   static int uordblks = 0;
+   static int fordblks = 0;
+   Eina_Bool changed = EINA_FALSE;
+
+   mi = mallinfo();
+
+#define HAS_CHANGED(Global, Local)                \
+   if (Global != Local)                                \
+     {                                                \
+        Global = Local;                                \
+        changed = EINA_TRUE;                        \
+     }
+
+   HAS_CHANGED(uordblks, mi.uordblks);
+   HAS_CHANGED(fordblks, mi.fordblks);
+
+   if (changed)
+     ERR("[%i] Memory total: %i, free: %i",
+         _ecore_memory_pid,
+         mi.uordblks,
+         mi.fordblks);
+
+   KEEP_MAX(_ecore_memory_max_total, mi.uordblks);
+   KEEP_MAX(_ecore_memory_max_free, mi.fordblks);
+
+   return ECORE_CALLBACK_RENEW;
+}
+#endif
diff --git a/tests/suite/ecore/src/lib/ecore_anim.c 
b/tests/suite/ecore/src/lib/ecore_anim.c
new file mode 100644
index 0000000..921071e
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_anim.c
@@ -0,0 +1,233 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <math.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+
+struct _Ecore_Animator
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+
+   Ecore_Task_Cb func;
+   void          *data;
+
+   Eina_Bool     delete_me : 1;
+   Eina_Bool     suspended : 1;
+};
+
+
+static Eina_Bool _ecore_animator(void *data);
+
+static Ecore_Timer    *timer = NULL;
+static int             animators_delete_me = 0;
+static Ecore_Animator *animators = NULL;
+static double          animators_frametime = 1.0 / 30.0;
+
+/**
+ * Add a animator to tick off at every animaton tick during main loop 
execution.
+ * @param func The function to call when it ticks off
+ * @param data The data to pass to the function
+ * @return A handle to the new animator
+ * @ingroup Ecore_Animator_Group
+ *
+ * This function adds a animator and returns its handle on success and NULL on
+ * failure. The function @p func will be called every N seconds where N is the
+ * frametime interval set by ecore_animator_frametime_set(). The function will
+ * be passed the @p data pointer as its parameter.
+ *
+ * When the animator @p func is called, it must return a value of either 1 or 
0.
+ * If it returns 1 (or ECORE_CALLBACK_RENEW), it will be called again at the
+ * next tick, or if it returns 0 (or ECORE_CALLBACK_CANCEL) it will be deleted
+ * automatically making any references/handles for it invalid.
+ */
+EAPI Ecore_Animator *
+ecore_animator_add(Ecore_Task_Cb func, const void *data)
+{
+   Ecore_Animator *animator;
+
+   if (!func) return NULL;
+   animator = calloc(1, sizeof(Ecore_Animator));
+   if (!animator) return NULL;
+   ECORE_MAGIC_SET(animator, ECORE_MAGIC_ANIMATOR);
+   animator->func = func;
+   animator->data = (void *)data;
+   animators = (Ecore_Animator 
*)eina_inlist_append(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator));
+   if (!timer)
+     {
+        double t_loop = ecore_loop_time_get();
+        double sync_0 = 0.0;
+        double d = -fmod(t_loop - sync_0, animators_frametime);
+
+        timer = ecore_timer_loop_add(animators_frametime, _ecore_animator, 
NULL);
+        ecore_timer_delay(timer, d);
+     }
+   return animator;
+}
+
+/**
+ * Delete the specified animator from the animator list.
+ * @param animator The animator to delete
+ * @return The data pointer set for the animator
+ * @ingroup Ecore_Animator_Group
+ *
+ * Delete the specified @p aqnimator from the set of animators that are 
executed
+ * during main loop execution. This function returns the data parameter that
+ * was being passed to the callback on success, or NULL on failure. After this
+ * call returns the specified animator object @p animator is invalid and 
should not
+ * be used again. It will not get called again after deletion.
+ */
+EAPI void *
+ecore_animator_del(Ecore_Animator *animator)
+{
+   if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
+     {
+        ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
+                         "ecore_animator_del");
+        return NULL;
+     }
+   if (animator->delete_me) return animator->data;
+   animator->delete_me = EINA_TRUE;
+   animators_delete_me++;
+   return animator->data;
+}
+
+/**
+ * Set the animator call interval in seconds.
+ * @param frametime The time in seconds in between animator ticks.
+ *
+ * This function sets the time interval (in seconds) between animator ticks.
+ */
+EAPI void
+ecore_animator_frametime_set(double frametime)
+{
+   if (frametime < 0.0) frametime = 0.0;
+   if (animators_frametime == frametime) return;
+   animators_frametime = frametime;
+   if (timer)
+     {
+        ecore_timer_del(timer);
+        timer = NULL;
+     }
+   if (animators)
+     timer = ecore_timer_add(animators_frametime, _ecore_animator, NULL);
+}
+
+/**
+ * Get the animator call interval in seconds.
+ * @return The time in second in between animator ticks.
+ *
+ * this function retrieves the time between animator ticks, in seconds.
+ */
+EAPI double
+ecore_animator_frametime_get(void)
+{
+   return animators_frametime;
+}
+
+/**
+ * Suspend the specified animator.
+ * @param animator The animator to delete
+ * @ingroup Ecore_Animator_Group
+ *
+ * The specified @p animator will be temporarly removed from the set of 
animators
+ * that are executed during main loop execution.
+ */
+EAPI void
+ecore_animator_freeze(Ecore_Animator *animator)
+{
+   if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
+     {
+        ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
+                         "ecore_animator_del");
+        return;
+     }
+   if (animator->delete_me) return;
+   animator->suspended = EINA_TRUE;
+}
+
+/**
+ * Restore execution of the specified animator.
+ * @param animator The animator to delete
+ * @ingroup Ecore_Animator_Group
+ *
+ * The specified @p animator will be put back in the set of animators
+ * that are executed during main loop execution.
+ */
+EAPI void
+ecore_animator_thaw(Ecore_Animator *animator)
+{
+   if (!ECORE_MAGIC_CHECK(animator, ECORE_MAGIC_ANIMATOR))
+     {
+        ECORE_MAGIC_FAIL(animator, ECORE_MAGIC_ANIMATOR,
+                         "ecore_animator_del");
+        return;
+     }
+   if (animator->delete_me) return;
+   animator->suspended = EINA_FALSE;
+}
+
+void
+_ecore_animator_shutdown(void)
+{
+   if (timer)
+     {
+        ecore_timer_del(timer);
+        timer = NULL;
+     }
+   while (animators)
+     {
+        Ecore_Animator *animator;
+
+        animator = animators;
+        animators = (Ecore_Animator *) 
eina_inlist_remove(EINA_INLIST_GET(animators), EINA_INLIST_GET(animators));
+        ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE);
+        free(animator);
+     }
+}
+
+static Eina_Bool
+_ecore_animator(void *data __UNUSED__)
+{
+   Ecore_Animator *animator;
+
+   EINA_INLIST_FOREACH(animators, animator)
+     {
+        if (!animator->delete_me && !animator->suspended)
+          {
+             if (!animator->func(animator->data))
+               {
+                  animator->delete_me = EINA_TRUE;
+                  animators_delete_me++;
+               }
+          }
+     }
+   if (animators_delete_me)
+     {
+        Ecore_Animator *l;
+        for(l = animators; l;)
+          {
+             animator = l;
+             l = (Ecore_Animator *) EINA_INLIST_GET(l)->next;
+             if (animator->delete_me)
+               {
+                  animators = (Ecore_Animator *) 
eina_inlist_remove(EINA_INLIST_GET(animators), EINA_INLIST_GET(animator));
+                  ECORE_MAGIC_SET(animator, ECORE_MAGIC_NONE);
+                  free(animator);
+                  animators_delete_me--;
+                  if (animators_delete_me == 0) break;
+               }
+          }
+     }
+   if (!animators)
+     {
+        timer = NULL;
+        return ECORE_CALLBACK_CANCEL;
+     }
+   return ECORE_CALLBACK_RENEW;
+}
diff --git a/tests/suite/ecore/src/lib/ecore_app.c 
b/tests/suite/ecore/src/lib/ecore_app.c
new file mode 100644
index 0000000..f9663a5
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_app.c
@@ -0,0 +1,77 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#else
+# include <process.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+static int app_argc = 0;
+static char **app_argv = NULL;
+
+/**
+ * Set up the programs command-line arguments.
+ * @param argc The same as passed as argc to the programs main() function
+ * @param argv The same as passed as argv to the programs main() function
+ *
+ * A call to this function will store the programs command-line arguments
+ * for later use by ecore_app_restart() or ecore_app_args_get().
+ */
+EAPI void
+ecore_app_args_set(int argc, const char **argv)
+{
+   if ((argc < 1) ||
+       (!argv)) return;
+   app_argc = argc;
+   app_argv = (char **)argv;
+}
+
+/**
+ * Return the programs stored command-line arguments.
+ * @param argc A pointer to the return value to hold argc
+ * @param argv A pointer to the return value to hold argv
+ *
+ * When called, this funciton returns the arguments for the program stored by
+ * ecore_app_args_set(). The integer pointed to by @p argc will be filled, if
+ * the pointer is not NULL, and the string array pointer @p argv will be filled
+ * also if the pointer is not NULL. The values they are filled with will be the
+ * same set by ecore_app_args_set().
+ */
+EAPI void
+ecore_app_args_get(int *argc, char ***argv)
+{
+   if (argc) *argc = app_argc;
+   if (argv) *argv = app_argv;
+}
+
+/**
+ * Restart the program executable with the command-line arguments stored.
+ *
+ * This function will restart & re-execute this program in place of itself
+ * using the command-line arguments stored by ecore_app_args_set(). This is
+ * an easy way for a program to restart itself for cleanup purposes,
+ * configuration reasons or in the event of a crash.
+ */
+EAPI void
+ecore_app_restart(void)
+{
+   char *args[4096];
+   int i;
+
+   if ((app_argc < 1) || (!app_argv)) return;
+   if (app_argc >= 4096) return;
+   for (i = 0; i < app_argc; i++) args[i] = app_argv[i];
+   args[i] = NULL;
+   execvp(app_argv[0], args);
+}
diff --git a/tests/suite/ecore/src/lib/ecore_events.c 
b/tests/suite/ecore/src/lib/ecore_events.c
new file mode 100644
index 0000000..470838c
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_events.c
@@ -0,0 +1,659 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+static int inpurge = 0;
+
+struct _Ecore_Event_Handler
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   int type;
+   Ecore_Event_Handler_Cb func;
+   void *data;
+   int       references;
+   Eina_Bool delete_me : 1;
+};
+
+struct _Ecore_Event_Filter
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   Ecore_Data_Cb func_start;
+   Ecore_Filter_Cb func_filter;
+   Ecore_End_Cb func_end;
+   void *loop_data;
+   void *data;
+   int       references;
+   Eina_Bool delete_me : 1;
+};
+
+struct _Ecore_Event
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   int type;
+   void *event;
+   Ecore_End_Cb func_free;
+   void *data;
+   int       references;
+   Eina_Bool delete_me : 1;
+};
+
+
+static int events_num = 0;
+static Ecore_Event *events = NULL;
+static Ecore_Event *event_current = NULL;
+static Ecore_Event *purge_events = NULL;
+
+static Ecore_Event_Handler **event_handlers = NULL;
+static Ecore_Event_Handler *event_handler_current = NULL;
+static int event_handlers_num = 0;
+static int event_handlers_alloc_num = 0;
+static Eina_List *event_handlers_delete_list = NULL;
+
+static Ecore_Event_Filter *event_filters = NULL;
+static Ecore_Event_Filter *event_filter_current = NULL;
+static Ecore_Event *event_filter_event_current = NULL;
+static int event_filters_delete_me = 0;
+static int event_id_max = ECORE_EVENT_COUNT;
+static int ecore_raw_event_type = ECORE_EVENT_NONE;
+static void *ecore_raw_event_event =  NULL;
+
+
+static void _ecore_event_purge_deleted(void);
+static void *_ecore_event_del(Ecore_Event *event);
+
+
+/**
+ * Add an event handler.
+ * @param type The type of the event this handler will get called for
+ * @param func The function to call when the event is found in the queue
+ * @param data A data pointer to pass to the called function @p func
+ * @return A new Event handler, or NULL on failure
+ *
+ * Add an event handler to the list of handlers. This will, on success, return
+ * a handle to the event handler object that was created, that can be used
+ * later to remove the handler using ecore_event_handler_del(). The @p type
+ * parameter is the integer of the event type that will trigger this callback
+ * to be called. The callback @p func is called when this event is processed
+ * and will be passed the event type, a pointer to the private event
+ * structure that is specific to that event type, and a data pointer that is
+ * provided in this call as the @p data parameter.
+ *
+ * When the callback @p func is called, it must return 1 or 0. If it returns
+ * 1 (or ECORE_CALLBACK_RENEW), It will keep being called as per normal, for
+ * each handler set up for that event type. If it returns 0 (or
+ * ECORE_CALLBACK_CANCEL), it will cease processing handlers for that 
particular
+ * event, so all handler set to handle that event type that have not already
+ * been called, will not be.
+ */
+EAPI Ecore_Event_Handler *
+ecore_event_handler_add(int type, Ecore_Event_Handler_Cb func, const void 
*data)
+{
+   Ecore_Event_Handler *eh;
+
+   if (!func) return NULL;
+   if ((type <= ECORE_EVENT_NONE) || (type >= event_id_max)) return NULL;
+   eh = calloc(1, sizeof(Ecore_Event_Handler));
+   if (!eh) return NULL;
+   ECORE_MAGIC_SET(eh, ECORE_MAGIC_EVENT_HANDLER);
+   eh->type = type;
+   eh->func = func;
+   eh->data = (void *)data;
+   if (type >= (event_handlers_num - 1))
+     {
+        int p_alloc_num;
+
+        p_alloc_num = event_handlers_alloc_num;
+        event_handlers_num = type + 1;
+        if (event_handlers_num > event_handlers_alloc_num)
+          {
+             Ecore_Event_Handler **new_handlers;
+             int i;
+
+             event_handlers_alloc_num = ((event_handlers_num + 16) / 16) * 16;
+             new_handlers = realloc(event_handlers, event_handlers_alloc_num * 
sizeof(Ecore_Event_Handler *));
+             if (!new_handlers)
+               {
+                  free(eh);
+                  return NULL;
+               }
+             event_handlers = new_handlers;
+             for (i = p_alloc_num; i < event_handlers_alloc_num; i++)
+               event_handlers[i] = NULL;
+          }
+     }
+   event_handlers[type] = (Ecore_Event_Handler *) 
eina_inlist_append(EINA_INLIST_GET(event_handlers[type]), EINA_INLIST_GET(eh));
+   return eh;
+}
+
+/**
+ * Delete an event handler.
+ * @param event_handler Event handler handle to delete
+ * @return Data passed to handler
+ *
+ * Delete a specified event handler from the handler list. On success this will
+ * delete the event handler and return the pointer passed as @p data when the
+ * handler was added by ecore_event_handler_add(). On failure NULL will be
+ * returned. Once a handler is deleted it will no longer be called.
+ */
+EAPI void *
+ecore_event_handler_del(Ecore_Event_Handler *event_handler)
+{
+   if (!ECORE_MAGIC_CHECK(event_handler, ECORE_MAGIC_EVENT_HANDLER))
+     {
+        ECORE_MAGIC_FAIL(event_handler, ECORE_MAGIC_EVENT_HANDLER,
+                         "ecore_event_handler_del");
+        return NULL;
+     }
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(event_handler->delete_me, NULL);
+   event_handler->delete_me = 1;
+   event_handlers_delete_list = eina_list_append(event_handlers_delete_list, 
event_handler);
+   return event_handler->data;
+}
+
+static void
+_ecore_event_generic_free (void *data __UNUSED__, void *event)
+{
+   free (event);
+}
+
+/**
+ * Add an event to the event queue.
+ * @param type The event type to add to the end of the event queue
+ * @param ev The private data structure for this event type
+ * @param func_free The function to be called to free this private structure
+ * @param data The data pointer to be passed to the free function
+ * @return A Handle for that event
+ *
+ * On success this function returns a handle to an event on the event queue, or
+ * NULL if it fails. If it succeeds, an event of type @p type will be added
+ * to the queue for processing by event handlers added by
+ * ecore_event_handler_add(). The @p ev parameter will be a pointer to the 
event
+ * private data that is specific to that event type. When the event is no
+ * longer needed, @p func_free will be called and passed the private structure
+ * pointer for cleaning up. If @p func_free is NULL, free() will be called
+ * with the private structure pointer.
+ * func_free is passed @p data as its data parameter.
+ */
+EAPI Ecore_Event *
+ecore_event_add(int type, void *ev, Ecore_End_Cb func_free, void *data)
+{
+/*   if (!ev) return NULL;*/
+   if (type <= ECORE_EVENT_NONE) return NULL;
+   if (type >= event_id_max) return NULL;
+   if ((ev) && (!func_free)) func_free = _ecore_event_generic_free;
+   return _ecore_event_add(type, ev, func_free, data);
+}
+
+/**
+ * Delete an event from the queue.
+ * @param event The event handle to delete
+ * @return The data pointer originally set for the event free function
+ *
+ * This deletes the event @p event from the event queue, and returns the
+ * @p data parameer originally set when adding it with ecore_event_add(). This
+ * does not immediately call the free function, and it may be called later on
+ * cleanup, and so if the free function depends on the data pointer to work,
+ * you should defer cleaning of this till the free function is called later.
+ */
+EAPI void *
+ecore_event_del(Ecore_Event *event)
+{
+   if (!ECORE_MAGIC_CHECK(event, ECORE_MAGIC_EVENT))
+     {
+        ECORE_MAGIC_FAIL(event, ECORE_MAGIC_EVENT, "ecore_event_del");
+        return NULL;
+     }
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(event->delete_me, NULL);
+   event->delete_me = 1;
+   return event->data;
+}
+
+/**
+ * Allocate a new event type id sensibly and return the new id.
+ * @return A new event type id.
+ *
+ * This function allocates a new event type id and returns it. Once an event
+ * type has been allocated it can never be de-allocated during the life of
+ * the program. There is no guarantee of the contents of this event ID, or how
+ * it is calculated, except that the ID will be unique to the current instance
+ * of the process.
+ */
+EAPI int
+ecore_event_type_new(void)
+{
+   event_id_max++;
+   return event_id_max - 1;
+}
+
+/**
+ * Add a filter the current event queue.
+ * @param func_start Function to call just before filtering and return data
+ * @param func_filter Function to call on each event
+ * @param func_end Function to call after the queu has been filtered
+ * @param data Data to pass to the filter functions
+ * @return A filter handle
+ *
+ * This adds a filter to call callbacks to loop through the event queue and
+ * filter events out of the queue. On failure NULL is returned. On success a
+ * Filter handle is returned. Filters are called on the queue just before
+ * Event handler processing to try and remove redundant events. Just as
+ * processing starts @p func_start is called and passed the @p data pointer.
+ * This function returns a pointer that is used as loop_data that is now 
passed to
+ * @p func_filter as loop_data. @p func_filter is also passed @p data and the
+ * event type and private event structure. If this callback returns 0, the
+ * event is removed from the queue. If it returns 1, the event is kept. When
+ * processing is finished @p func_end is called and is passed the loop_data
+ * and @p data pointer to clean up.
+ */
+EAPI Ecore_Event_Filter *
+ecore_event_filter_add(Ecore_Data_Cb func_start, Ecore_Filter_Cb func_filter, 
Ecore_End_Cb func_end, const void *data)
+{
+   Ecore_Event_Filter *ef;
+
+   if (!func_filter) return NULL;
+   ef = calloc(1, sizeof(Ecore_Event_Filter));
+   if (!ef) return NULL;
+   ECORE_MAGIC_SET(ef, ECORE_MAGIC_EVENT_FILTER);
+   ef->func_start = func_start;
+   ef->func_filter = func_filter;
+   ef->func_end = func_end;
+   ef->data = (void *)data;
+   event_filters = (Ecore_Event_Filter *) 
eina_inlist_append(EINA_INLIST_GET(event_filters), EINA_INLIST_GET(ef));
+   return ef;
+}
+
+/**
+ * Delete an event filter.
+ * @param ef The event filter handle
+ * @return The data set for the filter
+ *
+ * Delete a filter that has been added by its @p ef handle. On success this
+ * will return the data pointer set when this filter was added. On failure
+ * NULL is returned.
+ */
+EAPI void *
+ecore_event_filter_del(Ecore_Event_Filter *ef)
+{
+   if (!ECORE_MAGIC_CHECK(ef, ECORE_MAGIC_EVENT_FILTER))
+     {
+        ECORE_MAGIC_FAIL(ef, ECORE_MAGIC_EVENT_FILTER, 
"ecore_event_filter_del");
+        return NULL;
+     }
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(ef->delete_me, NULL);
+   ef->delete_me = 1;
+   event_filters_delete_me = 1;
+   return ef->data;
+}
+
+/**
+ * Return the current event type being handled.
+ * @return The current event type being handled if inside a handler callback
+ *
+ * If the program is currently inside an Ecore event handler callback this
+ * will return the type of the current event being processed. If Ecore is
+ * not inside an event handler, ECORE_EVENT_NONE is returned.
+ *
+ * This is useful when certain Ecore modules such as Ecore_Evas "swallow"
+ * events and not all the original information is passed on. In special cases
+ * this extra information may be useful or needed and using this call can let
+ * the program know if the event type being handled is one it wants to get more
+ * information about.
+ */
+EAPI int
+ecore_event_current_type_get(void)
+{
+   return ecore_raw_event_type;
+}
+
+/**
+ * Return the current event type pointer handled.
+ * @return The current event pointer being handled if inside a handler callback
+ *
+ * If the program is currently inside an Ecore event handler callback this
+ * will return the pointer of the current event being processed. If Ecore is
+ * not inside an event handler, NULL will be returned.
+ *
+ * This is useful when certain Ecore modules such as Ecore_Evas "swallow"
+ * events and not all the original information is passed on. In special cases
+ * this extra information may be useful or needed and using this call can let
+ * the program access the event data if the type of the event is handled by
+ * the program.
+ */
+EAPI void *
+ecore_event_current_event_get(void)
+{
+   return ecore_raw_event_event;
+}
+
+void
+_ecore_event_shutdown(void)
+{
+   int i;
+   Ecore_Event_Handler *eh;
+   Ecore_Event_Filter *ef;
+
+   while (events) _ecore_event_del(events);
+   event_current = NULL;
+   for (i = 0; i < event_handlers_num; i++)
+     {
+        while ((eh = event_handlers[i]))
+          {
+             event_handlers[i] = (Ecore_Event_Handler *) 
eina_inlist_remove(EINA_INLIST_GET(event_handlers[i]), 
EINA_INLIST_GET(event_handlers[i]));
+             ECORE_MAGIC_SET(eh, ECORE_MAGIC_NONE);
+             if (!eh->delete_me) free(eh);
+          }
+     }
+   EINA_LIST_FREE(event_handlers_delete_list, eh)
+     free(eh);
+   if (event_handlers) free(event_handlers);
+   event_handlers = NULL;
+   event_handlers_num = 0;
+   event_handlers_alloc_num = 0;
+   while ((ef = event_filters))
+     {
+        event_filters = (Ecore_Event_Filter *) 
eina_inlist_remove(EINA_INLIST_GET(event_filters), 
EINA_INLIST_GET(event_filters));
+        ECORE_MAGIC_SET(ef, ECORE_MAGIC_NONE);
+        free(ef);
+     }
+   event_filters_delete_me = 0;
+   event_filter_current = NULL;
+   event_filter_event_current = NULL;
+}
+
+int
+_ecore_event_exist(void)
+{
+   Ecore_Event *e;
+   EINA_INLIST_FOREACH(events, e)
+      if (!e->delete_me) return 1;
+   return 0;
+}
+
+Ecore_Event *
+_ecore_event_add(int type, void *ev, Ecore_End_Cb func_free, void *data)
+{
+   Ecore_Event *e;
+
+   e = calloc(1, sizeof(Ecore_Event));
+   if (!e) return NULL;
+   ECORE_MAGIC_SET(e, ECORE_MAGIC_EVENT);
+   e->type = type;
+   e->event = ev;
+   e->func_free = func_free;
+   e->data = data;
+   if (inpurge > 0)
+     {
+        purge_events = (Ecore_Event 
*)eina_inlist_append(EINA_INLIST_GET(purge_events), EINA_INLIST_GET(e));
+        events_num++;
+     }
+   else
+     {
+        events = (Ecore_Event *)eina_inlist_append(EINA_INLIST_GET(events), 
EINA_INLIST_GET(e));
+        events_num++;
+     }
+   return e;
+}
+
+void *
+_ecore_event_del(Ecore_Event *event)
+{
+   void *data;
+
+   data = event->data;
+   if (event->func_free) event->func_free(event->data, event->event);
+   events = (Ecore_Event *) eina_inlist_remove(EINA_INLIST_GET(events), 
EINA_INLIST_GET(event));
+   ECORE_MAGIC_SET(event, ECORE_MAGIC_NONE);
+   free(event);
+   events_num--;
+   return data;
+}
+
+static void
+_ecore_event_purge_deleted(void)
+{
+   Ecore_Event *itr = events;
+
+   inpurge++;
+   while (itr)
+     {
+        Ecore_Event *next = (Ecore_Event *)EINA_INLIST_GET(itr)->next;
+        if ((!itr->references) && (itr->delete_me))
+          _ecore_event_del(itr);
+        itr = next;
+     }
+   inpurge--;
+   while (purge_events)
+     {
+        Ecore_Event *e = purge_events;
+        purge_events = (Ecore_Event 
*)eina_inlist_remove(EINA_INLIST_GET(purge_events), 
EINA_INLIST_GET(purge_events));
+        events = (Ecore_Event *)eina_inlist_append(EINA_INLIST_GET(events), 
EINA_INLIST_GET(e));
+     }
+}
+
+static inline void
+_ecore_event_filters_apply()
+{
+
+   if (!event_filter_current)
+     {
+        /* regular main loop, start from head */
+        event_filter_current = event_filters;
+     }
+   else
+     {
+        /* recursive main loop, continue from where we were */
+        event_filter_current = (Ecore_Event_Filter 
*)EINA_INLIST_GET(event_filter_current)->next;
+     }
+
+   while (event_filter_current)
+     {
+        Ecore_Event_Filter *ef = event_filter_current;
+
+        if (!ef->delete_me)
+          {
+             ef->references++;
+
+             if (ef->func_start)
+               ef->loop_data = ef->func_start(ef->data);
+
+             if (!event_filter_event_current)
+               {
+                  /* regular main loop, start from head */
+                  event_filter_event_current = events;
+               }
+             else
+               {
+                  /* recursive main loop, continue from where we were */
+                  event_filter_event_current = (Ecore_Event 
*)EINA_INLIST_GET(event_filter_event_current)->next;
+               }
+
+             while (event_filter_event_current)
+               {
+                  Ecore_Event *e = event_filter_event_current;
+
+                  if (!ef->func_filter(ef->data, ef->loop_data,
+                                       e->type, e->event))
+                    {
+                       ecore_event_del(e);
+                    }
+
+                  if (event_filter_event_current) /* may have changed in 
recursive main loops */
+                    event_filter_event_current = (Ecore_Event 
*)EINA_INLIST_GET(event_filter_event_current)->next;
+               }
+             if (ef->func_end)
+               ef->func_end(ef->data, ef->loop_data);
+
+             ef->references--;
+          }
+
+        if (event_filter_current) /* may have changed in recursive main loops 
*/
+          event_filter_current = (Ecore_Event_Filter 
*)EINA_INLIST_GET(event_filter_current)->next;
+     }
+   if (event_filters_delete_me)
+     {
+        int deleted_in_use = 0;
+        Ecore_Event_Filter *l;
+        for (l = event_filters; l;)
+          {
+             Ecore_Event_Filter *ef = l;
+             l = (Ecore_Event_Filter *) EINA_INLIST_GET(l)->next;
+             if (ef->delete_me)
+               {
+                  if (ef->references)
+                    {
+                       deleted_in_use++;
+                       continue;
+                    }
+
+                  event_filters = (Ecore_Event_Filter *) 
eina_inlist_remove(EINA_INLIST_GET(event_filters), EINA_INLIST_GET(ef));
+                  ECORE_MAGIC_SET(ef, ECORE_MAGIC_NONE);
+                  free(ef);
+               }
+          }
+        if (!deleted_in_use)
+          event_filters_delete_me = 0;
+     }
+}
+void
+_ecore_event_call(void)
+{
+   Eina_List *l, *l_next;
+   Ecore_Event_Handler *eh;
+
+   _ecore_event_filters_apply();
+
+   if (!event_current)
+     {
+        /* regular main loop, start from head */
+        event_current = events;
+        event_handler_current = NULL;
+     }
+
+   while (event_current)
+     {
+        Ecore_Event *e = event_current;
+        int handle_count = 0;
+
+        if (e->delete_me)
+          {
+             event_current = (Ecore_Event 
*)EINA_INLIST_GET(event_current)->next;
+             continue;
+          }
+
+        ecore_raw_event_type = e->type;
+        ecore_raw_event_event = e->event;
+        e->references++;
+        if ((e->type >= 0) && (e->type < event_handlers_num))
+          {
+             if (!event_handler_current)
+               {
+                  /* regular main loop, start from head */
+                  event_handler_current = event_handlers[e->type];
+               }
+             else
+               {
+                  /* recursive main loop, continue from where we were */
+                  event_handler_current = (Ecore_Event_Handler 
*)EINA_INLIST_GET(event_handler_current)->next;
+               }
+
+             while ((event_handler_current) && (!e->delete_me))
+               {
+                  Ecore_Event_Handler *eh = event_handler_current;
+                  if (!eh->delete_me)
+                    {
+                       Eina_Bool ret;
+
+                       handle_count++;
+
+                       eh->references++;
+                       ret = eh->func(eh->data, e->type, e->event);
+                       eh->references--;
+
+                       if (!ret)
+                         {
+                            event_handler_current = NULL;
+                            break;  /* 0 == "call no further handlers" */
+                         }
+                    }
+
+                  if (event_handler_current) /* may have changed in recursive 
main loops */
+                    event_handler_current = (Ecore_Event_Handler 
*)EINA_INLIST_GET(event_handler_current)->next;
+               }
+          }
+        /* if no handlers were set for EXIT signal - then default is */
+        /* to quit the main loop */
+        if ((e->type == ECORE_EVENT_SIGNAL_EXIT) && (handle_count == 0))
+          ecore_main_loop_quit();
+        e->references--;
+        e->delete_me = 1;
+
+        if (event_current) /* may have changed in recursive main loops */
+          event_current = (Ecore_Event *)EINA_INLIST_GET(event_current)->next;
+     }
+
+   ecore_raw_event_type = ECORE_EVENT_NONE;
+   ecore_raw_event_event = NULL;
+
+   _ecore_event_purge_deleted();
+
+   EINA_LIST_FOREACH_SAFE(event_handlers_delete_list, l, l_next, eh)
+     {
+        if (eh->references) continue;
+
+        event_handlers_delete_list = 
eina_list_remove_list(event_handlers_delete_list, l);
+
+        event_handlers[eh->type] = (Ecore_Event_Handler *) 
eina_inlist_remove(EINA_INLIST_GET(event_handlers[eh->type]), 
EINA_INLIST_GET(eh));
+        ECORE_MAGIC_SET(eh, ECORE_MAGIC_NONE);
+        free(eh);
+     }
+}
+
+EAPI void *
+_ecore_event_signal_user_new(void)
+{
+   Ecore_Event_Signal_User *e;
+
+   e = calloc(1, sizeof(Ecore_Event_Signal_User));
+   return e;
+}
+
+void *
+_ecore_event_signal_hup_new(void)
+{
+   Ecore_Event_Signal_Hup *e;
+
+   e = calloc(1, sizeof(Ecore_Event_Signal_Hup));
+   return e;
+}
+
+void *
+_ecore_event_signal_exit_new(void)
+{
+   Ecore_Event_Signal_Exit *e;
+
+   e = calloc(1, sizeof(Ecore_Event_Signal_Exit));
+   return e;
+}
+
+void *
+_ecore_event_signal_power_new(void)
+{
+   Ecore_Event_Signal_Power *e;
+
+   e = calloc(1, sizeof(Ecore_Event_Signal_Power));
+   return e;
+}
+
+void *
+_ecore_event_signal_realtime_new(void)
+{
+   return calloc(1, sizeof(Ecore_Event_Signal_Realtime));
+}
diff --git a/tests/suite/ecore/src/lib/ecore_exe.c 
b/tests/suite/ecore/src/lib/ecore_exe.c
new file mode 100644
index 0000000..251157c
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_exe.c
@@ -0,0 +1,1846 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined (__FreeBSD__) || defined (__OpenBSD__) || defined (__NetBSD__)
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+
+   /* FIXME: Getting respawn to work
+    *
+    * There is no way that we can do anything about the internal state info of
+    * an external exe.  The same can be said about the state of user code.  
User
+    * code in this context means the code that is using ecore_exe to manage 
exe's
+    * for it.
+    *
+    * Document that the exe must be respawnable, in other words, there is no
+    * state that it cannot regenerate by just killing it and starting it again.
+    * This includes state that the user code knows about, as the respawn is
+    * transparent to that code.  On the other hand, maybe a respawn event might
+    * be useful, or maybe resend the currently non existent add event.  For
+    * consistancy with ecore_con, an add event is good anyway.
+    *
+    * The Ecore_exe structure is reused for respawning, so that the (opaque)
+    * pointer held by the user remains valid.  This means that the Ecore_Exe
+    * init and del functions may need to be split into two parts each to avoid
+    * duplicating code - common code part, and the rest.  This implies that
+    * the unchanging members mentioned next should NEVER change.
+    *
+    * These structure members don't need to change -
+    *   __list_data       - we stay on the list
+    *   ECORE_MAGIC       - this is a constant
+    *   data              - passed in originally
+    *   cmd               - passed in originally
+    *   flags             - passed in originally
+    *
+    * These structure members need to change -
+    *   tag               - state that must be regenerated, zap it
+    *   pid               - it will be different
+    *   child_fd_write    - it will be different
+    *   child_fd_read     - it will be different
+    *   child_fd_error    - it will be different
+    *   write_fd_handler  - we cannot change the fd used by a handler, this 
changes coz the fd changes.
+    *   read_fd_handler   - we cannot change the fd used by a handler, this 
changes coz the fd changes.
+    *   error_fd_handler  - we cannot change the fd used by a handler, this 
changes coz the fd changes.
+    *
+    * Hmm, the read, write, and error buffers could be tricky.
+    * They are not atomic, and could be in a semi complete state.
+    * They fall into the "state must be regenerated" mentioned above.
+    * A respawn/add event should take care of it.
+    *
+    * These structure members need to change -
+    *   write_data_buf    - state that must be regenerated, zap it
+    *   write_data_size   - state that must be regenerated, zap it
+    *   write_data_offset - state that must be regenerated, zap it
+    *   read_data_buf     - state that must be regenerated, zap it
+    *   read_data_size    - state that must be regenerated, zap it
+    *   error_data_buf    - state that must be regenerated, zap it
+    *   error_data_size   - state that must be regenerated, zap it
+    *   close_write       - state that must be regenerated, zap it
+    *
+    * There is the problem that an exe that fell over and needs respawning
+    * might keep falling over, keep needing to be respawned, and tie up system
+    * resources with the constant respawning.  An exponentially increasing
+    * timeout (with maximum timeout) between respawns should take care of that.
+    * Although this is not a "contention for a resource" problem, the exe 
falling
+    * over may be, so a random element added to the timeout may help, and won't
+    * hurt.  The user code may need to be informed that a timeout is in 
progress.
+    */
+
+struct _Ecore_Exe
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   pid_t pid;
+   void *data;
+   char *tag, *cmd;
+   Ecore_Exe_Flags  flags;
+   Ecore_Fd_Handler *write_fd_handler; /* the fd_handler to handle write to 
child - if this was used, or NULL if not */
+   Ecore_Fd_Handler *read_fd_handler; /* the fd_handler to handle read from 
child - if this was used, or NULL if not */
+   Ecore_Fd_Handler *error_fd_handler; /* the fd_handler to handle errors from 
child - if this was used, or NULL if not */
+   void  *write_data_buf; /* a data buffer for data to write to the child -
+                                 * realloced as needed for more data and 
flushed when the fd handler says writes are possible
+                                 */
+   int write_data_size; /* the size in bytes of the data buffer */
+   int write_data_offset; /* the offset in bytes in the data buffer */
+   void *read_data_buf; /* data read from the child awating delivery to an 
event */
+   int read_data_size; /* data read from child in bytes */
+   void *error_data_buf; /* errors read from the child awating delivery to an 
event */
+   int error_data_size; /* errors read from child in bytes */
+   int child_fd_write; /* fd to write TO to send data to the child */
+   int child_fd_read; /* fd to read FROM when child has sent us (the parent) 
data */
+   int child_fd_error; /* fd to read FROM when child has sent us (the parent) 
errors */
+   int child_fd_write_x; /* fd to write TO to send data to the child */
+   int child_fd_read_x; /* fd to read FROM when child has sent us (the parent) 
data */
+   int child_fd_error_x; /* fd to read FROM when child has sent us (the 
parent) errors */
+   Eina_Bool close_stdin : 1;
+
+   int start_bytes, end_bytes, start_lines, end_lines; /* Number of 
bytes/lines to auto pipe at start/end of stdout/stderr. */
+
+   Ecore_Timer *doomsday_clock; /* The Timer of Death.  Muahahahaha. */
+   void *doomsday_clock_dead; /* data for the doomsday clock */
+
+   Ecore_Exe_Cb pre_free_cb;
+};
+
+
+/* TODO: Something to let people build a command line and does auto escaping -
+ *
+ * ecore_exe_snprintf()
+ *
+ *   OR
+ *
+ * cmd = ecore_exe_comand_parameter_append(cmd, "firefox");
+ * cmd = ecore_exe_comand_parameter_append(cmd, 
"http://www.foo.com/bar.html?baz=yes";);
+ * each parameter appended is one argument, and it gets escaped, quoted, and
+ * appended with a preceding space.  The first is the command off course.
+ */
+
+struct _ecore_exe_dead_exe
+{
+   pid_t pid;
+   char *cmd;
+};
+
+static inline void _ecore_exe_exec_it(const char *exe_cmd, Ecore_Exe_Flags 
flags);
+static Eina_Bool _ecore_exe_data_generic_handler(void *data, Ecore_Fd_Handler 
*fd_handler, Ecore_Exe_Flags flags);
+static Eina_Bool _ecore_exe_data_error_handler(void *data, Ecore_Fd_Handler 
*fd_handler);
+static Eina_Bool _ecore_exe_data_read_handler(void *data, Ecore_Fd_Handler 
*fd_handler);
+static Eina_Bool _ecore_exe_data_write_handler(void *data, Ecore_Fd_Handler 
*fd_handler);
+static void _ecore_exe_flush(Ecore_Exe * exe);
+static void _ecore_exe_event_exe_data_free(void *data __UNUSED__, void *ev);
+static Ecore_Exe *_ecore_exe_is_it_alive(pid_t pid);
+static Eina_Bool _ecore_exe_make_sure_its_dead(void *data);
+static Eina_Bool _ecore_exe_make_sure_its_really_dead(void *data);
+static Ecore_Exe_Event_Add *_ecore_exe_event_add_new(void);
+static void _ecore_exe_event_add_free(void *data, void *ev);
+static void _ecore_exe_dead_attach(Ecore_Exe *exe);
+
+EAPI int ECORE_EXE_EVENT_ADD = 0;
+EAPI int ECORE_EXE_EVENT_DEL = 0;
+EAPI int ECORE_EXE_EVENT_DATA = 0;
+EAPI int ECORE_EXE_EVENT_ERROR = 0;
+
+static Ecore_Exe *exes = NULL;
+static const char *shell = NULL;
+
+/* FIXME: This errno checking stuff should be put elsewhere for everybody to 
use.
+ * For now it lives here though, just to make testing easier.
+ */
+static int _ecore_exe_check_errno(int result, const char *file, int line);
+
+#define E_IF_NO_ERRNO(result, foo, ok) \
+  while (((ok) = _ecore_exe_check_errno( (result) = (foo), __FILE__, 
__LINE__)) == -1)   sleep(1); \
+  if (ok)
+
+#define E_NO_ERRNO(result, foo, ok) \
+  while (((ok) = _ecore_exe_check_errno( (result) = (foo), __FILE__, 
__LINE__)) == -1)   sleep(1)
+
+#define E_IF_NO_ERRNO_NOLOOP(result, foo, ok) \
+  if (((ok) = _ecore_exe_check_errno( (result) = (foo), __FILE__, __LINE__)))
+
+static int
+_ecore_exe_check_errno(int result, const char *file, int line)
+{
+   int saved_errno = errno;
+
+   if (result == -1)
+     {
+        perror("*** errno reports ");
+/* What is currently supported -
+ *
+ *   pipe
+ *     EFAULT  Argument is not valid.
+ *     EMFILE  Too many file descriptors used by process.
+ *     ENFILE  Too many open files by system.
+ *   read
+ *     EAGAIN  No data now, try again.
+ *     EBADF   This is not an fd that can be read.
+ *     EFAULT  This is not a valid buffer.
+ *     EINTR   Interupted by signal, try again.
+ *     EINVAL  This is not an fd that can be read.
+ *     EIO     I/O error.
+ *     EISDIR  This is a directory, and cannot be read.
+ *     others  Depending on what sort of thing we are reading from.
+ *   close
+ *     EBADF   This is not an fd that can be closed.
+ *     EINTR   Interupted by signal, try again.
+ *     EIO     I/O error.
+ *   dup2
+ *     EBADF   This is not an fd that can be dup2'ed.
+ *     EBUSY   Race condition between open() and dup()
+ *     EINTR   Interupted by signal, try again.
+ *     EMFILE  Too many file descriptors used by process.
+ *   fcntl
+ *     EACCES, EAGAIN  Locked or mapped by something else, try again later.
+ *     EBADF   This is not an fd that can be fcntl'ed.
+ *     EDEADLK This will cause a deadlock.
+ *     EFAULT  This is not a valid lock.
+ *     EINTR   Interupted by signal, try again.
+ *     EINVAL  This is not a valid arg.
+ *     EMFILE  Too many file descriptors used by process.
+ *     ENOLCK  Problem getting a lock.
+ *     EPERM   Not allowed to do that.
+ *   fsync
+ *     EBADF   This is not an fd that is open for writing.
+ *     EINVAL, EROFS  This is not an fd that can be fsynced.
+ *     EIO     I/O error.
+ *
+ * How to use it -
+ *    int ok = 0;
+ *    int result;
+ *
+ *    E_IF_NO_ERRNO(result, foo(bar), ok)
+ *      {
+ *         E_IF_NO_ERRNO_NOLOOP(result, foo(bar), ok)
+ *            {
+ *            }
+ *      }
+ *
+ *   if (!ok)
+ *     {
+ *        // Something failed, cleanup.
+ *     }
+ */
+        switch (saved_errno)
+          {
+           case EACCES:
+           case EAGAIN:
+           case EINTR:
+               { /* Not now, try later. */
+                  ERR("*** Must try again in %s @%u.", file, line);
+                  result = -1;
+                  break;
+               }
+           case EMFILE:
+           case ENFILE:
+           case ENOLCK:
+               { /* Low on resources. */
+                  ERR("*** Low on resources in %s @%u.", file,
+                      line);
+                  result = 0;
+                  break;
+               }
+           case EIO:
+               { /* I/O error. */
+                  ERR("*** I/O error in %s @%u.", file, line);
+                  result = 0;
+                  break;
+               }
+           case EFAULT:
+           case EBADF:
+           case EINVAL:
+           case EROFS:
+           case EISDIR:
+           case EDEADLK:
+           case EPERM:
+           case EBUSY:
+               { /* Programmer fucked up. */
+                  ERR("*** NAUGHTY PROGRAMMER!!!\n"
+                      "*** SPANK SPANK SPANK!!!\n"
+                      "*** Now go fix your code in %s @%u. Tut tut tut!",
+                      file, line);
+                  result = 0;
+                  break;
+               }
+           default:
+               { /* Unsupported errno code, please add this one. */
+                  ERR("*** NAUGHTY PROGRAMMER!!!\n"
+                      "*** SPANK SPANK SPANK!!!\n"
+                      "*** Unsupported errno code %d, please add this one.\n"
+                      "*** Now go fix your code in %s @%u, from %s @%u. Tut 
tut tut!",
+                      saved_errno, __FILE__, __LINE__, file, line);
+                  result = 0;
+                  break;
+               }
+          }
+     }
+   else /* Everything is fine. */
+     result = 1;
+
+   errno = saved_errno;
+   return result;
+}
+
+/**
+ * @defgroup Ecore_Exe_Basic_Group Process Spawning Functions
+ *
+ * Functions that deal with spawned processes.
+ */
+
+static int run_pri = ECORE_EXE_PRIORITY_INHERIT;
+
+/**
+ * Sets the priority at which to launch processes
+ *
+ * This sets the priority of processes run by ecore_exe_run() and
+ * ecore_exe_pipe_run().
+ * @li On Windows, the child process is created by default with the
+ * #ECORE_EXE_WIN32_PRIORITY_NORMAL priority, unless the calling
+ * process is in #ECORE_EXE_WIN32_PRIORITY_IDLE or
+ * #ECORE_EXE_WIN32_PRIORITY_BELOW_NORMAL priority. In that case, the
+ * child process inherits this priority.
+ * @li On other platforms, if set to #ECORE_EXE_PRIORITY_INHERIT child
+ * processes inherits the priority of their parent. This is the default.
+ *
+ * @param   pri value a Ecore_Exe_Win32_Priority value on Windows, -20
+ * to 19 or ECORE_EXE_PRIORITY_INHERIT on other OS.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI void
+ecore_exe_run_priority_set(int pri)
+{
+   run_pri = pri;
+}
+
+/**
+ * Gets the priority at which to launch processes
+ *
+ * This gets ths priority of launched processes. See
+ * ecore_exe_run_priority_set() for details. This just returns the value set
+ * by this call.
+ *
+ * @return the value set by ecore_exe_run_priority_set()
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI int
+ecore_exe_run_priority_get(void)
+{
+   return run_pri;
+}
+
+/**
+ * Spawns a child process.
+ *
+ * This is now just a thin wrapper around ecore_exe_pipe_run()
+ *
+ * @param   exe_cmd The command to run with @c /bin/sh.
+ * @param   data    Data to attach to the returned process handle.
+ * @return  A process handle to the spawned process.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI Ecore_Exe *
+ecore_exe_run(const char *exe_cmd, const void *data)
+{
+/* I'm just being paranoid again, leaving in the original code in case there 
is a problem. */
+#if 0
+   Ecore_Exe *exe;
+   pid_t pid;
+
+   if (!exe_cmd)
+      return NULL;
+   pid = fork();
+   if (pid)
+     {
+        exe = calloc(1, sizeof(Ecore_Exe));
+        if (!exe)
+          {
+             kill(pid, SIGKILL);
+             return NULL;
+          }
+        ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE);
+        exe->pid = pid;
+        exe->data = (void *)data;
+        exe->cmd = strdup(exe_cmd);
+        exes = _ecore_list2_append(exes, exe);
+        return exe;
+     }
+   _ecore_exe_exec_it(exe_cmd, 0);
+   exit(127);
+   return NULL;
+#else
+   return ecore_exe_pipe_run(exe_cmd, 0, data);
+#endif
+}
+
+/**
+ * Spawns a child process with its stdin/out available for communication.
+ *
+ * This function forks and runs the given command using @c /bin/sh.
+ *
+ * Note that the process handle is only valid until a child process
+ * terminated event is received.  After all handlers for the child process
+ * terminated event have been called, the handle will be freed by Ecore.
+ *
+ * This function does the same thing as ecore_exe_run(), but also makes the
+ * standard in and/or out as well as stderr from the child process available
+ * for reading or writing.  To write use ecore_exe_send().  To read listen to
+ * ECORE_EXE_EVENT_DATA or ECORE_EXE_EVENT_ERROR events (set up handlers).
+ * Ecore may buffer read and error data until a newline character if asked
+ * for with the @p flags.  All data will be included in the events (newlines
+ * will be replaced with NULLS if line buffered).  ECORE_EXE_EVENT_DATA events
+ * will only happen if the process is run with ECORE_EXE_PIPE_READ enabled
+ * in the flags.  The same with the error version.  Writing will only be
+ * allowed with ECORE_EXE_PIPE_WRITE enabled in the flags.
+ *
+ * @param   exe_cmd The command to run with @c /bin/sh.
+ * @param   flags   The flag parameters for how to deal with inter-process I/O
+ * @param   data    Data to attach to the returned process handle.
+ * @return  A process handle to the spawned process.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI Ecore_Exe *
+ecore_exe_pipe_run(const char *exe_cmd, Ecore_Exe_Flags flags, const void 
*data)
+{
+   Ecore_Exe *exe = NULL;
+   int statusPipe[2] = { -1, -1 };
+   int errorPipe[2] = { -1, -1 };
+   int readPipe[2] = { -1, -1 };
+   int writePipe[2] = { -1, -1 };
+   int n = 0;
+   int ok = 1;
+   int result;
+
+   if (!exe_cmd) return NULL;
+   exe = calloc(1, sizeof(Ecore_Exe));
+   if (!exe) return NULL;
+
+   if ((flags & ECORE_EXE_PIPE_AUTO) && (!(flags & ECORE_EXE_PIPE_ERROR))
+       && (!(flags & ECORE_EXE_PIPE_READ)))
+     /* We need something to auto pipe. */
+     flags |= ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR;
+
+   exe->child_fd_error = -1;
+   exe->child_fd_read = -1;
+   exe->child_fd_write = -1;
+   exe->child_fd_error_x = -1;
+   exe->child_fd_read_x = -1;
+   exe->child_fd_write_x = -1;
+
+   /*  Create some pipes. */
+   if (ok)
+     {
+        E_IF_NO_ERRNO_NOLOOP(result, pipe(statusPipe), ok)
+          {
+          }
+     }
+   if (ok && (flags & ECORE_EXE_PIPE_ERROR))
+     {
+        E_IF_NO_ERRNO_NOLOOP(result, pipe(errorPipe), ok)
+          {
+             exe->child_fd_error = errorPipe[0];
+             exe->child_fd_error_x = errorPipe[1];
+          }
+     }
+   if (ok && (flags & ECORE_EXE_PIPE_READ))
+     {
+        E_IF_NO_ERRNO_NOLOOP(result, pipe(readPipe), ok)
+          {
+             exe->child_fd_read = readPipe[0];
+             exe->child_fd_read_x = readPipe[1];
+          }
+     }
+   if (ok && (flags & ECORE_EXE_PIPE_WRITE))
+     {
+        E_IF_NO_ERRNO_NOLOOP(result, pipe(writePipe), ok)
+          {
+             exe->child_fd_write = writePipe[1];
+             exe->child_fd_write_x = writePipe[0];
+          }
+     }
+   if (ok)
+     {
+        pid_t pid = 0;
+        volatile int vfork_exec_errno = 0;
+
+        /* FIXME: I should double check this.  After a quick look around, this 
is already done, but via a more modern method. */
+        /* signal(SIGPIPE, SIG_IGN);    We only want EPIPE on errors */
+        pid = fork();
+
+        if (pid == -1)
+          {
+             ERR("Failed to fork process");
+             pid = 0;
+          }
+        else if (pid == 0)        /* child */
+          {
+             if (run_pri != ECORE_EXE_PRIORITY_INHERIT)
+               {
+                  if ((run_pri >= -20) && (run_pri <= 19))
+                    setpriority(PRIO_PROCESS, 0, run_pri);
+               }
+             /* dup2 STDERR, STDIN, and STDOUT.  dup2() allegedly closes the
+              * second pipe if it's open. On the other hand, there was the
+              * Great FD Leak Scare of '06, so let's be paranoid. */
+             if (ok && (flags & ECORE_EXE_PIPE_ERROR))
+               {
+                  E_NO_ERRNO(result, close(STDERR_FILENO), ok);
+                  E_NO_ERRNO(result, dup2(errorPipe[1], STDERR_FILENO), ok);
+               }
+             if (ok && (flags & ECORE_EXE_PIPE_READ))
+               {
+                  E_NO_ERRNO(result, close(STDOUT_FILENO), ok);
+                  E_NO_ERRNO(result, dup2(readPipe[1], STDOUT_FILENO), ok);
+               }
+             if (ok && (flags & ECORE_EXE_PIPE_WRITE))
+               {
+                  E_NO_ERRNO(result, close(STDIN_FILENO), ok);
+                  E_NO_ERRNO(result, dup2(writePipe[0], STDIN_FILENO), ok);
+               }
+
+             if (ok)
+               {
+                  /* Setup the status pipe. */
+                  E_NO_ERRNO(result, close(statusPipe[0]), ok);
+                  E_IF_NO_ERRNO(result, fcntl(statusPipe[1], F_SETFD, 
FD_CLOEXEC), ok)        /* close on exec shows success */
+                    {
+                       /* Run the actual command. */
+                       _ecore_exe_exec_it(exe_cmd, flags); /* no return */
+                    }
+               }
+
+             /* Something went 'orribly wrong. */
+             vfork_exec_errno = errno;
+
+             /* Close the pipes. */
+             if (flags & ECORE_EXE_PIPE_ERROR)
+               E_NO_ERRNO(result, close(errorPipe[1]), ok);
+             if (flags & ECORE_EXE_PIPE_READ)
+               E_NO_ERRNO(result, close(readPipe[1]), ok);
+             if (flags & ECORE_EXE_PIPE_WRITE)
+               E_NO_ERRNO(result, close(writePipe[0]), ok);
+             E_NO_ERRNO(result, close(statusPipe[1]), ok);
+
+             _exit(-1);
+          }
+        else /* parent */
+          {
+             /* Close the unused pipes. */
+             E_NO_ERRNO(result, close(statusPipe[1]), ok);
+
+             /* FIXME: after having a good look at the current e fd
+              * handling, investigate fcntl(dataPipe[x], F_SETSIG, ...) */
+             /* FIXME: above F_SETSIG etc. - this is async SIGIO based IO
+              * which is also linux specific so we probably don't want to
+              * do this as long as select() is working fine. the only time
+              * we really want to think of SIGIO async IO is when it all
+              * actually works basically everywhere and we can turn all
+              * IO into DMA async activities (i.e. you do a read() then
+              * the read is complete not on return but when you get a
+              * SIGIO - the read() just starts the transfer and it is
+              * completed in the background by DMA (or whatever mechanism
+              * the kernel choses)) */
+
+             /* Wait for it to start executing. */
+             /* FIXME: this doesn't seem very nice - we sit and block
+              * waiting on a child process... even though it's just
+              * the segment between the fork() and the exec) it just feels
+              * wrong */
+             for (;;)
+               {
+                  char buf;
+
+                  E_NO_ERRNO(result, read(statusPipe[0], &buf, 1), ok);
+                  if (result == 0)
+                    {
+                       if (vfork_exec_errno != 0)
+                         {
+                            n = vfork_exec_errno;
+                            ERR("Could not start \"%s\"", exe_cmd);
+                            pid = 0;
+                         }
+                       break;
+                    }
+               }
+
+             /* Close the status pipe. */
+             E_NO_ERRNO(result, close(statusPipe[0]), ok);
+          }
+
+        if (pid)
+          {
+             /* Setup the exe structure. */
+             ECORE_MAGIC_SET(exe, ECORE_MAGIC_EXE);
+             exe->start_bytes = -1;
+             exe->end_bytes = -1;
+             exe->start_lines = -1;
+             exe->end_lines = -1;
+             exe->pid = pid;
+             exe->flags = flags;
+             exe->data = (void *)data;
+             if ((exe->cmd = strdup(exe_cmd)))
+               {
+                  if (flags & ECORE_EXE_PIPE_ERROR)
+                    { /* Setup the error stuff. */
+                       E_IF_NO_ERRNO(result,
+                                     fcntl(exe->child_fd_error, F_SETFL,
+                                           O_NONBLOCK), ok) {}
+                       E_IF_NO_ERRNO(result,
+                                     fcntl(exe->child_fd_error, F_SETFD,
+                                           FD_CLOEXEC), ok) {}
+                       E_IF_NO_ERRNO(result,
+                                     fcntl(exe->child_fd_error_x, F_SETFD,
+                                           FD_CLOEXEC), ok) {}
+                       {
+                          exe->error_fd_handler =
+                             ecore_main_fd_handler_add(exe->child_fd_error,
+                                                       ECORE_FD_READ,
+                                                       
_ecore_exe_data_error_handler,
+                                                       exe, NULL, NULL);
+                          if (!exe->error_fd_handler)
+                             ok = 0;
+                       }
+                    }
+                  if (ok && (flags & ECORE_EXE_PIPE_READ))
+                    { /* Setup the read stuff. */
+                       E_IF_NO_ERRNO(result,
+                                     fcntl(exe->child_fd_read, F_SETFL,
+                                           O_NONBLOCK), ok) {}
+                       E_IF_NO_ERRNO(result,
+                                     fcntl(exe->child_fd_read, F_SETFD,
+                                           FD_CLOEXEC), ok) {}
+                       E_IF_NO_ERRNO(result,
+                                     fcntl(exe->child_fd_read_x, F_SETFD,
+                                           FD_CLOEXEC), ok) {}
+                       {
+                          exe->read_fd_handler =
+                             ecore_main_fd_handler_add(exe->child_fd_read,
+                                                       ECORE_FD_READ,
+                                                       
_ecore_exe_data_read_handler,
+                                                       exe, NULL, NULL);
+                          if (!exe->read_fd_handler)
+                             ok = 0;
+                       }
+                    }
+                  if (ok && (flags & ECORE_EXE_PIPE_WRITE))
+                    {                /* Setup the write stuff. */
+                       E_IF_NO_ERRNO(result,
+                                     fcntl(exe->child_fd_write, F_SETFL,
+                                           O_NONBLOCK), ok) {}
+                       E_IF_NO_ERRNO(result,
+                                     fcntl(exe->child_fd_write, F_SETFD,
+                                           FD_CLOEXEC), ok) {}
+                       E_IF_NO_ERRNO(result,
+                                     fcntl(exe->child_fd_write_x, F_SETFD,
+                                           FD_CLOEXEC), ok) {}
+                       {
+                          exe->write_fd_handler =
+                             ecore_main_fd_handler_add(exe->child_fd_write,
+                                                       ECORE_FD_WRITE,
+                                                       
_ecore_exe_data_write_handler,
+                                                       exe, NULL, NULL);
+                          if (exe->write_fd_handler)
+                             
ecore_main_fd_handler_active_set(exe->write_fd_handler, 0);        /* Nothing 
to write to start with. */
+                          else
+                             ok = 0;
+                       }
+                    }
+
+                  exes = (Ecore_Exe *) 
eina_inlist_append(EINA_INLIST_GET(exes), EINA_INLIST_GET(exe));
+                  n = 0;
+               }
+             else
+               ok = 0;
+          }
+        else
+          ok = 0;
+     }
+
+   if (!ok)
+     { /* Something went wrong, so pull down everything. */
+        if (exe->pid) ecore_exe_terminate(exe);
+        IF_FN_DEL(ecore_exe_free, exe);
+     }
+   else
+     {
+        Ecore_Exe_Event_Add *e;
+
+        e = _ecore_exe_event_add_new();
+        e->exe = exe;
+        if (e) /* Send the event. */
+          ecore_event_add(ECORE_EXE_EVENT_ADD, e,
+                          _ecore_exe_event_add_free, NULL);
+        /* INF("Running as %d for %s.\n", exe->pid, exe->cmd); */
+     }
+
+   errno = n;
+   return exe;
+}
+
+/**
+ * Defines a function to be called before really freeing the handle data.
+ *
+ * This might be useful for language bindings such as Python and Perl
+ * that need to deallocate wrappers associated with this handle.
+ *
+ * This handle should never be modified by this call. It should be
+ * considered informative only. All getters are valid when the given
+ * function is called back.
+ *
+ * @param exe The child process to attach the pre_free function.
+ * @param func The function to call before @a exe is freed.
+ */
+EAPI void
+ecore_exe_callback_pre_free_set(Ecore_Exe *exe, Ecore_Exe_Cb func)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE,
+                         "ecore_exe_callback_pre_free_set");
+        return;
+     }
+   exe->pre_free_cb = func;
+}
+
+/**
+ * Sends data to the given child process which it receives on stdin.
+ *
+ * This function writes to a child processes standard in, with unlimited
+ * buffering. This call will never block. It may fail if the system runs out
+ * of memory.
+ *
+ * @param exe  The child process to send to
+ * @param data The data to send
+ * @param size The size of the data to send, in bytes
+ * @return EINA_TRUE if successful, EINA_FALSE on failure.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI Eina_Bool
+ecore_exe_send(Ecore_Exe * exe, const void *data, int size)
+{
+   void *buf;
+
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_send");
+        return EINA_FALSE;
+     }
+
+   if (exe->close_stdin)
+     {
+        ERR("Ecore_Exe %p stdin is closed! Cannot send %d bytes from %p",
+            exe, size, data);
+        return EINA_FALSE;
+     }
+
+   if (exe->child_fd_write == -1)
+     {
+        ERR("Ecore_Exe %p created without ECORE_EXE_PIPE_WRITE! "
+            "Cannot send %d bytes from %p", exe, size, data);
+        return EINA_FALSE;
+     }
+
+   buf = realloc(exe->write_data_buf, exe->write_data_size + size);
+   if (!buf) return EINA_FALSE;
+
+   exe->write_data_buf = buf;
+   memcpy((char *)exe->write_data_buf + exe->write_data_size, data, size);
+   exe->write_data_size += size;
+
+   if (exe->write_fd_handler)
+      ecore_main_fd_handler_active_set(exe->write_fd_handler, ECORE_FD_WRITE);
+
+   return EINA_TRUE;
+}
+
+/**
+ * The stdin of the given child process will close when the write buffer is 
empty.
+ *
+ * @param exe  The child process
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI void
+ecore_exe_close_stdin(Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_close_stdin");
+        return;
+     }
+   exe->close_stdin = 1;
+}
+
+/**
+ * Sets the auto pipe limits for the given process handle. On Windows
+ * this function does nothing.
+ *
+ * @param   exe The given process handle.
+ * @param   start_bytes limit of bytes at start of output to buffer.
+ * @param   end_bytes limit of bytes at end of output to buffer.
+ * @param   start_lines limit of lines at start of output to buffer.
+ * @param   end_lines limit of lines at end of output to buffer.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI void
+ecore_exe_auto_limits_set(Ecore_Exe *exe, int start_bytes, int end_bytes, int 
start_lines, int end_lines)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_auto_limits_set");
+        return;
+     }
+   /* FIXME: sanitize the input. */
+   exe->start_bytes = start_bytes;
+   exe->end_bytes = end_bytes;
+   exe->start_lines = start_lines;
+   exe->end_lines = end_lines;
+
+   /* FIXME: get this can of worms working.
+    *
+    * capture stderr & stdout internally
+    *
+    * raster and onefang keep moving the goal posts on this one.  It started 
out as
+    * "show users the error output if an exe fails" and is rapidly approaching
+    * "alternative method of getting the data, poll vs event driven".  Some 
serious
+    * thinking needs to be applied to this.  Do we really want to go that far? 
 If
+    * so, we should change the names.  The basic design will probably remain 
the
+    * same which ever way we go.  The constant goal post moving is probably 
due to
+    * generic design methods leading to feature creep as we inspired each 
other to
+    * more generic designs.  It does seem like the closer we get to poll 
driven,
+    * the more issues and corner cases there are.
+    *
+    * Instead of doing the usual register an event handler thing, we are 
ecore_exe,
+    * we can take some short cuts.  Don't send the events, just leave the exe 
buffers
+    * as is until the user asks for them, then return the event.
+    *
+    * start = 0,  end = 0;   clogged arteries get flushed, everything is 
ignored.
+    * start = -1, end = -1;  clogged arteries get transferred to internal 
buffers.  Actually, either == -1 means buffer everything.
+    * start = X,  end = 0;   buffer first X out of clogged arteries, flush and 
ignore rest.
+    * start = 0,  end = X;   circular buffer X
+    * start = X,  end = Y;   buffer first X out of clogged arteries, circular 
buffer Y from beginning.
+    *
+    * bytes vs lines, which ever one reaches the limit first.
+    * Before we go beyond the start+end limit, leave the end buffer empty, and 
store both in the start buffer, coz they overlap.
+    * After we pass the the start+end limit, insert "\n...\n" at the end of 
the start buffer, copy the rest to the end buffer, then store in the end buffer.
+    *
+    * Other issues -
+    * Spank programmer for polling data if polling is not turned on.
+    * Spank programmer for setting up event callbacks if polling is turned on.
+    * Spank programmer for freeing the event data if it came from the event 
system, as that autofrees.
+    * Spank the programmer if they try to set the limits bigger than what has 
been gathered & ignored already, coz they just lost data.
+    * Spank onefang and raster for opening this can of worms.
+    * Should we have separate out/err limits?
+    * Should we remove from the internal buffer the data that was delivered 
already?
+    * If so, what to do about limits, start, and end?  They could loose their 
meaning.
+    */
+}
+
+/**
+ * Gets the auto pipe data for the given process handle
+ *
+ * @param   exe The given process handle.
+ * @param   flags   Is this a ECORE_EXE_PIPE_READ or ECORE_EXE_PIPE_ERROR?
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI Ecore_Exe_Event_Data *
+ecore_exe_event_data_get(Ecore_Exe *exe, Ecore_Exe_Flags flags)
+{
+   Ecore_Exe_Event_Data *e = NULL;
+   int is_buffered = 0;
+   unsigned char *inbuf;
+   int inbuf_num;
+
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_event_data_get");
+        return NULL;
+     }
+
+   /* Sort out what sort of event we are. */
+   if (flags & ECORE_EXE_PIPE_READ)
+     {
+        flags = ECORE_EXE_PIPE_READ;
+        if (exe->flags & ECORE_EXE_PIPE_READ_LINE_BUFFERED)
+           is_buffered = 1;
+     }
+   else
+     {
+        flags = ECORE_EXE_PIPE_ERROR;
+        if (exe->flags & ECORE_EXE_PIPE_ERROR_LINE_BUFFERED)
+           is_buffered = 1;
+     }
+
+   /* Get the data. */
+   if (flags & ECORE_EXE_PIPE_READ)
+     {
+        inbuf = exe->read_data_buf;
+        inbuf_num = exe->read_data_size;
+        exe->read_data_buf = NULL;
+        exe->read_data_size = 0;
+     }
+   else
+     {
+        inbuf = exe->error_data_buf;
+        inbuf_num = exe->error_data_size;
+        exe->error_data_buf = NULL;
+        exe->error_data_size = 0;
+     }
+
+   e = calloc(1, sizeof(Ecore_Exe_Event_Data));
+   if (e)
+     {
+        e->exe = exe;
+        e->data = inbuf;
+        e->size = inbuf_num;
+
+        if (is_buffered)
+          {                        /* Deal with line buffering. */
+             int max = 0;
+             int count = 0;
+             int i;
+             int last = 0;
+             char *c;
+
+             c = (char *)inbuf;
+             for (i = 0; i < inbuf_num; i++)        /* Find the lines. */
+               {
+                  if (inbuf[i] == '\n')
+                    {
+                       if (count >= max)
+                         {
+                            /* In testing, the lines seem to arrive in batches 
of 500 to 1000 lines at most, roughly speaking. */
+                            max += 10;        /* FIXME: Maybe keep track of 
the largest number of lines ever sent, and add half that many instead of 10. */
+                            e->lines = realloc(e->lines, 
sizeof(Ecore_Exe_Event_Data_Line) * (max + 1));        /* Allow room for the 
NULL termination. */
+                         }
+                       /* raster said to leave the line endings as line 
endings, however -
+                        * This is line buffered mode, we are not dealing with 
binary here, but lines.
+                        * If we are not dealing with binary, we must be 
dealing with ASCII, unicode, or some other text format.
+                        * Thus the user is most likely gonna deal with this 
text as strings.
+                        * Thus the user is most likely gonna pass this data to 
str functions.
+                        * rasters way - the endings are always gonna be '\n';  
onefangs way - they will always be '\0'
+                        * We are handing them the string length as a 
convenience.
+                        * Thus if they really want it in raw format, they can 
e->lines[i].line[e->lines[i].size - 1] = '\n'; easily enough.
+                        * In the default case, we can do this conversion 
quicker than the user can, as we already have the index and pointer.
+                        * Let's make it easy on them to use these as standard 
C strings.
+                        *
+                        * onefang is proud to announce that he has just set a 
new personal record for the
+                        * most over documentation of a simple assignment 
statement.  B-)
+                        */
+                       inbuf[i] = '\0';
+                       e->lines[count].line = c;
+                       e->lines[count].size = i - last;
+                       last = i + 1;
+                       c = (char *)&inbuf[last];
+                       count++;
+                    }
+               }
+             if (count == 0)        /* No lines to send, cancel the event. */
+               {
+                  _ecore_exe_event_exe_data_free(NULL, e);
+                  e = NULL;
+               }
+             else                /* NULL terminate the array, so that people 
know where the end is. */
+               {
+                  e->lines[count].line = NULL;
+                  e->lines[count].size = 0;
+               }
+             if (i > last)        /* Partial line left over, save it for next 
time. */
+               {
+                  if (e) e->size = last;
+                  if (flags & ECORE_EXE_PIPE_READ)
+                    {
+                       exe->read_data_size = i - last;
+                       exe->read_data_buf = malloc(exe->read_data_size);
+                       memcpy(exe->read_data_buf, c, exe->read_data_size);
+                    }
+                  else
+                    {
+                       exe->error_data_size = i - last;
+                       exe->error_data_buf = malloc(exe->error_data_size);
+                       memcpy(exe->error_data_buf, c, exe->error_data_size);
+                    }
+               }
+          }
+     }
+
+   return e;
+}
+
+/**
+ * Sets the string tag for the given process handle
+ *
+ * @param   exe The given process handle.
+ * @param   tag The string tag to set on the process handle.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI void
+ecore_exe_tag_set(Ecore_Exe *exe, const char *tag)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_set");
+        return;
+     }
+   IF_FREE(exe->tag);
+   if (tag)
+      exe->tag = strdup(tag);
+   else
+      exe->tag = NULL;
+}
+
+/**
+ * Retrieves the tag attached to the given process handle. There is no need to
+ * free it as it just returns the internal pointer value. This value is only
+ * valid as long as the @p exe is valid or until the tag is set to something
+ * else on this @p exe.
+ *
+ * @param   exe The given process handle.
+ * @return The string attached to @p exe. It is a handle to existing
+ *         internal string and should not be modified, use
+ *         ecore_exe_tag_set() to change it. It might be @c NULL.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI const char *
+ecore_exe_tag_get(const Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_tag_get");
+        return NULL;
+     }
+   return exe->tag;
+}
+
+/**
+ * Frees the given process handle.
+ *
+ * Note that the process that the handle represents is unaffected by this
+ * function.
+ *
+ * @param   exe The given process handle.
+ * @return  The data attached to the handle when @ref ecore_exe_run was
+ *          called.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI void *
+ecore_exe_free(Ecore_Exe *exe)
+{
+   void *data;
+   int ok = 0;
+   int result;
+
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_free");
+        return NULL;
+     }
+
+   data = exe->data;
+
+   if (exe->pre_free_cb)
+     exe->pre_free_cb(data, exe);
+
+   if (exe->doomsday_clock)
+     {
+        struct _ecore_exe_dead_exe *dead;
+
+        ecore_timer_del(exe->doomsday_clock);
+        exe->doomsday_clock = NULL;
+        dead = exe->doomsday_clock_dead;
+        if (dead)
+          {
+             IF_FREE(dead->cmd);
+             free(dead);
+             exe->doomsday_clock_dead = NULL;
+          }
+     }
+   IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler);
+   IF_FN_DEL(ecore_main_fd_handler_del, exe->read_fd_handler);
+   IF_FN_DEL(ecore_main_fd_handler_del, exe->error_fd_handler);
+   if (exe->child_fd_write_x != -1)
+      E_NO_ERRNO(result, close(exe->child_fd_write_x), ok);
+   if (exe->child_fd_read_x != -1)
+      E_NO_ERRNO(result, close(exe->child_fd_read_x), ok);
+   if (exe->child_fd_error_x != -1)
+      E_NO_ERRNO(result, close(exe->child_fd_error_x), ok);
+   if (exe->child_fd_write != -1)
+      E_NO_ERRNO(result, close(exe->child_fd_write), ok);
+   if (exe->child_fd_read != -1)
+      E_NO_ERRNO(result, close(exe->child_fd_read), ok);
+   if (exe->child_fd_error != -1)
+      E_NO_ERRNO(result, close(exe->child_fd_error), ok);
+   IF_FREE(exe->write_data_buf);
+   IF_FREE(exe->read_data_buf);
+   IF_FREE(exe->error_data_buf);
+   IF_FREE(exe->cmd);
+
+   exes = (Ecore_Exe *) eina_inlist_remove(EINA_INLIST_GET(exes), 
EINA_INLIST_GET(exe));
+   ECORE_MAGIC_SET(exe, ECORE_MAGIC_NONE);
+   IF_FREE(exe->tag);
+   free(exe);
+   return data;
+}
+
+/**
+ * Frees the given event data.
+ *
+ * @param   e The given event data.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI void
+ecore_exe_event_data_free(Ecore_Exe_Event_Data *e)
+{
+   if (!e) return;
+   IF_FREE(e->lines);
+   IF_FREE(e->data);
+   free(e);
+}
+
+/**
+ * Retrieves the process ID of the given spawned process.
+ * @param   exe Handle to the given spawned process.
+ * @return  The process ID on success.  @c -1 otherwise.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI pid_t
+ecore_exe_pid_get(const Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pid_get");
+        return -1;
+     }
+   return exe->pid;
+}
+
+/**
+ * Retrieves the command of the given spawned process.
+ * @param   exe Handle to the given spawned process.
+ * @return The command on success.  NULL otherwise. This string is the
+ *         pointer to the internal value and must not be modified in
+ *         any way.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI const char *
+ecore_exe_cmd_get(const Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_cmd_get");
+        return NULL;
+     }
+   return exe->cmd;
+}
+
+/**
+ * Retrieves the data attached to the given process handle.
+ * @param   exe The given process handle.
+ * @return The data pointer attached to @p exe Given to
+ *         ecore_exe_run() or ecore_exe_pipe_run()
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI void *
+ecore_exe_data_get(const Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get");
+        return NULL;
+     }
+   return exe->data;
+}
+
+/**
+ * Retrieves the flags attached to the given process handle.
+ * @param   exe The given process handle.
+ * @return  The flags attached to @p exe.
+ * @ingroup Ecore_Exe_Basic_Group
+ */
+EAPI Ecore_Exe_Flags
+ecore_exe_flags_get(const Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_data_get");
+        return 0;
+     }
+   return exe->flags;
+}
+
+/**
+ * @defgroup Ecore_Exe_Signal_Group Spawned Process Signal Functions
+ *
+ * Functions that send signals to spawned processes.
+ */
+
+/**
+ * Pauses the given process by sending it a @c SIGSTOP signal.
+ * @param   exe Process handle to the given process.
+ * @ingroup Ecore_Exe_Signal_Group
+ */
+EAPI void
+ecore_exe_pause(Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_pause");
+        return;
+     }
+   kill(exe->pid, SIGSTOP);
+}
+
+/**
+ * Continues the given paused process by sending it a @c SIGCONT signal.
+ * @param   exe Process handle to the given process.
+ * @ingroup Ecore_Exe_Signal_Group
+ */
+EAPI void
+ecore_exe_continue(Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_continue");
+        return;
+     }
+   kill(exe->pid, SIGCONT);
+}
+
+/**
+ * Sends the given spawned process a interrupt (@c SIGINT) signal.
+ * @param   exe Process handle to the given process.
+ * @ingroup Ecore_Exe_Signal_Group
+ */
+EAPI void
+ecore_exe_interrupt(Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_interrupt");
+        return;
+     }
+   _ecore_exe_dead_attach(exe);
+   kill(exe->pid, SIGINT);
+}
+
+/**
+ * Sends the given spawned process a quit (@c SIGQUIT) signal.
+ * @param   exe Process handle to the given process.
+ * @ingroup Ecore_Exe_Signal_Group
+ */
+EAPI void
+ecore_exe_quit(Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_quit");
+        return;
+     }
+   _ecore_exe_dead_attach(exe);
+   kill(exe->pid, SIGQUIT);
+}
+
+/**
+ * Sends the given spawned process a terminate (@c SIGTERM) signal.
+ * @param   exe Process handle to the given process.
+ * @ingroup Ecore_Exe_Signal_Group
+ */
+EAPI void
+ecore_exe_terminate(Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_terminate");
+        return;
+     }
+   _ecore_exe_dead_attach(exe);
+   INF("Sending TERM signal to %s (%d).", exe->cmd, exe->pid);
+   kill(exe->pid, SIGTERM);
+}
+
+/**
+ * Kills the given spawned process by sending it a @c SIGKILL signal.
+ * @param   exe Process handle to the given process.
+ * @ingroup Ecore_Exe_Signal_Group
+ */
+EAPI void
+ecore_exe_kill(Ecore_Exe *exe)
+{
+   struct _ecore_exe_dead_exe *dead;
+
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_kill");
+        return;
+     }
+
+   dead = calloc(1, sizeof(struct _ecore_exe_dead_exe));
+   if (dead)
+     {
+        dead->pid = exe->pid;
+        dead->cmd = strdup(exe->cmd);
+        IF_FN_DEL(ecore_timer_del, exe->doomsday_clock);
+        exe->doomsday_clock =
+           ecore_timer_add(10.0, _ecore_exe_make_sure_its_really_dead, dead);
+     }
+
+   INF("Sending KILL signal to %s (%d).", exe->cmd, exe->pid);
+   kill(exe->pid, SIGKILL);
+}
+
+/**
+ * Sends a @c SIGUSR signal to the given spawned process.
+ * @param   exe Process handle to the given process.
+ * @param   num The number user signal to send.  Must be either 1 or 2, or
+ *              the signal will be ignored.
+ * @ingroup Ecore_Exe_Signal_Group
+ */
+EAPI void
+ecore_exe_signal(Ecore_Exe *exe, int num)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_signal");
+        return;
+     }
+   if (num == 1)
+      kill(exe->pid, SIGUSR1);
+   else if (num == 2)
+      kill(exe->pid, SIGUSR2);
+}
+
+/**
+ * Sends a @c SIGHUP signal to the given spawned process.
+ * @param   exe Process handle to the given process.
+ * @ingroup Ecore_Exe_Signal_Group
+ */
+EAPI void
+ecore_exe_hup(Ecore_Exe *exe)
+{
+   if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+     {
+        ECORE_MAGIC_FAIL(exe, ECORE_MAGIC_EXE, "ecore_exe_hup");
+        return;
+     }
+   kill(exe->pid, SIGHUP);
+}
+
+static Ecore_Exe *
+_ecore_exe_is_it_alive(pid_t pid)
+{
+   Ecore_Exe *exe = NULL;
+
+   /* FIXME: There is no nice, safe, OS independent way to tell if a
+    * particular PID is still alive.  I have written code to do so
+    * for my urunlevel busybox applet (http://urunlevel.sourceforge.net/),
+    * but it's for linux only, and still not guaranteed.
+    *
+    * So for now, we just check that a valid Ecore_Exe structure
+    * exists for it.  Even that is not a guarantee, as the structure
+    * can be freed without killing the process.
+    *
+    * I think we can safely put exe's into two categories, those users
+    * that care about the life of the exe, and the run and forget type.
+    * The run and forget type starts up the exe, then free's the
+    * Ecore_Exe structure straight away.  They can never call any of
+    * the functions that can call this, so we don't worry about them.
+    *
+    * Those user's that care about the life of exe's will keep the
+    * Ecore_Exe structure around, terminate them eventually, or
+    * register for exit events.  For these ones the assumption
+    * that valid Ecore_Exe struct == live exe is almost valid.
+    *
+    * I will probably copy my urunlevel code into here someday.
+    */
+   exe = _ecore_exe_find(pid);
+   if (exe)
+     {
+        if (!ECORE_MAGIC_CHECK(exe, ECORE_MAGIC_EXE))
+           exe = NULL;
+     }
+
+   return exe;
+}
+
+static Eina_Bool
+_ecore_exe_make_sure_its_dead(void *data)
+{
+   struct _ecore_exe_dead_exe *dead;
+
+   dead = data;
+   if (dead)
+     {
+        Ecore_Exe *exe = NULL;
+
+        if ((exe = _ecore_exe_is_it_alive(dead->pid)))
+          {
+             if (dead->cmd)
+                INF("Sending KILL signal to allegedly dead %s (%d).",
+                       dead->cmd, dead->pid);
+             else
+                INF("Sending KILL signal to allegedly dead PID %d.",
+                    dead->pid);
+             exe->doomsday_clock =
+                ecore_timer_add(10.0, _ecore_exe_make_sure_its_really_dead,
+                                dead);
+             kill(dead->pid, SIGKILL);
+          }
+        else
+          {
+             IF_FREE(dead->cmd);
+             free(dead);
+          }
+     }
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static Eina_Bool
+_ecore_exe_make_sure_its_really_dead(void *data)
+{
+   struct _ecore_exe_dead_exe *dead;
+
+   dead = data;
+   if (dead)
+     {
+        Ecore_Exe *exe = NULL;
+
+        if ((exe = _ecore_exe_is_it_alive(dead->pid)))
+          {
+             ERR("RUN!  The zombie wants to eat your brains!  And your CPU!");
+             if (dead->cmd)
+                INF("%s (%d) is not really dead.", dead->cmd, dead->pid);
+             else
+                INF("PID %d is not really dead.", dead->pid);
+             exe->doomsday_clock = NULL;
+          }
+        IF_FREE(dead->cmd);
+        free(dead);
+     }
+   return ECORE_CALLBACK_CANCEL;
+}
+
+void
+_ecore_exe_init(void)
+{
+   ECORE_EXE_EVENT_ADD = ecore_event_type_new();
+   ECORE_EXE_EVENT_DEL = ecore_event_type_new();
+   ECORE_EXE_EVENT_DATA = ecore_event_type_new();
+   ECORE_EXE_EVENT_ERROR = ecore_event_type_new();
+}
+
+void
+_ecore_exe_shutdown(void)
+{
+   while (exes)
+     ecore_exe_free(exes);
+}
+
+Ecore_Exe *
+_ecore_exe_find(pid_t pid)
+{
+   Ecore_Exe *exe;
+
+   EINA_INLIST_FOREACH(exes, exe)
+     {
+        if (exe->pid == pid)
+           return exe;
+     }
+   return NULL;
+}
+
+Ecore_Timer *
+_ecore_exe_doomsday_clock_get(Ecore_Exe *exe)
+{
+   return exe->doomsday_clock;
+}
+
+void
+_ecore_exe_doomsday_clock_set(Ecore_Exe *exe, Ecore_Timer *dc)
+{
+   exe->doomsday_clock = dc;
+}
+
+static inline void
+_ecore_exe_exec_it(const char *exe_cmd, Ecore_Exe_Flags flags)
+{
+   char use_sh = 1;
+   char *buf = NULL;
+   char **args = NULL;
+   int  save_errno = 0;
+
+   /* So what is this doing?
+    *
+    * We are trying to avoid wrapping the exe call with /bin/sh -c.
+    * We conservatively search for certain shell meta characters,
+    * If we don't find them, we can call the exe directly.
+    */
+   if (!strpbrk(exe_cmd, "|&;<>()$`\\\"'*?#"))
+     {
+        char *token;
+        char pre_command = 1;
+        int num_tokens = 0;
+
+        if (!(buf = strdup(exe_cmd)))
+           return;
+
+        token = strtok(buf, " \t\n\v");
+        while (token)
+          {
+             if (token[0] == '~')
+               break;
+             if (pre_command)
+               {
+                  if (token[0] == '[')
+                    break;
+                  if (strchr(token, '='))
+                    break;
+                  else
+                    pre_command = 0;
+               }
+             num_tokens++;
+             token = strtok(NULL, " \t\n\v");
+          }
+        IF_FREE(buf);
+        if ((!token) && (num_tokens))
+          {
+             int i = 0;
+
+             if (!(buf = strdup(exe_cmd)))
+               return;
+
+             token = strtok(buf, " \t\n\v");
+             use_sh = 0;
+             if (!(args = (char **)calloc(num_tokens + 1, sizeof(char *))))
+               {
+                  IF_FREE(buf);
+                  return;
+               }
+             for (i = 0; i < num_tokens; i++)
+               {
+                  if (token)
+                    args[i] = token;
+                  token = strtok(NULL, " \t\n\v");
+               }
+             args[num_tokens] = NULL;
+          }
+     }
+
+   if (!(flags & ECORE_EXE_NOT_LEADER)) setsid();
+   if ((flags & ECORE_EXE_USE_SH))
+     {
+        errno = 0;
+        execl("/bin/sh", "/bin/sh", "-c", exe_cmd, (char *)NULL);
+     }
+   else if (use_sh)
+     {                                /* We have to use a shell to run this. */
+        if (!shell)
+          {                        /* Find users preferred shell. */
+             shell = getenv("SHELL");
+             if (!shell)
+               shell = "/bin/sh";
+          }
+        errno = 0;
+        execl(shell, shell, "-c", exe_cmd, (char *)NULL);
+     }
+   else
+     {                                /* We can run this directly. */
+        errno = 0;
+        execvp(args[0], args);
+     }
+
+   save_errno = errno;
+   IF_FREE(buf);
+   IF_FREE(args);
+   errno = save_errno;
+   return;
+}
+
+static Eina_Bool
+_ecore_exe_data_generic_handler(void *data, Ecore_Fd_Handler *fd_handler, 
Ecore_Exe_Flags flags)
+{
+   Ecore_Exe *exe;
+   int child_fd;
+   int event_type;
+
+   exe = data;
+
+   /* Sort out what sort of handler we are. */
+   if (flags & ECORE_EXE_PIPE_READ)
+     {
+        flags = ECORE_EXE_PIPE_READ;
+        event_type = ECORE_EXE_EVENT_DATA;
+        child_fd = exe->child_fd_read;
+     }
+   else
+     {
+        flags = ECORE_EXE_PIPE_ERROR;
+        event_type = ECORE_EXE_EVENT_ERROR;
+        child_fd = exe->child_fd_error;
+     }
+
+   if ((fd_handler)
+       && (ecore_main_fd_handler_active_get(fd_handler, ECORE_FD_READ)))
+     {
+        unsigned char *inbuf;
+        int inbuf_num;
+
+        /* Get any left over data from last time. */
+        if (flags & ECORE_EXE_PIPE_READ)
+          {
+             inbuf = exe->read_data_buf;
+             inbuf_num = exe->read_data_size;
+             exe->read_data_buf = NULL;
+             exe->read_data_size = 0;
+          }
+        else
+          {
+             inbuf = exe->error_data_buf;
+             inbuf_num = exe->error_data_size;
+             exe->error_data_buf = NULL;
+             exe->error_data_size = 0;
+          }
+
+        for (;;)
+          {
+             int num, lost_exe;
+             char buf[READBUFSIZ];
+
+             lost_exe = 0;
+             errno = 0;
+             if ((num = read(child_fd, buf, READBUFSIZ)) < 1)
+               /* FIXME: SPEED/SIZE TRADE OFF - add a smaller READBUFSIZE
+                * (currently 64k) to inbuf, use that instead of buf, and
+                * save ourselves a memcpy(). */
+               {
+                  lost_exe = ((errno == EIO) ||
+                              (errno == EBADF) ||
+                              (errno == EPIPE) ||
+                              (errno == EINVAL) || (errno == ENOSPC));
+                  if ((errno != EAGAIN) && (errno != EINTR))
+                     perror("_ecore_exe_generic_handler() read problem ");
+               }
+             if (num > 0)
+               {                /* data got read. */
+                  inbuf = realloc(inbuf, inbuf_num + num);
+                  memcpy(inbuf + inbuf_num, buf, num);
+                  inbuf_num += num;
+               }
+             else
+               {                /* No more data to read. */
+                  if (inbuf)
+                    {
+                       Ecore_Exe_Event_Data *e;
+
+                       /* Stash the data away for later. */
+                       if (flags & ECORE_EXE_PIPE_READ)
+                         {
+                            exe->read_data_buf = inbuf;
+                            exe->read_data_size = inbuf_num;
+                         }
+                       else
+                         {
+                            exe->error_data_buf = inbuf;
+                            exe->error_data_size = inbuf_num;
+                         }
+
+                       if (!(exe->flags & ECORE_EXE_PIPE_AUTO))
+                         {
+                            e = ecore_exe_event_data_get(exe, flags);
+                            if (e)        /* Send the event. */
+                              ecore_event_add(event_type, e,
+                                              _ecore_exe_event_exe_data_free,
+                                              NULL);
+                         }
+                    }
+                  if (lost_exe)
+                    {
+                       if (flags & ECORE_EXE_PIPE_READ)
+                         {
+                            if (exe->read_data_size)
+                              INF("There are %d bytes left unsent from the 
dead exe %s.",
+                                  exe->read_data_size, exe->cmd);
+                         }
+                       else
+                         {
+                            if (exe->error_data_size)
+                              INF("There are %d bytes left unsent from the 
dead exe %s.",
+                                  exe->error_data_size, exe->cmd);
+                         }
+                       /* Thought about this a bit.  If the exe has actually
+                        * died, this won't do any harm as it must have died
+                        * recently and the pid has not had a chance to recycle.
+                        * It is also a paranoid catchall, coz the usual 
ecore_signal
+                        * mechenism should kick in.  But let's give it a good
+                        * kick in the head anyway.
+                        */
+                       ecore_exe_terminate(exe);
+                    }
+                  break;
+               }
+          }
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static Eina_Bool
+_ecore_exe_data_error_handler(void *data, Ecore_Fd_Handler *fd_handler)
+{
+   return _ecore_exe_data_generic_handler(data, fd_handler,
+                                          ECORE_EXE_PIPE_ERROR);
+}
+
+static Eina_Bool
+_ecore_exe_data_read_handler(void *data, Ecore_Fd_Handler *fd_handler)
+{
+   return _ecore_exe_data_generic_handler(data, fd_handler,
+                                          ECORE_EXE_PIPE_READ);
+}
+
+static Eina_Bool
+_ecore_exe_data_write_handler(void *data, Ecore_Fd_Handler *fd_handler 
__UNUSED__)
+{
+   Ecore_Exe *exe;
+
+   exe = data;
+   if ((exe->write_fd_handler) &&
+       (ecore_main_fd_handler_active_get
+        (exe->write_fd_handler, ECORE_FD_WRITE)))
+     _ecore_exe_flush(exe);
+
+   /* If we have sent all there is to send, and we need to close the pipe, 
then close it. */
+   if ((exe->close_stdin == 1)
+       && (exe->write_data_size == exe->write_data_offset))
+     {
+        int ok = 0;
+        int result;
+
+        INF("Closing stdin for %s", exe->cmd);
+        /* if (exe->child_fd_write != -1)  E_NO_ERRNO(result, 
fsync(exe->child_fd_write), ok);   This a) doesn't work, and b) isn't needed. */
+        IF_FN_DEL(ecore_main_fd_handler_del, exe->write_fd_handler);
+        if (exe->child_fd_write != -1)
+           E_NO_ERRNO(result, close(exe->child_fd_write), ok);
+        exe->child_fd_write = -1;
+        IF_FREE(exe->write_data_buf);
+     }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+static void
+_ecore_exe_flush(Ecore_Exe *exe)
+{
+   int count;
+
+   /* check whether we need to write anything at all. */
+   if ((exe->child_fd_write == -1) || (!exe->write_data_buf))
+      return;
+   if (exe->write_data_size == exe->write_data_offset)
+      return;
+
+   count = write(exe->child_fd_write,
+                 (char *)exe->write_data_buf + exe->write_data_offset,
+                 exe->write_data_size - exe->write_data_offset);
+   if (count < 1)
+     {
+        if (errno == EIO || errno == EBADF || errno == EPIPE || errno == 
EINVAL || errno == ENOSPC)        /* we lost our exe! */
+          {
+             ecore_exe_terminate(exe);
+             if (exe->write_fd_handler)
+                ecore_main_fd_handler_active_set(exe->write_fd_handler, 0);
+          }
+     }
+   else
+     {
+        exe->write_data_offset += count;
+        if (exe->write_data_offset >= exe->write_data_size)
+          {                        /* Nothing left to write, clean up. */
+             exe->write_data_size = 0;
+             exe->write_data_offset = 0;
+             IF_FREE(exe->write_data_buf);
+             if (exe->write_fd_handler)
+                ecore_main_fd_handler_active_set(exe->write_fd_handler, 0);
+          }
+     }
+}
+
+static void
+_ecore_exe_event_exe_data_free(void *data __UNUSED__, void *ev)
+{
+   Ecore_Exe_Event_Data *e;
+
+   e = ev;
+   ecore_exe_event_data_free(e);
+}
+
+static Ecore_Exe_Event_Add *
+_ecore_exe_event_add_new(void)
+{
+   Ecore_Exe_Event_Add *e;
+
+   e = calloc(1, sizeof(Ecore_Exe_Event_Add));
+   return e;
+}
+
+static void
+_ecore_exe_event_add_free(void *data __UNUSED__, void *ev)
+{
+   Ecore_Exe_Event_Add *e;
+
+   e = ev;
+   free(e);
+}
+
+void               *
+_ecore_exe_event_del_new(void)
+{
+   Ecore_Exe_Event_Del *e;
+
+   e = calloc(1, sizeof(Ecore_Exe_Event_Del));
+   return e;
+}
+
+void
+_ecore_exe_event_del_free(void *data __UNUSED__, void *ev)
+{
+   Ecore_Exe_Event_Del *e;
+
+   e = ev;
+   if (e->exe)
+     ecore_exe_free(e->exe);
+   free(e);
+}
+
+static void
+_ecore_exe_dead_attach(Ecore_Exe *exe)
+{
+   struct _ecore_exe_dead_exe *dead;
+
+   if (exe->doomsday_clock_dead) return;
+   dead = calloc(1, sizeof(struct _ecore_exe_dead_exe));
+   if (dead)
+     {
+        dead->pid = exe->pid;
+        dead->cmd = strdup(exe->cmd);
+        IF_FN_DEL(ecore_timer_del, exe->doomsday_clock);
+        exe->doomsday_clock =
+           ecore_timer_add(10.0, _ecore_exe_make_sure_its_dead, dead);
+        exe->doomsday_clock_dead = dead;
+     }
+}
diff --git a/tests/suite/ecore/src/lib/ecore_getopt.c 
b/tests/suite/ecore/src/lib/ecore_getopt.c
new file mode 100644
index 0000000..5b1c7bf
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_getopt.c
@@ -0,0 +1,1735 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef ENABLE_NLS
+# include <libintl.h>
+#else
+# define gettext(x) (x)
+# define dgettext(domain, x) (x)
+#endif
+
+#define _(x) dgettext("ecore", x)
+
+#ifdef _WIN32_WCE
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "Ecore_Getopt.h"
+
+static const char *prog = NULL;
+static char **argv = NULL;
+static int argc = 0;
+static int cols = 80;
+static int helpcol = 80 / 3;
+
+static void
+_ecore_getopt_help_print_replace_program(FILE *fp, const Ecore_Getopt *parser 
__UNUSED__, const char *text)
+{
+   do
+     {
+        const char *d = strchr(text, '%');
+
+        if (!d)
+          {
+             fputs(text, fp);
+             break;
+          }
+
+        if (fwrite(text, 1, d - text, fp) != (size_t)(d - text))
+          return;
+        d++;
+        if (strncmp(d, "prog", sizeof("prog") - 1) == 0)
+          {
+             fputs(prog ? prog : "???", fp);
+             d += sizeof("prog") - 1;
+          }
+        else
+          {
+             if (d[0] == '%')
+               d++;
+             fputc('%', fp);
+          }
+
+        text = d;
+     }
+   while (text[0] != '\0');
+
+   fputc('\n', fp);
+}
+
+static void
+_ecore_getopt_version(FILE *fp, const Ecore_Getopt *parser)
+{
+   fputs(_("Version:"), fp);
+   fputc(' ', fp);
+   _ecore_getopt_help_print_replace_program(fp, parser, parser->version);
+}
+
+static void
+_ecore_getopt_help_usage(FILE *fp, const Ecore_Getopt *parser)
+{
+   fputs(_("Usage:"), fp);
+   fputc(' ', fp);
+
+   if (!parser->usage)
+     {
+        fprintf(fp, _("%s [options]\n"), prog);
+        return;
+     }
+
+   _ecore_getopt_help_print_replace_program(fp, parser, 
gettext(parser->usage));
+}
+
+static int
+_ecore_getopt_help_line(FILE *fp, const int base, const int total, int used, 
const char *text, int len)
+{
+   int linebreak = 0;
+   do
+     {
+        /* process line considering spaces (new line and tabs are spaces!) */
+        while ((used < total) && (len > 0))
+          {
+             const char *space = NULL;
+             int i, todo;
+
+             todo = total - used;
+             if (todo > len)
+               todo = len;
+
+             for (i = 0; i < todo; i++)
+               if (isspace(text[i]))
+                 {
+                    space = text + i;
+                    break;
+                 }
+
+             if (space)
+               {
+                  i = fwrite(text, 1, i, fp);
+                  i++;
+                  text += i;
+                  len -= i;
+                  used += i;
+
+                  if (linebreak)
+                    {
+                       linebreak = 0;
+                       continue;
+                    }
+
+                  if (space[0] == '\n')
+                    break;
+                  else if (space[0] == '\t')
+                    {
+                       int c;
+
+                       used--;
+                       c = ((used / 8) + 1) * 8;
+                       if (c < total)
+                         {
+                            for (; used < c; used++)
+                              fputc(' ', fp);
+                         }
+                       else
+                         {
+                            text--;
+                            len++;
+                            break;
+                         }
+                    }
+                  else if (used < total)
+                    fputc(space[0], fp);
+               }
+             else
+               {
+                  i = fwrite(text, 1, i, fp);
+                  text += i;
+                  len -= i;
+                  used += i;
+               }
+             linebreak = 0;
+          }
+        if (len <= 0)
+          break;
+        linebreak = 1;
+        fputc('\n', fp);
+        for (used = 0; used < base; used++)
+          fputc(' ', fp);
+     }
+   while (1);
+
+   return used;
+}
+
+static void
+_ecore_getopt_help_description(FILE *fp, const Ecore_Getopt *parser)
+{
+   const char *p, *prg, *ver;
+   int used, prglen, verlen;
+
+   p = gettext(parser->description);
+   if (!p)
+     return;
+
+   fputc('\n', fp);
+
+   prg = prog ? prog : "???";
+   ver = parser->version ? parser->version : "???";
+
+   prglen = strlen(prg);
+   verlen = strlen(ver);
+
+   used = 0;
+
+   do
+     {
+        const char *d = strchr(p, '%');
+
+        if (!d)
+          {
+             _ecore_getopt_help_line(fp, 0, cols, used, p, strlen(p));
+             break;
+          }
+
+        used = _ecore_getopt_help_line(fp, 0, cols, used, p, d - p);
+        d++;
+        if (strncmp(d, "prog", sizeof("prog") - 1) == 0)
+          {
+             used = _ecore_getopt_help_line(fp, 0, cols, used, prg, prglen);
+             d += sizeof("prog") - 1;
+          }
+        else if (strncmp(d, "version", sizeof("version") - 1) == 0)
+          {
+             used = _ecore_getopt_help_line(fp, 0, cols, used, ver, verlen);
+             d += sizeof("version") - 1;
+          }
+        else
+          {
+             if (d[0] == '%')
+               d++;
+             used = _ecore_getopt_help_line(fp, 0, cols, used, "%", 1);
+          }
+
+        p = d;
+     }
+   while (p[0] != '\0');
+
+   fputs("\n\n", fp);
+}
+
+static void
+_ecore_getopt_copyright(FILE *fp, const Ecore_Getopt *parser)
+{
+   const char *txt = gettext(parser->copyright);
+   fputs(_("Copyright:"), fp);
+   fputs("\n   ", fp);
+   _ecore_getopt_help_line
+     (fp, 3, cols, 3, txt, strlen(txt));
+   fputc('\n', fp);
+}
+
+static void
+_ecore_getopt_license(FILE *fp, const Ecore_Getopt *parser)
+{
+   const char *txt = gettext(parser->license);
+   fputs(_("License:"), fp);
+   fputs("\n   ", fp);
+   _ecore_getopt_help_line
+     (fp, 3, cols, 3, txt, strlen(txt));
+   fputc('\n', fp);
+}
+
+static Ecore_Getopt_Desc_Arg_Requirement
+_ecore_getopt_desc_arg_requirement(const Ecore_Getopt_Desc *desc)
+{
+   switch (desc->action)
+     {
+      case ECORE_GETOPT_ACTION_STORE:
+         return desc->action_param.store.arg_req;
+      case ECORE_GETOPT_ACTION_STORE_CONST:
+         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+      case ECORE_GETOPT_ACTION_STORE_TRUE:
+         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+      case ECORE_GETOPT_ACTION_STORE_FALSE:
+         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+      case ECORE_GETOPT_ACTION_CHOICE:
+         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES;
+      case ECORE_GETOPT_ACTION_APPEND:
+         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES;
+      case ECORE_GETOPT_ACTION_COUNT:
+         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+      case ECORE_GETOPT_ACTION_CALLBACK:
+         return desc->action_param.callback.arg_req;
+      case ECORE_GETOPT_ACTION_HELP:
+         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+      case ECORE_GETOPT_ACTION_VERSION:
+         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+      default:
+         return ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO;
+     }
+}
+
+static void
+_ecore_getopt_help_desc_setup_metavar(const Ecore_Getopt_Desc *desc, char 
*metavar, int *metavarlen, int maxsize)
+{
+   if (desc->metavar)
+     {
+        const char *txt = gettext(desc->metavar);
+        *metavarlen = strlen(txt);
+        if (*metavarlen > maxsize - 1)
+          *metavarlen = maxsize - 1;
+
+        memcpy(metavar, txt, *metavarlen);
+        metavar[*metavarlen] = '\0';
+     }
+   else if (desc->longname)
+     {
+        int i;
+
+        *metavarlen = strlen(desc->longname);
+        if (*metavarlen > maxsize - 1)
+          *metavarlen = maxsize - 1;
+
+        for (i = 0; i < *metavarlen; i++)
+          metavar[i] = toupper(desc->longname[i]);
+        metavar[i] = '\0';
+     }
+}
+
+static int
+_ecore_getopt_help_desc_show_arg(FILE *fp, Ecore_Getopt_Desc_Arg_Requirement 
requirement, const char *metavar, int metavarlen)
+{
+   int used;
+
+   if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+     return 0;
+
+   used = 0;
+
+   if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL)
+     {
+        fputc('[', fp);
+        used++;
+     }
+
+   if (requirement != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+     {
+        fputc('=', fp);
+        fputs(metavar, fp);
+        used += metavarlen + 1;
+     }
+
+   if (requirement == ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL)
+     {
+        fputc(']', fp);
+        used++;
+     }
+
+   return used;
+}
+
+static int
+_ecore_getopt_help_desc_store(FILE *fp, const int base, const int total, int 
used, const Ecore_Getopt_Desc *desc)
+{
+   const Ecore_Getopt_Desc_Store *store = &desc->action_param.store;
+   char buf[64];
+   const char *str;
+   size_t len;
+
+   fputc('\n', fp);
+   for (used = 0; used < base; used++)
+     fputc(' ', fp);
+
+   switch (store->type)
+     {
+      case ECORE_GETOPT_TYPE_STR:
+         str = "STR";
+         len = sizeof("STR") - 1;
+         break;
+      case ECORE_GETOPT_TYPE_BOOL:
+         str = "BOOL";
+         len = sizeof("BOOL") - 1;
+         break;
+      case ECORE_GETOPT_TYPE_SHORT:
+         str = "SHORT";
+         len = sizeof("SHORT") - 1;
+         break;
+      case ECORE_GETOPT_TYPE_INT:
+         str = "INT";
+         len = sizeof("INT") - 1;
+         break;
+      case ECORE_GETOPT_TYPE_LONG:
+         str = "LONG";
+         len = sizeof("LONG") - 1;
+         break;
+      case ECORE_GETOPT_TYPE_USHORT:
+         str = "USHORT";
+         len = sizeof("USHORT") - 1;
+         break;
+      case ECORE_GETOPT_TYPE_UINT:
+         str = "UINT";
+         len = sizeof("UINT") - 1;
+         break;
+      case ECORE_GETOPT_TYPE_ULONG:
+         str = "ULONG";
+         len = sizeof("ULONG") - 1;
+         break;
+      case ECORE_GETOPT_TYPE_DOUBLE:
+         str = "DOUBLE";
+         len = sizeof("DOUBLE") - 1;
+         break;
+      default:
+         str = "???";
+         len = sizeof("???") - 1;
+     }
+
+   used = _ecore_getopt_help_line
+     (fp, base, total, used, _("Type: "), strlen(_("Type: ")));
+   used = _ecore_getopt_help_line(fp, base, total, used, str, len);
+
+   if (store->arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES)
+     goto end;
+
+   used = _ecore_getopt_help_line
+     (fp, base, total, used, ". ", sizeof(". ") - 1);
+
+   switch (store->type)
+     {
+      case ECORE_GETOPT_TYPE_STR:
+         str = store->def.strv;
+         len = str ? strlen(str) : 0;
+         break;
+      case ECORE_GETOPT_TYPE_BOOL:
+         str = store->def.boolv ? "true" : "false";
+         len = strlen(str);
+         break;
+      case ECORE_GETOPT_TYPE_SHORT:
+         str = buf;
+         len = snprintf(buf, sizeof(buf), "%hd", store->def.shortv);
+         if (len > sizeof(buf) - 1)
+           len = sizeof(buf) - 1;
+         break;
+      case ECORE_GETOPT_TYPE_INT:
+         str = buf;
+         len = snprintf(buf, sizeof(buf), "%d", store->def.intv);
+         if (len > sizeof(buf) - 1)
+           len = sizeof(buf) - 1;
+         break;
+      case ECORE_GETOPT_TYPE_LONG:
+         str = buf;
+         len = snprintf(buf, sizeof(buf), "%ld", store->def.longv);
+         if (len > sizeof(buf) - 1)
+           len = sizeof(buf) - 1;
+         break;
+      case ECORE_GETOPT_TYPE_USHORT:
+         str = buf;
+         len = snprintf(buf, sizeof(buf), "%hu", store->def.ushortv);
+         if (len > sizeof(buf) - 1)
+           len = sizeof(buf) - 1;
+         break;
+      case ECORE_GETOPT_TYPE_UINT:
+         str = buf;
+         len = snprintf(buf, sizeof(buf), "%u", store->def.uintv);
+         if (len > sizeof(buf) - 1)
+           len = sizeof(buf) - 1;
+         break;
+      case ECORE_GETOPT_TYPE_ULONG:
+         str = buf;
+         len = snprintf(buf, sizeof(buf), "%lu", store->def.ulongv);
+         if (len > sizeof(buf) - 1)
+           len = sizeof(buf) - 1;
+         break;
+      case ECORE_GETOPT_TYPE_DOUBLE:
+         str = buf;
+         len = snprintf(buf, sizeof(buf), "%f", store->def.doublev);
+         if (len > sizeof(buf) - 1)
+           len = sizeof(buf) - 1;
+         break;
+      default:
+         str = "???";
+         len = sizeof("???") - 1;
+     }
+
+   used = _ecore_getopt_help_line
+     (fp, base, total, used, _("Default: "), strlen(_("Default: ")));
+   used = _ecore_getopt_help_line(fp, base, total, used, str, len);
+
+ end:
+   return _ecore_getopt_help_line(fp, base, total, used, ".", 1);
+}
+
+static int
+_ecore_getopt_help_desc_choices(FILE *fp, const int base, const int total, int 
used, const Ecore_Getopt_Desc *desc)
+{
+   const char *const *itr;
+   const char sep[] = ", ";
+   const int seplen = sizeof(sep) - 1;
+
+   if (used > 0)
+     {
+        fputc('\n', fp);
+        used = 0;
+     }
+   for (; used < base; used++)
+     fputc(' ', fp);
+
+   used = _ecore_getopt_help_line
+     (fp, base, total, used, _("Choices: "), strlen(_("Choices: ")));
+
+   for (itr = desc->action_param.choices; *itr; itr++)
+     {
+        used = _ecore_getopt_help_line
+          (fp, base, total, used, *itr, strlen(*itr));
+        if (itr[1])
+          used = _ecore_getopt_help_line(fp, base, total, used, sep, seplen);
+     }
+
+   return _ecore_getopt_help_line(fp, base, total, used, ".", 1);
+}
+
+static void
+_ecore_getopt_help_desc(FILE *fp, const Ecore_Getopt_Desc *desc)
+{
+   Ecore_Getopt_Desc_Arg_Requirement arg_req;
+   char metavar[32] = "ARG";
+   int metavarlen = 3;
+   int used;
+
+   arg_req = _ecore_getopt_desc_arg_requirement(desc);
+   if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+     _ecore_getopt_help_desc_setup_metavar
+       (desc, metavar, &metavarlen, sizeof(metavar));
+
+   fputs("  ", fp);
+   used = 2;
+
+   if (desc->shortname)
+     {
+        fputc('-', fp);
+        fputc(desc->shortname, fp);
+        used += 2;
+        used += _ecore_getopt_help_desc_show_arg
+          (fp, arg_req, metavar, metavarlen);
+     }
+
+   if (desc->shortname && desc->longname)
+     {
+        fputs(", ", fp);
+        used += 2;
+     }
+
+   if (desc->longname)
+     {
+        int namelen = strlen(desc->longname);
+
+        fputs("--", fp);
+        fputs(desc->longname, fp);
+        used += 2 + namelen;
+        used += _ecore_getopt_help_desc_show_arg
+          (fp, arg_req, metavar, metavarlen);
+     }
+
+   if (!desc->help)
+     goto end;
+
+   if (used + 3 >= helpcol)
+     {
+        fputc('\n', fp);
+        used = 0;
+     }
+
+   for (; used < helpcol; used++)
+     fputc(' ', fp);
+
+   used = _ecore_getopt_help_line
+     (fp, helpcol, cols, used, desc->help, strlen(desc->help));
+
+   switch (desc->action)
+     {
+      case ECORE_GETOPT_ACTION_STORE:
+         _ecore_getopt_help_desc_store(fp, helpcol, cols, used, desc);
+         break;
+      case ECORE_GETOPT_ACTION_CHOICE:
+         _ecore_getopt_help_desc_choices(fp, helpcol, cols, used, desc);
+         break;
+      default:
+         break;
+     }
+
+ end:
+   fputc('\n', fp);
+}
+
+static unsigned char
+_ecore_getopt_desc_is_sentinel(const Ecore_Getopt_Desc *desc)
+{
+   return (desc->shortname == '\0') && (!desc->longname);
+}
+
+static void
+_ecore_getopt_help_options(FILE *fp, const Ecore_Getopt *parser)
+{
+   const Ecore_Getopt_Desc *desc;
+
+   fputs(_("Options:\n"), fp);
+
+   for (desc = parser->descs; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+     _ecore_getopt_help_desc(fp, desc);
+
+   fputc('\n', fp);
+}
+
+/**
+ * Show nicely formatted help message for the given parser.
+ *
+ * Message will be print to stderr.
+ */
+void
+ecore_getopt_help(FILE *fp, const Ecore_Getopt *parser)
+{
+   const char *var;
+
+   if (!parser) return;
+
+   if (argc < 1)
+     {
+        ecore_app_args_get(&argc, &argv);
+        if ((argc > 0) && (argv[0]))
+          prog = argv[0];
+        else
+          prog = parser->prog;
+     }
+
+   var = getenv("COLUMNS");
+   if (var)
+     {
+        cols = atoi(var);
+        if (cols < 20)
+          cols = 20;
+
+        helpcol = cols / 3;
+     }
+
+   _ecore_getopt_help_usage(fp, parser);
+   _ecore_getopt_help_description(fp, parser);
+   _ecore_getopt_help_options(fp, parser);
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_parse_find_long(const Ecore_Getopt *parser, const char *name)
+{
+   const Ecore_Getopt_Desc *desc = parser->descs;
+   const char *p = strchr(name, '=');
+   int len = 0;
+
+   if (p)
+     len = p - name;
+
+   for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+     {
+        if (!desc->longname)
+          continue;
+
+        if (p)
+          {
+             if ((strncmp(name, desc->longname, len) == 0) &&
+                 (desc->longname[len] == '\0'))
+               return desc;
+          }
+        else
+          {
+             if (strcmp(name, desc->longname) == 0)
+               return desc;
+          }
+     }
+
+   return NULL;
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_parse_find_short(const Ecore_Getopt *parser, char name)
+{
+   const Ecore_Getopt_Desc *desc = parser->descs;
+   for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+     if (name == desc->shortname)
+       return desc;
+   return NULL;
+}
+
+static int
+_ecore_getopt_parse_find_nonargs_base(const Ecore_Getopt *parser, int argc, 
char **argv)
+{
+   char **nonargs;
+   int src, dst, used, base;
+
+   nonargs = alloca(sizeof(char*) * argc);
+   src = 1;
+   dst = 1;
+   used = 0;
+   base = 0;
+   while (src < argc)
+     {
+        const Ecore_Getopt_Desc *desc;
+        Ecore_Getopt_Desc_Arg_Requirement arg_req;
+        char *arg = argv[src];
+
+        if (arg[0] != '-')
+          goto found_nonarg;
+
+        if (arg[1] == '-')
+          {
+             if (arg[2] == '\0') /* explicit end of options, "--" */
+               {
+                  base = 1;
+                  break;
+               }
+             desc = _ecore_getopt_parse_find_long(parser, arg + 2);
+          }
+        else
+          desc = _ecore_getopt_parse_find_short(parser, arg[1]);
+
+        if (!desc)
+          {
+             if (arg[1] == '-')
+               fprintf(stderr, _("ERROR: unknown option --%s.\n"), arg + 2);
+             else
+               fprintf(stderr, _("ERROR: unknown option -%c.\n"), arg[1]);
+             if (parser->strict)
+               {
+                  memmove(argv + dst, nonargs, used * sizeof(char *));
+                  return -1;
+               }
+             else
+               goto found_nonarg;
+          }
+
+        if (src != dst)
+          argv[dst] = argv[src];
+        src++;
+        dst++;
+
+        arg_req = _ecore_getopt_desc_arg_requirement(desc);
+        if (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+          continue;
+
+        if (strchr(arg, '='))
+          continue;
+
+        if ((src >= argc) || (argv[src][0] == '-'))
+          continue;
+
+        if (src != dst)
+          argv[dst] = argv[src];
+        src++;
+        dst++;
+        continue;
+
+     found_nonarg:
+        nonargs[used] = arg;
+        used++;
+        src++;
+     }
+
+   if (!base) /* '--' not found */
+     base = dst;
+   else
+     {
+        base = dst;
+        if (src != dst)
+          argv[dst] = argv[src];
+        dst++;
+     }
+
+   memmove(argv + dst, nonargs, used * sizeof(char *));
+   return base;
+}
+
+static void
+_ecore_getopt_desc_print_error(const Ecore_Getopt_Desc *desc, const char *fmt, 
...)
+{
+   va_list ap;
+
+   fputs(_("ERROR: "), stderr);
+
+   if (desc->shortname)
+     {
+        fputc('-', stderr);
+        fputc(desc->shortname, stderr);
+     }
+
+   if (desc->shortname && desc->longname)
+     fputs(", ", stderr);
+
+   if (desc->longname)
+     {
+        fputs("--", stderr);
+        fputs(desc->longname, stderr);
+     }
+
+   fputs(": ", stderr);
+
+   va_start(ap, fmt);
+   vfprintf(stderr, fmt, ap);
+   va_end(ap);
+}
+
+static unsigned char
+_ecore_getopt_parse_bool(const char *str, unsigned char *v)
+{
+   if ((strcmp(str, "0") == 0) ||
+       (strcasecmp(str, "f") == 0) ||
+       (strcasecmp(str, "false") == 0) ||
+       (strcasecmp(str, "no") == 0) ||
+       (strcasecmp(str, "off") == 0)
+       )
+     {
+        *v = 0;
+        return 1;
+     }
+   else if ((strcmp(str, "1") == 0) ||
+            (strcasecmp(str, "t") == 0) ||
+            (strcasecmp(str, "true") == 0) ||
+            (strcasecmp(str, "yes") == 0) ||
+            (strcasecmp(str, "on") == 0)
+            )
+     {
+        *v = 1;
+        return 1;
+     }
+
+   return 0;
+}
+
+static unsigned char
+_ecore_getopt_parse_long(const char *str, long int *v)
+{
+   char *endptr = NULL;
+   *v = strtol(str, &endptr, 0);
+   return endptr > str;
+}
+
+static unsigned char
+_ecore_getopt_parse_double(const char *str, double *v)
+{
+   char *endptr = NULL;
+   *v = strtod(str, &endptr);
+   return endptr > str;
+}
+
+static unsigned char
+_ecore_getopt_parse_store(const Ecore_Getopt *parser __UNUSED__, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *value, const char *arg_val)
+{
+   const Ecore_Getopt_Desc_Store *store = &desc->action_param.store;
+   long int v;
+   double d;
+   unsigned char b;
+
+   if (!value->ptrp)
+     {
+        _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+        return 0;
+     }
+
+   switch (store->arg_req)
+     {
+      case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO:
+         goto use_optional;
+      case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL:
+         if (!arg_val)
+           goto use_optional;
+      case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES:
+         break;
+     }
+
+   switch (store->type)
+     {
+      case ECORE_GETOPT_TYPE_STR:
+         *value->strp = (char *)arg_val;
+         return 1;
+      case ECORE_GETOPT_TYPE_BOOL:
+         if (_ecore_getopt_parse_bool(arg_val, &b))
+           {
+              *value->boolp = b;
+              return 1;
+           }
+         else
+           {
+              _ecore_getopt_desc_print_error
+                (desc, _("unknown boolean value %s.\n"), arg_val);
+              return 0;
+           }
+      case ECORE_GETOPT_TYPE_SHORT:
+         if (!_ecore_getopt_parse_long(arg_val, &v))
+           goto error;
+         *value->shortp = v;
+         return 1;
+      case ECORE_GETOPT_TYPE_INT:
+         if (!_ecore_getopt_parse_long(arg_val, &v))
+           goto error;
+         *value->intp = v;
+         return 1;
+      case ECORE_GETOPT_TYPE_LONG:
+         if (!_ecore_getopt_parse_long(arg_val, &v))
+           goto error;
+         *value->longp = v;
+         return 1;
+      case ECORE_GETOPT_TYPE_USHORT:
+         if (!_ecore_getopt_parse_long(arg_val, &v))
+           goto error;
+         *value->ushortp = v;
+         return 1;
+      case ECORE_GETOPT_TYPE_UINT:
+         if (!_ecore_getopt_parse_long(arg_val, &v))
+           goto error;
+         *value->uintp = v;
+         return 1;
+      case ECORE_GETOPT_TYPE_ULONG:
+         if (!_ecore_getopt_parse_long(arg_val, &v))
+           goto error;
+         *value->ulongp = v;
+         return 1;
+      case ECORE_GETOPT_TYPE_DOUBLE:
+         if (!_ecore_getopt_parse_double(arg_val, &d))
+           goto error;
+         *value->doublep = d;
+         break;
+     }
+
+   return 1;
+
+ error:
+   _ecore_getopt_desc_print_error
+     (desc, _("invalid number format %s\n"), arg_val);
+   return 0;
+
+ use_optional:
+   switch (store->type)
+     {
+      case ECORE_GETOPT_TYPE_STR:
+         *value->strp = (char *)store->def.strv;
+         break;
+      case ECORE_GETOPT_TYPE_BOOL:
+         *value->boolp = store->def.boolv;
+         break;
+      case ECORE_GETOPT_TYPE_SHORT:
+         *value->shortp = store->def.shortv;
+         break;
+      case ECORE_GETOPT_TYPE_INT:
+         *value->intp = store->def.intv;
+         break;
+      case ECORE_GETOPT_TYPE_LONG:
+         *value->longp = store->def.longv;
+         break;
+      case ECORE_GETOPT_TYPE_USHORT:
+         *value->ushortp = store->def.ushortv;
+         break;
+      case ECORE_GETOPT_TYPE_UINT:
+         *value->uintp = store->def.uintv;
+         break;
+      case ECORE_GETOPT_TYPE_ULONG:
+         *value->ulongp = store->def.ulongv;
+         break;
+      case ECORE_GETOPT_TYPE_DOUBLE:
+         *value->doublep = store->def.doublev;
+         break;
+     }
+
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_store_const(const Ecore_Getopt *parser __UNUSED__, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val 
__UNUSED__)
+{
+   if (!val->ptrp)
+     {
+        _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+        return 0;
+     }
+
+   *val->ptrp = (void *)desc->action_param.store_const;
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_store_true(const Ecore_Getopt *parser __UNUSED__, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val 
__UNUSED__)
+{
+   if (!val->boolp)
+     {
+        _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+        return 0;
+     }
+   *val->boolp = 1;
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_store_false(const Ecore_Getopt *parser __UNUSED__, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val 
__UNUSED__)
+{
+   if (!val->boolp)
+     {
+        _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+        return 0;
+     }
+   *val->boolp = 0;
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_choice(const Ecore_Getopt *parser __UNUSED__, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val)
+{
+   const char * const *pchoice;
+
+   if (!val->strp)
+     {
+        _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+        return 0;
+     }
+
+   pchoice = desc->action_param.choices;
+   for (; *pchoice; pchoice++)
+     if (strcmp(*pchoice, arg_val) == 0)
+       {
+          *val->strp = (char *)*pchoice;
+          return 1;
+       }
+
+   _ecore_getopt_desc_print_error
+     (desc, _("invalid choice \"%s\". Valid values are: "), arg_val);
+
+   pchoice = desc->action_param.choices;
+   for (; *pchoice; pchoice++)
+     {
+        fputs(*pchoice, stderr);
+        if (pchoice[1])
+          fputs(", ", stderr);
+     }
+
+   fputs(".\n", stderr);
+   return 0;
+}
+
+static unsigned char
+_ecore_getopt_parse_append(const Ecore_Getopt *parser __UNUSED__, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val)
+{
+   void *data;
+   long int v;
+   double d;
+   unsigned char b;
+
+   if (!arg_val)
+     {
+        _ecore_getopt_desc_print_error
+          (desc, _("missing parameter to append.\n"));
+        return 0;
+     }
+
+   if (!val->listp)
+     {
+        _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+        return 0;
+     }
+
+   switch (desc->action_param.append_type)
+     {
+      case ECORE_GETOPT_TYPE_STR:
+         data = strdup(arg_val);
+         break;
+      case ECORE_GETOPT_TYPE_BOOL:
+        {
+           if (_ecore_getopt_parse_bool(arg_val, &b))
+             {
+                data = malloc(sizeof(unsigned char));
+                if (data)
+                  *(unsigned char *)data = b;
+             }
+           else
+             {
+                _ecore_getopt_desc_print_error
+                  (desc, _("unknown boolean value %s.\n"), arg_val);
+                return 0;
+             }
+        }
+        break;
+      case ECORE_GETOPT_TYPE_SHORT:
+        {
+           if (!_ecore_getopt_parse_long(arg_val, &v))
+             goto error;
+           data = malloc(sizeof(short));
+           if (data)
+             *(short *)data = (short)v;
+        }
+        break;
+      case ECORE_GETOPT_TYPE_INT:
+        {
+           if (!_ecore_getopt_parse_long(arg_val, &v))
+             goto error;
+           data = malloc(sizeof(int));
+           if (data)
+             *(int *)data = (int)v;
+        }
+        break;
+      case ECORE_GETOPT_TYPE_LONG:
+        {
+           if (!_ecore_getopt_parse_long(arg_val, &v))
+             goto error;
+           data = malloc(sizeof(long));
+           if (data)
+             *(long *)data = v;
+        }
+        break;
+      case ECORE_GETOPT_TYPE_USHORT:
+        {
+           if (!_ecore_getopt_parse_long(arg_val, &v))
+             goto error;
+           data = malloc(sizeof(unsigned short));
+           if (data)
+             *(unsigned short *)data = (unsigned short)v;
+        }
+        break;
+      case ECORE_GETOPT_TYPE_UINT:
+        {
+           if (!_ecore_getopt_parse_long(arg_val, &v))
+             goto error;
+           data = malloc(sizeof(unsigned int));
+           if (data)
+             *(unsigned int *)data = (unsigned int)v;
+        }
+        break;
+      case ECORE_GETOPT_TYPE_ULONG:
+        {
+           if (!_ecore_getopt_parse_long(arg_val, &v))
+             goto error;
+           data = malloc(sizeof(unsigned long));
+           if (data)
+             *(unsigned long *)data = v;
+        }
+        break;
+      case ECORE_GETOPT_TYPE_DOUBLE:
+        {
+           if (!_ecore_getopt_parse_double(arg_val, &d))
+             goto error;
+           data = malloc(sizeof(double));
+           if (data)
+             *(double *)data = d;
+        }
+        break;
+      default:
+        {
+           _ecore_getopt_desc_print_error(desc, _("could not parse value.\n"));
+           return 0;
+        }
+     }
+
+   *val->listp = eina_list_append(*val->listp, data);
+   return 1;
+
+ error:
+   _ecore_getopt_desc_print_error
+     (desc, _("invalid number format %s\n"), arg_val);
+   return 0;
+}
+
+static unsigned char
+_ecore_getopt_parse_count(const Ecore_Getopt *parser __UNUSED__, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val 
__UNUSED__)
+{
+   if (!val->intp)
+     {
+        _ecore_getopt_desc_print_error(desc, _("value has no pointer set.\n"));
+        return 0;
+     }
+
+   (*val->intp)++;
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_callback(const Ecore_Getopt *parser, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val)
+{
+   const Ecore_Getopt_Desc_Callback *cb = &desc->action_param.callback;
+
+   switch (cb->arg_req)
+     {
+      case ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO:
+         arg_val = cb->def;
+         break;
+      case ECORE_GETOPT_DESC_ARG_REQUIREMENT_OPTIONAL:
+         if (!arg_val)
+           arg_val = cb->def;
+         break;
+      case ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES:
+         break;
+     }
+
+   if (cb->arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+     {
+        if ((!arg_val) || (arg_val[0] == '\0'))
+          {
+             _ecore_getopt_desc_print_error(desc, _("missing parameter.\n"));
+             return 0;
+          }
+
+        if (!val->ptrp)
+          {
+             _ecore_getopt_desc_print_error
+               (desc, _("value has no pointer set.\n"));
+             return 0;
+          }
+     }
+
+   if (!cb->func)
+     {
+        _ecore_getopt_desc_print_error(desc, _("missing callback 
function!\n"));
+        return 0;
+     }
+
+   return cb->func(parser, desc, arg_val, (void *)cb->data, val);
+}
+
+static unsigned char
+_ecore_getopt_parse_help(const Ecore_Getopt *parser, const Ecore_Getopt_Desc 
*desc __UNUSED__, Ecore_Getopt_Value *val, const char *arg_val __UNUSED__)
+{
+   if (val->boolp)
+     (*val->boolp) = 1;
+   ecore_getopt_help(stdout, parser);
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_version(const Ecore_Getopt *parser, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val 
__UNUSED__)
+{
+   if (val->boolp)
+     (*val->boolp) = 1;
+   if (!parser->version)
+     {
+        _ecore_getopt_desc_print_error(desc, _("no version was defined.\n"));
+        return 0;
+     }
+   _ecore_getopt_version(stdout, parser);
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_copyright(const Ecore_Getopt *parser, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val 
__UNUSED__)
+{
+   if (val->boolp)
+     (*val->boolp) = 1;
+   if (!parser->copyright)
+     {
+        _ecore_getopt_desc_print_error(desc, _("no copyright was defined.\n"));
+        return 0;
+     }
+   _ecore_getopt_copyright(stdout, parser);
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_license(const Ecore_Getopt *parser, const 
Ecore_Getopt_Desc *desc, Ecore_Getopt_Value *val, const char *arg_val 
__UNUSED__)
+{
+   if (val->boolp)
+     (*val->boolp) = 1;
+   if (!parser->license)
+     {
+        _ecore_getopt_desc_print_error(desc, _("no license was defined.\n"));
+        return 0;
+     }
+   _ecore_getopt_license(stdout, parser);
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_desc_handle(const Ecore_Getopt *parser, const Ecore_Getopt_Desc 
*desc, Ecore_Getopt_Value *value, const char *arg_val)
+{
+   switch (desc->action)
+     {
+      case ECORE_GETOPT_ACTION_STORE:
+         return _ecore_getopt_parse_store(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_STORE_CONST:
+         return _ecore_getopt_parse_store_const(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_STORE_TRUE:
+         return _ecore_getopt_parse_store_true(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_STORE_FALSE:
+         return _ecore_getopt_parse_store_false(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_CHOICE:
+         return _ecore_getopt_parse_choice(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_APPEND:
+         return _ecore_getopt_parse_append(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_COUNT:
+         return _ecore_getopt_parse_count(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_CALLBACK:
+         return _ecore_getopt_parse_callback(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_HELP:
+         return _ecore_getopt_parse_help(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_VERSION:
+         return _ecore_getopt_parse_version(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_COPYRIGHT:
+         return _ecore_getopt_parse_copyright(parser, desc, value, arg_val);
+      case ECORE_GETOPT_ACTION_LICENSE:
+         return _ecore_getopt_parse_license(parser, desc, value, arg_val);
+      default:
+         return 0;
+     }
+}
+
+static unsigned char
+_ecore_getopt_parse_arg_long(const Ecore_Getopt *parser, Ecore_Getopt_Value 
*values, int argc __UNUSED__, char **argv, int *idx, int *nonargs, const char 
*arg)
+{
+   const Ecore_Getopt_Desc *desc;
+   Ecore_Getopt_Desc_Arg_Requirement arg_req;
+   const char *arg_val;
+   int desc_idx;
+   Ecore_Getopt_Value *value;
+   unsigned char ret;
+
+   desc = _ecore_getopt_parse_find_long(parser, arg);
+   if (!desc)
+     {
+        fprintf(stderr, _("ERROR: unknown option --%s, ignored.\n"), arg);
+        if (parser->strict)
+          return 0;
+
+        (*idx)++;
+        return 1;
+     }
+
+   (*idx)++;
+
+   arg_req = _ecore_getopt_desc_arg_requirement(desc);
+   if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+     {
+        arg_val = strchr(arg, '=');
+        if (arg_val)
+          arg_val++;
+        else
+          {
+             if ((*idx < *nonargs) && (argv[*idx][0] != '-'))
+               {
+                  arg_val = argv[*idx];
+                  (*idx)++;
+               }
+             else
+               arg_val = NULL;
+          }
+
+        if (arg_val && arg_val[0] == '\0')
+          arg_val = NULL;
+
+        if ((!arg_val) && (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES))
+          {
+             fprintf
+               (stderr, _("ERROR: option --%s requires an argument!\n"), arg);
+             if (parser->strict)
+               return 0;
+             return 1;
+          }
+     }
+   else
+     arg_val = NULL;
+
+   desc_idx = desc - parser->descs;
+   value = values + desc_idx;
+   ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val);
+   if ((!ret) && parser->strict)
+     return 0;
+
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_arg_short(const Ecore_Getopt *parser, Ecore_Getopt_Value 
*values, int argc __UNUSED__, char **argv, int *idx, int *nonargs, const char 
*arg)
+{
+   int run = 1;
+   while (run && (arg[0] != '\0'))
+     {
+        int opt = arg[0];
+        const Ecore_Getopt_Desc *desc;
+        Ecore_Getopt_Desc_Arg_Requirement arg_req;
+        const char *arg_val;
+        int desc_idx;
+        Ecore_Getopt_Value *value;
+        unsigned char ret;
+
+        desc = _ecore_getopt_parse_find_short(parser, arg[0]);
+        if (!desc)
+          {
+             fprintf
+               (stderr, _("ERROR: unknown option -%c, ignored.\n"), arg[0]);
+             if (parser->strict)
+               return 0;
+
+             arg++;
+             continue;
+          }
+
+        arg++;
+
+        arg_req = _ecore_getopt_desc_arg_requirement(desc);
+        if (arg_req != ECORE_GETOPT_DESC_ARG_REQUIREMENT_NO)
+          {
+             (*idx)++;
+             run = 0;
+
+             if (arg[0] == '=')
+               arg_val = arg + 1;
+             else if (arg[0] != '\0')
+               arg_val = arg;
+             else
+               {
+                  if ((*idx < *nonargs) && (argv[*idx][0] != '-'))
+                    {
+                       arg_val = argv[*idx];
+                       (*idx)++;
+                    }
+                  else
+                    arg_val = NULL;
+               }
+
+             if (arg_val && arg_val[0] == '\0')
+               arg_val = NULL;
+
+             if ((!arg_val) &&
+                 (arg_req == ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES))
+               {
+                  fprintf
+                    (stderr, _("ERROR: option -%c requires an argument!\n"),
+                     opt);
+                  if (parser->strict)
+                    return 0;
+                  return 1;
+               }
+          }
+        else
+          arg_val = NULL;
+
+        desc_idx = desc - parser->descs;
+        value = values + desc_idx;
+        ret = _ecore_getopt_desc_handle(parser, desc, value, arg_val);
+        if ((!ret) && parser->strict)
+          return 0;
+     }
+
+   if (run)
+     (*idx)++;
+
+   return 1;
+}
+
+static unsigned char
+_ecore_getopt_parse_arg(const Ecore_Getopt *parser, Ecore_Getopt_Value 
*values, int argc, char **argv, int *idx, int *nonargs)
+{
+   char *arg = argv[*idx];
+
+   if (arg[0] != '-')
+     {
+        char **dst, **src, **src_end;
+
+        dst = argv + *idx;
+        src = dst + 1;
+        src_end = src + *nonargs - *idx - 1;
+
+        for (; src < src_end; src++, dst++)
+          *dst = *src;
+
+        *dst = arg;
+        (*nonargs)--;
+        return 1;
+     }
+
+   if (arg[1] == '-')
+     return _ecore_getopt_parse_arg_long
+       (parser, values, argc, argv, idx, nonargs, arg + 2);
+   else
+     return _ecore_getopt_parse_arg_short
+       (parser, values, argc, argv, idx, nonargs, arg + 1);
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_parse_find_short_other(const Ecore_Getopt *parser, const 
Ecore_Getopt_Desc *orig)
+{
+   const Ecore_Getopt_Desc *desc = parser->descs;
+   const char c = orig->shortname;
+
+   for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+     {
+        if (desc == orig)
+          return NULL;
+
+        if (c == desc->shortname)
+          return desc;
+     }
+
+   return NULL;
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_parse_find_long_other(const Ecore_Getopt *parser, const 
Ecore_Getopt_Desc *orig)
+{
+   const Ecore_Getopt_Desc *desc = parser->descs;
+   const char *name = orig->longname;
+
+   for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+     {
+        if (desc == orig)
+          return NULL;
+
+        if (desc->longname && (strcmp(name, desc->longname) == 0))
+          return desc;
+     }
+
+   return NULL;
+}
+
+/**
+ * Check parser for duplicate entries, print them out.
+ *
+ * @return 1 if there are duplicates, 0 otherwise.
+ */
+unsigned char
+ecore_getopt_parser_has_duplicates(const Ecore_Getopt *parser)
+{
+   const Ecore_Getopt_Desc *desc = parser->descs;
+   for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+     {
+       if (desc->shortname)
+         {
+           const Ecore_Getopt_Desc *other;
+           other = _ecore_getopt_parse_find_short_other(parser, desc);
+           if (other)
+             {
+                _ecore_getopt_desc_print_error
+                  (desc, "short name -%c already exists.", desc->shortname);
+
+                if (other->longname)
+                  fprintf(stderr, " Other is --%s.\n", other->longname);
+                else
+                  fputc('\n', stderr);
+                return 1;
+             }
+         }
+
+       if (desc->longname)
+         {
+           const Ecore_Getopt_Desc *other;
+           other = _ecore_getopt_parse_find_long_other(parser, desc);
+           if (other)
+             {
+                _ecore_getopt_desc_print_error
+                  (desc, "long name --%s already exists.", desc->longname);
+
+                if (other->shortname)
+                  fprintf(stderr, " Other is -%c.\n", other->shortname);
+                else
+                  fputc('\n', stderr);
+                return 1;
+             }
+         }
+     }
+   return 0;
+}
+
+static const Ecore_Getopt_Desc *
+_ecore_getopt_find_help(const Ecore_Getopt *parser)
+{
+   const Ecore_Getopt_Desc *desc = parser->descs;
+   for (; !_ecore_getopt_desc_is_sentinel(desc); desc++)
+     if (desc->action == ECORE_GETOPT_ACTION_HELP)
+       return desc;
+   return NULL;
+}
+
+/**
+ * Parse command line parameters.
+ *
+ * Walks the command line parameters and parse them based on @a parser
+ * description, doing actions based on @c parser->descs->action, like
+ * showing help text, license, copyright, storing values in values and
+ * so on.
+ *
+ * It is expected that values is of the same size than @c parser->descs,
+ * options that do not need a value it will be left untouched.
+ *
+ * All values are expected to be initialized before use. Options with
+ * action @c ECORE_GETOPT_ACTION_STORE and non required arguments
+ * (others than @c ECORE_GETOPT_DESC_ARG_REQUIREMENT_YES), are expected
+ * to provide a value in @c def to be used.
+ *
+ * The following actions will store 1 on value as a boolean
+ * (@c value->boolp) if it's not NULL to indicate these actions were executed:
+ *   - @c ECORE_GETOPT_ACTION_HELP
+ *   - @c ECORE_GETOPT_ACTION_VERSION
+ *   - @c ECORE_GETOPT_ACTION_COPYRIGHT
+ *   - @c ECORE_GETOPT_ACTION_LICENSE
+ *
+ * Just @c ECORE_GETOPT_ACTION_APPEND will allocate memory and thus
+ * need to be freed. For consistency between all of appended subtypes,
+ * @c eina_list->data will contain an allocated memory with the value,
+ * that is, for @c ECORE_GETOPT_TYPE_STR it will contain a copy of the
+ * argument, @c ECORE_GETOPT_TYPE_INT a pointer to an allocated
+ * integer and so on.
+ *
+ * If parser is in strict mode (see @c Ecore_Getopt->strict), then any
+ * error will abort parsing and -1 is returned. Otherwise it will try
+ * to continue as far as possible.
+ *
+ * This function may reorder @a argv elements.
+ *
+ * Translation of help strings (description), metavar, usage, license
+ * and copyright may be translated, standard/global gettext() call
+ * will be applied on them if ecore was compiled with such support.
+ *
+ * @param parser description of how to work.
+ * @param value where to store values, it is assumed that this is a vector
+ *        of the same size as @c parser->descs. Values should be previously
+ *        initialized.
+ * @param argc how many elements in @a argv. If not provided it will be
+ *        retrieved with ecore_app_args_get().
+ * @param argv command line parameters.
+ *
+ * @return index of first non-option parameter or -1 on error.
+ */
+int
+ecore_getopt_parse(const Ecore_Getopt *parser, Ecore_Getopt_Value *values, int 
argc, char **argv)
+{
+   int i, nonargs;
+
+   if (!parser)
+     {
+        fputs(_("ERROR: no parser provided.\n"), stderr);
+        return -1;
+     }
+   if (!values)
+     {
+        fputs(_("ERROR: no values provided.\n"), stderr);
+        return -1;
+     }
+
+   if ((argc < 1) || (!argv))
+     ecore_app_args_get(&argc, &argv);
+
+   if (argc < 1)
+     {
+        fputs(_("ERROR: no arguments provided.\n"), stderr);
+        return -1;
+     }
+
+   if (argv[0])
+     prog = argv[0];
+   else
+     prog = parser->prog;
+
+   nonargs = _ecore_getopt_parse_find_nonargs_base(parser, argc, argv);
+   if (nonargs < 0)
+     goto error;
+
+   if (nonargs > argc)
+     nonargs = argc;
+
+   i = 1;
+   while (i < nonargs)
+     if (!_ecore_getopt_parse_arg(parser, values, argc, argv, &i, &nonargs))
+       goto error;
+
+   return nonargs;
+
+ error:
+   {
+      const Ecore_Getopt_Desc *help;
+      fputs(_("ERROR: invalid options found."), stderr);
+
+      help = _ecore_getopt_find_help(parser);
+      if (!help)
+        fputc('\n', stderr);
+      else if (help->longname)
+        fprintf(stderr, _(" See --%s.\n"), help->longname);
+      else
+        fprintf(stderr, _(" See -%c.\n"), help->shortname);
+   }
+
+   return -1;
+}
+
+/**
+ * Utility to free list and nodes allocated by @a ECORE_GETOPT_ACTION_APPEND.
+ *
+ * @param list pointer to list to be freed.
+ * @return always NULL, so you can easily make your list head NULL.
+ */
+Eina_List *
+ecore_getopt_list_free(Eina_List *list)
+{
+   void *data;
+
+   EINA_LIST_FREE(list, data)
+     free(data);
+   return NULL;
+}
+
+/**
+ * Helper ecore_getopt callback to parse geometry (x:y:w:h).
+ *
+ * Storage must be a pointer to @c Eina_Rectangle and will be used to
+ * store the four values passed in the given string.
+ *
+ * @c callback_data value is ignored, you can safely use @c NULL.
+ */
+unsigned char
+ecore_getopt_callback_geometry_parse(const Ecore_Getopt *parser __UNUSED__, 
const Ecore_Getopt_Desc *desc __UNUSED__, const char *str, void *data 
__UNUSED__, Ecore_Getopt_Value *storage)
+{
+   Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp;
+
+   if (sscanf(str, "%d:%d:%d:%d", &v->x, &v->y, &v->w, &v->h) != 4)
+     {
+        fprintf(stderr, _("ERROR: incorrect geometry value '%s'\n"), str);
+        return 0;
+     }
+
+   return 1;
+}
+
+/**
+ * Helper ecore_getopt callback to parse geometry size (WxH).
+ *
+ * Storage must be a pointer to @c Eina_Rectangle and will be used to
+ * store the two values passed in the given string and 0 in the x and y
+ * fields.
+ *
+ * @c callback_data value is ignored, you can safely use @c NULL.
+ */
+unsigned char
+ecore_getopt_callback_size_parse(const Ecore_Getopt *parser __UNUSED__, const 
Ecore_Getopt_Desc *desc __UNUSED__, const char *str, void *data __UNUSED__, 
Ecore_Getopt_Value *storage)
+{
+   Eina_Rectangle *v = (Eina_Rectangle *)storage->ptrp;
+
+   if (sscanf(str, "%dx%d", &v->w, &v->h) != 2)
+     {
+        fprintf(stderr, _("ERROR: incorrect size value '%s'\n"), str);
+        return 0;
+     }
+   v->x = 0;
+   v->y = 0;
+
+   return 1;
+}
diff --git a/tests/suite/ecore/src/lib/ecore_glib.c 
b/tests/suite/ecore/src/lib/ecore_glib.c
new file mode 100644
index 0000000..0972776
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_glib.c
@@ -0,0 +1,286 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#ifdef HAVE_GLIB
+#include <glib.h>
+
+static Eina_Bool _ecore_glib_active = EINA_FALSE;
+static Ecore_Select_Function _ecore_glib_select_original;
+static GCond *_ecore_glib_cond = NULL;
+static GPollFD *_ecore_glib_fds = NULL;
+static size_t _ecore_glib_fds_size = 0;
+static const size_t ECORE_GLIB_FDS_INITIAL = 128;
+static const size_t ECORE_GLIB_FDS_STEP = 8;
+static const size_t ECORE_GLIB_FDS_MAX_FREE = 256;
+
+static Eina_Bool
+_ecore_glib_fds_resize(size_t size)
+{
+   void *tmp = realloc(_ecore_glib_fds, sizeof(GPollFD) * size);
+   
+   if (!tmp)
+     {
+        ERR("Could not realloc from %zu to %zu buckets.",
+            _ecore_glib_fds_size, size);
+        return EINA_FALSE;
+     }
+   
+   _ecore_glib_fds = tmp;
+   _ecore_glib_fds_size = size;
+   return EINA_TRUE;
+}
+
+static int
+_ecore_glib_context_query(GMainContext *ctx, int priority, int *p_timer)
+{
+   int reqfds;
+
+   if (_ecore_glib_fds_size == 0)
+     {
+        if (!_ecore_glib_fds_resize(ECORE_GLIB_FDS_INITIAL)) return -1;
+     }
+   
+   while (1)
+     {
+        size_t size;
+        
+        reqfds = g_main_context_query
+          (ctx, priority, p_timer, _ecore_glib_fds, _ecore_glib_fds_size);
+        if (reqfds <= (int)_ecore_glib_fds_size) break;
+
+        size = (1 + reqfds / ECORE_GLIB_FDS_STEP) * ECORE_GLIB_FDS_STEP;
+        if (!_ecore_glib_fds_resize(size)) return -1;
+     }
+
+   if (reqfds + ECORE_GLIB_FDS_MAX_FREE < _ecore_glib_fds_size)
+     {
+        size_t size;
+
+        size = (1 + reqfds / ECORE_GLIB_FDS_MAX_FREE) * 
ECORE_GLIB_FDS_MAX_FREE;
+        _ecore_glib_fds_resize(size);
+     }
+
+   return reqfds;
+}
+
+static int
+_ecore_glib_context_poll_from(const GPollFD *pfds, int count, fd_set *rfds, 
fd_set *wfds, fd_set *efds)
+{
+   const GPollFD *itr = pfds, *itr_end = pfds + count;
+   int glib_fds = -1;
+   
+   for (; itr < itr_end; itr++)
+     {
+        if (glib_fds < itr->fd)
+          glib_fds = itr->fd;
+
+        if (itr->events & G_IO_IN)
+          FD_SET(itr->fd, rfds);
+        if (itr->events & G_IO_OUT)
+          FD_SET(itr->fd, wfds);
+        if (itr->events & (G_IO_HUP | G_IO_ERR))
+          FD_SET(itr->fd, efds);
+     }
+
+   return glib_fds + 1;
+}
+
+static int
+_ecore_glib_context_poll_to(GPollFD *pfds, int count, const fd_set *rfds, 
const fd_set *wfds, const fd_set *efds, int ready)
+{
+   GPollFD *itr = pfds, *itr_end = pfds + count;
+   
+   for (; itr < itr_end && ready > 0; itr++)
+     {
+        itr->revents = 0;
+        if (FD_ISSET(itr->fd, rfds))
+          {
+             itr->revents |= G_IO_IN;
+             ready--;
+          }
+        if (FD_ISSET(itr->fd, wfds))
+          {
+             itr->revents |= G_IO_OUT;
+             ready--;
+          }
+        if (FD_ISSET(itr->fd, efds))
+          {
+             itr->revents |= G_IO_ERR;
+             ready--;
+          }
+     }
+   return ready;
+}
+
+static int
+_ecore_glib_select__locked(GMainContext *ctx, int ecore_fds, fd_set *rfds, 
fd_set *wfds, fd_set *efds, struct timeval *ecore_timeout)
+{
+   int priority, maxfds, glib_fds, reqfds, reqtimeout, ret;
+   struct timeval *timeout, glib_timeout;
+
+   g_main_context_prepare(ctx, &priority);
+   reqfds = _ecore_glib_context_query(ctx, priority, &reqtimeout);
+   if (reqfds < 0) goto error;
+
+   glib_fds = _ecore_glib_context_poll_from
+     (_ecore_glib_fds, reqfds, rfds, wfds, efds);
+
+   if (reqtimeout == -1)
+     timeout = ecore_timeout;
+   else
+     {
+        glib_timeout.tv_sec = reqtimeout / 1000;
+        glib_timeout.tv_usec = (reqtimeout % 1000) * 1000;
+        
+        if (!ecore_timeout || timercmp(ecore_timeout, &glib_timeout, >))
+          timeout = &glib_timeout;
+        else
+          timeout = ecore_timeout;
+     }
+
+   maxfds = (ecore_fds >= glib_fds) ? ecore_fds : glib_fds;
+   ret = _ecore_glib_select_original(maxfds, rfds, wfds, efds, timeout);
+
+   ret = _ecore_glib_context_poll_to
+     (_ecore_glib_fds, reqfds, rfds, wfds, efds, ret);
+
+   if (g_main_context_check(ctx, priority, _ecore_glib_fds, reqfds))
+     g_main_context_dispatch(ctx);
+
+   return ret;
+
+ error:
+   return _ecore_glib_select_original
+     (ecore_fds, rfds, wfds, efds, ecore_timeout);
+}
+
+static int
+_ecore_glib_select(int ecore_fds, fd_set *rfds, fd_set *wfds, fd_set *efds, 
struct timeval *ecore_timeout)
+{
+   GStaticMutex lock = G_STATIC_MUTEX_INIT;
+   GMutex *mutex = g_static_mutex_get_mutex(&lock);
+   GMainContext *ctx = g_main_context_default();
+   int ret;
+
+   if (g_main_context_acquire(ctx))
+     g_mutex_lock(mutex);
+   else
+     {
+        if (!_ecore_glib_cond)
+          _ecore_glib_cond = g_cond_new();
+
+        while (!g_main_context_wait(ctx, _ecore_glib_cond, mutex))
+          g_thread_yield();
+     }
+
+   ret = _ecore_glib_select__locked
+     (ctx, ecore_fds, rfds, wfds, efds, ecore_timeout);
+
+   g_mutex_unlock(mutex);
+   g_main_context_release(ctx);
+
+   return ret;
+}
+#endif
+
+void
+_ecore_glib_init(void)
+{
+}
+
+void
+_ecore_glib_shutdown(void)
+{
+#ifdef HAVE_GLIB
+   if (!_ecore_glib_active) return;
+   _ecore_glib_active = EINA_FALSE;
+
+   if (ecore_main_loop_select_func_get() == _ecore_glib_select)
+     ecore_main_loop_select_func_set(_ecore_glib_select_original);
+   
+   if (_ecore_glib_fds)
+     {
+        free(_ecore_glib_fds);
+        _ecore_glib_fds = NULL;
+     }
+   _ecore_glib_fds_size = 0;
+
+   if (_ecore_glib_cond)
+     {
+        g_cond_free(_ecore_glib_cond);
+        _ecore_glib_cond = NULL;
+     }
+#endif
+}
+
+/**
+ * Request ecore to integrate GLib's main loop.
+ *
+ * This will add a small overhead during every main loop interaction
+ * by checking glib's default main context (used by its main loop). If
+ * it have events to be checked (timers, file descriptors or idlers),
+ * then these will be polled alongside with Ecore's own events, then
+ * dispatched before Ecore's. This is done by calling
+ * ecore_main_loop_select_func_set().
+ *
+ * This will cooperate with previously set
+ * ecore_main_loop_select_func_set() by calling the old
+ * function. Similarly, if you want to override
+ * ecore_main_loop_select_func_set() after main loop is integrated,
+ * call the new select function set by this call (get it by calling
+ * ecore_main_loop_select_func_get() right after
+ * ecore_main_loop_glib_integrate()).
+ *
+ * This is useful to use GMainLoop libraries, like GTK, GUPnP,
+ * LibSoup, GConf and more. Adobe Flash plugin and other plugins
+ * systems depend on this as well.
+ *
+ * Once initialized/integrated, it will be valid until Ecore is
+ * completely shut down.
+ *
+ * @note this is only available if Ecore was compiled with GLib support.
+ *
+ * @return @c EINA_TRUE on success of @c EINA_FALSE if it failed,
+ *         likely no GLib support in Ecore.
+ */
+EAPI Eina_Bool
+ecore_main_loop_glib_integrate(void)
+{
+#ifdef HAVE_GLIB
+   void *func;
+
+   if (_ecore_glib_active) return EINA_TRUE;
+   func = ecore_main_loop_select_func_get();
+   if (func == _ecore_glib_select) return EINA_TRUE;
+   _ecore_glib_select_original = func;
+   ecore_main_loop_select_func_set(_ecore_glib_select);
+   _ecore_glib_active = EINA_TRUE;
+   return EINA_TRUE;
+#else
+   fputs("ERROR: no glib support in ecore.\n", stderr);
+   return EINA_FALSE;
+#endif
+}
+
+Eina_Bool _ecore_glib_always_integrate = 1;
+
+/**
+ * Disable always integrating glib
+ * 
+ * If ecore is compiled with --enable-glib-integration-always (to always
+ * call ecore_main_loop_glib_integrate() when ecore_init() is called), then
+ * calling this before calling ecore_init() will disable the integration.
+ * This is for apps that explicitly do not want this to happen for whatever
+ * reasons they may have.
+ */
+EAPI void
+ecore_main_loop_glib_always_integrate_disable(void)
+{
+   _ecore_glib_always_integrate = 0;
+}
diff --git a/tests/suite/ecore/src/lib/ecore_idle_enterer.c 
b/tests/suite/ecore/src/lib/ecore_idle_enterer.c
new file mode 100644
index 0000000..2b827ce
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_idle_enterer.c
@@ -0,0 +1,171 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+
+struct _Ecore_Idle_Enterer
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   Ecore_Task_Cb func;
+   void        *data;
+   int          references;
+   Eina_Bool    delete_me : 1;
+};
+
+
+static Ecore_Idle_Enterer *idle_enterers = NULL;
+static Ecore_Idle_Enterer *idle_enterer_current = NULL;
+static int                 idle_enterers_delete_me = 0;
+
+/**
+ * Add an idle enterer handler.
+ * @param   func The function to call when entering an idle state.
+ * @param   data The data to be passed to the @p func call
+ * @return  A handle to the idle enterer callback if successful.  Otherwise,
+ *          NULL is returned.
+ * @ingroup Idle_Group
+ */
+EAPI Ecore_Idle_Enterer *
+ecore_idle_enterer_add(Ecore_Task_Cb func, const void *data)
+{
+   Ecore_Idle_Enterer *ie;
+
+   if (!func) return NULL;
+   ie = calloc(1, sizeof(Ecore_Idle_Enterer));
+   if (!ie) return NULL;
+   ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER);
+   ie->func = func;
+   ie->data = (void *)data;
+   idle_enterers = (Ecore_Idle_Enterer *) 
eina_inlist_append(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
+   return ie;
+}
+
+/**
+ * Add an idle enterer handler at the start of the list so it gets called 
earlier than others.
+ * @param   func The function to call when entering an idle state.
+ * @param   data The data to be passed to the @p func call
+ * @return  A handle to the idle enterer callback if successful.  Otherwise,
+ *          NULL is returned.
+ * @ingroup Idle_Group
+ */
+EAPI Ecore_Idle_Enterer *
+ecore_idle_enterer_before_add(Ecore_Task_Cb func, const void *data)
+{
+   Ecore_Idle_Enterer *ie;
+
+   if (!func) return NULL;
+   ie = calloc(1, sizeof(Ecore_Idle_Enterer));
+   if (!ie) return NULL;
+   ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_ENTERER);
+   ie->func = func;
+   ie->data = (void *)data;
+   idle_enterers = (Ecore_Idle_Enterer *) 
eina_inlist_prepend(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
+   return ie;
+}
+
+/**
+ * Delete an idle enterer callback.
+ * @param   idle_enterer The idle enterer to delete
+ * @return  The data pointer passed to the idler enterer callback on success.
+ *          NULL otherwise.
+ * @ingroup Idle_Group
+ */
+EAPI void *
+ecore_idle_enterer_del(Ecore_Idle_Enterer *idle_enterer)
+{
+   if (!ECORE_MAGIC_CHECK(idle_enterer, ECORE_MAGIC_IDLE_ENTERER))
+     {
+        ECORE_MAGIC_FAIL(idle_enterer, ECORE_MAGIC_IDLE_ENTERER,
+                         "ecore_idle_enterer_del");
+        return NULL;
+     }
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_enterer->delete_me, NULL);
+   idle_enterer->delete_me = 1;
+   idle_enterers_delete_me = 1;
+   return idle_enterer->data;
+}
+
+void
+_ecore_idle_enterer_shutdown(void)
+{
+   Ecore_Idle_Enterer *ie;
+   while ((ie = idle_enterers))
+     {
+        idle_enterers = (Ecore_Idle_Enterer *) 
eina_inlist_remove(EINA_INLIST_GET(idle_enterers), 
EINA_INLIST_GET(idle_enterers));
+        ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
+        free(ie);
+     }
+   idle_enterers_delete_me = 0;
+   idle_enterer_current = NULL;
+}
+
+void
+_ecore_idle_enterer_call(void)
+{
+   if (!idle_enterer_current)
+     {
+        /* regular main loop, start from head */
+        idle_enterer_current = idle_enterers;
+     }
+   else
+     {
+        /* recursive main loop, continue from where we were */
+        idle_enterer_current =
+          (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next;
+     }
+
+   while (idle_enterer_current)
+     {
+        Ecore_Idle_Enterer *ie = (Ecore_Idle_Enterer *)idle_enterer_current;
+        if (!ie->delete_me)
+          {
+             ie->references++;
+             if (!ie->func(ie->data))
+               {
+                  if (!ie->delete_me) ecore_idle_enterer_del(ie);
+               }
+             ie->references--;
+          }
+        if (idle_enterer_current) /* may have changed in recursive main loops 
*/
+          idle_enterer_current =
+            (Ecore_Idle_Enterer *)EINA_INLIST_GET(idle_enterer_current)->next;
+     }
+   if (idle_enterers_delete_me)
+     {
+        Ecore_Idle_Enterer *l;
+        int deleted_idler_enterers_in_use = 0;
+
+        for (l = idle_enterers; l;)
+          {
+             Ecore_Idle_Enterer *ie = l;
+             l = (Ecore_Idle_Enterer *) EINA_INLIST_GET(l)->next;
+             if (ie->delete_me)
+               {
+                  if (ie->references)
+                    {
+                       deleted_idler_enterers_in_use++;
+                       continue;
+                    }
+
+                  idle_enterers = (Ecore_Idle_Enterer *) 
eina_inlist_remove(EINA_INLIST_GET(idle_enterers), EINA_INLIST_GET(ie));
+                  ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
+                  free(ie);
+               }
+          }
+        if (!deleted_idler_enterers_in_use)
+          idle_enterers_delete_me = 0;
+     }
+}
+
+int
+_ecore_idle_enterer_exist(void)
+{
+   if (idle_enterers) return 1;
+   return 0;
+}
diff --git a/tests/suite/ecore/src/lib/ecore_idle_exiter.c 
b/tests/suite/ecore/src/lib/ecore_idle_exiter.c
new file mode 100644
index 0000000..d8234e3
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_idle_exiter.c
@@ -0,0 +1,148 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+
+struct _Ecore_Idle_Exiter
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   Ecore_Task_Cb func;
+   void        *data;
+   int          references;
+   Eina_Bool    delete_me : 1;
+};
+
+
+static Ecore_Idle_Exiter *idle_exiters = NULL;
+static Ecore_Idle_Exiter *idle_exiter_current = NULL;
+static int                idle_exiters_delete_me = 0;
+
+/**
+ * Add an idle exiter handler.
+ * @param func The function to call when exiting an idle state.
+ * @param data The data to be passed to the @p func call
+ * @return A handle to the idle exiter callback on success.  NULL otherwise.
+ * @ingroup Idle_Group
+ */
+EAPI Ecore_Idle_Exiter *
+ecore_idle_exiter_add(Ecore_Task_Cb func, const void *data)
+{
+   Ecore_Idle_Exiter *ie;
+
+   if (!func) return NULL;
+   ie = calloc(1, sizeof(Ecore_Idle_Exiter));
+   if (!ie) return NULL;
+   ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLE_EXITER);
+   ie->func = func;
+   ie->data = (void *)data;
+   idle_exiters = (Ecore_Idle_Exiter *) 
eina_inlist_append(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie));
+   return ie;
+}
+
+/**
+ * Delete an idle exiter handler from the list to be run on exiting idle state.
+ * @param idle_exiter The idle exiter to delete
+ * @return The data pointer that was being being passed to the handler if
+ *         successful.  NULL otherwise.
+ * @ingroup Idle_Group
+ */
+EAPI void *
+ecore_idle_exiter_del(Ecore_Idle_Exiter *idle_exiter)
+{
+   if (!ECORE_MAGIC_CHECK(idle_exiter, ECORE_MAGIC_IDLE_EXITER))
+     {
+        ECORE_MAGIC_FAIL(idle_exiter, ECORE_MAGIC_IDLE_EXITER,
+                         "ecore_idle_exiter_del");
+        return NULL;
+     }
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(idle_exiter->delete_me, NULL);
+   idle_exiter->delete_me = 1;
+   idle_exiters_delete_me = 1;
+   return idle_exiter->data;
+}
+
+void
+_ecore_idle_exiter_shutdown(void)
+{
+   Ecore_Idle_Exiter *ie;
+   while ((ie = idle_exiters))
+     {
+        idle_exiters = (Ecore_Idle_Exiter *) 
eina_inlist_remove(EINA_INLIST_GET(idle_exiters), 
EINA_INLIST_GET(idle_exiters));
+        ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
+        free(ie);
+     }
+   idle_exiters_delete_me = 0;
+   idle_exiter_current = NULL;
+}
+
+void
+_ecore_idle_exiter_call(void)
+{
+   if (!idle_exiter_current)
+     {
+        /* regular main loop, start from head */
+        idle_exiter_current = idle_exiters;
+     }
+   else
+     {
+        /* recursive main loop, continue from where we were */
+        idle_exiter_current =
+          (Ecore_Idle_Exiter *)EINA_INLIST_GET(idle_exiter_current)->next;
+     }
+
+   while (idle_exiter_current)
+     {
+        Ecore_Idle_Exiter *ie = (Ecore_Idle_Exiter *)idle_exiter_current;
+        if (!ie->delete_me)
+          {
+             ie->references++;
+             if (!ie->func(ie->data))
+               {
+                  if (!ie->delete_me) ecore_idle_exiter_del(ie);
+               }
+             ie->references--;
+          }
+        if (idle_exiter_current) /* may have changed in recursive main loops */
+          idle_exiter_current =
+            (Ecore_Idle_Exiter *)EINA_INLIST_GET(idle_exiter_current)->next;
+     }
+   if (idle_exiters_delete_me)
+     {
+        Ecore_Idle_Exiter *l;
+        int deleted_idler_exiters_in_use = 0;
+
+        for (l = idle_exiters; l;)
+          {
+             Ecore_Idle_Exiter *ie = l;
+
+             l = (Ecore_Idle_Exiter *) EINA_INLIST_GET(l)->next;
+             if (ie->delete_me)
+               {
+                  if (ie->references)
+                    {
+                       deleted_idler_exiters_in_use++;
+                       continue;
+                    }
+
+                  idle_exiters = (Ecore_Idle_Exiter *) 
eina_inlist_remove(EINA_INLIST_GET(idle_exiters), EINA_INLIST_GET(ie));
+                  ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
+                  free(ie);
+               }
+          }
+        if (!deleted_idler_exiters_in_use)
+          idle_exiters_delete_me = 0;
+     }
+}
+
+int
+_ecore_idle_exiter_exist(void)
+{
+   if (idle_exiters) return 1;
+   return 0;
+}
diff --git a/tests/suite/ecore/src/lib/ecore_idler.c 
b/tests/suite/ecore/src/lib/ecore_idler.c
new file mode 100644
index 0000000..8f1c820
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_idler.c
@@ -0,0 +1,154 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+
+struct _Ecore_Idler
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   Ecore_Task_Cb func;
+   void        *data;
+   int          references;
+   Eina_Bool    delete_me : 1;
+};
+
+
+static Ecore_Idler *idlers = NULL;
+static Ecore_Idler *idler_current = NULL;
+static int          idlers_delete_me = 0;
+
+/**
+ * Add an idler handler.
+ * @param  func The function to call when idling.
+ * @param  data The data to be passed to this @p func call.
+ * @return A idler handle if successfully added.  NULL otherwise.
+ * @ingroup Idle_Group
+ *
+ * Add an idler handle to the event loop, returning a handle on success and
+ * NULL otherwise.  The function @p func will be called repeatedly while
+ * no other events are ready to be processed, as long as it returns 1
+ * (or ECORE_CALLBACK_RENEW). A return of 0 (or ECORE_CALLBACK_CANCEL) deletes
+ * the idler.
+ *
+ * Idlers are useful for progressively prossessing data without blocking.
+ */
+EAPI Ecore_Idler *
+ecore_idler_add(Ecore_Task_Cb func, const void *data)
+{
+   Ecore_Idler *ie;
+
+   if (!func) return NULL;
+   ie = calloc(1, sizeof(Ecore_Idler));
+   if (!ie) return NULL;
+   ECORE_MAGIC_SET(ie, ECORE_MAGIC_IDLER);
+   ie->func = func;
+   ie->data = (void *)data;
+   idlers = (Ecore_Idler *) eina_inlist_append(EINA_INLIST_GET(idlers), 
EINA_INLIST_GET(ie));
+   return ie;
+}
+
+/**
+ * Delete an idler callback from the list to be executed.
+ * @param  idler The handle of the idler callback to delete
+ * @return The data pointer passed to the idler callback on success.  NULL
+ *         otherwise.
+ * @ingroup Idle_Group
+ */
+EAPI void *
+ecore_idler_del(Ecore_Idler *idler)
+{
+   if (!ECORE_MAGIC_CHECK(idler, ECORE_MAGIC_IDLER))
+     {
+        ECORE_MAGIC_FAIL(idler, ECORE_MAGIC_IDLER,
+                         "ecore_idler_del");
+        return NULL;
+     }
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(idler->delete_me, NULL);
+   idler->delete_me = 1;
+   idlers_delete_me = 1;
+   return idler->data;
+}
+
+void
+_ecore_idler_shutdown(void)
+{
+   Ecore_Idler *ie;
+   while ((ie = idlers))
+     {
+        idlers = (Ecore_Idler *) eina_inlist_remove(EINA_INLIST_GET(idlers), 
EINA_INLIST_GET(idlers));
+        ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
+        free(ie);
+     }
+   idlers_delete_me = 0;
+   idler_current = NULL;
+}
+
+int
+_ecore_idler_call(void)
+{
+   if (!idler_current)
+     {
+        /* regular main loop, start from head */
+        idler_current = idlers;
+     }
+   else
+     {
+        /* recursive main loop, continue from where we were */
+        idler_current = (Ecore_Idler *)EINA_INLIST_GET(idler_current)->next;
+     }
+
+   while (idler_current)
+     {
+        Ecore_Idler *ie = (Ecore_Idler *)idler_current;
+        if (!ie->delete_me)
+          {
+             ie->references++;
+             if (!ie->func(ie->data))
+               {
+                  if (!ie->delete_me) ecore_idler_del(ie);
+               }
+             ie->references--;
+          }
+        if (idler_current) /* may have changed in recursive main loops */
+          idler_current = (Ecore_Idler *)EINA_INLIST_GET(idler_current)->next;
+     }
+   if (idlers_delete_me)
+     {
+        Ecore_Idler *l;
+        int deleted_idlers_in_use = 0;
+        for (l = idlers; l;)
+          {
+             Ecore_Idler *ie = l;
+             l = (Ecore_Idler *) EINA_INLIST_GET(l)->next;
+             if (ie->delete_me)
+               {
+                  if (ie->references)
+                    {
+                       deleted_idlers_in_use++;
+                       continue;
+                    }
+
+                  idlers = (Ecore_Idler *) 
eina_inlist_remove(EINA_INLIST_GET(idlers), EINA_INLIST_GET(ie));
+                  ECORE_MAGIC_SET(ie, ECORE_MAGIC_NONE);
+                  free(ie);
+               }
+          }
+        if (!deleted_idlers_in_use)
+          idlers_delete_me = 0;
+     }
+   if (idlers) return 1;
+   return 0;
+}
+
+int
+_ecore_idler_exist(void)
+{
+   if (idlers) return 1;
+   return 0;
+}
diff --git a/tests/suite/ecore/src/lib/ecore_job.c 
b/tests/suite/ecore/src/lib/ecore_job.c
new file mode 100644
index 0000000..cd519f7
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_job.c
@@ -0,0 +1,106 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+static Eina_Bool _ecore_job_event_handler(void *data, int type, void *ev);
+static void _ecore_job_event_free(void *data, void *ev);
+
+static int ecore_event_job_type = 0;
+static Ecore_Event_Handler* _ecore_job_handler = NULL;
+
+struct _Ecore_Job
+{
+   ECORE_MAGIC;
+   Ecore_Event  *event;
+   Ecore_Cb func;
+   void         *data;
+};
+
+void
+_ecore_job_init(void)
+{
+   ecore_event_job_type = ecore_event_type_new();
+   _ecore_job_handler = ecore_event_handler_add(ecore_event_job_type, 
_ecore_job_event_handler, NULL);
+}
+
+void
+_ecore_job_shutdown(void)
+{
+   ecore_event_handler_del(_ecore_job_handler);
+   _ecore_job_handler = NULL;
+}
+
+/**
+ * Add a job to the event queue.
+ * @param   func The function to call when the job gets handled.
+ * @param   data Data pointer to be passed to the job function when the job is
+ *               handled.
+ * @return  The handle of the job.  @c NULL is returned if the job could not be
+ *          added to the queue.
+ * @ingroup Ecore_Job_Group
+ * @note    Once the job has been executed, the job handle is invalid.
+ */
+EAPI Ecore_Job *
+ecore_job_add(Ecore_Cb func, const void *data)
+{
+   Ecore_Job *job;
+   
+   if (!func) return NULL;
+
+   job = calloc(1, sizeof(Ecore_Job));
+   if (!job) return NULL;
+   ECORE_MAGIC_SET(job, ECORE_MAGIC_JOB);
+   job->event = ecore_event_add(ecore_event_job_type, job, 
_ecore_job_event_free, NULL);
+   if (!job->event)
+     {
+        free(job);
+        return NULL;
+     }
+   job->func = func;
+   job->data = (void *)data;
+   return job;
+}
+
+/**
+ * Delete a queued job that has not yet been executed.
+ * @param   job  Handle of the job to delete.
+ * @return  The data pointer that was to be passed to the job.
+ * @ingroup Ecore_Job_Group
+ */
+EAPI void *
+ecore_job_del(Ecore_Job *job)
+{
+   void *data;
+   
+   if (!ECORE_MAGIC_CHECK(job, ECORE_MAGIC_JOB))
+     {
+        ECORE_MAGIC_FAIL(job, ECORE_MAGIC_JOB,
+                         "ecore_job_del");
+        return NULL;
+     }
+   data = job->data;
+   ECORE_MAGIC_SET(job, ECORE_MAGIC_NONE);
+   ecore_event_del(job->event);
+   return data;
+}
+
+static Eina_Bool
+_ecore_job_event_handler(void *data __UNUSED__, int type __UNUSED__, void *ev)
+{
+   Ecore_Job *job;
+   
+   job = ev;
+   job->func(job->data);
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_ecore_job_event_free(void *data __UNUSED__, void *ev)
+{
+   free(ev);
+}
diff --git a/tests/suite/ecore/src/lib/ecore_main.c 
b/tests/suite/ecore/src/lib/ecore_main.c
new file mode 100644
index 0000000..de507da
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_main.c
@@ -0,0 +1,1453 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <winsock2.h>
+# undef WIN32_LEAN_AND_MEAN
+# ifndef USER_TIMER_MINIMUM
+#  define USER_TIMER_MINIMUM 0x0a
+# endif
+#endif
+
+#ifdef __SUNPRO_C
+# include <ieeefp.h>
+# include <string.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <math.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifndef _MSC_VER
+#include <sys/time.h>
+# include <unistd.h>
+#else
+# include <float.h>
+#endif
+
+#define FIX_HZ 1
+
+#ifdef FIX_HZ
+# ifndef _MSC_VER
+#  include <sys/param.h>
+# endif
+# ifndef HZ
+#  define HZ 100
+# endif
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#ifdef HAVE_SYS_EPOLL_H
+# define HAVE_EPOLL
+# include <sys/epoll.h>
+#endif
+
+#ifdef USE_G_MAIN_LOOP
+#include <glib.h>
+#endif
+
+struct _Ecore_Fd_Handler
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   int                      fd;
+   Ecore_Fd_Handler_Flags   flags;
+   Ecore_Fd_Cb              func;
+   void                    *data;
+   Ecore_Fd_Cb              buf_func;
+   void                    *buf_data;
+   Ecore_Fd_Prep_Cb         prep_func;
+   void                    *prep_data;
+   int                      references;
+   Eina_Bool                read_active : 1;
+   Eina_Bool                write_active : 1;
+   Eina_Bool                error_active : 1;
+   Eina_Bool                delete_me : 1;
+};
+
+#ifdef _WIN32
+struct _Ecore_Win32_Handler
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   HANDLE         h;
+   Ecore_Fd_Win32_Cb func;
+   void          *data;
+   int            references;
+   Eina_Bool      delete_me : 1;
+};
+#endif
+
+
+static int  _ecore_main_select(double timeout);
+static void _ecore_main_prepare_handlers(void);
+static void _ecore_main_fd_handlers_cleanup(void);
+#ifndef _WIN32
+static void _ecore_main_fd_handlers_bads_rem(void);
+#endif
+static void _ecore_main_fd_handlers_call(void);
+static int  _ecore_main_fd_handlers_buf_call(void);
+#ifndef USE_G_MAIN_LOOP
+static void _ecore_main_loop_iterate_internal(int once_only);
+#endif
+
+#ifdef _WIN32
+static int _ecore_main_win32_select(int nfds, fd_set *readfds, fd_set 
*writefds,
+                                    fd_set *exceptfds, struct timeval 
*timeout);
+static void _ecore_main_win32_handlers_cleanup(void);
+#endif
+
+static int               in_main_loop = 0;
+static int               do_quit = 0;
+static Ecore_Fd_Handler *fd_handlers = NULL;
+static Ecore_Fd_Handler *fd_handler_current = NULL;
+static int               fd_handlers_delete_me = 0;
+#ifdef _WIN32
+static Ecore_Win32_Handler *win32_handlers = NULL;
+static Ecore_Win32_Handler *win32_handler_current = NULL;
+static int                  win32_handlers_delete_me = 0;
+#endif
+
+#ifdef _WIN32
+static Ecore_Select_Function main_loop_select = _ecore_main_win32_select;
+#else
+static Ecore_Select_Function main_loop_select = select;
+#endif
+
+static double            t1 = 0.0;
+static double            t2 = 0.0;
+
+#ifdef HAVE_EPOLL
+static int epoll_fd = -1;
+#endif
+
+#ifdef USE_G_MAIN_LOOP
+static GSource *ecore_epoll_source;
+static GPollFD ecore_epoll_fd;
+static guint ecore_epoll_id;
+static GMainLoop* ecore_main_loop;
+static gboolean ecore_idling;
+static gboolean ecore_fds_ready;
+#endif
+
+#ifdef HAVE_EPOLL
+static inline int _ecore_poll_events_from_fdh(Ecore_Fd_Handler *fdh)
+{
+   int events = 0;
+   if (fdh->flags & ECORE_FD_READ)  events |= EPOLLIN;
+   if (fdh->flags & ECORE_FD_WRITE) events |= EPOLLOUT;
+   if (fdh->flags & ECORE_FD_ERROR) events |= EPOLLERR;
+   return events;
+}
+#else
+static inline int _ecore_poll_events_from_fdh(Ecore_Fd_Handler *fdh __UNUSED__)
+{
+   return 0;
+}
+#endif
+
+#ifdef HAVE_EPOLL
+static inline int _ecore_main_fdh_epoll_add(Ecore_Fd_Handler *fdh)
+{
+   int r = 0;
+   struct epoll_event ev;
+
+   memset(&ev, 0, sizeof (ev));
+   ev.events = _ecore_poll_events_from_fdh(fdh);
+   ev.data.ptr = fdh;
+   INF("adding poll on %d %08x", fdh->fd, ev.events);
+   r = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fdh->fd, &ev);
+   return r;
+}
+#else
+static inline int _ecore_main_fdh_epoll_add(Ecore_Fd_Handler *fdh __UNUSED__)
+{
+   return 0;
+}
+#endif
+
+#ifdef HAVE_EPOLL
+static inline void _ecore_main_fdh_epoll_del(Ecore_Fd_Handler *fdh)
+{
+   struct epoll_event ev;
+
+   memset(&ev, 0, sizeof (ev));
+   INF("removing poll on %d", fdh->fd);
+   /* could get an EBADF if somebody closed the FD before removing it */
+   if ((epoll_ctl(epoll_fd, EPOLL_CTL_DEL, fdh->fd, &ev) < 0) &&
+       (errno != EBADF))
+     {
+        ERR("Failed to delete epoll fd %d! (errno=%d)", fdh->fd, errno);
+     }
+}
+#else
+static inline void _ecore_main_fdh_epoll_del(Ecore_Fd_Handler *fdh __UNUSED__)
+{
+}
+#endif
+
+#ifdef HAVE_EPOLL
+static inline int _ecore_main_fdh_epoll_modify(Ecore_Fd_Handler *fdh)
+{
+   int r = 0;
+   struct epoll_event ev;
+
+   memset(&ev, 0, sizeof (ev));
+   ev.events = _ecore_poll_events_from_fdh(fdh);
+   ev.data.ptr = fdh;
+   INF("modifing epoll on %d to %08x", fdh->fd, ev.events);
+   r = epoll_ctl(epoll_fd, EPOLL_CTL_MOD, fdh->fd, &ev);
+   return r;
+}
+#else
+static inline int _ecore_main_fdh_epoll_modify(Ecore_Fd_Handler *fdh 
__UNUSED__)
+{
+   return 0;
+}
+#endif
+
+#ifdef HAVE_EPOLL
+static inline int _ecore_main_fdh_epoll_mark_active(void)
+{
+   struct epoll_event ev[32];
+   int i, ret;
+
+   memset(&ev, 0, sizeof (ev));
+   ret = epoll_wait(epoll_fd, ev, sizeof(ev) / sizeof(struct epoll_event), 0);
+   if (ret < 0)
+     {
+        if (errno == EINTR) return -1;
+        ERR("epoll_wait failed %d", errno);
+        return -1;
+     }
+
+   for (i = 0; i < ret; i++)
+     {
+        Ecore_Fd_Handler *fdh;
+        
+        fdh = ev[i].data.ptr;
+        if (!ECORE_MAGIC_CHECK(fdh, ECORE_MAGIC_FD_HANDLER))
+          {
+             ECORE_MAGIC_FAIL(fdh, ECORE_MAGIC_FD_HANDLER,
+                              "_ecore_main_fdh_epoll_mark_active");
+             continue;
+          }
+        if (fdh->delete_me)
+          {
+             ERR("deleted fd in epoll");
+             continue;
+          }
+        if (ev->events & EPOLLIN)
+          fdh->read_active = 1;
+        if (ev->events & EPOLLOUT)
+          fdh->write_active = 1;
+        if (ev->events & EPOLLERR)
+          fdh->error_active = 1;
+     }
+
+   return ret;
+}
+#endif
+
+#ifdef USE_G_MAIN_LOOP
+
+/* like we are about to enter main_loop_select in  _ecore_main_select */
+static gboolean
+_ecore_main_gsource_prepare(GSource *source, gint *next_time)
+{
+   double t = _ecore_timer_next_get();
+   gboolean running;
+
+   INF("enter, next timeout in %.1f", t);
+   in_main_loop++;
+
+   if (!ecore_idling)
+     {
+         while (_ecore_timer_call(_ecore_time_loop_time));
+          _ecore_timer_cleanup();
+
+         /* when idling, busy loop checking the fds only */
+         if (!ecore_idling) _ecore_idle_enterer_call();
+     }
+
+   /* don't check fds if somebody quit */
+   running = g_main_loop_is_running(ecore_main_loop);
+   if (running)
+     {
+        /* only set idling state in dispatch */
+        if (ecore_idling && !_ecore_idler_exist())
+          {
+             if (_ecore_timers_exists())
+               {
+                  double t = _ecore_timer_next_get();
+                  *next_time = (t / 1000.0);
+               }
+             else
+               *next_time = -1;
+          }
+        else
+          *next_time = 0;
+
+        _ecore_main_prepare_handlers();
+     }
+
+   in_main_loop--;
+   INF("leave, timeout = %d", *next_time);
+
+   /* ready if we're not running (about to quit) */
+   return !running;
+}
+
+static gboolean
+_ecore_main_gsource_check(GSource *source)
+{
+   INF("enter");
+   in_main_loop++;
+
+   ecore_fds_ready = (_ecore_main_fdh_epoll_mark_active() > 0);
+   _ecore_main_fd_handlers_cleanup();
+
+   _ecore_time_loop_time = ecore_time_get();
+   _ecore_timer_enable_new();
+
+   in_main_loop--;
+   INF("leave");
+
+   return TRUE; /* always dispatch */
+}
+
+/* like we just came out of main_loop_select in  _ecore_main_select */
+static gboolean
+_ecore_main_gsource_dispatch(GSource *source, GSourceFunc callback, gpointer 
user_data)
+{
+   gboolean events_ready, timers_ready, idlers_ready, signals_ready;
+   double next_time = _ecore_timer_next_get();
+
+   events_ready = _ecore_event_exist();
+   timers_ready = _ecore_timers_exists() && (0.0 <= next_time);
+   idlers_ready = _ecore_idler_exist();
+   signals_ready = (_ecore_signal_count_get() > 0);
+
+   in_main_loop++;
+   INF("enter idling=%d fds=%d events=%d signals=%d timers=%d (next=%.2f) 
idlers=%d",
+       ecore_idling, ecore_fds_ready, events_ready, signals_ready,
+       _ecore_timers_exists(), next_time, idlers_ready);
+
+   if (ecore_idling && events_ready)
+     {
+        INF("calling idle exiters");
+        _ecore_idle_exiter_call();
+        ecore_idling = 0;
+     }
+   else if (!ecore_idling && !events_ready)
+     {
+        INF("start idling");
+        ecore_idling = 1;
+     }
+
+   if (ecore_idling)
+     {
+        INF("calling idler");
+        _ecore_idler_call();
+
+        events_ready = _ecore_event_exist();
+        timers_ready = _ecore_timers_exists() && (0.0 <= next_time);
+        idlers_ready = _ecore_idler_exist();
+
+        if ((ecore_fds_ready || events_ready || timers_ready || idlers_ready 
|| signals_ready))
+          {
+             INF("calling idle exiters");
+             _ecore_idle_exiter_call();
+             ecore_idling = 0;
+          }
+     }
+
+   /* process events */
+   if (!ecore_idling)
+     {
+        INF("work");
+        _ecore_main_fd_handlers_call();
+        _ecore_main_fd_handlers_buf_call();
+        while (_ecore_signal_count_get()) _ecore_signal_call();
+        _ecore_event_call();
+        _ecore_main_fd_handlers_cleanup();
+     }
+
+   in_main_loop--;
+
+   INF("leave");
+
+   return TRUE; /* what should be returned here? */
+}
+
+static void
+_ecore_main_gsource_finalize(GSource *source)
+{
+   INF("finalize");
+}
+
+static GSourceFuncs ecore_gsource_funcs =
+{
+   .prepare  = _ecore_main_gsource_prepare,
+   .check    = _ecore_main_gsource_check,
+   .dispatch = _ecore_main_gsource_dispatch,
+   .finalize = _ecore_main_gsource_finalize,
+};
+
+#endif
+
+void
+_ecore_main_loop_init(void)
+{
+   INF("enter");
+#ifdef HAVE_EPOLL
+   epoll_fd = epoll_create(1);
+   if (epoll_fd < 0)
+      CRIT("Failed to create epoll fd!");
+#endif
+
+#ifdef USE_G_MAIN_LOOP
+   ecore_epoll_source = g_source_new(&ecore_gsource_funcs, sizeof (GSource));
+   if (!ecore_epoll_source)
+      CRIT("Failed to create glib source for epoll!");
+   else
+     {
+        ecore_epoll_fd.fd = epoll_fd;
+        ecore_epoll_fd.events = G_IO_IN;
+        ecore_epoll_fd.revents = 0;
+        g_source_add_poll(ecore_epoll_source, &ecore_epoll_fd);
+        ecore_epoll_id = g_source_attach(ecore_epoll_source, NULL);
+        if (ecore_epoll_id <= 0)
+           CRIT("Failed to attach glib source to default context");
+     }
+#endif
+   INF("leave");
+}
+
+void
+_ecore_main_loop_shutdown(void)
+{
+#ifdef USE_G_MAIN_LOOP
+   if (ecore_epoll_source)
+     {
+        g_source_destroy(ecore_epoll_source);
+        ecore_epoll_source = NULL;
+     }
+#endif
+
+#ifdef HAVE_EPOLL
+   if (epoll_fd >= 0)
+     {
+        close(epoll_fd);
+        epoll_fd = -1;
+     }
+#endif
+}
+
+
+/**
+ * @defgroup Ecore_Main_Loop_Group Main Loop Functions
+ *
+ * These functions control the Ecore event handling loop.  This loop is
+ * designed to work on embedded systems all the way to large and
+ * powerful mutli-cpu workstations.
+ *
+ * It serialises all system signals and events into a single event
+ * queue, that can be easily processed without needing to worry about
+ * concurrency.  A properly written, event-driven program using this
+ * kind of programming does not need threads.  It makes the program very
+ * robust and easy to follow.
+ *
+ * Here is an example of simple program and its basic event loop flow:
+ * @image html prog_flow.png
+ *
+ * For examples of setting up and using a main loop, see
+ * @ref event_handler_example.c and @ref timer_example.c.
+ */
+
+/**
+ * Runs a single iteration of the main loop to process everything on the
+ * queue.
+ * @ingroup Ecore_Main_Loop_Group
+ */
+EAPI void
+ecore_main_loop_iterate(void)
+{
+#ifndef USE_G_MAIN_LOOP
+   _ecore_main_loop_iterate_internal(1);
+#else
+    g_main_context_iteration(NULL, 1);
+#endif
+}
+
+/**
+ * Runs the application main loop.
+ *
+ * This function will not return until @ref ecore_main_loop_quit is called.
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ */
+EAPI void
+ecore_main_loop_begin(void)
+{
+#ifndef USE_G_MAIN_LOOP
+   in_main_loop++;
+   while (do_quit == 0) _ecore_main_loop_iterate_internal(0);
+   do_quit = 0;
+   in_main_loop--;
+#else
+   ecore_main_loop = g_main_loop_new(NULL, FALSE);
+   g_main_loop_run(ecore_main_loop);
+#endif
+}
+
+/**
+ * Quits the main loop once all the events currently on the queue have
+ * been processed.
+ * @ingroup Ecore_Main_Loop_Group
+ */
+EAPI void
+ecore_main_loop_quit(void)
+{
+#ifndef USE_G_MAIN_LOOP
+   do_quit = 1;
+#else
+   INF("enter");
+   g_main_loop_quit(ecore_main_loop);
+   INF("leave");
+#endif
+}
+
+/**
+ * Sets the function to use when monitoring multiple file descriptors,
+ * and waiting until one of more of the file descriptors before ready
+ * for some class of I/O operation.
+ *
+ * This function will be used instead of the system call select and
+ * could possible be used to integrate the Ecore event loop with an
+ * external event loop.
+ *
+ * @warning you don't know how to use, don't even try to use it.
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ */
+EAPI void
+ecore_main_loop_select_func_set(Ecore_Select_Function func)
+{
+   main_loop_select = func;
+}
+
+/**
+ * Gets the select function set by ecore_select_func_set(),
+ * or the native select function if none was set.
+ *
+ * @ingroup Ecore_Main_Loop_Group
+ */
+EAPI void *
+ecore_main_loop_select_func_get(void)
+{
+   return main_loop_select;
+}
+
+/**
+ * @defgroup Ecore_FD_Handler_Group File Event Handling Functions
+ *
+ * Functions that deal with file descriptor handlers.
+ */
+
+/**
+ * Adds a callback for activity on the given file descriptor.
+ *
+ * @p func will be called during the execution of @ref ecore_main_loop_begin
+ * when the file descriptor is available for reading, or writing, or both.
+ *
+ * Normally the return value from the @p func is "zero means this handler is
+ * finished and can be deleted" as is usual for handler callbacks.  However,
+ * if the @p buf_func is supplied, then the return value from the @p func is
+ * "non zero means the handler should be called again in a tight loop".
+ *
+ * @p buf_func is called during event loop handling to check if data that has
+ * been read from the file descriptor is in a buffer and is available to
+ * read.  Some systems (notably xlib) handle their own buffering, and would
+ * otherwise not work with select().  These systems should use a @p buf_func.
+ * This is a most annoying hack, only ecore_x uses it, so refer to that for
+ * an example.  NOTE - @p func should probably return "one" always if
+ * @p buf_func is used, to avoid confusion with the other return value
+ * semantics.
+ *
+ * @param   fd       The file descriptor to watch.
+ * @param   flags    To watch it for read (@c ECORE_FD_READ) and/or
+ *                   (@c ECORE_FD_WRITE) write ability.  @c ECORE_FD_ERROR
+ *
+ * @param   func     The callback function.
+ * @param   data     The data to pass to the callback.
+ * @param   buf_func The function to call to check if any data has been
+ *                   buffered and already read from the fd.  Can be @c NULL.
+ * @param   buf_data The data to pass to the @p buf_func function.
+ * @return  A fd handler handle if successful.  @c NULL otherwise.
+ * @ingroup Ecore_FD_Handler_Group
+ */
+EAPI Ecore_Fd_Handler *
+ecore_main_fd_handler_add(int fd, Ecore_Fd_Handler_Flags flags, Ecore_Fd_Cb 
func, const void *data,
+                          Ecore_Fd_Cb buf_func, const void *buf_data)
+{
+   Ecore_Fd_Handler *fdh;
+
+   if ((fd < 0) || (flags == 0) || (!func)) return NULL;
+
+   fdh = calloc(1, sizeof(Ecore_Fd_Handler));
+   if (!fdh) return NULL;
+   ECORE_MAGIC_SET(fdh, ECORE_MAGIC_FD_HANDLER);
+   fdh->fd = fd;
+   fdh->flags = flags;
+   if (0 > _ecore_main_fdh_epoll_add(fdh))
+     {
+        ERR("Failed to add epoll fd %d (errno = %d)!", fd, errno);
+        free(fdh);
+        return NULL;
+     }
+   fdh->read_active = 0;
+   fdh->write_active = 0;
+   fdh->error_active = 0;
+   fdh->delete_me = 0;
+   fdh->func = func;
+   fdh->data = (void *)data;
+   fdh->buf_func = buf_func;
+   fdh->buf_data = (void *)buf_data;
+   fd_handlers = (Ecore_Fd_Handler *)
+     eina_inlist_append(EINA_INLIST_GET(fd_handlers),
+                        EINA_INLIST_GET(fdh));
+   return fdh;
+}
+
+#ifdef _WIN32
+EAPI Ecore_Win32_Handler *
+ecore_main_win32_handler_add(void *h, Ecore_Fd_Win32_Cb func, const void *data)
+{
+   Ecore_Win32_Handler *wh;
+
+   if (!h || !func) return NULL;
+
+   wh = calloc(1, sizeof(Ecore_Win32_Handler));
+   if (!wh) return NULL;
+   ECORE_MAGIC_SET(wh, ECORE_MAGIC_WIN32_HANDLER);
+   wh->h = (HANDLE)h;
+   wh->delete_me = 0;
+   wh->func = func;
+   wh->data = (void *)data;
+   win32_handlers = (Ecore_Win32_Handler *)
+     eina_inlist_append(EINA_INLIST_GET(win32_handlers),
+                        EINA_INLIST_GET(wh));
+   return wh;
+}
+#else
+EAPI Ecore_Win32_Handler *
+ecore_main_win32_handler_add(void *h __UNUSED__, Ecore_Fd_Win32_Cb func 
__UNUSED__,
+                             const void *data __UNUSED__)
+{
+   return NULL;
+}
+#endif
+
+/**
+ * Deletes the given FD handler.
+ * @param   fd_handler The given FD handler.
+ * @return  The data pointer set using @ref ecore_main_fd_handler_add,
+ *          for @p fd_handler on success.  @c NULL otherwise.
+ * @ingroup Ecore_FD_Handler_Group
+ *
+ * Beware that if the fd is already closed, ecore may complain if it uses
+ * epoll internally, and that in some rare cases this may be able to cause
+ * crashes and instability. Remember to delete your fd handlers before the
+ * fd's they listen to are closed.
+ */
+EAPI void *
+ecore_main_fd_handler_del(Ecore_Fd_Handler *fd_handler)
+{
+   if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+     {
+        ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+                         "ecore_main_fd_handler_del");
+        return NULL;
+     }
+   fd_handler->delete_me = 1;
+   fd_handlers_delete_me = 1;
+   _ecore_main_fdh_epoll_del(fd_handler);
+   return fd_handler->data;
+}
+
+#ifdef _WIN32
+EAPI void *
+ecore_main_win32_handler_del(Ecore_Win32_Handler *win32_handler)
+{
+   if (!ECORE_MAGIC_CHECK(win32_handler, ECORE_MAGIC_WIN32_HANDLER))
+     {
+        ECORE_MAGIC_FAIL(win32_handler, ECORE_MAGIC_WIN32_HANDLER,
+                         "ecore_main_win32_handler_del");
+        return NULL;
+     }
+   win32_handler->delete_me = 1;
+   win32_handlers_delete_me = 1;
+   return win32_handler->data;
+}
+#else
+EAPI void *
+ecore_main_win32_handler_del(Ecore_Win32_Handler *win32_handler __UNUSED__)
+{
+   return NULL;
+}
+#endif
+
+EAPI void
+ecore_main_fd_handler_prepare_callback_set(Ecore_Fd_Handler *fd_handler, 
Ecore_Fd_Prep_Cb func, const void *data)
+{
+   if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+     {
+        ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+                         "ecore_main_fd_handler_prepare_callback_set");
+        return;
+     }
+   fd_handler->prep_func = func;
+   fd_handler->prep_data = (void *) data;
+}
+
+/**
+ * Retrieves the file descriptor that the given handler is handling.
+ * @param   fd_handler The given FD handler.
+ * @return  The file descriptor the handler is watching.
+ * @ingroup Ecore_FD_Handler_Group
+ */
+EAPI int
+ecore_main_fd_handler_fd_get(Ecore_Fd_Handler *fd_handler)
+{
+   if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+     {
+        ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+                         "ecore_main_fd_handler_fd_get");
+        return -1;
+     }
+   return fd_handler->fd;
+}
+
+/**
+ * Return if read, write or error, or a combination thereof, is active on the
+ * file descriptor of the given FD handler.
+ * @param   fd_handler The given FD handler.
+ * @param   flags      The flags, @c ECORE_FD_READ, @c ECORE_FD_WRITE or
+ *                     @c ECORE_FD_ERROR to query.
+ * @return  #EINA_TRUE if any of the given flags are active. #EINA_FALSE 
otherwise.
+ * @ingroup Ecore_FD_Handler_Group
+ */
+EAPI Eina_Bool
+ecore_main_fd_handler_active_get(Ecore_Fd_Handler *fd_handler, 
Ecore_Fd_Handler_Flags flags)
+{
+   int ret = EINA_FALSE;
+
+   if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+     {
+        ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+                         "ecore_main_fd_handler_active_get");
+        return EINA_FALSE;
+     }
+   if ((flags & ECORE_FD_READ) && (fd_handler->read_active)) ret = EINA_TRUE;
+   if ((flags & ECORE_FD_WRITE) && (fd_handler->write_active)) ret = EINA_TRUE;
+   if ((flags & ECORE_FD_ERROR) && (fd_handler->error_active)) ret = EINA_TRUE;
+   return ret;
+}
+
+/**
+ * Set what active streams the given FD handler should be monitoring.
+ * @param   fd_handler The given FD handler.
+ * @param   flags      The flags to be watching.
+ * @ingroup Ecore_FD_Handler_Group
+ */
+EAPI void
+ecore_main_fd_handler_active_set(Ecore_Fd_Handler *fd_handler, 
Ecore_Fd_Handler_Flags flags)
+{
+   if (!ECORE_MAGIC_CHECK(fd_handler, ECORE_MAGIC_FD_HANDLER))
+     {
+        ECORE_MAGIC_FAIL(fd_handler, ECORE_MAGIC_FD_HANDLER,
+                         "ecore_main_fd_handler_active_set");
+        return;
+     }
+   fd_handler->flags = flags;
+   if (0 > _ecore_main_fdh_epoll_modify(fd_handler))
+     {
+       ERR("Failed to mod epoll fd %d!", fd_handler->fd);
+     }
+}
+
+void
+_ecore_main_shutdown(void)
+{
+   if (in_main_loop)
+     {
+       ERR("\n"
+           "*** ECORE WARINING: Calling ecore_shutdown() while still in the 
main loop.\n"
+           "***                 Program may crash or behave strangely now.");
+        return;
+     }
+   while (fd_handlers)
+     {
+        Ecore_Fd_Handler *fdh;
+
+        fdh = fd_handlers;
+        fd_handlers = (Ecore_Fd_Handler *) 
eina_inlist_remove(EINA_INLIST_GET(fd_handlers),
+                                                              
EINA_INLIST_GET(fdh));
+        ECORE_MAGIC_SET(fdh, ECORE_MAGIC_NONE);
+        free(fdh);
+     }
+   fd_handlers_delete_me = 0;
+   fd_handler_current = NULL;
+
+#ifdef _WIN32
+   while (win32_handlers)
+     {
+        Ecore_Win32_Handler *wh;
+
+        wh = win32_handlers;
+        win32_handlers = (Ecore_Win32_Handler *) 
eina_inlist_remove(EINA_INLIST_GET(win32_handlers),
+                                                                    
EINA_INLIST_GET(wh));
+        ECORE_MAGIC_SET(wh, ECORE_MAGIC_NONE);
+        free(wh);
+     }
+   win32_handlers_delete_me = 0;
+   win32_handler_current = NULL;
+#endif
+}
+
+static void
+_ecore_main_prepare_handlers(void)
+{
+   Ecore_Fd_Handler *fdh;
+
+   /* call the prepare callback for all handlers */
+   EINA_INLIST_FOREACH(fd_handlers, fdh)
+     {
+        if (!fdh->delete_me && fdh->prep_func)
+          {
+             fdh->references++;
+             fdh->prep_func (fdh->prep_data, fdh);
+             fdh->references--;
+          }
+     }
+}
+
+static int
+_ecore_main_select(double timeout)
+{
+   struct timeval tv, *t;
+   fd_set         rfds, wfds, exfds;
+   int            max_fd;
+   int            ret;
+
+   t = NULL;
+   if ((!finite(timeout)) || (timeout == 0.0)) /* finite() tests for NaN, too 
big, too small, and infinity.  */
+     {
+        tv.tv_sec = 0;
+        tv.tv_usec = 0;
+        t = &tv;
+     }
+   else if (timeout > 0.0)
+     {
+        int sec, usec;
+
+#ifdef FIX_HZ
+        timeout += (0.5 / HZ);
+        sec = (int)timeout;
+        usec = (int)((timeout - (double)sec) * 1000000);
+#else
+        sec = (int)timeout;
+        usec = (int)((timeout - (double)sec) * 1000000);
+#endif
+        tv.tv_sec = sec;
+        tv.tv_usec = usec;
+        t = &tv;
+     }
+   max_fd = 0;
+   FD_ZERO(&rfds);
+   FD_ZERO(&wfds);
+   FD_ZERO(&exfds);
+
+   /* call the prepare callback for all handlers */
+   _ecore_main_prepare_handlers();
+#ifndef HAVE_EPOLL
+   Ecore_Fd_Handler *fdh;
+
+   EINA_INLIST_FOREACH(fd_handlers, fdh)
+     {
+        if (!fdh->delete_me)
+          {
+             if (fdh->flags & ECORE_FD_READ)
+               {
+                  FD_SET(fdh->fd, &rfds);
+                  if (fdh->fd > max_fd) max_fd = fdh->fd;
+               }
+             if (fdh->flags & ECORE_FD_WRITE)
+               {
+                  FD_SET(fdh->fd, &wfds);
+                  if (fdh->fd > max_fd) max_fd = fdh->fd;
+               }
+             if (fdh->flags & ECORE_FD_ERROR)
+               {
+                  FD_SET(fdh->fd, &exfds);
+                  if (fdh->fd > max_fd) max_fd = fdh->fd;
+               }
+          }
+     }
+#else /* HAVE_EPOLL */
+   /* polling on the epoll fd will wake when an fd in the epoll set is active 
*/
+   FD_SET(epoll_fd, &rfds);
+   max_fd = epoll_fd;
+#endif /* HAVE_EPOLL */
+
+   if (_ecore_signal_count_get()) return -1;
+
+   ret = main_loop_select(max_fd + 1, &rfds, &wfds, &exfds, t);
+
+   _ecore_time_loop_time = ecore_time_get();
+   if (ret < 0)
+     {
+#ifndef _WIN32
+        if (errno == EINTR) return -1;
+        else if (errno == EBADF) _ecore_main_fd_handlers_bads_rem();
+#endif
+     }
+   if (ret > 0)
+     {
+#ifdef HAVE_EPOLL
+        _ecore_main_fdh_epoll_mark_active();
+#else /* HAVE_EPOLL */
+        Ecore_Fd_Handler *fdh;
+
+        EINA_INLIST_FOREACH(fd_handlers, fdh)
+          {
+             if (!fdh->delete_me)
+               {
+                  if (FD_ISSET(fdh->fd, &rfds))
+                     fdh->read_active = 1;
+                  if (FD_ISSET(fdh->fd, &wfds))
+                     fdh->write_active = 1;
+                  if (FD_ISSET(fdh->fd, &exfds))
+                     fdh->error_active = 1;
+               }
+          }
+#endif /* HAVE_EPOLL */
+        _ecore_main_fd_handlers_cleanup();
+#ifdef _WIN32
+        _ecore_main_win32_handlers_cleanup();
+#endif
+        return 1;
+     }
+   return 0;
+}
+
+#ifndef _WIN32
+static void
+_ecore_main_fd_handlers_bads_rem(void)
+{
+   Ecore_Fd_Handler *fdh;
+   Eina_Inlist *l;
+   int found = 0;
+
+   ERR("Removing bad fds");
+   for (l = EINA_INLIST_GET(fd_handlers); l; )
+     {
+        fdh = (Ecore_Fd_Handler *) l;
+        l = l->next;
+        errno = 0;
+
+        if ((fcntl(fdh->fd, F_GETFD) < 0) && (errno == EBADF))
+          {
+             ERR("Found bad fd at index %d", fdh->fd);
+             if (fdh->flags & ECORE_FD_ERROR)
+               {
+                  ERR("Fd set for error! calling user");
+                  fdh->references++;
+                  if (!fdh->func(fdh->data, fdh))
+                    {
+                       ERR("Fd function err returned 0, remove it");
+                       fdh->delete_me = 1;
+                       fd_handlers_delete_me = 1;
+                       found++;
+                    }
+                  fdh->references--;
+               }
+             else
+               {
+                  ERR("Problematic fd found at %d! setting it for delete", 
fdh->fd);
+                  fdh->delete_me = 1;
+                  fd_handlers_delete_me = 1;
+                  found++;
+               }
+          }
+    }
+   if (found == 0)
+     {
+#ifdef HAVE_GLIB
+        ERR("No bad fd found. Maybe a foreign fd from glib?");
+#else        
+        ERR("No bad fd found. EEEK!");
+#endif        
+     }
+   _ecore_main_fd_handlers_cleanup();
+}
+#endif
+
+static void
+_ecore_main_fd_handlers_cleanup(void)
+{
+   Ecore_Fd_Handler *fdh;
+   Eina_Inlist *l;
+   int deleted_in_use = 0;
+
+   if (!fd_handlers_delete_me) return;
+   for (l = EINA_INLIST_GET(fd_handlers); l; )
+     {
+        fdh = (Ecore_Fd_Handler *) l;
+
+        l = l->next;
+        if (fdh->delete_me)
+          {
+             if (fdh->references)
+               {
+                  deleted_in_use++;
+                  continue;
+               }
+             
+             fd_handlers = (Ecore_Fd_Handler *)
+                eina_inlist_remove(EINA_INLIST_GET(fd_handlers),
+                                   EINA_INLIST_GET(fdh));
+             ECORE_MAGIC_SET(fdh, ECORE_MAGIC_NONE);
+             free(fdh);
+          }
+     }
+   if (!deleted_in_use) fd_handlers_delete_me = 0;
+}
+
+#ifdef _WIN32
+static void
+_ecore_main_win32_handlers_cleanup(void)
+{
+   Ecore_Win32_Handler *wh;
+   Eina_Inlist *l;
+   int deleted_in_use = 0;
+
+   if (!win32_handlers_delete_me) return;
+   for (l = EINA_INLIST_GET(win32_handlers); l; )
+     {
+        wh = (Ecore_Win32_Handler *)l;
+
+        l = l->next;
+        if (wh->delete_me)
+          {
+             if (wh->references)
+               {
+                  deleted_in_use++;
+                  continue;
+               }
+             
+             win32_handlers = (Ecore_Win32_Handler *)
+                eina_inlist_remove(EINA_INLIST_GET(win32_handlers),
+                                   EINA_INLIST_GET(wh));
+             ECORE_MAGIC_SET(wh, ECORE_MAGIC_NONE);
+             free(wh);
+          }
+     }
+   if (!deleted_in_use) win32_handlers_delete_me = 0;
+}
+#endif
+
+static void
+_ecore_main_fd_handlers_call(void)
+{
+   if (!fd_handler_current)
+     {
+        /* regular main loop, start from head */
+        fd_handler_current = fd_handlers;
+     }
+   else
+     {
+        /* recursive main loop, continue from where we were */
+        fd_handler_current = (Ecore_Fd_Handler 
*)EINA_INLIST_GET(fd_handler_current)->next;
+     }
+
+   while (fd_handler_current)
+     {
+        Ecore_Fd_Handler *fdh = fd_handler_current;
+
+        if (!fdh->delete_me)
+          {
+             if ((fdh->read_active) ||
+                 (fdh->write_active) ||
+                 (fdh->error_active))
+               {
+                  fdh->references++;
+                  if (!fdh->func(fdh->data, fdh))
+                    {
+                       fdh->delete_me = 1;
+                       fd_handlers_delete_me = 1;
+                    }
+                  fdh->references--;
+
+                  fdh->read_active = 0;
+                  fdh->write_active = 0;
+                  fdh->error_active = 0;
+               }
+          }
+
+        if (fd_handler_current) /* may have changed in recursive main loops */
+          fd_handler_current = (Ecore_Fd_Handler 
*)EINA_INLIST_GET(fd_handler_current)->next;
+     }
+}
+
+static int
+_ecore_main_fd_handlers_buf_call(void)
+{
+   Ecore_Fd_Handler *fdh;
+   int ret;
+
+   ret = 0;
+   EINA_INLIST_FOREACH(fd_handlers, fdh)
+     {
+        if (!fdh->delete_me)
+          {
+             if (fdh->buf_func)
+               {
+                  fdh->references++;
+                  if (fdh->buf_func(fdh->buf_data, fdh))
+                    {
+                       ret |= fdh->func(fdh->data, fdh);
+                       fdh->read_active = 1;
+                    }
+                  fdh->references--;
+               }
+          }
+     }
+   return ret;
+}
+
+#ifndef USE_G_MAIN_LOOP
+static void
+_ecore_main_loop_iterate_internal(int once_only)
+{
+   double next_time = -1.0;
+   int    have_event = 0;
+   int    have_signal;
+
+   in_main_loop++;
+   /* expire any timers */
+   while (_ecore_timer_call(_ecore_time_loop_time));
+   _ecore_timer_cleanup();
+
+   /* process signals into events .... */
+   while (_ecore_signal_count_get()) _ecore_signal_call();
+   if (_ecore_event_exist())
+     {
+        _ecore_idle_enterer_call();
+        have_event = 1;
+        _ecore_main_select(0.0);
+        _ecore_time_loop_time = ecore_time_get();
+        _ecore_timer_enable_new();
+        goto process_events;
+     }
+   /* call idle enterers ... */
+   if (!once_only) _ecore_idle_enterer_call();
+   else
+     {
+        have_event = have_signal = 0;
+
+        if (_ecore_main_select(0.0) > 0) have_event = 1;
+        if (_ecore_signal_count_get() > 0) have_signal = 1;
+        if (have_signal || have_event)
+          {
+             _ecore_time_loop_time = ecore_time_get();
+             _ecore_timer_enable_new();
+             goto process_events;
+          }
+     }
+
+   /* if these calls caused any buffered events to appear - deal with them */
+   _ecore_main_fd_handlers_buf_call();
+
+   /* if there are any - jump to processing them */
+   if (_ecore_event_exist())
+     {
+        have_event = 1;
+        _ecore_main_select(0.0);
+        _ecore_time_loop_time = ecore_time_get();
+        _ecore_timer_enable_new();
+        goto process_events;
+     }
+   if (once_only)
+     {
+        _ecore_idle_enterer_call();
+        in_main_loop--;
+        _ecore_time_loop_time = ecore_time_get();
+        _ecore_timer_enable_new();
+        return;
+     }
+
+   if (_ecore_fps_debug)
+     {
+        t2 = ecore_time_get();
+        if ((t1 > 0.0) && (t2 > 0.0))
+          _ecore_fps_debug_runtime_add(t2 - t1);
+     }
+   start_loop:
+   /* any timers re-added as a result of these are allowed to go */
+   _ecore_timer_enable_new();
+   if (do_quit)
+     {
+        _ecore_time_loop_time = ecore_time_get();
+        in_main_loop--;
+        _ecore_timer_enable_new();
+        return;
+     }
+   if (!_ecore_event_exist())
+     {
+        /* init flags */
+        have_event = have_signal = 0;
+        next_time = _ecore_timer_next_get();
+        /* no timers */
+        if (next_time < 0)
+          {
+             /* no idlers */
+             if (!_ecore_idler_exist())
+               {
+                  if (_ecore_main_select(-1.0) > 0) have_event = 1;
+               }
+             /* idlers */
+             else
+               {
+                  for (;;)
+                    {
+                       if (!_ecore_idler_call()) goto start_loop;
+                       if (_ecore_event_exist()) break;
+                       if (_ecore_main_select(0.0) > 0) have_event = 1;
+                       if (_ecore_signal_count_get() > 0) have_signal = 1;
+                       if (have_event || have_signal) break;
+                       if (_ecore_timers_exists()) goto start_loop;
+                       if (do_quit) break;
+                    }
+               }
+          }
+        /* timers */
+        else
+          {
+             /* no idlers */
+             if (!_ecore_idler_exist())
+               {
+                  if (_ecore_main_select(next_time) > 0) have_event = 1;
+               }
+             /* idlers */
+             else
+               {
+                  for (;;)
+                    {
+                       if (!_ecore_idler_call()) goto start_loop;
+                       if (_ecore_event_exist()) break;
+                       if (_ecore_main_select(0.0) > 0) have_event = 1;
+                       if (_ecore_signal_count_get() > 0) have_signal = 1;
+                       if (have_event || have_signal) break;
+                       next_time = _ecore_timer_next_get();
+                       if (next_time <= 0) break;
+                       if (do_quit) break;
+                    }
+               }
+          }
+        _ecore_time_loop_time = ecore_time_get();
+     }
+   if (_ecore_fps_debug) t1 = ecore_time_get();
+   /* we came out of our "wait state" so idle has exited */
+   if (!once_only) _ecore_idle_exiter_call();
+   /* call the fd handler per fd that became alive... */
+   /* this should read or write any data to the monitored fd and then */
+   /* post events onto the ecore event pipe if necessary */
+   process_events:
+   _ecore_main_fd_handlers_call();
+   _ecore_main_fd_handlers_buf_call();
+   /* process signals into events .... */
+   while (_ecore_signal_count_get()) _ecore_signal_call();
+   /* handle events ... */
+   _ecore_event_call();
+   _ecore_main_fd_handlers_cleanup();
+
+   if (once_only) _ecore_idle_enterer_call();
+   in_main_loop--;
+}
+#endif
+
+#ifdef _WIN32
+static int
+_ecore_main_win32_select(int nfds __UNUSED__, fd_set *readfds, fd_set 
*writefds,
+                         fd_set *exceptfds, struct timeval *tv)
+{
+   HANDLE       objects[MAXIMUM_WAIT_OBJECTS];
+   int          sockets[MAXIMUM_WAIT_OBJECTS];
+   Ecore_Fd_Handler *fdh;
+   Ecore_Win32_Handler *wh;
+   unsigned int objects_nbr = 0;
+   unsigned int handles_nbr = 0;
+   unsigned int events_nbr = 0;
+   DWORD        result;
+   DWORD        timeout;
+   MSG          msg;
+   unsigned int i;
+   int          res;
+
+   /* Create an event object per socket */
+   EINA_INLIST_FOREACH(fd_handlers, fdh)
+     {
+        WSAEVENT event;
+        long network_event;
+
+        network_event = 0;
+        if (FD_ISSET(fdh->fd, readfds))
+          network_event |= FD_READ;
+        if (FD_ISSET(fdh->fd, writefds))
+          network_event |= FD_WRITE;
+        if (FD_ISSET(fdh->fd, exceptfds))
+          network_event |= FD_OOB;
+
+        if (network_event)
+          {
+             event = WSACreateEvent();
+             WSAEventSelect(fdh->fd, event, network_event);
+             objects[objects_nbr] = event;
+             sockets[events_nbr] = fdh->fd;
+             events_nbr++;
+             objects_nbr++;
+          }
+     }
+
+   /* store the HANDLEs in the objects to wait for */
+   EINA_INLIST_FOREACH(win32_handlers, wh)
+     {
+        objects[objects_nbr] = wh->h;
+        handles_nbr++;
+        objects_nbr++;
+     }
+
+   /* Empty the queue before waiting */
+   while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+     {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+     }
+
+   /* Wait for any message sent or posted to this queue */
+   /* or for one of the passed handles be set to signaled. */
+   if (!tv)
+     timeout = INFINITE;
+   else
+     timeout = (DWORD)((tv->tv_sec * 1000.0) + (tv->tv_usec / 1000.0));
+
+   if (timeout == 0) return 0;
+
+   result = MsgWaitForMultipleObjects(objects_nbr, (const HANDLE *)objects, 
EINA_FALSE,
+                                      timeout, QS_ALLINPUT);
+
+   FD_ZERO(readfds);
+   FD_ZERO(writefds);
+   FD_ZERO(exceptfds);
+
+   /* The result tells us the type of event we have. */
+   if (result == WAIT_FAILED)
+     {
+        char *msg;
+
+        msg = evil_last_error_get();
+        ERR(" * %s\n", msg);
+        free(msg);
+        res = -1;
+     }
+   else if (result == WAIT_TIMEOUT)
+     {
+        /* ERR("time out\n"); */
+        res = 0;
+     }
+   else if (result == (WAIT_OBJECT_0 + objects_nbr))
+     {
+        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+          {
+             TranslateMessage(&msg);
+             DispatchMessage(&msg);
+          }
+
+        res = 0;
+     }
+   else if ((result >= 0) && (result < WAIT_OBJECT_0 + events_nbr))
+     {
+        WSANETWORKEVENTS network_event;
+
+        WSAEnumNetworkEvents(sockets[result], objects[result], &network_event);
+
+        if (network_event.lNetworkEvents & FD_READ)
+          FD_SET(sockets[result], readfds);
+        if (network_event.lNetworkEvents & FD_WRITE)
+          FD_SET(sockets[result], writefds);
+        if (network_event.lNetworkEvents & FD_OOB)
+          FD_SET(sockets[result], exceptfds);
+
+        res = 1;
+     }
+   else if ((result >= (WAIT_OBJECT_0 + events_nbr)) && 
+            (result < (WAIT_OBJECT_0 + objects_nbr)))
+     {
+        if (!win32_handler_current)
+          {
+             /* regular main loop, start from head */
+             win32_handler_current = win32_handlers;
+          }
+        else
+          {
+             /* recursive main loop, continue from where we were */
+             win32_handler_current = (Ecore_Win32_Handler 
*)EINA_INLIST_GET(win32_handler_current)->next;
+          }
+
+        while (win32_handler_current)
+          {
+             wh = win32_handler_current;
+
+             if (objects[result - WAIT_OBJECT_0] == wh->h)
+               {
+                  if (!wh->delete_me)
+                    {
+                       wh->references++;
+                       if (!wh->func(wh->data, wh))
+                         {
+                            wh->delete_me = 1;
+                            win32_handlers_delete_me = 1;
+                         }
+                       wh->references--;
+                    }
+               }
+             if (win32_handler_current) /* may have changed in recursive main 
loops */
+               win32_handler_current = (Ecore_Win32_Handler 
*)EINA_INLIST_GET(win32_handler_current)->next;
+          }
+        res = 1;
+     }
+   else
+     {
+        ERR("unknown result...\n");
+        res = -1;
+     }
+
+   /* Remove event objects again */
+   for (i = 0; i < events_nbr; i++) WSACloseEvent(objects[i]);
+
+   return res;
+}
+#endif
diff --git a/tests/suite/ecore/src/lib/ecore_pipe.c 
b/tests/suite/ecore/src/lib/ecore_pipe.c
new file mode 100644
index 0000000..8a8aca5
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_pipe.c
@@ -0,0 +1,595 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+/* How of then we should retry to write to the pipe */
+#define ECORE_PIPE_WRITE_RETRY 6
+
+/*
+ * On Windows, pipe() is implemented with sockets.
+ * Contrary to Linux, Windows uses different functions
+ * for sockets and fd's: write() is for fd's and send
+ * is for sockets. So I need to put some win32 code
+ * here. I can't think of a solution where the win32
+ * code is in Evil and not here.
+ */
+
+#ifdef _WIN32
+
+# include <winsock2.h>
+
+# define pipe_write(fd, buffer, size) send((fd), (char *)(buffer), size, 0)
+# define pipe_read(fd, buffer, size)  recv((fd), (char *)(buffer), size, 0)
+# define pipe_close(fd)               closesocket(fd)
+# define PIPE_FD_INVALID              INVALID_SOCKET
+# define PIPE_FD_ERROR                SOCKET_ERROR
+
+#else
+
+# include <unistd.h>
+# include <fcntl.h>
+
+# define pipe_write(fd, buffer, size) write((fd), buffer, size)
+# define pipe_read(fd, buffer, size)  read((fd), buffer, size)
+# define pipe_close(fd)               close(fd)
+# define PIPE_FD_INVALID              -1
+# define PIPE_FD_ERROR                -1
+
+#endif /* ! _WIN32 */
+
+struct _Ecore_Pipe
+{
+   ECORE_MAGIC;
+   int               fd_read;
+   int               fd_write;
+   Ecore_Fd_Handler *fd_handler;
+   const void       *data;
+   Ecore_Pipe_Cb     handler;
+   unsigned int      len;
+   size_t            already_read;
+   void             *passed_data;
+};
+
+
+static Eina_Bool _ecore_pipe_read(void *data, Ecore_Fd_Handler *fd_handler);
+
+/**
+ * @defgroup Ecore_Pipe_Group Pipe wrapper
+ *
+ * These functions wrap the pipe / write / read functions to
+ * easily integrate a loop that is in its own thread to the ecore
+ * main loop.
+ *
+ * The ecore_pipe_add() function creates file descriptors (sockets on
+ * Windows) and attach an handle to the ecore main loop. That handle is
+ * called when data is read in the pipe. To write data in the pipe,
+ * just call ecore_pipe_write(). When you are done, just call
+ * ecore_pipe_del().
+ *
+ * Here is an example that uses the pipe wrapper with a Gstreamer
+ * pipeline. For each decoded frame in the Gstreamer thread, a handle
+ * is called in the ecore thread.
+ *
+ * @code#include <gst/gst.h>
+ * #include <Ecore.h>
+ *
+ * static int nbr = 0;
+ *
+ * static GstElement *_buid_pipeline (gchar *filename, Ecore_Pipe *pipe);
+ *
+ * static void new_decoded_pad_cb (GstElement *demuxer,
+ *                                 GstPad     *new_pad,
+ *                                 gpointer    user_data);
+ *
+ * static void handler(void *data, void *buf, unsigned int len)
+ * {
+ *   GstBuffer  *buffer = *((GstBuffer **)buf);
+ *
+ *   printf ("handler : %p\n", buffer);
+ *   printf ("frame  : %d %p %lld %p\n", nbr++, data, (long 
long)GST_BUFFER_DURATION(buffer), buffer);
+ *   gst_buffer_unref (buffer);
+ * }
+ *
+ *
+ * static void handoff (GstElement* object,
+ *                      GstBuffer* arg0,
+ *                      GstPad* arg1,
+ *                      gpointer user_data)
+ * {
+ *   Ecore_Pipe *pipe;
+ *
+ *   pipe = (Ecore_Pipe *)user_data;
+ *   printf ("handoff : %p\n", arg0);
+ *   gst_buffer_ref (arg0);
+ *   ecore_pipe_write(pipe, &arg0, sizeof(arg0));
+ * }
+ *
+ * int
+ * main (int argc, char *argv[])
+ * {
+ *   GstElement *pipeline;
+ *   char *filename;
+ *   Ecore_Pipe *pipe;
+ *
+ *   gst_init (&argc, &argv);
+ *
+ *   if (!ecore_init ())
+ *     {
+ *       gst_deinit ();
+ *       return 0;
+ *     }
+ *
+ *   pipe = ecore_pipe_add (handler);
+ *   if (!pipe)
+ *     {
+ *       ecore_shutdown ();
+ *       gst_deinit ();
+ *       return 0;
+ *     }
+ *
+ *   if (argc < 2) {
+ *     g_print ("usage: %s file.avi\n", argv[0]);
+ *     ecore_pipe_del (pipe);
+ *     ecore_shutdown ();
+ *     gst_deinit ();
+ *     return 0;
+ *   }
+ *   filename = argv[1];
+ *
+ *   pipeline = _buid_pipeline (filename, pipe);
+ *   if (!pipeline) {
+ *     g_print ("Error during the pipeline building\n");
+ *     ecore_pipe_del (pipe);
+ *     ecore_shutdown ();
+ *     gst_deinit ();
+ *     return -1;
+ *   }
+ *
+ *   gst_element_set_state (pipeline, GST_STATE_PLAYING);
+ *
+ *   ecore_main_loop_begin();
+ *
+ *   ecore_pipe_del (pipe);
+ *   ecore_shutdown ();
+ *   gst_deinit ();
+ *
+ *   return 0;
+ * }
+ *
+ * static void
+ * new_decoded_pad_cb (GstElement *demuxer,
+ *                     GstPad     *new_pad,
+ *                     gpointer    user_data)
+ * {
+ *   GstElement *decoder;
+ *   GstPad *pad;
+ *   GstCaps *caps;
+ *   gchar *str;
+ *
+ *   caps = gst_pad_get_caps (new_pad);
+ *   str = gst_caps_to_string (caps);
+ *
+ *   if (g_str_has_prefix (str, "video/")) {
+ *     decoder = GST_ELEMENT (user_data);
+ *
+ *     pad = gst_element_get_pad (decoder, "sink");
+ *     if (GST_PAD_LINK_FAILED (gst_pad_link (new_pad, pad))) {
+ *       g_warning ("Failed to link %s:%s to %s:%s", GST_DEBUG_PAD_NAME 
(new_pad),
+ *                  GST_DEBUG_PAD_NAME (pad));
+ *     }
+ *   }
+ *   g_free (str);
+ *   gst_caps_unref (caps);
+ * }
+ *
+ * static GstElement *
+ * _buid_pipeline (gchar *filename, Ecore_Pipe *pipe)
+ * {
+ *   GstElement          *pipeline;
+ *   GstElement          *filesrc;
+ *   GstElement          *demuxer;
+ *   GstElement          *decoder;
+ *   GstElement          *sink;
+  GstStateChangeReturn res;
+ *
+ *   pipeline = gst_pipeline_new ("pipeline");
+ *   if (!pipeline)
+ *     return NULL;
+ *
+ *   filesrc = gst_element_factory_make ("filesrc", "filesrc");
+ *   if (!filesrc) {
+ *     printf ("no filesrc");
+ *     goto failure;
+ *   }
+ *   g_object_set (G_OBJECT (filesrc), "location", filename, NULL);
+ *
+ *   demuxer = gst_element_factory_make ("oggdemux", "demuxer");
+ *   if (!demuxer) {
+ *     printf ("no demux");
+ *     goto failure;
+ *   }
+ *
+ *   decoder = gst_element_factory_make ("theoradec", "decoder");
+ *   if (!decoder) {
+ *     printf ("no dec");
+ *     goto failure;
+ *   }
+ *
+ *   g_signal_connect (demuxer, "pad-added",
+ *                     G_CALLBACK (new_decoded_pad_cb), decoder);
+ *
+ *   sink = gst_element_factory_make ("fakesink", "sink");
+ *   if (!sink) {
+ *     printf ("no sink");
+ *     goto failure;
+ *   }
+ *   g_object_set (G_OBJECT (sink), "sync", EINA_TRUE, NULL);
+ *   g_object_set (G_OBJECT (sink), "signal-handoffs", EINA_TRUE, NULL);
+ *   g_signal_connect (sink, "handoff",
+ *                     G_CALLBACK (handoff), pipe);
+ *
+ *   gst_bin_add_many (GST_BIN (pipeline),
+ *                     filesrc, demuxer, decoder, sink, NULL);
+ *
+ *   if (!gst_element_link (filesrc, demuxer))
+ *     goto failure;
+ *   if (!gst_element_link (decoder, sink))
+ *     goto failure;
+ *
+ *   res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
+ *   if (res == GST_STATE_CHANGE_FAILURE)
+ *     goto failure;
+ *
+ *   res = gst_element_get_state( pipeline, NULL, NULL, GST_CLOCK_TIME_NONE );
+ *   if (res != GST_STATE_CHANGE_SUCCESS)
+ *     goto failure;
+ *
+ *   return pipeline;
+ *
+ *  failure:
+ *   gst_object_unref (GST_OBJECT (pipeline));
+ *   return NULL;
+ * }
+ * @endcode
+ */
+
+
+/**
+ * Create two file descriptors (sockets on Windows). Add
+ * a callback that will be called when the file descriptor that
+ * is listened receives data. An event is also put in the event
+ * queue when data is received.
+ *
+ * @param handler The handler called when data is received.
+ * @param data    Data to pass to @p handler when it is called.
+ * @return        A newly created Ecore_Pipe object if successful.
+ *                @c NULL otherwise.
+ * @ingroup Ecore_Pipe_Group
+ */
+EAPI Ecore_Pipe *
+ecore_pipe_add(Ecore_Pipe_Cb handler, const void *data)
+{
+   Ecore_Pipe *p;
+   int         fds[2];
+
+   if (!handler) return NULL;
+
+   p = (Ecore_Pipe *)calloc(1, sizeof(Ecore_Pipe));
+   if (!p) return NULL;
+
+   if (pipe(fds))
+     {
+        free(p);
+        return NULL;
+     }
+
+   ECORE_MAGIC_SET(p, ECORE_MAGIC_PIPE);
+   p->fd_read = fds[0];
+   p->fd_write = fds[1];
+   p->handler = handler;
+   p->data = data;
+
+   fcntl(p->fd_read, F_SETFL, O_NONBLOCK);
+   p->fd_handler = ecore_main_fd_handler_add(p->fd_read,
+                                          ECORE_FD_READ,
+                                          _ecore_pipe_read,
+                                          p,
+                                          NULL, NULL);
+   return p;
+}
+
+/**
+ * Free an Ecore_Pipe object created with ecore_pipe_add().
+ *
+ * @param p The Ecore_Pipe object to be freed.
+ * @return The pointer to the private data
+ * @ingroup Ecore_Pipe_Group
+ */
+EAPI void *
+ecore_pipe_del(Ecore_Pipe *p)
+{
+   void *data;
+
+   if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+     {
+        ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_del");
+        return NULL;
+     }
+   if (p->fd_handler) ecore_main_fd_handler_del(p->fd_handler);
+   if (p->fd_read != PIPE_FD_INVALID) pipe_close(p->fd_read);
+   if (p->fd_write != PIPE_FD_INVALID) pipe_close(p->fd_write);
+   data = (void *)p->data;
+   free(p);
+   return data;
+}
+
+/**
+ * Close the read end of an Ecore_Pipe object created with ecore_pipe_add().
+ *
+ * @param p The Ecore_Pipe object.
+ * @ingroup Ecore_Pipe_Group
+ */
+EAPI void
+ecore_pipe_read_close(Ecore_Pipe *p)
+{
+   if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+     {
+        ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_read_close");
+        return;
+     }
+   ecore_main_fd_handler_del(p->fd_handler);
+   p->fd_handler = NULL;
+   pipe_close(p->fd_read);
+   p->fd_read = PIPE_FD_INVALID;
+}
+
+/**
+ * Close the write end of an Ecore_Pipe object created with ecore_pipe_add().
+ *
+ * @param p The Ecore_Pipe object.
+ * @ingroup Ecore_Pipe_Group
+ */
+EAPI void
+ecore_pipe_write_close(Ecore_Pipe *p)
+{
+   if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+     {
+        ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write_close");
+        return;
+     }
+   pipe_close(p->fd_write);
+   p->fd_write = PIPE_FD_INVALID;
+}
+
+/**
+ * Write on the file descriptor the data passed as parameter.
+ *
+ * @param p      The Ecore_Pipe object.
+ * @param buffer The data to write into the pipe.
+ * @param nbytes The size of the @p buffer in bytes
+ * @return       Returns EINA_TRUE on a successful write, EINA_FALSE on an 
error
+ * @ingroup Ecore_Pipe_Group
+ */
+EAPI Eina_Bool
+ecore_pipe_write(Ecore_Pipe *p, const void *buffer, unsigned int nbytes)
+{
+   ssize_t ret;
+   size_t  already_written = 0;
+   int     retry = ECORE_PIPE_WRITE_RETRY;
+
+   if (!ECORE_MAGIC_CHECK(p, ECORE_MAGIC_PIPE))
+     {
+        ECORE_MAGIC_FAIL(p, ECORE_MAGIC_PIPE, "ecore_pipe_write");
+        return EINA_FALSE;
+     }
+
+   if (p->fd_write == PIPE_FD_INVALID) return EINA_FALSE;
+
+   /* First write the len into the pipe */
+   do
+     {
+        ret = pipe_write(p->fd_write, &nbytes, sizeof(nbytes));
+        if (ret == sizeof(nbytes))
+          {
+             retry = ECORE_PIPE_WRITE_RETRY;
+             break;
+          }
+        else if (ret > 0)
+          {
+             /* XXX What should we do here? */
+             ERR("The length of the data was not written complete"
+                 " to the pipe");
+             return EINA_FALSE;
+          }
+        else if (ret == PIPE_FD_ERROR && errno == EPIPE)
+          {
+             pipe_close(p->fd_write);
+             p->fd_write = PIPE_FD_INVALID;
+             return EINA_FALSE;
+          }
+        else if (ret == PIPE_FD_ERROR && errno == EINTR)
+          /* try it again */
+          ;
+        else
+          {
+             ERR("An unhandled error (ret: %zd errno: %d)"
+                 "occurred while writing to the pipe the length",
+                 ret, errno);
+          }
+     }
+   while (retry--);
+
+   if (retry != ECORE_PIPE_WRITE_RETRY) return EINA_FALSE;
+
+   /* and now pass the data to the pipe */
+   do
+     {
+        ret = pipe_write(p->fd_write,
+                         ((unsigned char *)buffer) + already_written,
+                         nbytes - already_written);
+        
+        if (ret == (ssize_t)(nbytes - already_written))
+          return EINA_TRUE;
+        else if (ret >= 0)
+          {
+             already_written -= ret;
+             continue;
+          }
+        else if (ret == PIPE_FD_ERROR && errno == EPIPE)
+          {
+             pipe_close(p->fd_write);
+             p->fd_write = PIPE_FD_INVALID;
+             return EINA_FALSE;
+          }
+        else if (ret == PIPE_FD_ERROR && errno == EINTR)
+          /* try it again */
+          ;
+        else
+          {
+             ERR("An unhandled error (ret: %zd errno: %d)"
+                 "occurred while writing to the pipe the length",
+                 ret, errno);
+          }
+     }
+   while (retry--);
+
+   return EINA_FALSE;
+}
+
+/* Private function */
+
+static Eina_Bool
+_ecore_pipe_read(void *data, Ecore_Fd_Handler *fd_handler __UNUSED__)
+{
+   Ecore_Pipe  *p;
+   double       start_time;
+
+   p = (Ecore_Pipe *)data;
+   start_time = ecore_time_get();
+
+   do
+     {
+        ssize_t       ret;
+
+        /* if we already have read some data we don't need to read the len
+         * but to finish the already started job
+         */
+        if (p->len == 0)
+          {
+             /* read the len of the passed data */
+             ret = pipe_read(p->fd_read, &p->len, sizeof(p->len));
+
+             /* catch the non error case first */
+             if (ret == sizeof(p->len))
+               ;
+             else if (ret > 0)
+               {
+                  /* XXX What should we do here? */
+                  ERR("Only read %zd bytes from the pipe, although"
+                      " we need to read %zd bytes.", ret, sizeof(p->len));
+               }
+             else if (ret == 0)
+               {
+                  p->handler((void *)p->data, NULL, 0);
+                  pipe_close(p->fd_read);
+                  p->fd_read = PIPE_FD_INVALID;
+                  p->fd_handler = NULL;
+                  return ECORE_CALLBACK_CANCEL;
+               }
+#ifndef _WIN32
+             else if ((ret == PIPE_FD_ERROR) && ((errno == EINTR) || (errno == 
EAGAIN)))
+               return ECORE_CALLBACK_RENEW;
+             else
+               {
+                  ERR("An unhandled error (ret: %zd errno: %d)"
+                      "occurred while reading from the pipe the length",
+                      ret, errno);
+                  return ECORE_CALLBACK_RENEW;
+               }
+#else
+             else /* ret == PIPE_FD_ERROR is the only other case on Windows */
+               {
+                  if (WSAGetLastError() != WSAEWOULDBLOCK)
+                    {
+                       p->handler((void *)p->data, NULL, 0);
+                       pipe_close(p->fd_read);
+                       p->fd_read = PIPE_FD_INVALID;
+                       p->fd_handler = NULL;
+                       return ECORE_CALLBACK_CANCEL;
+                    }
+               }
+#endif
+          }
+
+        if (!p->passed_data)
+          p->passed_data = malloc(p->len);
+
+        /* and read the passed data */
+        ret = pipe_read(p->fd_read,
+                        ((unsigned char *)p->passed_data) + p->already_read,
+                        p->len - p->already_read);
+        
+        /* catch the non error case first */
+        if (ret == (ssize_t)(p->len - p->already_read))
+          {
+             p->handler((void *)p->data, p->passed_data, p->len);
+             free(p->passed_data);
+             /* reset all values to 0 */
+             p->passed_data = NULL;
+             p->already_read = 0;
+             p->len = 0;
+          }
+        else if (ret >= 0)
+          {
+             p->already_read += ret;
+             return ECORE_CALLBACK_RENEW;
+          }
+        else if (ret == 0)
+          {
+             p->handler((void *)p->data, NULL, 0);
+             pipe_close(p->fd_read);
+             p->fd_read = PIPE_FD_INVALID;
+             p->fd_handler = NULL;
+             return ECORE_CALLBACK_CANCEL;
+          }
+#ifndef _WIN32
+        else if (ret == PIPE_FD_ERROR && (errno == EINTR || errno == EAGAIN))
+          return ECORE_CALLBACK_RENEW;
+        else
+          {
+             ERR("An unhandled error (ret: %zd errno: %d)"
+                 "occurred while reading from the pipe the data",
+                 ret, errno);
+             return ECORE_CALLBACK_RENEW;
+          }
+#else
+        else /* ret == PIPE_FD_ERROR is the only other case on Windows */
+          {
+             if (WSAGetLastError() != WSAEWOULDBLOCK)
+               {
+                  p->handler((void *)p->data, NULL, 0);
+                  pipe_close(p->fd_read);
+                  p->fd_read = PIPE_FD_INVALID;
+                  p->fd_handler = NULL;
+                  return ECORE_CALLBACK_CANCEL;
+               }
+             else
+               break;
+          }
+#endif
+     }
+   while (ecore_time_get() - start_time < ecore_animator_frametime_get());
+   
+   return ECORE_CALLBACK_RENEW;
+}
diff --git a/tests/suite/ecore/src/lib/ecore_poll.c 
b/tests/suite/ecore/src/lib/ecore_poll.c
new file mode 100644
index 0000000..d5bc6ba
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_poll.c
@@ -0,0 +1,442 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+
+struct _Ecore_Poller
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   int           ibit;
+   unsigned char delete_me : 1;
+   Ecore_Task_Cb func;
+   void          *data;
+};
+
+
+static Ecore_Timer    *timer = NULL;
+static int             min_interval = -1;
+static int             interval_incr = 0;
+static int             at_tick = 0;
+static int             just_added_poller = 0;
+static int             poller_delete_count = 0;
+static int             poller_walking = 0;
+static double          poll_interval = 0.125;
+static double          poll_cur_interval = 0.0;
+static double          last_tick = 0.0;
+static Ecore_Poller   *pollers[16] =
+{
+   NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,
+   NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL
+};
+static unsigned short  poller_counters[16] =
+{
+   0,0,0,0,0,0,0,0,
+   0,0,0,0,0,0,0,0
+};
+
+static void _ecore_poller_next_tick_eval(void);
+static Eina_Bool _ecore_poller_cb_timer(void *data);
+
+static void
+_ecore_poller_next_tick_eval(void)
+{
+   int i;
+   double interval;
+
+   min_interval = -1;
+   for (i = 0; i < 15; i++)
+     {
+        if (pollers[i])
+          {
+             min_interval = i;
+             break;
+          }
+     }
+   if (min_interval < 0)
+     {
+        /* no pollers */
+        if (timer)
+          {
+             ecore_timer_del(timer);
+             timer = NULL;
+          }
+        return;
+     }
+   interval_incr = (1 << min_interval);
+   interval = interval_incr * poll_interval;
+   /* we are at the tick callback - so no need to do inter-tick adjustments
+    * so we can fasttrack this as t -= last_tick in theory is 0.0 (though
+    * in practice it will be a very very very small value. also the tick
+    * callback will adjust the timer interval at the end anyway */
+   if (at_tick)
+     {
+        if (!timer)
+          timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
+     }
+   else
+     {
+        double t;
+
+        if (!timer)
+          timer = ecore_timer_add(interval, _ecore_poller_cb_timer, NULL);
+        else
+          {
+             t = ecore_time_get();
+             if (interval != poll_cur_interval)
+               {
+                  t -= last_tick; /* time since we last ticked */
+                  /* delete the timer and reset it to tick off in the new
+                   * time interval. at the tick this will be adjusted */
+                  ecore_timer_del(timer);
+                  timer = ecore_timer_add(interval - t,
+                                          _ecore_poller_cb_timer, NULL);
+               }
+          }
+     }
+   poll_cur_interval = interval;
+}
+
+static Eina_Bool
+_ecore_poller_cb_timer(void *data __UNUSED__)
+{
+   int i;
+   Ecore_Poller *poller, *l;
+   int changes = 0;
+
+   at_tick++;
+   last_tick = ecore_time_get();
+   /* we have 16 counters - each incriments every time the poller counter
+    * "ticks". it incriments by the minimum interval (which can be 1, 2, 4,
+    * 7, 16 etc. up to 32768) */
+   for (i = 0; i < 15; i++)
+     {
+        poller_counters[i] += interval_incr;
+        /* wrap back to 0 if we exceed out loop count for the counter */
+        if (poller_counters[i] >= (1 << i)) poller_counters[i] = 0;
+     }
+
+   just_added_poller = 0;
+   /* walk the pollers now */
+   poller_walking++;
+   for (i = 0; i < 15; i++)
+     {
+        /* if the counter is @ 0 - this means that counter "went off" this
+         * tick interval, so run all pollers hooked to that counter */
+        if (poller_counters[i] == 0)
+          {
+             EINA_INLIST_FOREACH(pollers[i], poller)
+               {
+                  if (!poller->delete_me)
+                    {
+                       if (!poller->func(poller->data))
+                         {
+                            if (!poller->delete_me)
+                              {
+                                 poller->delete_me = 1;
+                                 poller_delete_count++;
+                              }
+                         }
+                    }
+               }
+          }
+     }
+   poller_walking--;
+
+   /* handle deletes afterwards */
+   if (poller_delete_count > 0)
+     {
+        /* FIXME: walk all pollers and remove deleted ones */
+        for (i = 0; i < 15; i++)
+          {
+             for (l = pollers[i]; l;)
+               {
+                  poller = l;
+                  l = (Ecore_Poller *) EINA_INLIST_GET(l)->next;
+                  if (poller->delete_me)
+                    {
+                       pollers[i] = (Ecore_Poller *) 
eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(poller));
+                       free(poller);
+                       poller_delete_count--;
+                       changes++;
+                       if (poller_delete_count <= 0) break;
+                    }
+               }
+             if (poller_delete_count <= 0) break;
+          }
+     }
+   /* if we deleted or added any pollers, then we need to re-evaluate our
+    * minimum poll interval */
+   if ((changes > 0) || (just_added_poller > 0))
+     _ecore_poller_next_tick_eval();
+
+   just_added_poller = 0;
+   poller_delete_count = 0;
+
+   at_tick--;
+
+   /* if the timer was deleted then there is no point returning 1 - ambiguous
+    * if we do as it im plies "keep running me" but we have been deleted
+    * anyway */
+   if (!timer) return ECORE_CALLBACK_CANCEL;
+
+   /* adjust interval */
+   ecore_timer_interval_set(timer, poll_cur_interval);
+   return ECORE_CALLBACK_RENEW;
+}
+
+/**
+ * @defgroup Ecore_Poll_Group Ecore Poll Functions
+ *
+ * These functions are for the need to poll information, but provide a shared
+ * abstracted API to pool such polling to minimise wakeup and ensure all the
+ * polling happens in as few spots as possible areound a core poll interval.
+ * For now only 1 core poller type is supprted: ECORE_POLLER_CORE
+ */
+
+
+/**
+ * Sets the time between ticks (in seconds) for the given ticker clock.
+ * @param   type The ticker type to adjust
+ * @param   poll_time The time (in seconds) between ticks of the clock
+ * @ingroup Ecore_Poller_Group
+ *
+ * This will adjust the time between ticks of the given ticker type defined
+ * by @p type to the time period defined by @p poll_time.
+ */
+EAPI void
+ecore_poller_poll_interval_set(Ecore_Poller_Type type __UNUSED__, double 
poll_time)
+{
+   poll_interval = poll_time;
+   _ecore_poller_next_tick_eval();
+}
+
+/**
+ * Gets the time between ticks (in seconds) for the given ticker clock.
+ * @param   type The ticker type to query
+ * @return  The time in seconds between ticks of the ticker clock
+ * @ingroup Ecore_Poller_Group
+ *
+ * This will get the time between ticks of the specifider ticker clock.
+ */
+EAPI double
+ecore_poller_poll_interval_get(Ecore_Poller_Type type __UNUSED__)
+{
+   return poll_interval;
+}
+
+/**
+ * Creates a poller to call the given function at a particular tick interval.
+ * @param   type The ticker type to attach the poller to
+ * @param   interval The poll interval
+ * @param   func The given function.  If @p func returns 1, the poller is
+ *               rescheduled for the next tick interval.
+ * @param   data Data to pass to @p func when it is called.
+ * @return  A poller object on success.  @c NULL on failure.
+ * @ingroup Ecore_Poller_Group
+ *
+ * This function adds a poller callback that is to be called regularly
+ * along with all other poller callbacks so the pollers are synchronized with
+ * all other pollers running off the same poller type and at the same tick
+ * interval. This should be used for polling things when polling is desired
+ * or required, and you do not have specific requirements on the exact times
+ * to poll and want to avoid extra process wakeups for polling. This will
+ * save power as the CPU has more of a chance to go into a low power state
+ * the longer it is asleep for, so this should be used if you are at all
+ * power conscious.
+ *
+ * The @p type parameter defines the poller tick type (there is a virtual
+ * clock ticking all the time - though ecore avoids making it tick when
+ * there will not be any work to do at that tick point). There is only one
+ * ticker at the moment - that is ECORE_POLLER_CORE. This is here for future
+ * expansion if multiple clocks with different frequencies are really required.
+ * The default time between ticks for the ECORE_POLLER_CORE ticker is 0.125
+ * seconds.
+ *
+ * The @p interval is the number of ticker ticks that will pass by in between
+ * invocations of the @p func callback. This must be between 1 and 32768
+ * inclusive, and must be a power of 2 (i.e. 1, 2, 4, 8, 16, ... 16384, 32768).
+ * If it is 1, then the function will be called every tick. if it is 2, then it
+ * will be called every 2nd tick, if it is 8, then every 8th tick etc. Exactly
+ * which tick is undefined, as only the interval between calls can be defined.
+ * Ecore will endeavour to keep pollers synchronised and to call as many in
+ * 1 wakeup event as possible.
+ *
+ * This function adds a poller and returns its handle on success and NULL on
+ * failure. The function @p func will be called at tick intervals described
+ * above. The function will be passed the @p data pointer as its parameter.
+ *
+ * When the poller @p func is called, it must return a value of either
+ * 1 (or ECORE_CALLBACK_RENEW) or 0 (or ECORE_CALLBACK_CANCEL). If it
+ * returns 1, it will be called again at the next tick, or if it returns
+ * 0 it will be deleted automatically making any references/handles for it
+ * invalid.
+ */
+EAPI Ecore_Poller *
+ecore_poller_add(Ecore_Poller_Type type __UNUSED__, int interval, 
Ecore_Task_Cb func, const void *data)
+{
+   Ecore_Poller *poller;
+   int ibit;
+
+   if (!func) return NULL;
+   if (interval < 1) interval = 1;
+
+   poller = calloc(1, sizeof(Ecore_Poller));
+   if (!poller) return NULL;
+   ECORE_MAGIC_SET(poller, ECORE_MAGIC_POLLER);
+   /* interval MUST be a power of 2, so enforce it */
+   if (interval < 1) interval = 1;
+   ibit = -1;
+   while (interval != 0)
+     {
+        ibit++;
+        interval >>= 1;
+     }
+   /* only allow up to 32768 - i.e. ibit == 15, so limit it */
+   if (ibit > 15) ibit = 15;
+
+   poller->ibit = ibit;
+   poller->func = func;
+   poller->data = (void *)data;
+   pollers[poller->ibit] = (Ecore_Poller *) 
eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), 
EINA_INLIST_GET(poller));
+   if (poller_walking)
+     just_added_poller++;
+   else
+     _ecore_poller_next_tick_eval();
+   return poller;
+}
+
+/**
+ * Changes the polling interval rate of @p poller.
+ *
+ * @param poller The Ecore_Poller to change the interval of
+ * @param interval The tick interval to set; must be a power of 2 but <= 32768
+ * @return Returns true on success, false on failure
+ *
+ * This allows the changing of a poller's polling interval.  It is useful when 
you want to alter
+ * a poll rate without deleting and re-creating a poller.
+ * @ingroup Ecore_Poller_Group
+ */
+EAPI Eina_Bool
+ecore_poller_poller_interval_set(Ecore_Poller *poller, int interval)
+{
+   int ibit;
+
+   if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER))
+     {
+        ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER,
+           "ecore_poller_poller_interval_set");
+        return EINA_FALSE;
+     }
+
+   /* interval MUST be a power of 2, so enforce it */
+   if (interval < 1) interval = 1;
+   ibit = -1;
+   while (interval != 0)
+     {
+       ibit++;
+       interval >>= 1;
+     }
+   /* only allow up to 32768 - i.e. ibit == 15, so limit it */
+   if (ibit > 15) ibit = 15;
+   /* if interval specified is the same as interval set, return true without 
wasting time */
+   if (poller->ibit == ibit)
+     return EINA_TRUE;
+   pollers[poller->ibit] = (Ecore_Poller *) 
eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), 
EINA_INLIST_GET(poller));
+   poller->ibit = ibit;
+   pollers[poller->ibit] = (Ecore_Poller *) 
eina_inlist_prepend(EINA_INLIST_GET(pollers[poller->ibit]), 
EINA_INLIST_GET(poller));
+   if (poller_walking)
+     just_added_poller++;
+   else
+     _ecore_poller_next_tick_eval();
+   return EINA_TRUE;
+}
+
+/**
+ * Gets the polling interval rate of @p poller.
+ *
+ * @param poller The Ecore_Poller to change the interval of
+ * @return Returns the interval, in ticks, that @p poller polls at
+ *
+ * This returns a poller's polling interval, or 0 on error.
+ * @ingroup Ecore_Poller_Group
+ */
+EAPI int
+ecore_poller_poller_interval_get(Ecore_Poller *poller)
+{
+   int ibit, interval = 1;
+
+   if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER))
+     {
+        ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER,
+           "ecore_poller_poller_interval_get");
+        return 0;
+     }
+
+   ibit = poller->ibit;
+   while (ibit != 0)
+     {
+       ibit--;
+       interval <<= 1;
+     }
+   return interval;
+}
+
+/**
+ * Delete the specified poller from the timer list.
+ * @param   poller The poller to delete.
+ * @return  The data pointer set for the timer when @ref ecore_poller_add was
+ *          called.  @c NULL is returned if the function is unsuccessful.
+ * @ingroup Ecore_Poller_Group
+ *
+ * Note: @p poller must be a valid handle. If the poller function has already
+ * returned 0, the handle is no longer valid (and does not need to be delete).
+ */
+EAPI void *
+ecore_poller_del(Ecore_Poller *poller)
+{
+   void *data;
+
+   if (!ECORE_MAGIC_CHECK(poller, ECORE_MAGIC_POLLER))
+     {
+        ECORE_MAGIC_FAIL(poller, ECORE_MAGIC_POLLER,
+           "ecore_poller_del");
+        return NULL;
+     }
+   /* we are walking the poller list - a bad idea to remove from it while
+    * walking it, so just flag it as delete_me and come back to it after
+    * the loop has finished */
+   if (poller_walking > 0)
+     {
+        poller_delete_count++;
+        poller->delete_me = 1;
+        return poller->data;
+     }
+   /* not in loop so safe - delete immediately */
+   data = poller->data;
+   pollers[poller->ibit] = (Ecore_Poller *) 
eina_inlist_remove(EINA_INLIST_GET(pollers[poller->ibit]), 
EINA_INLIST_GET(poller));
+   free(poller);
+   _ecore_poller_next_tick_eval();
+   return data;
+}
+
+void
+_ecore_poller_shutdown(void)
+{
+   int i;
+   Ecore_Poller *poller;
+
+   for (i = 0; i < 15; i++)
+     {
+        while ((poller = pollers[i]))
+          {
+             pollers[i] = (Ecore_Poller *) 
eina_inlist_remove(EINA_INLIST_GET(pollers[i]), EINA_INLIST_GET(pollers[i]));
+             free(poller);
+          }
+     }
+}
diff --git a/tests/suite/ecore/src/lib/ecore_private.h 
b/tests/suite/ecore/src/lib/ecore_private.h
new file mode 100644
index 0000000..5f08f8a
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_private.h
@@ -0,0 +1,208 @@
+#ifndef _ECORE_PRIVATE_H
+#define _ECORE_PRIVATE_H
+
+extern int _ecore_log_dom ;
+#ifdef  _ECORE_DEFAULT_LOG_DOM
+# undef _ECORE_DEFAULT_LOG_DOM
+#endif
+#define _ECORE_DEFAULT_LOG_DOM _ecore_log_dom
+
+#ifdef ECORE_DEFAULT_LOG_COLOR
+# undef ECORE_DEFAULT_LOG_COLOR
+#endif
+#define ECORE_DEFAULT_LOG_COLOR EINA_COLOR_BLUE
+
+#ifdef ERR
+# undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifdef DBG
+# undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifdef INF
+# undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifdef WRN
+# undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifdef CRIT
+# undef CRIT
+#endif
+#define CRIT(...) EINA_LOG_DOM_CRIT(_ECORE_DEFAULT_LOG_DOM, __VA_ARGS__)
+
+#ifndef PATH_MAX
+# define PATH_MAX 4096
+#endif
+
+#ifndef MIN
+# define MIN(x, y) (((x) > (y)) ? (y) : (x))
+#endif
+
+#ifndef MAX
+# define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+#ifndef ABS
+# define ABS(x) ((x) < 0 ? -(x) : (x))
+#endif
+
+#ifndef CLAMP
+# define CLAMP(x, min, max) (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : 
(x)))
+#endif
+
+#define EVAS_FRAME_QUEUING 1 /* for test */
+
+#define READBUFSIZ 65536
+
+#define ECORE_MAGIC_NONE            0x1234fedc
+#define ECORE_MAGIC_EXE             0xf7e812f5
+#define ECORE_MAGIC_TIMER           0xf7d713f4
+#define ECORE_MAGIC_IDLER           0xf7c614f3
+#define ECORE_MAGIC_IDLE_ENTERER    0xf7b515f2
+#define ECORE_MAGIC_IDLE_EXITER     0xf7601afd
+#define ECORE_MAGIC_FD_HANDLER      0xf7a416f1
+#define ECORE_MAGIC_EVENT_HANDLER   0xf79317f0
+#define ECORE_MAGIC_EVENT_FILTER    0xf78218ff
+#define ECORE_MAGIC_EVENT           0xf77119fe
+#define ECORE_MAGIC_ANIMATOR        0xf7643ea5
+#define ECORE_MAGIC_POLLER          0xf7568127
+#define ECORE_MAGIC_PIPE            0xf7458226
+#define ECORE_MAGIC_WIN32_HANDLER   0xf7e8f1a3
+#define ECORE_MAGIC_JOB             0x76543210
+
+
+#define ECORE_MAGIC                 Ecore_Magic  __magic
+
+#define ECORE_MAGIC_SET(d, m)       (d)->__magic = (m)
+#define ECORE_MAGIC_CHECK(d, m)     ((d) && ((d)->__magic == (m)))
+#define ECORE_MAGIC_FAIL(d, m, fn)  _ecore_magic_fail((d), (d) ? (d)->__magic 
: 0, (m), (fn));
+
+/* undef the following, we want our version */
+#undef FREE
+#define FREE(ptr) free(ptr); ptr = NULL;
+
+#undef IF_FREE
+#define IF_FREE(ptr) if (ptr) free(ptr); ptr = NULL;
+
+#undef IF_FN_DEL
+#define IF_FN_DEL(_fn, ptr) if (ptr) { _fn(ptr); ptr = NULL; }
+
+EAPI void ecore_print_warning(const char *function, const char *sparam);
+
+/* convenience macros for checking pointer parameters for non-NULL */
+#undef CHECK_PARAM_POINTER_RETURN
+#define CHECK_PARAM_POINTER_RETURN(sparam, param, ret) \
+     if (!(param)) \
+         { \
+            ecore_print_warning(__FUNCTION__, sparam); \
+            return ret; \
+         }
+
+#undef CHECK_PARAM_POINTER
+#define CHECK_PARAM_POINTER(sparam, param) \
+     if (!(param)) \
+         { \
+            ecore_print_warning(__FUNCTION__, sparam); \
+            return; \
+         }
+
+typedef unsigned int              Ecore_Magic;
+
+EAPI void          _ecore_magic_fail(const void *d, Ecore_Magic m, Ecore_Magic 
req_m, const char *fname);
+
+void          _ecore_time_init(void);
+
+void          _ecore_timer_shutdown(void);
+void          _ecore_timer_cleanup(void);
+void          _ecore_timer_enable_new(void);
+double        _ecore_timer_next_get(void);
+int           _ecore_timers_exists(void);
+int           _ecore_timer_call(double when);
+
+void          _ecore_idler_shutdown(void);
+int           _ecore_idler_call(void);
+int           _ecore_idler_exist(void);
+
+void          _ecore_idle_enterer_shutdown(void);
+void          _ecore_idle_enterer_call(void);
+int           _ecore_idle_enterer_exist(void);
+
+void          _ecore_idle_exiter_shutdown(void);
+void          _ecore_idle_exiter_call(void);
+int           _ecore_idle_exiter_exist(void);
+
+void          _ecore_event_shutdown(void);
+int           _ecore_event_exist(void);
+Ecore_Event  *_ecore_event_add(int type, void *ev, Ecore_End_Cb func_free, 
void *data);
+void          _ecore_event_call(void);
+
+Ecore_Timer  *_ecore_exe_doomsday_clock_get(Ecore_Exe *exe);
+void          _ecore_exe_doomsday_clock_set(Ecore_Exe *exe, Ecore_Timer *dc);
+
+EAPI void    *_ecore_event_signal_user_new(void);
+void         *_ecore_event_signal_hup_new(void);
+void         *_ecore_event_signal_exit_new(void);
+void         *_ecore_event_signal_power_new(void);
+void         *_ecore_event_signal_realtime_new(void);
+
+void          _ecore_main_shutdown(void);
+
+#ifdef _WIN32
+static inline void _ecore_signal_shutdown(void) { }
+static inline void _ecore_signal_init(void) { }
+static inline int  _ecore_signal_count_get(void) { return 0; }
+static inline void _ecore_signal_call(void) { }
+#else
+void          _ecore_signal_shutdown(void);
+void          _ecore_signal_init(void);
+int           _ecore_signal_count_get(void);
+void          _ecore_signal_call(void);
+#endif
+
+void          _ecore_exe_init(void);
+void          _ecore_exe_shutdown(void);
+#ifndef _WIN32
+Ecore_Exe    *_ecore_exe_find(pid_t pid);
+void         *_ecore_exe_event_del_new(void);
+void          _ecore_exe_event_del_free(void *data, void *ev);
+#endif
+
+void          _ecore_animator_shutdown(void);
+
+void          _ecore_poller_shutdown(void);
+
+EAPI void         *_ecore_list2_append           (void *in_list, void 
*in_item);
+EAPI void         *_ecore_list2_prepend          (void *in_list, void 
*in_item);
+EAPI void         *_ecore_list2_append_relative  (void *in_list, void 
*in_item, void *in_relative);
+EAPI void         *_ecore_list2_prepend_relative (void *in_list, void 
*in_item, void *in_relative);
+EAPI void         *_ecore_list2_remove           (void *in_list, void 
*in_item);
+EAPI void         *_ecore_list2_find             (void *in_list, void 
*in_item);
+
+void          _ecore_fps_debug_init(void);
+void          _ecore_fps_debug_shutdown(void);
+void          _ecore_fps_debug_runtime_add(double t);
+
+void _ecore_thread_init(void);
+void _ecore_thread_shutdown(void);
+
+void _ecore_glib_init(void);
+void _ecore_glib_shutdown(void);
+
+void _ecore_job_init(void);
+void _ecore_job_shutdown(void);
+
+void _ecore_main_loop_init(void);
+void _ecore_main_loop_shutdown(void);
+
+extern int    _ecore_fps_debug;
+extern double _ecore_time_loop_time;
+extern Eina_Bool _ecore_glib_always_integrate;
+
+#endif
diff --git a/tests/suite/ecore/src/lib/ecore_signal.c 
b/tests/suite/ecore/src/lib/ecore_signal.c
new file mode 100644
index 0000000..10a4711
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_signal.c
@@ -0,0 +1,620 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <unistd.h>
+#include <assert.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+/* make mono happy - this is evil though... */
+#undef SIGPWR
+/* valgrind in some versions/setups uses SIGRT's... hmmm */
+#undef SIGRTMIN
+
+typedef void (*Signal_Handler)(int sig, siginfo_t *si, void *foo);
+
+static void _ecore_signal_callback_set(int sig, Signal_Handler func);
+static void _ecore_signal_callback_ignore(int sig, siginfo_t *si, void *foo);
+static void _ecore_signal_callback_sigchld(int sig, siginfo_t *si, void *foo);
+static void _ecore_signal_callback_sigusr1(int sig, siginfo_t *si, void *foo);
+static void _ecore_signal_callback_sigusr2(int sig, siginfo_t *si, void *foo);
+static void _ecore_signal_callback_sighup(int sig, siginfo_t *si, void *foo);
+static void _ecore_signal_callback_sigquit(int sig, siginfo_t *si, void *foo);
+static void _ecore_signal_callback_sigint(int sig, siginfo_t *si, void *foo);
+static void _ecore_signal_callback_sigterm(int sig, siginfo_t *si, void *foo);
+#ifdef SIGPWR
+static void _ecore_signal_callback_sigpwr(int sig, siginfo_t *si, void *foo);
+#endif
+
+#ifdef SIGRTMIN
+static void _ecore_signal_callback_sigrt(int sig, siginfo_t *si, void *foo);
+#endif
+
+static Eina_Bool _ecore_signal_exe_exit_delay(void *data);
+
+//#define MAXSIGQ 256 // 32k
+#define MAXSIGQ 64 // 8k
+
+static volatile sig_atomic_t sig_count = 0;
+static volatile sig_atomic_t sigchld_count = 0;
+static volatile sig_atomic_t sigusr1_count = 0;
+static volatile sig_atomic_t sigusr2_count = 0;
+static volatile sig_atomic_t sighup_count = 0;
+static volatile sig_atomic_t sigquit_count = 0;
+static volatile sig_atomic_t sigint_count = 0;
+static volatile sig_atomic_t sigterm_count = 0;
+#ifdef SIGPWR
+static volatile sig_atomic_t sigpwr_count = 0;
+#endif
+#ifdef SIGRTMIN
+static volatile sig_atomic_t *sigrt_count = NULL;
+#endif
+
+static volatile siginfo_t sigchld_info[MAXSIGQ];
+static volatile siginfo_t sigusr1_info[MAXSIGQ];
+static volatile siginfo_t sigusr2_info[MAXSIGQ];
+static volatile siginfo_t sighup_info[MAXSIGQ];
+static volatile siginfo_t sigquit_info[MAXSIGQ];
+static volatile siginfo_t sigint_info[MAXSIGQ];
+static volatile siginfo_t sigterm_info[MAXSIGQ];
+#ifdef SIGPWR
+static volatile siginfo_t sigpwr_info[MAXSIGQ];
+#endif
+#ifdef SIGRTMIN
+static volatile siginfo_t *sigrt_info[MAXSIGQ];
+#endif
+
+void
+_ecore_signal_shutdown(void)
+{
+#ifdef SIGRTMIN
+   int i, num = SIGRTMAX - SIGRTMIN;
+#endif
+
+   _ecore_signal_callback_set(SIGPIPE, (Signal_Handler) SIG_DFL);
+   _ecore_signal_callback_set(SIGALRM, (Signal_Handler) SIG_DFL);
+   _ecore_signal_callback_set(SIGCHLD, (Signal_Handler) SIG_DFL);
+   _ecore_signal_callback_set(SIGUSR1, (Signal_Handler) SIG_DFL);
+   _ecore_signal_callback_set(SIGUSR2, (Signal_Handler) SIG_DFL);
+   _ecore_signal_callback_set(SIGHUP,  (Signal_Handler) SIG_DFL);
+   _ecore_signal_callback_set(SIGQUIT, (Signal_Handler) SIG_DFL);
+   _ecore_signal_callback_set(SIGINT,  (Signal_Handler) SIG_DFL);
+   _ecore_signal_callback_set(SIGTERM, (Signal_Handler) SIG_DFL);
+#ifdef SIGPWR
+   _ecore_signal_callback_set(SIGPWR, (Signal_Handler) SIG_DFL);
+   sigpwr_count = 0;
+#endif
+   sigchld_count = 0;
+   sigusr1_count = 0;
+   sigusr2_count = 0;
+   sighup_count = 0;
+   sigquit_count = 0;
+   sigint_count = 0;
+   sigterm_count = 0;
+   sig_count = 0;
+
+#ifdef SIGRTMIN
+   for (i = 0; i < num; i++)
+     {
+        _ecore_signal_callback_set(SIGRTMIN + i, (Signal_Handler) SIG_DFL);
+        sigrt_count[i] = 0;
+     }
+
+   if (sigrt_count)
+     {
+        free((sig_atomic_t *) sigrt_count);
+        sigrt_count = NULL;
+     }
+
+   for (i = 0; i < MAXSIGQ; i++)
+     {
+        if (sigrt_info[i])
+          {
+             free((siginfo_t *) sigrt_info[i]);
+             sigrt_info[i] = NULL;
+          }
+     }
+#endif
+}
+
+void
+_ecore_signal_init(void)
+{
+#ifdef SIGRTMIN
+   int i, num = SIGRTMAX - SIGRTMIN;
+#endif
+
+   _ecore_signal_callback_set(SIGPIPE, _ecore_signal_callback_ignore);
+   _ecore_signal_callback_set(SIGALRM, _ecore_signal_callback_ignore);
+   _ecore_signal_callback_set(SIGCHLD, _ecore_signal_callback_sigchld);
+   _ecore_signal_callback_set(SIGUSR1, _ecore_signal_callback_sigusr1);
+   _ecore_signal_callback_set(SIGUSR2, _ecore_signal_callback_sigusr2);
+   _ecore_signal_callback_set(SIGHUP,  _ecore_signal_callback_sighup);
+   _ecore_signal_callback_set(SIGQUIT, _ecore_signal_callback_sigquit);
+   _ecore_signal_callback_set(SIGINT,  _ecore_signal_callback_sigint);
+   _ecore_signal_callback_set(SIGTERM, _ecore_signal_callback_sigterm);
+#ifdef SIGPWR
+   _ecore_signal_callback_set(SIGPWR,  _ecore_signal_callback_sigpwr);
+#endif
+
+#ifdef SIGRTMIN
+   sigrt_count = calloc(1, sizeof(sig_atomic_t) * num);
+   assert(sigrt_count);
+
+   for (i = 0; i < MAXSIGQ; i++)
+     {
+        sigrt_info[i] = calloc(1, sizeof(siginfo_t) * num);
+        assert(sigrt_info[i]);
+     }
+
+   for (i = 0; i < num; i++)
+      _ecore_signal_callback_set(SIGRTMIN + i, _ecore_signal_callback_sigrt);
+#endif
+}
+
+int
+_ecore_signal_count_get(void)
+{
+   return sig_count;
+}
+
+void
+_ecore_signal_call(void)
+{
+#ifdef SIGRTMIN
+   int i, num = SIGRTMAX - SIGRTMIN;
+#endif
+   volatile sig_atomic_t n;
+   sigset_t oldset, newset;
+
+   if (sig_count == 0) return;
+   sigemptyset(&newset);
+   sigaddset(&newset, SIGPIPE);
+   sigaddset(&newset, SIGALRM);
+   sigaddset(&newset, SIGCHLD);
+   sigaddset(&newset, SIGUSR1);
+   sigaddset(&newset, SIGUSR2);
+   sigaddset(&newset, SIGHUP);
+   sigaddset(&newset, SIGQUIT);
+   sigaddset(&newset, SIGINT);
+   sigaddset(&newset, SIGTERM);
+#ifdef SIGPWR
+   sigaddset(&newset, SIGPWR);
+#endif
+#ifdef SIGRTMIN
+   for (i = 0; i < num; i++)
+     sigaddset(&newset, SIGRTMIN + i);
+#endif
+   sigprocmask(SIG_BLOCK, &newset, &oldset);
+   if (sigchld_count > MAXSIGQ)
+     WRN("%i SIGCHLD in queue. max queue size %i. losing "
+          "siginfo for extra signals.", sigchld_count, MAXSIGQ);
+   for (n = 0; n < sigchld_count; n++)
+     {
+        pid_t pid;
+        int status;
+
+        while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
+          {
+             Ecore_Exe_Event_Del *e;
+
+             /* FIXME: If this process is set respawn, respawn with a suitable 
backoff
+              * period for those that need too much respawning.
+              */
+             e = _ecore_exe_event_del_new();
+             if (e)
+               {
+                  if (WIFEXITED(status))
+                    {
+                       e->exit_code = WEXITSTATUS(status);
+                       e->exited = 1;
+                    }
+                  else if (WIFSIGNALED(status))
+                    {
+                       e->exit_signal = WTERMSIG(status);
+                       e->signalled = 1;
+                    }
+                  e->pid = pid;
+                  e->exe = _ecore_exe_find(pid);
+
+                  if ((n < MAXSIGQ) && (sigchld_info[n].si_signo))
+                    e->data = sigchld_info[n]; /* No need to clone this. */
+
+                  if ((e->exe) && (ecore_exe_flags_get(e->exe) & 
(ECORE_EXE_PIPE_READ | ECORE_EXE_PIPE_ERROR)))
+                     {
+                        /* We want to report the Last Words of the exe, so 
delay this event.
+                         * This is twice as relevant for stderr.
+                         * There are three possibilities here -
+                         *  1 There are no Last Words.
+                         *  2 There are Last Words, they are not ready to be 
read.
+                         *  3 There are Last Words, they are ready to be read.
+                         *
+                         * For 1 we don't want to delay, for 3 we want to 
delay.
+                         * 2 is the problem.  If we check for data now and 
there
+                         * is none, then there is no way to differentiate 1 
and 2.
+                         * If we don't delay, we may loose data, but if we do 
delay,
+                         * there may not be data and the exit event never gets 
sent.
+                         *
+                         * Any way you look at it, there has to be some time 
passed
+                         * before the exit event gets sent.  So the strategy 
here is
+                         * to setup a timer event that will send the exit 
event after
+                         * an arbitrary, but brief, time.
+                         *
+                         * This is probably paranoid, for the less paraniod, 
we could
+                         * check to see for Last Words, and only delay if 
there are any.
+                         * This has it's own set of problems.
+                         */
+                        Ecore_Timer *doomsday_clock;
+
+                        doomsday_clock = _ecore_exe_doomsday_clock_get(e->exe);
+                        IF_FN_DEL(ecore_timer_del, doomsday_clock);
+                        _ecore_exe_doomsday_clock_set(e->exe, 
ecore_timer_add(0.1, _ecore_signal_exe_exit_delay, e));
+                     }
+                  else
+                    {
+                       _ecore_event_add(ECORE_EXE_EVENT_DEL, e,
+                                   _ecore_exe_event_del_free, NULL);
+                    }
+               }
+          }
+        sig_count--;
+     }
+   sigchld_count = 0;
+
+   if (sigusr1_count > MAXSIGQ)
+     WRN("%i SIGUSR1 in queue. max queue size %i. losing "
+         "siginfo for extra signals.", sigusr1_count, MAXSIGQ);
+   for (n = 0; n < sigusr1_count; n++)
+     {
+        Ecore_Event_Signal_User *e;
+
+        e = _ecore_event_signal_user_new();
+        if (e)
+          {
+             e->number = 1;
+
+             if ((n < MAXSIGQ) && (sigusr1_info[n].si_signo))
+               e->data = sigusr1_info[n];
+
+             ecore_event_add(ECORE_EVENT_SIGNAL_USER, e, NULL, NULL);
+          }
+        sig_count--;
+     }
+   sigusr1_count = 0;
+
+   if (sigusr2_count > MAXSIGQ)
+     WRN("%i SIGUSR2 in queue. max queue size %i. losing "
+         "siginfo for extra signals.", sigusr2_count, MAXSIGQ);
+   for (n = 0; n < sigusr2_count; n++)
+     {
+        Ecore_Event_Signal_User *e;
+
+        e = _ecore_event_signal_user_new();
+        if (e)
+          {
+             e->number = 2;
+
+             if ((n < MAXSIGQ) && (sigusr2_info[n].si_signo))
+               e->data = sigusr2_info[n];
+
+             ecore_event_add(ECORE_EVENT_SIGNAL_USER, e, NULL, NULL);
+          }
+        sig_count--;
+     }
+   sigusr2_count = 0;
+
+   if (sighup_count > MAXSIGQ)
+     WRN("%i SIGHUP in queue. max queue size %i. losing "
+         "siginfo for extra signals.", sighup_count, MAXSIGQ);
+   for (n = 0; n < sighup_count; n++)
+     {
+        Ecore_Event_Signal_Hup *e;
+
+        e = _ecore_event_signal_hup_new();
+        if (e)
+          {
+             if ((n < MAXSIGQ) && (sighup_info[n].si_signo))
+               e->data = sighup_info[n];
+
+             ecore_event_add(ECORE_EVENT_SIGNAL_HUP, e, NULL, NULL);
+          }
+        sig_count--;
+     }
+   sighup_count = 0;
+
+   if (sigquit_count > MAXSIGQ)
+     WRN("%i SIGQUIT in queue. max queue size %i. losing "
+         "siginfo for extra signals.", sigquit_count, MAXSIGQ);
+   for (n = 0; n < sigquit_count; n++)
+     {
+        Ecore_Event_Signal_Exit *e;
+
+        e = _ecore_event_signal_exit_new();
+        if (e)
+          {
+             e->quit = 1;
+
+             if ((n < MAXSIGQ) && (sigquit_info[n].si_signo))
+               e->data = sigquit_info[n];
+
+             ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, NULL, NULL);
+          }
+        sig_count--;
+     }
+   sigquit_count = 0;
+
+   if (sigint_count > MAXSIGQ)
+     WRN("%i SIGINT in queue. max queue size %i. losing "
+         "siginfo for extra signals.", sigint_count, MAXSIGQ);
+   for (n = 0; n < sigint_count; n++)
+     {
+        Ecore_Event_Signal_Exit *e;
+
+        e = _ecore_event_signal_exit_new();
+        if (e)
+          {
+             e->interrupt = 1;
+
+             if ((n < MAXSIGQ) && (sigint_info[n].si_signo))
+               e->data = sigint_info[n];
+
+             ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, NULL, NULL);
+          }
+        sig_count--;
+     }
+   sigint_count = 0;
+
+   if (sigterm_count > MAXSIGQ)
+     WRN("%i SIGTERM in queue. max queue size %i. losing "
+         "siginfo for extra signals.", sigterm_count, MAXSIGQ);
+   for (n = 0; n < sigterm_count; n++)
+     {
+        Ecore_Event_Signal_Exit *e;
+
+        e = _ecore_event_signal_exit_new();
+        if (e)
+          {
+             e->terminate = 1;
+
+             if ((n < MAXSIGQ) && (sigterm_info[n].si_signo))
+               e->data = sigterm_info[n];
+
+             ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e, NULL, NULL);
+          }
+        sig_count--;
+     }
+   sigterm_count = 0;
+
+#ifdef SIGPWR
+   if (sigpwr_count > MAXSIGQ)
+     WRN("%i SIGPWR in queue. max queue size %i. losing "
+         "siginfo for extra signals.", sigpwr_count, MAXSIGQ);
+   for (n = 0; n < sigpwr_count; n++)
+     {
+        Ecore_Event_Signal_Power *e;
+
+        e = _ecore_event_signal_power_new();
+        if (e)
+          {
+             if ((n < MAXSIGQ) && (sigpwr_info[n].si_signo))
+               e->data = sigpwr_info[n];
+
+             ecore_event_add(ECORE_EVENT_SIGNAL_POWER, e, NULL, NULL);
+          }
+        sig_count--;
+     }
+   sigpwr_count = 0;
+#endif
+
+#ifdef SIGRTMIN
+   for (i = 0; i < num; i++)
+     {
+        if (sigrt_count[i] > MAXSIGQ)
+          WRN("%i SIGRT%i in queue. max queue size %i. losing "
+              "siginfo for extra signals.", i + 1, sigrt_count[i], MAXSIGQ);
+        for (n = 0; n < sigrt_count[i]; n++)
+          {
+             Ecore_Event_Signal_Realtime *e;
+
+             if ((e = _ecore_event_signal_realtime_new()))
+               {
+                  e->num = i;
+
+                  if ((n < MAXSIGQ) && (sigrt_info[n][i].si_signo))
+                    e->data = sigrt_info[n][i];
+
+                  ecore_event_add(ECORE_EVENT_SIGNAL_REALTIME, e, NULL, NULL);
+               }
+             sig_count--;
+          }
+        sigrt_count[i] = 0;
+     }
+#endif
+   sigprocmask(SIG_SETMASK, &oldset, NULL);
+}
+
+static void
+_ecore_signal_callback_set(int sig, Signal_Handler func)
+{
+   struct sigaction  sa;
+
+   sa.sa_sigaction = func;
+   sa.sa_flags = SA_RESTART | SA_SIGINFO;
+   sigemptyset(&sa.sa_mask);
+   sigaction(sig, &sa, NULL);
+}
+
+static void
+_ecore_signal_callback_ignore(int sig __UNUSED__, siginfo_t *si __UNUSED__, 
void *foo __UNUSED__)
+{
+}
+
+static void
+_ecore_signal_callback_sigchld(int sig __UNUSED__, siginfo_t *si, void *foo 
__UNUSED__)
+{
+   volatile sig_atomic_t n;
+   n = sigchld_count;
+   if (n < MAXSIGQ)
+     {
+        if (si)
+          sigchld_info[n] = *si;
+        else
+          sigchld_info[n].si_signo = 0;
+     }
+
+   sigchld_count++;
+   sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigusr1(int sig __UNUSED__, siginfo_t *si, void *foo 
__UNUSED__)
+{
+   volatile sig_atomic_t n;
+   n = sigchld_count;
+   if (n < MAXSIGQ)
+     {
+        if (si)
+          sigusr1_info[n] = *si;
+        else
+          sigusr1_info[n].si_signo = 0;
+     }
+   sigusr1_count++;
+   sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigusr2(int sig __UNUSED__, siginfo_t *si, void *foo 
__UNUSED__)
+{
+   volatile sig_atomic_t n;
+   n = sigchld_count;
+   if (n < MAXSIGQ)
+     {
+        if (si)
+          sigusr2_info[n] = *si;
+        else
+          sigusr2_info[n].si_signo = 0;
+     }
+   sigusr2_count++;
+   sig_count++;
+}
+
+static void
+_ecore_signal_callback_sighup(int sig __UNUSED__, siginfo_t *si, void *foo 
__UNUSED__)
+{
+   volatile sig_atomic_t n;
+   n = sigchld_count;
+   if (n < MAXSIGQ)
+     {
+        if (si)
+          sighup_info[n] = *si;
+        else
+          sighup_info[n].si_signo = 0;
+     }
+   sighup_count++;
+   sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigquit(int sig __UNUSED__, siginfo_t *si, void *foo 
__UNUSED__)
+{
+   volatile sig_atomic_t n;
+   n = sigchld_count;
+   if (n < MAXSIGQ)
+     {
+        if (si)
+          sigquit_info[n] = *si;
+        else
+          sigquit_info[n].si_signo = 0;
+     }
+   sigquit_count++;
+   sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigint(int sig __UNUSED__, siginfo_t *si, void *foo 
__UNUSED__)
+{
+   volatile sig_atomic_t n;
+   n = sigchld_count;
+   if (n < MAXSIGQ)
+     {
+        if (si)
+          sigint_info[n] = *si;
+        else
+          sigint_info[n].si_signo = 0;
+     }
+   sigint_count++;
+   sig_count++;
+}
+
+static void
+_ecore_signal_callback_sigterm(int sig __UNUSED__, siginfo_t *si, void *foo 
__UNUSED__)
+{
+   volatile sig_atomic_t n;
+   n = sigchld_count;
+   if (n < MAXSIGQ)
+     {
+        if (si)
+          sigterm_info[n] = *si;
+        else
+          sigterm_info[n].si_signo = 0;
+     }
+   sigterm_count++;
+   sig_count++;
+}
+
+#ifdef SIGPWR
+static void
+_ecore_signal_callback_sigpwr(int sig __UNUSED__, siginfo_t *si, void *foo 
__UNUSED__)
+{
+   volatile sig_atomic_t n;
+   n = sigchld_count;
+   if (n < MAXSIGQ)
+     {
+        if (si)
+          sigpwr_info[n] = *si;
+        else
+          sigpwr_info[n].si_signo = 0;
+     }
+   sigpwr_count++;
+   sig_count++;
+}
+#endif
+
+#ifdef SIGRTMIN
+static void
+_ecore_signal_callback_sigrt(int sig, siginfo_t *si, void *foo __UNUSED__)
+{
+   volatile sig_atomic_t n;
+   n = sigchld_count;
+   if (n < MAXSIGQ)
+     {
+        if (si)
+          sigrt_info[n][sig - SIGRTMIN] = *si;
+        else
+          sigrt_info[n][sig - SIGRTMIN].si_signo = 0;
+     }
+   sigrt_count[sig - SIGRTMIN]++;
+   sig_count++;
+}
+#endif
+
+static Eina_Bool
+_ecore_signal_exe_exit_delay(void *data)
+{
+   Ecore_Exe_Event_Del *e;
+
+   e = data;
+   if (e)
+     {
+        _ecore_exe_doomsday_clock_set(e->exe, NULL);
+        _ecore_event_add(ECORE_EXE_EVENT_DEL, e,
+                         _ecore_exe_event_del_free, NULL);
+     }
+   return ECORE_CALLBACK_CANCEL;
+}
diff --git a/tests/suite/ecore/src/lib/ecore_thread.c 
b/tests/suite/ecore/src/lib/ecore_thread.c
new file mode 100644
index 0000000..c8a5daf
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_thread.c
@@ -0,0 +1,1226 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#ifdef EFL_HAVE_PTHREAD
+# include <pthread.h>
+# ifdef __linux__
+#  ifndef _GNU_SOURCE
+#   define _GNU_SOURCE 1
+#  endif
+#  include <sched.h>
+#  include <sys/time.h>
+#  include <sys/resource.h>
+#  include <unistd.h>
+#  include <sys/syscall.h>
+#  include <errno.h>
+# endif
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+typedef struct _Ecore_Pthread_Worker Ecore_Pthread_Worker;
+typedef struct _Ecore_Pthread Ecore_Pthread;
+typedef struct _Ecore_Thread_Data  Ecore_Thread_Data;
+
+struct _Ecore_Thread_Data
+{
+   void *data;
+   Eina_Free_Cb cb;
+};
+
+struct _Ecore_Pthread_Worker
+{
+   union {
+      struct {
+         Ecore_Cb func_blocking;
+      } short_run;
+      struct {
+         Ecore_Thread_Heavy_Cb func_heavy;
+         Ecore_Thread_Notify_Cb func_notify;
+         Ecore_Pipe *notify;
+      } feedback_run;
+   } u;
+   
+   Ecore_Cb func_cancel;
+   Ecore_Cb func_end;
+#ifdef EFL_HAVE_PTHREAD
+   pthread_t self;
+   Eina_Hash *hash;
+   pthread_cond_t cond;
+   pthread_mutex_t mutex;
+#endif
+   
+   const void *data;
+   
+   Eina_Bool cancel : 1;
+   Eina_Bool feedback_run : 1;
+};
+
+#ifdef EFL_HAVE_PTHREAD
+typedef struct _Ecore_Pthread_Data Ecore_Pthread_Data;
+
+struct _Ecore_Pthread_Data
+{
+   Ecore_Pipe *p;
+   void *data;
+   pthread_t thread;
+};
+#endif
+
+static int _ecore_thread_count_max = 0;
+static int ECORE_THREAD_PIPE_DEL = 0;
+
+#ifdef EFL_HAVE_PTHREAD
+static int _ecore_thread_count = 0;
+
+static Eina_List *_ecore_active_job_threads = NULL;
+static Eina_List *_ecore_pending_job_threads = NULL;
+static Eina_List *_ecore_pending_job_threads_feedback = NULL;
+static Ecore_Event_Handler *del_handler = NULL;
+static pthread_mutex_t _ecore_pending_job_threads_mutex = 
PTHREAD_MUTEX_INITIALIZER;
+
+static Eina_Hash *_ecore_thread_global_hash = NULL;
+static pthread_rwlock_t _ecore_thread_global_hash_lock = 
PTHREAD_RWLOCK_INITIALIZER;
+static pthread_mutex_t _ecore_thread_global_hash_mutex = 
PTHREAD_MUTEX_INITIALIZER;
+static pthread_cond_t _ecore_thread_global_hash_cond = 
PTHREAD_COND_INITIALIZER;
+static pthread_t main_loop_thread;
+static Eina_Bool have_main_loop_thread = 0;
+static void
+_ecore_thread_data_free(void *data)
+{
+   Ecore_Thread_Data *d = data;
+
+   if (d->cb) d->cb(d->data);
+   free(d);
+}
+
+static void
+_ecore_thread_pipe_free(void *data __UNUSED__, void *event)
+{
+   Ecore_Pipe *p = event;
+
+   ecore_pipe_del(p);
+}
+
+static Eina_Bool
+_ecore_thread_pipe_del(void *data __UNUSED__, int type __UNUSED__, void *event 
__UNUSED__)
+{
+   /* This is a hack to delay pipe destruction until we are out of its 
internal loop. */
+   return ECORE_CALLBACK_CANCEL;
+}
+
+static void
+_ecore_thread_end(Ecore_Pthread_Data *pth)
+{
+   Ecore_Pipe *p;
+
+   if (pthread_join(pth->thread, (void **) &p) != 0)
+     return ;
+
+   _ecore_active_job_threads = eina_list_remove(_ecore_active_job_threads, 
pth);
+
+   ecore_event_add(ECORE_THREAD_PIPE_DEL, pth->p, _ecore_thread_pipe_free, 
NULL);
+   free(pth);
+}
+
+static void
+_ecore_thread_handler(void *data __UNUSED__, void *buffer, unsigned int nbyte)
+{
+   Ecore_Pthread_Worker *work;
+
+   if (nbyte != sizeof (Ecore_Pthread_Worker *)) return ;
+
+   work = *(Ecore_Pthread_Worker **)buffer;
+
+   if (work->cancel)
+     {
+        if (work->func_cancel)
+          work->func_cancel((void *) work->data);
+     }
+   else
+     {
+        if (work->func_end)
+          work->func_end((void *) work->data);
+     }
+
+   if (work->feedback_run)
+        ecore_pipe_del(work->u.feedback_run.notify);
+   pthread_cond_destroy(&work->cond);
+   pthread_mutex_destroy(&work->mutex);
+   if (work->hash)
+     eina_hash_free(work->hash);
+   free(work);
+}
+
+static void
+_ecore_notify_handler(void *data, void *buffer, unsigned int nbyte)
+{
+   Ecore_Pthread_Worker *work = data;
+   void *user_data;
+
+   if (nbyte != sizeof (Ecore_Pthread_Worker *)) return ;
+
+   user_data = *(void **)buffer;
+
+   if (work->u.feedback_run.func_notify)
+     work->u.feedback_run.func_notify((Ecore_Thread *) work, user_data, (void 
*) work->data);
+}
+
+static void
+_ecore_short_job(Ecore_Pipe *end_pipe)
+{
+   Ecore_Pthread_Worker *work;
+
+   while (_ecore_pending_job_threads)
+     {
+        pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+
+        if (!_ecore_pending_job_threads)
+          {
+             pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+             break;
+          }
+
+        work = eina_list_data_get(_ecore_pending_job_threads);
+        _ecore_pending_job_threads = 
eina_list_remove_list(_ecore_pending_job_threads, _ecore_pending_job_threads);
+
+        pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+
+        if (!work->cancel)
+          work->u.short_run.func_blocking((void *) work->data);
+
+        ecore_pipe_write(end_pipe, &work, sizeof (Ecore_Pthread_Worker *));
+     }
+}
+
+static void
+_ecore_feedback_job(Ecore_Pipe *end_pipe, pthread_t thread)
+{
+   Ecore_Pthread_Worker *work;
+
+   while (_ecore_pending_job_threads_feedback)
+     {
+        pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+
+        if (!_ecore_pending_job_threads_feedback)
+          {
+             pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+             break;
+          }
+
+        work = eina_list_data_get(_ecore_pending_job_threads_feedback);
+        _ecore_pending_job_threads_feedback = 
eina_list_remove_list(_ecore_pending_job_threads_feedback, 
_ecore_pending_job_threads_feedback);
+
+        pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+
+        work->self = thread;
+        if (!work->cancel)
+          work->u.feedback_run.func_heavy((Ecore_Thread *) work, (void *) 
work->data);
+
+        ecore_pipe_write(end_pipe, &work, sizeof (Ecore_Pthread_Worker *));
+     }
+}
+
+static void *
+_ecore_direct_worker(Ecore_Pthread_Worker *work)
+{
+   Ecore_Pthread_Data *pth;
+
+   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+   pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+   eina_sched_prio_drop();
+
+   pth = malloc(sizeof (Ecore_Pthread_Data));
+   if (!pth) return NULL;
+
+   pth->p = ecore_pipe_add(_ecore_thread_handler, NULL);
+   if (!pth->p)
+     {
+        free(pth);
+        return NULL;
+     }
+   pth->thread = pthread_self();
+
+   work->self = pth->thread;
+   work->u.feedback_run.func_heavy((Ecore_Thread *) work, (void *) work->data);
+
+   ecore_pipe_write(pth->p, &work, sizeof (Ecore_Pthread_Worker *));
+
+   work = malloc(sizeof (Ecore_Pthread_Worker));
+   if (!work)
+     {
+        ecore_pipe_del(pth->p);
+        free(pth);
+        return NULL;
+     }
+
+   work->data = pth;
+   work->u.short_run.func_blocking = NULL;
+   work->func_end = (void *) _ecore_thread_end;
+   work->func_cancel = NULL;
+   work->cancel = EINA_FALSE;
+   work->feedback_run = EINA_FALSE;
+   work->hash = NULL;
+   pthread_cond_init(&work->cond, NULL);
+   pthread_mutex_init(&work->mutex, NULL);
+
+   ecore_pipe_write(pth->p, &work, sizeof (Ecore_Pthread_Worker *));
+
+   return pth->p;
+}
+
+static void *
+_ecore_thread_worker(Ecore_Pthread_Data *pth)
+{
+   Ecore_Pthread_Worker *work;
+
+   pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+   pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
+   eina_sched_prio_drop();
+
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+   _ecore_thread_count++;
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+
+ on_error:
+   if (_ecore_pending_job_threads) _ecore_short_job(pth->p);
+   if (_ecore_pending_job_threads_feedback) _ecore_feedback_job(pth->p, 
pth->thread);
+
+   /* FIXME: Check if there is feedback running task todo, and switch to 
feedback run handler. */
+
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+   if (_ecore_pending_job_threads)
+     {
+        pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+        goto on_error;
+     }
+   if (_ecore_pending_job_threads_feedback)
+     {
+        pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+        goto on_error;
+     }
+
+   _ecore_thread_count--;
+
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+
+   work = malloc(sizeof (Ecore_Pthread_Worker));
+   if (!work) return NULL;
+
+   work->data = pth;
+   work->u.short_run.func_blocking = NULL;
+   work->func_end = (void *) _ecore_thread_end;
+   work->func_cancel = NULL;
+   work->cancel = EINA_FALSE;
+   work->feedback_run = EINA_FALSE;
+   work->hash = NULL;
+   pthread_cond_init(&work->cond, NULL);
+   pthread_mutex_init(&work->mutex, NULL);
+
+   ecore_pipe_write(pth->p, &work, sizeof (Ecore_Pthread_Worker *));
+
+   return pth->p;
+}
+
+#endif
+
+void
+_ecore_thread_init(void)
+{
+   _ecore_thread_count_max = eina_cpu_count();
+   if (_ecore_thread_count_max <= 0)
+     _ecore_thread_count_max = 1;
+
+   ECORE_THREAD_PIPE_DEL = ecore_event_type_new();
+#ifdef EFL_HAVE_PTHREAD
+   del_handler = ecore_event_handler_add(ECORE_THREAD_PIPE_DEL, 
_ecore_thread_pipe_del, NULL);
+   main_loop_thread = pthread_self();
+   have_main_loop_thread = 1;
+#endif
+}
+
+void
+_ecore_thread_shutdown(void)
+{
+   /* FIXME: If function are still running in the background, should we kill 
them ? */
+#ifdef EFL_HAVE_PTHREAD
+   Ecore_Pthread_Worker *work;
+   Ecore_Pthread_Data *pth;
+
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+
+   EINA_LIST_FREE(_ecore_pending_job_threads, work)
+     {
+        if (work->func_cancel)
+          work->func_cancel((void *)work->data);
+        free(work);
+     }
+
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+
+   EINA_LIST_FREE(_ecore_active_job_threads, pth)
+     {
+        Ecore_Pipe *p;
+
+        pthread_cancel(pth->thread);
+        pthread_join(pth->thread, (void **) &p);
+
+        ecore_pipe_del(pth->p);
+     }
+   if (_ecore_thread_global_hash)
+     eina_hash_free(_ecore_thread_global_hash);
+   ecore_event_handler_del(del_handler);
+   have_main_loop_thread = 0;
+   del_handler = NULL;
+#endif
+}
+/**
+ * @addtogroup Ecore_Thread Ecore Thread Functions
+ * These functions allow for ecore-managed threads which integrate with 
ecore's main loop.
+ * @{
+ */
+
+/**
+ * @brief Run some blocking code in a parallel thread to avoid locking the 
main loop.
+ * @param func_blocking The function that should run in another thread.
+ * @param func_end The function that will be called in the main loop if the 
thread terminate correctly.
+ * @param func_cancel The function that will be called in the main loop if the 
thread is cancelled.
+ * @param data User context data to pass to all callback.
+ * @return A reference to the newly created thread instance, or NULL if it 
failed.
+ *
+ * ecore_thread_run provide a facility for easily managing blocking task in a
+ * parallel thread. You should provide three function. The first one, 
func_blocking,
+ * that will do the blocking work in another thread (so you should not use the
+ * EFL in it except Eina if you are careful). The second one, func_end,
+ * that will be called in Ecore main loop when func_blocking is done. So you
+ * can use all the EFL inside this function. The last one, func_cancel, will
+ * be called in the main loop if the thread is cancelled or could not run at 
all.
+ *
+ * Be aware, that you can't make assumption on the result order of func_end
+ * after many call to ecore_thread_run, as we start as much thread as the
+ * host CPU can handle.
+ */
+EAPI Ecore_Thread *
+ecore_thread_run(Ecore_Cb func_blocking,
+                 Ecore_Cb func_end,
+                 Ecore_Cb func_cancel,
+                 const void *data)
+{
+#ifdef EFL_HAVE_PTHREAD
+   Ecore_Pthread_Worker *work;
+   Ecore_Pthread_Data *pth = NULL;
+
+   if (!func_blocking) return NULL;
+
+   work = malloc(sizeof (Ecore_Pthread_Worker));
+   if (!work)
+     {
+        func_cancel((void *) data);
+        return NULL;
+     }
+
+   work->u.short_run.func_blocking = func_blocking;
+   work->hash = NULL;
+   pthread_cond_init(&work->cond, NULL);
+   pthread_mutex_init(&work->mutex, NULL);
+   work->func_end = func_end;
+   work->func_cancel = func_cancel;
+   work->cancel = EINA_FALSE;
+   work->feedback_run = EINA_FALSE;
+   work->data = data;
+
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+   _ecore_pending_job_threads = eina_list_append(_ecore_pending_job_threads, 
work);
+
+   if (_ecore_thread_count == _ecore_thread_count_max)
+     {
+        pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+        return (Ecore_Thread *) work;
+     }
+
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+
+   /* One more thread could be created. */
+   pth = malloc(sizeof (Ecore_Pthread_Data));
+   if (!pth) goto on_error;
+
+   pth->p = ecore_pipe_add(_ecore_thread_handler, NULL);
+   if (!pth->p) goto on_error;
+
+   if (pthread_create(&pth->thread, NULL, (void *) _ecore_thread_worker, pth) 
== 0)
+      return (Ecore_Thread *) work;
+
+ on_error:
+   if (pth)
+     {
+        if (pth->p) ecore_pipe_del(pth->p);
+        free(pth);
+     }
+
+   if (_ecore_thread_count == 0)
+     {
+        if (work->func_cancel)
+          work->func_cancel((void *) work->data);
+        free(work);
+        work = NULL;
+     }
+   return (Ecore_Thread *) work;
+#else
+   /*
+     If no thread and as we don't want to break app that rely on this
+     facility, we will lock the interface until we are done.
+    */
+   func_blocking((void *)data);
+   func_end((void *)data);
+
+   return NULL;
+#endif
+}
+
+/**
+ * @brief Cancel a running thread.
+ * @param thread The thread to cancel.
+ * @return Will return EINA_TRUE if the thread has been cancelled,
+ *         EINA_FALSE if it is pending.
+ *
+ * ecore_thread_cancel give the possibility to cancel a task still running. It
+ * will return EINA_FALSE, if the destruction is delayed or EINA_TRUE if it is
+ * cancelled after this call.
+ *
+ * You should use this function only in the main loop.
+ *
+ * func_end, func_cancel will destroy the handler, so don't use it after.
+ * And if ecore_thread_cancel return EINA_TRUE, you should not use 
Ecore_Thread also.
+ */
+EAPI Eina_Bool
+ecore_thread_cancel(Ecore_Thread *thread)
+{
+#ifdef EFL_HAVE_PTHREAD
+   Ecore_Pthread_Worker *work = (Ecore_Pthread_Worker *)thread;
+   Eina_List *l;
+   
+   if (!work)
+      return EINA_TRUE;
+   
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+   
+   if ((have_main_loop_thread) &&
+       (pthread_equal(main_loop_thread, pthread_self())))
+     {
+        EINA_LIST_FOREACH(_ecore_pending_job_threads, l, work)
+          {
+             if ((void *) work == (void *) thread)
+               {
+                  _ecore_pending_job_threads = 
eina_list_remove_list(_ecore_pending_job_threads, l);
+                  
+                  pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+                  
+                  if (work->func_cancel)
+                     work->func_cancel((void *) work->data);
+                  free(work);
+                  
+                  return EINA_TRUE;
+               }
+          }
+     }
+
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+
+   /* Delay the destruction */
+   ((Ecore_Pthread_Worker *)thread)->cancel = EINA_TRUE;
+   return EINA_FALSE;
+#else
+   return EINA_TRUE;
+#endif
+}
+
+/**
+ * @brief Tell if a thread was canceled or not.
+ * @param thread The thread to test.
+ * @return EINA_TRUE if the thread is cancelled,
+ *         EINA_FALSE if it is not.
+ *
+ * You can use this function in main loop and in the thread.
+ */
+EAPI Eina_Bool
+ecore_thread_check(Ecore_Thread *thread)
+{
+   Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
+
+   if (!worker) return EINA_TRUE;
+   return worker->cancel;
+}
+
+/**
+ * @brief Run some heavy code in a parallel thread to avoid locking the main 
loop.
+ * @param func_heavy The function that should run in another thread.
+ * @param func_notify The function that will receive the data send by 
func_heavy in the main loop.
+ * @param func_end The function that will be called in the main loop if the 
thread terminate correctly.
+ * @param func_cancel The function that will be called in the main loop if the 
thread is cancelled.
+ * @param data User context data to pass to all callback.
+ * @param try_no_queue If you wan't to run outside of the thread pool.
+ * @return A reference to the newly created thread instance, or NULL if it 
failed.
+ *
+ * ecore_thread_feedback_run provide a facility for easily managing heavy task 
in a
+ * parallel thread. You should provide four functions. The first one, 
func_heavy,
+ * that will do the heavy work in another thread (so you should not use the
+ * EFL in it except Eina and Eet if you are careful). The second one, 
func_notify,
+ * will receive the data send from the thread function (func_heavy) by 
ecore_thread_notify
+ * in the main loop (and so, can use all the EFL). Tje third, func_end,
+ * that will be called in Ecore main loop when func_heavy is done. So you
+ * can use all the EFL inside this function. The last one, func_cancel, will
+ * be called in the main loop also, if the thread is cancelled or could not 
run at all.
+ *
+ * Be aware, that you can't make assumption on the result order of func_end
+ * after many call to ecore_feedback_run, as we start as much thread as the
+ * host CPU can handle.
+ *
+ * If you set try_no_queue, it will try to run outside of the thread pool, 
this can bring
+ * the CPU down, so be careful with that. Of course if it can't start a new 
thread, it will
+ * try to use one from the pool.
+ */
+EAPI Ecore_Thread *ecore_thread_feedback_run(Ecore_Thread_Heavy_Cb func_heavy,
+                                             Ecore_Thread_Notify_Cb 
func_notify,
+                                             Ecore_Cb func_end,
+                                             Ecore_Cb func_cancel,
+                                             const void *data,
+                                             Eina_Bool try_no_queue)
+{
+
+#ifdef EFL_HAVE_PTHREAD
+   Ecore_Pthread_Worker *worker;
+   Ecore_Pthread_Data *pth = NULL;
+
+   if (!func_heavy) return NULL;
+
+   worker = malloc(sizeof (Ecore_Pthread_Worker));
+   if (!worker) goto on_error;
+
+   worker->u.feedback_run.func_heavy = func_heavy;
+   worker->u.feedback_run.func_notify = func_notify;
+   worker->hash = NULL;
+   pthread_cond_init(&worker->cond, NULL);
+   pthread_mutex_init(&worker->mutex, NULL);
+   worker->func_cancel = func_cancel;
+   worker->func_end = func_end;
+   worker->data = data;
+   worker->cancel = EINA_FALSE;
+   worker->feedback_run = EINA_TRUE;
+
+   worker->u.feedback_run.notify = ecore_pipe_add(_ecore_notify_handler, 
worker);
+
+   if (!try_no_queue)
+     {
+        pthread_t t;
+
+        if (pthread_create(&t, NULL, (void *) _ecore_direct_worker, worker) == 
0)
+           return (Ecore_Thread *) worker;
+     }
+
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+   _ecore_pending_job_threads_feedback = 
eina_list_append(_ecore_pending_job_threads_feedback, worker);
+
+   if (_ecore_thread_count == _ecore_thread_count_max)
+     {
+        pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+        return (Ecore_Thread *) worker;
+     }
+
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+
+   /* One more thread could be created. */
+   pth = malloc(sizeof (Ecore_Pthread_Data));
+   if (!pth) goto on_error;
+
+   pth->p = ecore_pipe_add(_ecore_thread_handler, NULL);
+   if (!pth->p) goto on_error;
+
+   if (pthread_create(&pth->thread, NULL, (void *) _ecore_thread_worker, pth) 
== 0)
+      return (Ecore_Thread *) worker;
+
+ on_error:
+   if (pth)
+     {
+        if (pth->p) ecore_pipe_del(pth->p);
+        free(pth);
+     }
+
+   if (_ecore_thread_count == 0)
+     {
+        if (func_cancel) func_cancel((void *) data);
+
+        if (worker)
+          {
+             ecore_pipe_del(worker->u.feedback_run.notify);
+             free(worker);
+             worker = NULL;
+          }
+     }
+
+   return (Ecore_Thread *) worker;
+#else
+   Ecore_Pthread_Worker worker;
+
+   (void) try_no_queue;
+
+   /*
+     If no thread and as we don't want to break app that rely on this
+     facility, we will lock the interface until we are done.
+    */
+   worker.u.feedback_run.func_heavy = func_heavy;
+   worker.u.feedback_run.func_notify = func_notify;
+   worker.u.feedback_run.notify = NULL;
+   worker.func_cancel = func_cancel;
+   worker.func_end = func_end;
+   worker.data = data;
+   worker.cancel = EINA_FALSE;
+   worker.feedback_run = EINA_TRUE;
+
+   func_heavy((Ecore_Thread *) &worker, (void *)data);
+
+   if (worker.cancel) func_cancel((void *)data);
+   else func_end((void *)data);
+
+   return NULL;
+#endif
+}
+
+/**
+ * @brief Send data to main loop from worker thread.
+ * @param thread The current Ecore_Thread context to send data from
+ * @param data Data to be transmitted to the main loop
+ * @return EINA_TRUE if data was successfully send to main loop,
+ *         EINA_FALSE if anything goes wrong.
+ *
+ * After a succesfull call, the data should be considered owned
+ * by the main loop.
+ *
+ * You should use this function only in the func_heavy call.
+ */
+EAPI Eina_Bool
+ecore_thread_feedback(Ecore_Thread *thread, const void *data)
+{
+   Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
+
+   if (!worker) return EINA_FALSE;
+   if (!worker->feedback_run) return EINA_FALSE;
+
+#ifdef EFL_HAVE_PTHREAD
+   if (!pthread_equal(worker->self, pthread_self())) return EINA_FALSE;
+
+   ecore_pipe_write(worker->u.feedback_run.notify, &data, sizeof (void *));
+
+   return EINA_TRUE;
+#else
+   worker->u.feedback_run.func_notify(thread, (void*) data, (void*) 
worker->data);
+
+   return EINA_TRUE;
+#endif
+}
+
+/**
+ * @brief Get number of active thread jobs
+ * @return Number of active threads running jobs
+ * This returns the number of threads currently running jobs through the
+ * ecore_thread api.
+ */
+EAPI int
+ecore_thread_active_get(void)
+{
+#ifdef EFL_HAVE_PTHREAD
+   return _ecore_thread_count;
+#else
+   return 0;
+#endif
+}
+
+/**
+ * @brief Get number of pending (short) thread jobs
+ * @return Number of pending threads running "short" jobs
+ * This returns the number of threads currently running jobs through the
+ * ecore_thread_run api call.
+ */
+EAPI int
+ecore_thread_pending_get(void)
+{
+   int ret;
+#ifdef EFL_HAVE_PTHREAD
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+   ret = eina_list_count(_ecore_pending_job_threads);
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+   return ret;
+#else
+   return 0;
+#endif
+}
+
+/**
+ * @brief Get number of pending feedback thread jobs
+ * @return Number of pending threads running "feedback" jobs
+ * This returns the number of threads currently running jobs through the
+ * ecore_thread_feedback_run api call.
+ */
+EAPI int
+ecore_thread_pending_feedback_get(void)
+{
+   int ret;
+#ifdef EFL_HAVE_PTHREAD
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+   ret = eina_list_count(_ecore_pending_job_threads_feedback);
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+   return ret;
+#else
+   return 0;
+#endif
+}
+
+/**
+ * @brief Get number of pending thread jobs
+ * @return Number of pending threads running jobs
+ * This returns the number of threads currently running jobs through the
+ * ecore_thread_run and ecore_thread_feedback_run api calls combined.
+ */
+EAPI int
+ecore_thread_pending_total_get(void)
+{
+   int ret;
+#ifdef EFL_HAVE_PTHREAD
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+   ret = eina_list_count(_ecore_pending_job_threads) + 
eina_list_count(_ecore_pending_job_threads_feedback);
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+   return ret;
+#else
+   return 0;
+#endif
+}
+
+/**
+ * @brief Get the max number of threads that can run simultaneously
+ * @return Max number of threads ecore will run
+ * This returns the total number of threads that ecore will attempt to run
+ * simultaneously.
+ */
+EAPI int
+ecore_thread_max_get(void)
+{
+   return _ecore_thread_count_max;
+}
+
+/**
+ * @brief Set the max number of threads that can run simultaneously
+ * @param num The new maximum
+ * This sets the maximum number of threads that ecore will try to run
+ * simultaneously.  This number cannot be < 1 or >= 2x the number of active 
cpus.
+ */
+EAPI void
+ecore_thread_max_set(int num)
+{
+   if (num < 1) return;
+   /* avoid doing something hilarious by blocking dumb users */
+   if (num >= (2 * eina_cpu_count())) return;
+
+   _ecore_thread_count_max = num;
+}
+
+/**
+ * @brief Reset the max number of threads that can run simultaneously
+ * This resets the maximum number of threads that ecore will try to run
+ * simultaneously to the number of active cpus.
+ */
+EAPI void
+ecore_thread_max_reset(void)
+{
+   _ecore_thread_count_max = eina_cpu_count();
+}
+
+/**
+ * @brief Get the number of threads which are available to be used
+ * @return The number of available threads
+ * This returns the number of threads slots that ecore has currently available.
+ * Assuming that you haven't changed the max number of threads with @ref 
ecore_thread_max_set
+ * this should be equal to (num_cpus - (active_running + 
active_feedback_running))
+ */
+EAPI int
+ecore_thread_available_get(void)
+{
+   int ret;
+#ifdef EFL_HAVE_PTHREAD
+   pthread_mutex_lock(&_ecore_pending_job_threads_mutex);
+   ret = _ecore_thread_count_max - _ecore_thread_count;
+   pthread_mutex_unlock(&_ecore_pending_job_threads_mutex);
+   return ret;
+#else
+   return 0;
+#endif
+}
+
+/**
+ * @brief Add data to the thread for subsequent use
+ * @param thread The thread context to add to
+ * @param key The name string to add the data with
+ * @param value The data to add
+ * @param cb The callback to free the data with
+ * @param direct If true, this will not copy the key string (like 
eina_hash_direct_add)
+ * @return EINA_TRUE on success, EINA_FALSE on failure
+ * This adds data to the thread context, allowing the thread
+ * to retrieve and use it without complicated mutexing.  This function can 
only be called by a
+ * *_run thread INSIDE the thread and will return EINA_FALSE in any case but 
success.
+ * All data added to the thread will be freed with its associated callback (if 
present)
+ * upon thread termination.  If no callback is specified, it is expected that 
the user will free the
+ * data, but this is most likely not what you want.
+ */
+EAPI Eina_Bool
+ecore_thread_local_data_add(Ecore_Thread *thread, const char *key, void 
*value, Eina_Free_Cb cb, Eina_Bool direct)
+{
+   Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
+   Ecore_Thread_Data *d;
+   Eina_Bool ret;
+
+   if ((!thread) || (!key) || (!value))
+     return EINA_FALSE;
+#ifdef EFL_HAVE_PTHREAD
+   if (!pthread_equal(worker->self, pthread_self())) return EINA_FALSE;
+
+   if (!worker->hash)
+     worker->hash = eina_hash_string_small_new(_ecore_thread_data_free);
+
+   if (!worker->hash)
+     return EINA_FALSE;
+
+   if (!(d = malloc(sizeof(Ecore_Thread_Data))))
+     return EINA_FALSE;
+
+   d->data = value;
+   d->cb = cb;
+
+   if (direct)
+     ret = eina_hash_direct_add(worker->hash, key, d);
+   else
+     ret = eina_hash_add(worker->hash, key, d);
+   pthread_cond_broadcast(&worker->cond);
+   return ret;
+#else
+   return EINA_TRUE;
+#endif
+}
+
+/**
+ * @brief Modify data in the thread, or add if not found
+ * @param thread The thread context
+ * @param key The name string to add the data with
+ * @param value The data to add
+ * @param cb The callback to free the data with
+ * @return The old data associated with @p key on success if modified, NULL if 
added
+ * This adds/modifies data in the thread context, adding only if modify fails.
+ * This function can only be called by a *_run thread INSIDE the thread.
+ * All data added to the thread pool will be freed with its associated 
callback (if present)
+ * upon thread termination.  If no callback is specified, it is expected that 
the user will free the
+ * data, but this is most likely not what you want.
+ */
+EAPI void *
+ecore_thread_local_data_set(Ecore_Thread *thread, const char *key, void 
*value, Eina_Free_Cb cb)
+{
+   Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
+   Ecore_Thread_Data *d, *r;
+   void *ret;
+   if ((!thread) || (!key) || (!value))
+     return NULL;
+#ifdef EFL_HAVE_PTHREAD
+   if (!pthread_equal(worker->self, pthread_self())) return NULL;
+
+   if (!worker->hash)
+     worker->hash = eina_hash_string_small_new(_ecore_thread_data_free);
+
+   if (!worker->hash)
+     return NULL;
+
+   if (!(d = malloc(sizeof(Ecore_Thread_Data))))
+     return NULL;
+
+   d->data = value;
+   d->cb = cb;
+
+   r = eina_hash_set(worker->hash, key, d);
+   pthread_cond_broadcast(&worker->cond);
+   ret = r->data;
+   free(r);
+   return ret;
+#else
+   return NULL;
+#endif
+}
+
+/**
+ * @brief Find data in the thread's data
+ * @param thread The thread context
+ * @param key The name string the data is associated with
+ * @return The value, or NULL on error
+ * This finds data in the thread context that has been previously added with 
@ref ecore_thread_local_data_add
+ * This function can only be called by a *_run thread INSIDE the thread, and 
will return NULL
+ * in any case but success.
+ */
+
+EAPI void *
+ecore_thread_local_data_find(Ecore_Thread *thread, const char *key)
+{
+   Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
+   Ecore_Thread_Data *d;
+
+   if ((!thread) || (!key))
+     return NULL;
+#ifdef EFL_HAVE_PTHREAD
+   if (!pthread_equal(worker->self, pthread_self())) return NULL;
+
+   if (!worker->hash)
+     return NULL;
+
+   d = eina_hash_find(worker->hash, key);
+   return d->data;
+#else
+   return NULL;
+#endif
+}
+
+/**
+ * @brief Delete data from the thread's data
+ * @param thread The thread context
+ * @param key The name string the data is associated with
+ * @return EINA_TRUE on success, EINA_FALSE on failure
+ * This deletes the data pointer from the thread context which was previously 
added with @ref ecore_thread_local_data_add
+ * This function can only be called by a *_run thread INSIDE the thread, and 
will return EINA_FALSE
+ * in any case but success.  Note that this WILL free the data if a callback 
was specified.
+ */
+EAPI Eina_Bool
+ecore_thread_local_data_del(Ecore_Thread *thread, const char *key)
+{
+   Ecore_Pthread_Worker *worker = (Ecore_Pthread_Worker *) thread;
+   Ecore_Thread_Data *d;
+   if ((!thread) || (!key))
+     return EINA_FALSE;
+#ifdef EFL_HAVE_PTHREAD
+   if (!pthread_equal(worker->self, pthread_self())) return EINA_FALSE;
+
+   if (!worker->hash)
+     return EINA_FALSE;
+   if ((d = eina_hash_find(worker->hash, key)))
+     _ecore_thread_data_free(d);
+   return eina_hash_del_by_key(worker->hash, key);
+#else
+   return EINA_TRUE;
+#endif
+}
+
+/**
+ * @brief Add data to the global data
+ * @param key The name string to add the data with
+ * @param value The data to add
+ * @param cb The optional callback to free the data with once ecore is shut 
down
+ * @param direct If true, this will not copy the key string (like 
eina_hash_direct_add)
+ * @return EINA_TRUE on success, EINA_FALSE on failure
+ * This adds data to the global thread data, and will return EINA_FALSE in any 
case but success.
+ * All data added to global can be manually freed, or a callback can be 
provided with @p cb which will
+ * be called upon ecore_thread shutting down.  Note that if you have manually 
freed data that a callback
+ * was specified for, you will most likely encounter a segv later on.
+ */
+EAPI Eina_Bool
+ecore_thread_global_data_add(const char *key, void *value, Eina_Free_Cb cb, 
Eina_Bool direct)
+{
+   Eina_Bool ret;
+   Ecore_Thread_Data *d;
+
+   if ((!key) || (!value))
+     return EINA_FALSE;
+#ifdef EFL_HAVE_PTHREAD
+   pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock);
+   if (!_ecore_thread_global_hash)
+     _ecore_thread_global_hash = 
eina_hash_string_small_new(_ecore_thread_data_free);
+   pthread_rwlock_unlock(&_ecore_thread_global_hash_lock);
+
+   if (!(d = malloc(sizeof(Ecore_Thread_Data))))
+     return EINA_FALSE;
+
+   d->data = value;
+   d->cb = cb;
+
+   if (!_ecore_thread_global_hash)
+     return EINA_FALSE;
+   pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock);
+   if (direct)
+     ret = eina_hash_direct_add(_ecore_thread_global_hash, key, d);
+   else
+     ret = eina_hash_add(_ecore_thread_global_hash, key, d);
+   pthread_rwlock_unlock(&_ecore_thread_global_hash_lock);
+   pthread_cond_broadcast(&_ecore_thread_global_hash_cond);
+   return ret;
+#else
+   return EINA_TRUE;
+#endif
+}
+
+/**
+ * @brief Add data to the global data
+ * @param key The name string to add the data with
+ * @param value The data to add
+ * @param cb The optional callback to free the data with once ecore is shut 
down
+ * @return An Ecore_Thread_Data on success, NULL on failure
+ * This adds data to the global thread data and returns NULL, or replaces the 
previous data
+ * associated with @p key and returning the previous data if it existed.  To 
see if an error occurred,
+ * one must use eina_error_get.
+ * All data added to global can be manually freed, or a callback can be 
provided with @p cb which will
+ * be called upon ecore_thread shutting down.  Note that if you have manually 
freed data that a callback
+ * was specified for, you will most likely encounter a segv later on.
+ */
+EAPI void *
+ecore_thread_global_data_set(const char *key, void *value, Eina_Free_Cb cb)
+{
+   Ecore_Thread_Data *d, *r;
+   void *ret;
+
+   if ((!key) || (!value))
+     return NULL;
+#ifdef EFL_HAVE_PTHREAD
+   pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock);
+   if (!_ecore_thread_global_hash)
+     _ecore_thread_global_hash = 
eina_hash_string_small_new(_ecore_thread_data_free);
+   pthread_rwlock_unlock(&_ecore_thread_global_hash_lock);
+
+   if (!_ecore_thread_global_hash)
+     return NULL;
+
+   if (!(d = malloc(sizeof(Ecore_Thread_Data))))
+     return NULL;
+
+   d->data = value;
+   d->cb = cb;
+
+   pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock);
+   r = eina_hash_set(_ecore_thread_global_hash, key, d);
+   pthread_rwlock_unlock(&_ecore_thread_global_hash_lock);
+   pthread_cond_broadcast(&_ecore_thread_global_hash_cond);
+
+   ret = r->data;
+   free(r);
+   return ret;
+#else
+   return NULL;
+#endif
+}
+
+/**
+ * @brief Find data in the global data
+ * @param key The name string the data is associated with
+ * @return The value, or NULL on error
+ * This finds data in the global data that has been previously added with @ref 
ecore_thread_global_data_add
+ * This function will return NULL in any case but success.
+ * All data added to global can be manually freed, or a callback can be 
provided with @p cb which will
+ * be called upon ecore_thread shutting down.  Note that if you have manually 
freed data that a callback
+ * was specified for, you will most likely encounter a segv later on.
+ * @note Keep in mind that the data returned can be used by multiple threads 
at a time, so you will most likely want to mutex
+ * if you will be doing anything with it.
+ */
+
+EAPI void *
+ecore_thread_global_data_find(const char *key)
+{
+   Ecore_Thread_Data *ret;
+   if (!key)
+     return NULL;
+#ifdef EFL_HAVE_PTHREAD
+   if (!_ecore_thread_global_hash) return NULL;
+
+   pthread_rwlock_rdlock(&_ecore_thread_global_hash_lock);
+   ret = eina_hash_find(_ecore_thread_global_hash, key);
+   pthread_rwlock_unlock(&_ecore_thread_global_hash_lock);
+   return ret->data;
+#else
+   return NULL;
+#endif
+}
+
+/**
+ * @brief Delete data from the global data
+ * @param key The name string the data is associated with
+ * @return EINA_TRUE on success, EINA_FALSE on failure
+ * This deletes the data pointer from the global data which was previously 
added with @ref ecore_thread_global_data_add
+ * This function will return EINA_FALSE in any case but success.
+ * Note that this WILL free the data if an @c Eina_Free_Cb was specified when 
the data was added.
+ */
+EAPI Eina_Bool
+ecore_thread_global_data_del(const char *key)
+{
+   Eina_Bool ret;
+   Ecore_Thread_Data *d;
+
+   if (!key)
+     return EINA_FALSE;
+#ifdef EFL_HAVE_PTHREAD
+   if (!_ecore_thread_global_hash)
+     return EINA_FALSE;
+
+   pthread_rwlock_wrlock(&_ecore_thread_global_hash_lock);
+   if ((d = eina_hash_find(_ecore_thread_global_hash, key)))
+     _ecore_thread_data_free(d);
+   ret = eina_hash_del_by_key(_ecore_thread_global_hash, key);
+   pthread_rwlock_unlock(&_ecore_thread_global_hash_lock);
+   return ret;
+#else
+   return EINA_TRUE;
+#endif
+}
+
+/**
+ * @brief Find data in the global data and optionally wait for the data if not 
found
+ * @param key The name string the data is associated with
+ * @param seconds The amount of time in seconds to wait for the data.  If 0, 
the call will be async and not wait for data.
+ * If < 0 the call will wait indefinitely for the data.
+ * @return The value, or NULL on failure
+ * This finds data in the global data that has been previously added with @ref 
ecore_thread_global_data_add
+ * This function will return NULL in any case but success.
+ * Use @p seconds to specify the amount of time to wait.  Use > 0 for an 
actual wait time, 0 to not wait, and < 0 to wait indefinitely.
+ * @note Keep in mind that the data returned can be used by multiple threads 
at a time, so you will most likely want to mutex
+ * if you will be doing anything with it.
+ */
+EAPI void *
+ecore_thread_global_data_wait(const char *key, double seconds)
+{
+   double time = 0;
+   Ecore_Thread_Data *ret = NULL;
+   if (!key)
+     return NULL;
+#ifdef EFL_HAVE_PTHREAD
+   if (!_ecore_thread_global_hash)
+     return NULL;
+   if (seconds > 0)
+     time = ecore_time_get() + seconds;
+
+   while (1)
+     {
+        struct timespec t = { 0, 0 };
+
+        t.tv_sec = (long int)time;
+        t.tv_nsec = (long int)((time - (double)t.tv_sec) * 1000000000);
+        pthread_rwlock_rdlock(&_ecore_thread_global_hash_lock);
+        ret = eina_hash_find(_ecore_thread_global_hash, key);
+        pthread_rwlock_unlock(&_ecore_thread_global_hash_lock);
+        if ((ret) || (!seconds) || ((seconds > 0) && (time <= 
ecore_time_get())))
+          break;
+        pthread_mutex_lock(&_ecore_thread_global_hash_mutex);
+        pthread_cond_timedwait(&_ecore_thread_global_hash_cond, 
&_ecore_thread_global_hash_mutex, &t);
+        pthread_mutex_unlock(&_ecore_thread_global_hash_mutex);
+     }
+   if (ret) return ret->data;
+   return NULL;
+#else
+   return NULL;
+#endif
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/ecore_time.c 
b/tests/suite/ecore/src/lib/ecore_time.c
new file mode 100644
index 0000000..1fbb478
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_time.c
@@ -0,0 +1,156 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+
+#ifdef HAVE_SYS_TIME_H
+# include <sys/time.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+#include <time.h>
+
+#ifdef HAVE_CLOCK_GETTIME
+static clockid_t _ecore_time_clock_id = -1;
+#endif
+double _ecore_time_loop_time = -1.0;
+
+/**
+ * Retrieves the current system time as a floating point value in seconds.
+ *
+ * This uses a monotonic clock and thus never goes back in time while
+ * machine is live (even if user changes time or timezone changes,
+ * however it may be reset whenever the machine is restarted).
+ *
+ * @see ecore_loop_time_get().
+ * @see ecore_time_unix_get().
+ *
+ * @return The number of seconds. Start time is not defined (it may be
+ *         when the machine was booted, unix time, etc), all it is
+ *         defined is that it never goes backwards (unless you got big critical
+ *         messages when the application started).
+ * @ingroup Ecore_Time_Group
+ */
+EAPI double
+ecore_time_get(void)
+{
+#ifdef HAVE_CLOCK_GETTIME
+   struct timespec t;
+
+   if (EINA_UNLIKELY(_ecore_time_clock_id < 0))
+      return ecore_time_unix_get();
+
+   if (EINA_UNLIKELY(clock_gettime(_ecore_time_clock_id, &t)))
+     {
+        CRIT("Cannot get current time.");
+        /* Try to at least return the latest value retrieved*/
+        return _ecore_time_loop_time;
+     }
+
+   return (double)t.tv_sec + (((double)t.tv_nsec) / 1000000000.0);
+#else
+   return ecore_time_unix_get();
+#endif
+}
+
+/**
+ * Retrieves the current UNIX time as a floating point value in seconds.
+ *
+ * @see ecore_time_get().
+ * @see ecore_loop_time_get().
+ *
+ * @return  The number of seconds since 12.00AM 1st January 1970.
+ * @ingroup Ecore_Time_Group
+ */
+EAPI double
+ecore_time_unix_get(void)
+{
+#ifdef HAVE_EVIL
+  return evil_time_get();
+#else
+# ifdef HAVE_GETTIMEOFDAY
+   struct timeval timev;
+
+   gettimeofday(&timev, NULL);
+   return (double)timev.tv_sec + (((double)timev.tv_usec) / 1000000);
+# else
+#  error "Your platform isn't supported yet"
+# endif
+#endif
+}
+
+/**
+ * Retrieves the time at which the last loop stopped waiting for timeouts or
+ * events.
+ *
+ * This gets the time that the main loop ceased waiting for timouts and/or
+ * events to come in or for signals or any other interrupt source. This should
+ * be considered a reference point for all time based activity that should
+ * calculate its timepoint from the return of ecore_loop_time_get(). Use this
+ * UNLESS you absolutely must get the current actual timepoint - then use
+ * ecore_time_get(). Note that this time is meant to be used as relative to
+ * other times obtained on this run. If you need absolute time references, use
+ * ecore_time_unix_get() instead.
+ *
+ * This function can be called before any loop has ever been run, but either
+ * ecore_init() or ecore_time_get() must have been called once.
+ *
+ * @return The number of seconds. Start time is not defined (it may be
+ *         when the machine was booted, unix time, etc), all it is
+ *         defined is that it never goes backwards (unless you got big critical
+ *         messages when the application started).
+ * @ingroup Ecore_Time_Group
+ */
+EAPI double
+ecore_loop_time_get(void)
+{
+   return _ecore_time_loop_time;
+}
+
+
+/**********************   Internal methods   ********************************/
+
+/* TODO: Documentation says "All  implementations  support  the  system-wide
+ * real-time clock, which is identified by CLOCK_REALTIME. Check if the 
fallback
+ * to unix time (without specifying the resolution) might be removed
+ */
+void
+_ecore_time_init(void)
+{
+#ifdef HAVE_CLOCK_GETTIME
+   struct timespec t;
+
+   if (_ecore_time_clock_id != -1) return;
+
+   if (!clock_gettime(CLOCK_MONOTONIC, &t))
+     {
+        _ecore_time_clock_id = CLOCK_MONOTONIC;
+        DBG("using CLOCK_MONOTONIC.");
+     }
+   else if (!clock_gettime(CLOCK_REALTIME, &t))
+     {
+        /* may go backwards */
+        _ecore_time_clock_id = CLOCK_REALTIME;
+        WRN("CLOCK_MONOTONIC not available. Fallback to CLOCK_REALTIME.");
+     }
+   else
+     {
+        _ecore_time_clock_id = -2;
+        CRIT("Cannot get a valid clock_gettime() clock id! "
+             "Fallback to unix time.");
+     }
+#else
+# warning "Your platform isn't supported yet"
+   CRIT("Platform does not support clock_gettime. "
+        "Fallback to unix time.");
+#endif
+
+   _ecore_time_loop_time = ecore_time_get();
+}
diff --git a/tests/suite/ecore/src/lib/ecore_timer.c 
b/tests/suite/ecore/src/lib/ecore_timer.c
new file mode 100644
index 0000000..fd6c64e
--- /dev/null
+++ b/tests/suite/ecore/src/lib/ecore_timer.c
@@ -0,0 +1,591 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "Ecore.h"
+#include "ecore_private.h"
+
+
+struct _Ecore_Timer
+{
+   EINA_INLIST;
+   ECORE_MAGIC;
+   double          in;
+   double          at;
+   double          pending;
+   Ecore_Task_Cb   func;
+   void           *data;
+
+   int             references;
+   unsigned char   delete_me : 1;
+   unsigned char   just_added : 1;
+   unsigned char   frozen : 1;
+};
+
+
+static void _ecore_timer_set(Ecore_Timer *timer, double at, double in, 
Ecore_Task_Cb func, void *data);
+
+static int          timers_added = 0;
+static int          timers_delete_me = 0;
+static Ecore_Timer *timers = NULL;
+static Ecore_Timer *timer_current = NULL;
+static Ecore_Timer *suspended = NULL;
+static double       last_check = 0.0;
+static double       precision = 10.0 / 1000000.0;
+
+/**
+ * @defgroup Ecore_Time_Group Ecore Time Functions
+ *
+ * Functions that deal with time.  These functions include those that simply
+ * retrieve it in a given format, and those that create events based on it.
+ */
+
+/**
+ * Retrieves the current precision used by timer infrastructure.
+ *
+ * @see ecore_timer_precision_set()
+ */
+EAPI double
+ecore_timer_precision_get(void)
+{
+   return precision;
+}
+
+/**
+ * Sets the precision to be used by timer infrastructure.
+ *
+ * When system calculates time to expire the next timer we'll be able
+ * to delay the timer by the given amount so more timers will fit in
+ * the same dispatch, waking up the system less often and thus being
+ * able to save power.
+ *
+ * Be aware that kernel may delay delivery even further, these delays
+ * are always possible due other tasks having higher priorities or
+ * other scheduler policies.
+ *
+ * Example:
+ *  We have 2 timers, one that expires in a 2.0s and another that
+ *  expires in 2.1s, if precision is 0.1s, then the Ecore will request
+ *  for the next expire to happen in 2.1s and not 2.0s and another one
+ *  of 0.1 as it would before.
+ *
+ * @note Ecore is smart enough to see if there are timers in the
+ * precision range, if it does not, in our example if no second timer
+ * in (T + precision) existed, then it would use the minimum timeout.
+ *
+ * @param value allowed introduced timeout delay, in seconds.
+ */
+EAPI void
+ecore_timer_precision_set(double value)
+{
+   if (value < 0.0)
+     {
+        ERR("Precision %f less than zero, ignored", value);
+        return;
+     }
+   precision = value;
+}
+
+/**
+ * Creates a timer to call the given function in the given period of time.
+ * @param   in   The interval in seconds.
+ * @param   func The given function.  If @p func returns 1, the timer is
+ *               rescheduled for the next interval @p in.
+ * @param   data Data to pass to @p func when it is called.
+ * @return  A timer object on success.  @c NULL on failure.
+ * @ingroup Ecore_Time_Group
+ *
+ * This function adds a timer and returns its handle on success and NULL on
+ * failure. The function @p func will be called every @p in seconds. The
+ * function will be passed the @p data pointer as its parameter.
+ *
+ * When the timer @p func is called, it must return a value of either 1
+ * (or ECORE_CALLBACK_RENEW) or 0 (or ECORE_CALLBACK_CANCEL).
+ * If it returns 1, it will be called again at the next tick, or if it returns
+ * 0 it will be deleted automatically making any references/handles for it
+ * invalid.
+ */
+EAPI Ecore_Timer *
+ecore_timer_add(double in, Ecore_Task_Cb func, const void *data)
+{
+   double now;
+   Ecore_Timer *timer;
+
+   if (!func) return NULL;
+   if (in < 0.0) in = 0.0;
+   timer = calloc(1, sizeof(Ecore_Timer));
+   if (!timer) return NULL;
+   ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
+   now = ecore_time_get();
+   _ecore_timer_set(timer, now + in, in, func, (void *)data);
+   return timer;
+}
+
+/**
+ * Creates a timer to call the given function in the given period of time.
+ * @param   in   The interval in seconds from current loop time.
+ * @param   func The given function.  If @p func returns 1, the timer is
+ *               rescheduled for the next interval @p in.
+ * @param   data Data to pass to @p func when it is called.
+ * @return  A timer object on success.  @c NULL on failure.
+ * @ingroup Ecore_Time_Group
+ *
+ * This is the same as ecore_timer_add(), but "now" is the time from
+ * ecore_loop_time_get() not ecore_time_get() as ecore_timer_add() uses. See
+ * ecore_timer_add() for more details.
+ */
+EAPI Ecore_Timer *
+ecore_timer_loop_add(double in, Ecore_Task_Cb func, const void *data)
+{
+   double now;
+   Ecore_Timer *timer;
+
+   if (!func) return NULL;
+   if (in < 0.0) in = 0.0;
+   timer = calloc(1, sizeof(Ecore_Timer));
+   if (!timer) return NULL;
+   ECORE_MAGIC_SET(timer, ECORE_MAGIC_TIMER);
+   now = ecore_loop_time_get();
+   _ecore_timer_set(timer, now + in, in, func, (void *)data);
+   return timer;
+}
+
+/**
+ * Delete the specified timer from the timer list.
+ * @param   timer The timer to delete.
+ * @return  The data pointer set for the timer when @ref ecore_timer_add was
+ *          called.  @c NULL is returned if the function is unsuccessful.
+ * @ingroup Ecore_Time_Group
+ *
+ * Note: @p timer must be a valid handle. If the timer function has already
+ * returned 0, the handle is no longer valid (and does not need to be delete).
+ */
+EAPI void *
+ecore_timer_del(Ecore_Timer *timer)
+{
+   if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
+     {
+        ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
+                         "ecore_timer_del");
+        return NULL;
+     }
+
+   if (timer->frozen && !timer->references)
+     {
+        void *data = timer->data;
+
+        suspended = (Ecore_Timer *) 
eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
+
+        if (timer->delete_me)
+          timers_delete_me--;
+
+        free(timer);
+        return data;
+     }
+
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(timer->delete_me, NULL);
+   timer->delete_me = 1;
+   timers_delete_me++;
+   return timer->data;
+}
+
+/**
+ * Change the interval the timer ticks of. If set during
+ * a timer call, this will affect the next interval.
+ *
+ * @param   timer The timer to change.
+ * @param   in    The interval in seconds.
+ * @ingroup Ecore_Time_Group
+ */
+EAPI void
+ecore_timer_interval_set(Ecore_Timer *timer, double in)
+{
+   if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
+     {
+        ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
+                         "ecore_timer_interval_set");
+        return;
+     }
+   timer->in = in;
+}
+
+/**
+ * Get the interval the timer ticks on.
+ *
+ * @param   timer The timer to retrieve the interval from
+ * @return  The interval on success. -1 on failure.
+ * @ingroup Ecore_Time_Group
+ */
+EAPI double
+ecore_timer_interval_get(Ecore_Timer *timer)
+{
+   if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
+     {
+        ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
+                         "ecore_timer_interval_get");
+        return -1.0;
+     }
+
+   return timer->in;
+}
+
+/**
+ * Add some delay for the next occurrence of a timer.
+ * This doesn't affect the interval of a timer.
+ *
+ * @param   timer The timer to change.
+ * @param   add   The dalay to add to the next iteration.
+ * @ingroup Ecore_Time_Group
+ */
+EAPI void
+ecore_timer_delay(Ecore_Timer *timer, double add)
+{
+   if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
+     {
+        ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
+                         "ecore_timer_delay");
+        return;
+     }
+
+   if (timer->frozen)
+     {
+        timer->pending += add;
+     }
+   else
+     {
+        timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), 
EINA_INLIST_GET(timer));
+        _ecore_timer_set(timer, timer->at + add, timer->in, timer->func, 
timer->data);
+     }
+}
+
+/**
+ * Get the pending time regarding a timer.
+ *
+ * @param        timer The timer to learn from.
+ * @ingroup        Ecore_Time_Group
+ */
+EAPI double
+ecore_timer_pending_get(Ecore_Timer *timer)
+{
+   double        now;
+
+   if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
+     {
+        ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
+                         "ecore_timer_pending_get");
+        return 0;
+     }
+
+   now = ecore_time_get();
+
+   if (timer->frozen)
+     return timer->pending;
+   return timer->at - now;
+}
+
+/**
+ *
+ *
+ */
+EAPI void
+ecore_timer_freeze(Ecore_Timer *timer)
+{
+   double now;
+
+   if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
+     {
+        ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
+                         "ecore_timer_freeze");
+        return ;
+     }
+
+   /* Timer already frozen */
+   if (timer->frozen)
+     return ;
+
+   timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), 
EINA_INLIST_GET(timer));
+   suspended = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(suspended), 
EINA_INLIST_GET(timer));
+
+   now = ecore_time_get();
+
+   timer->pending = timer->at - now;
+   timer->at = 0.0;
+   timer->frozen = 1;
+}
+
+EAPI void
+ecore_timer_thaw(Ecore_Timer *timer)
+{
+   double now;
+
+   if (!ECORE_MAGIC_CHECK(timer, ECORE_MAGIC_TIMER))
+     {
+        ECORE_MAGIC_FAIL(timer, ECORE_MAGIC_TIMER,
+                         "ecore_timer_thaw");
+        return ;
+     }
+
+   /* Timer not frozen */
+   if (!timer->frozen)
+     return ;
+
+   suspended = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(suspended), 
EINA_INLIST_GET(timer));
+   now = ecore_time_get();
+
+   _ecore_timer_set(timer, timer->pending + now, timer->in, timer->func, 
timer->data);
+}
+
+void
+_ecore_timer_shutdown(void)
+{
+   Ecore_Timer *timer;
+
+   while ((timer = timers))
+     {
+        timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), 
EINA_INLIST_GET(timers));
+        ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
+        free(timer);
+     }
+
+   while ((timer = suspended))
+     {
+        suspended = (Ecore_Timer *) 
eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(suspended));
+        ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
+        free(timer);
+     }
+
+   timer_current = NULL;
+}
+
+void
+_ecore_timer_cleanup(void)
+{
+   Ecore_Timer *l;
+   int in_use = 0, todo = timers_delete_me, done = 0;
+
+   if (!timers_delete_me) return;
+   for (l = timers; l;)
+     {
+        Ecore_Timer *timer = l;
+
+        l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
+        if (timer->delete_me)
+          {
+             if (timer->references)
+               {
+                  in_use++;
+                  continue;
+               }
+             timers = (Ecore_Timer *) 
eina_inlist_remove(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer));
+             ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
+             free(timer);
+             timers_delete_me--;
+             done++;
+             if (timers_delete_me == 0) return;
+          }
+     }
+   for (l = suspended; l;)
+     {
+        Ecore_Timer *timer = l;
+
+        l = (Ecore_Timer *) EINA_INLIST_GET(l)->next;
+        if (timer->delete_me)
+          {
+             if (timer->references)
+               {
+                  in_use++;
+                  continue;
+               }
+             suspended = (Ecore_Timer *) 
eina_inlist_remove(EINA_INLIST_GET(suspended), EINA_INLIST_GET(timer));
+             ECORE_MAGIC_SET(timer, ECORE_MAGIC_NONE);
+             free(timer);
+             timers_delete_me--;
+             done++;
+             if (timers_delete_me == 0) return;
+          }
+     }
+
+   if ((!in_use) && (timers_delete_me))
+     {
+        ERR("%d timers to delete, but they were not found!"
+            "Stats: todo=%d, done=%d, pending=%d, in_use=%d. "
+            "reset counter.",
+            timers_delete_me, todo, done, todo - done, in_use);
+        timers_delete_me = 0;
+     }
+}
+
+void
+_ecore_timer_enable_new(void)
+{
+   Ecore_Timer *timer;
+
+   if (!timers_added) return;
+   timers_added = 0;
+   EINA_INLIST_FOREACH(timers, timer) timer->just_added = 0;
+}
+
+int
+_ecore_timers_exists(void)
+{
+   Ecore_Timer *timer = timers;
+
+   while ((timer) && (timer->delete_me))
+     timer = (Ecore_Timer *)EINA_INLIST_GET(timer)->next;
+
+   return !!timer;
+}
+
+static inline Ecore_Timer *
+_ecore_timer_first_get(void)
+{
+   Ecore_Timer *timer = timers;
+
+   while ((timer) && ((timer->delete_me) || (timer->just_added)))
+     timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
+
+   return timer;
+}
+
+static inline Ecore_Timer *
+_ecore_timer_after_get(Ecore_Timer *base)
+{
+   Ecore_Timer *timer = (Ecore_Timer *) EINA_INLIST_GET(base)->next;
+   double maxtime = base->at + precision;
+
+   while ((timer) && ((timer->delete_me) || (timer->just_added)) && (timer->at 
<= maxtime))
+     timer = (Ecore_Timer *) EINA_INLIST_GET(timer)->next;
+
+   if ((!timer) || (timer->at > maxtime))
+     return NULL;
+
+   return timer;
+}
+
+double
+_ecore_timer_next_get(void)
+{
+   double now;
+   double in;
+   Ecore_Timer *first, *second;
+
+   first = _ecore_timer_first_get();
+   if (!first) return -1;
+
+   second = _ecore_timer_after_get(first);
+   if (second)
+     first = second;
+
+   now = ecore_loop_time_get();
+   in = first->at - now;
+   if (in < 0) in = 0;
+   return in;
+}
+
+static inline void
+_ecore_timer_reschedule(Ecore_Timer *timer, double when)
+{
+   if ((timer->delete_me) || (timer->frozen)) return;
+
+   timers = (Ecore_Timer *) eina_inlist_remove(EINA_INLIST_GET(timers), 
EINA_INLIST_GET(timer));
+
+   /* if the timer would have gone off more than 15 seconds ago,
+    * assume that the system hung and set the timer to go off
+    * timer->in from now. this handles system hangs, suspends
+    * and more, so ecore will only "replay" the timers while
+    * the system is suspended if it is suspended for less than
+    * 15 seconds (basically). this also handles if the process
+    * is stopped in a debugger or IO and other handling gets
+    * really slow within the main loop.
+    */
+   if ((timer->at + timer->in) < (when - 15.0))
+     _ecore_timer_set(timer, when + timer->in, timer->in, timer->func, 
timer->data);
+   else
+     _ecore_timer_set(timer, timer->at + timer->in, timer->in, timer->func, 
timer->data);
+}
+
+int
+_ecore_timer_call(double when)
+{
+   if (!timers) return 0;
+   if (last_check > when)
+     {
+        Ecore_Timer *timer;
+        /* User set time backwards */
+        EINA_INLIST_FOREACH(timers, timer) timer->at -= (last_check - when);
+     }
+   last_check = when;
+
+   if (!timer_current)
+     {
+        /* regular main loop, start from head */
+        timer_current = timers;
+     }
+   else
+     {
+        /* recursive main loop, continue from where we were */
+        Ecore_Timer *timer_old = timer_current;
+        timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
+        _ecore_timer_reschedule(timer_old, when);
+     }
+
+   while (timer_current)
+     {
+        Ecore_Timer *timer = timer_current;
+
+        if (timer->at > when)
+          {
+             timer_current = NULL; /* ended walk, next should restart. */
+             return 0;
+          }
+
+        if ((timer->just_added) || (timer->delete_me))
+          {
+             timer_current = 
(Ecore_Timer*)EINA_INLIST_GET(timer_current)->next;
+             continue;
+          }
+
+        timer->references++;
+        if (!timer->func(timer->data))
+          {
+             if (!timer->delete_me) ecore_timer_del(timer);
+          }
+        timer->references--;
+
+        if (timer_current) /* may have changed in recursive main loops */
+          timer_current = (Ecore_Timer *)EINA_INLIST_GET(timer_current)->next;
+
+        _ecore_timer_reschedule(timer, when);
+     }
+   return 0;
+}
+
+static void
+_ecore_timer_set(Ecore_Timer *timer, double at, double in, Ecore_Task_Cb func, 
void *data)
+{
+   Ecore_Timer *t2;
+
+   timers_added = 1;
+   timer->at = at;
+   timer->in = in;
+   timer->func = func;
+   timer->data = data;
+   timer->just_added = 1;
+   timer->frozen = 0;
+   timer->pending = 0.0;
+   if (timers)
+     {
+        EINA_INLIST_REVERSE_FOREACH(EINA_INLIST_GET(timers), t2)
+          {
+             if (timer->at > t2->at)
+               {
+                  timers = (Ecore_Timer *) 
eina_inlist_append_relative(EINA_INLIST_GET(timers), EINA_INLIST_GET(timer), 
EINA_INLIST_GET(t2));
+                  return;
+               }
+          }
+     }
+   timers = (Ecore_Timer *) eina_inlist_prepend(EINA_INLIST_GET(timers), 
EINA_INLIST_GET(timer));
+}
diff --git a/tests/suite/ecore/src/lib/eina_accessor.c 
b/tests/suite/ecore/src/lib/eina_accessor.c
new file mode 100644
index 0000000..cb20cab
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_accessor.c
@@ -0,0 +1,267 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_accessor.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static const char EINA_MAGIC_ACCESSOR_STR[] = "Eina Accessor";
+
+#define EINA_MAGIC_CHECK_ACCESSOR(d)                            \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_ACCESSOR)) {              \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_ACCESSOR); }                  \
+     } while(0)
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the accessor module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the accessor module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_accessor_init(void)
+{
+   return eina_magic_string_set(EINA_MAGIC_ACCESSOR, EINA_MAGIC_ACCESSOR_STR);
+}
+
+/**
+ * @internal
+ * @brief Shut down the accessor module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the accessor module set up by
+ * eina_accessor_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_accessor_shutdown(void)
+{
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Accessor_Group Accessor Functions
+ *
+ * @brief These functions manage accessor on containers.
+ *
+ * These functions allow to access elements of a container in a
+ * generic way, without knowing which container is used (a bit like
+ * iterators in the C++ STL). Accessors allows random access (that is, any
+ * element in the container). For sequential access, see
+ * @ref Eina_Iterator_Group.
+ *
+ * An accessor is created from container data types, so no creation
+ * function is available here. An accessor is deleted with
+ * eina_accessor_free(). To get the data of an element at a given
+ * position, use eina_accessor_data_get(). To call a function on
+ * chosen elements of a container, use eina_accessor_over().
+ *
+ * @{
+ */
+
+/**
+ * @brief Free an accessor.
+ *
+ * @param accessor The accessor to free.
+ *
+ * This function frees @p accessor if it is not @c NULL;
+ */
+EAPI void
+eina_accessor_free(Eina_Accessor *accessor)
+{
+   EINA_MAGIC_CHECK_ACCESSOR(accessor);
+   EINA_SAFETY_ON_NULL_RETURN(accessor);
+   EINA_SAFETY_ON_NULL_RETURN(accessor->free);
+   accessor->free(accessor);
+}
+
+/**
+ * @brief Return the container of an accessor.
+ *
+ * @param accessor The accessor.
+ * @return The container which created the accessor.
+ *
+ * This function returns the container which created @p accessor. If
+ * @p accessor is @c NULL, this function returns @c NULL.
+ */
+EAPI void *
+eina_accessor_container_get(Eina_Accessor *accessor)
+{
+   EINA_MAGIC_CHECK_ACCESSOR(accessor);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(accessor,                NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(accessor->get_container, NULL);
+   return accessor->get_container(accessor);
+}
+
+/**
+ * @brief Retrieve the data of an accessor at a given position.
+ *
+ * @param accessor The accessor.
+ * @param position The position of the element.
+ * @param data The pointer that stores the data to retrieve.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function retrieves the data of the element pointed by
+ * @p accessor at the porition @p position, and stores it in
+ * @p data. If @p accessor is @c NULL or if an error occurred,
+ * #EINA_FALSE is returned, otherwise EINA_TRUE is returned.
+ */
+EAPI Eina_Bool
+eina_accessor_data_get(Eina_Accessor *accessor,
+                       unsigned int position,
+                       void **data)
+{
+   EINA_MAGIC_CHECK_ACCESSOR(accessor);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(accessor,         EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(accessor->get_at, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data,             EINA_FALSE);
+   return accessor->get_at(accessor, position, data);
+}
+
+/**
+ * @brief Iterate over the container and execute a callback on chosen elements.
+ *
+ * @param accessor The accessor.
+ * @param cb The callback called on the chosen elements.
+ * @param start The position of the first element.
+ * @param end The position of the last element.
+ * @param fdata The data passed to the callback.
+ *
+ * This function iterates over the elements pointed by @p accessor,
+ * starting from the element at position @p start and ending to the
+ * element at position @p end. For Each element, the callback
+ * @p cb is called with the data @p fdata. If @p accessor is @c NULL
+ * or if @p start is greter or equal than @p end, the function returns
+ * immediately.
+ */
+EAPI void
+eina_accessor_over(Eina_Accessor *accessor,
+                   Eina_Each_Cb cb,
+                   unsigned int start,
+                   unsigned int end,
+                   const void *fdata)
+{
+   const void *container;
+   void *data;
+   unsigned int i;
+
+   EINA_MAGIC_CHECK_ACCESSOR(accessor);
+   EINA_SAFETY_ON_NULL_RETURN(accessor);
+   EINA_SAFETY_ON_NULL_RETURN(accessor->get_container);
+   EINA_SAFETY_ON_NULL_RETURN(accessor->get_at);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+   EINA_SAFETY_ON_FALSE_RETURN(start < end);
+
+   if (!eina_accessor_lock(accessor))
+      return ;
+
+   container = accessor->get_container(accessor);
+   for (i = start; i < end && accessor->get_at(accessor, i, &data) == 
EINA_TRUE;
+        ++i)
+      if (cb(container, data, (void *)fdata) != EINA_TRUE)
+        goto on_exit;
+
+ on_exit:
+   (void) eina_accessor_unlock(accessor);
+}
+
+/**
+ * @brief Lock the container of the accessor.
+ *
+ * @param accessor The accessor.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * If the container of the @p accessor permit it, it will be locked.
+ * If @p accessor is @c NULL or if a problem occurred, #EINA_FALSE is
+ * returned, otherwise #EINA_TRUE is returned. If the container
+ * is not lockable, it will return EINA_TRUE.
+ */
+EAPI Eina_Bool
+eina_accessor_lock(Eina_Accessor *accessor)
+{
+   EINA_MAGIC_CHECK_ACCESSOR(accessor);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(accessor, EINA_FALSE);
+
+   if (accessor->lock)
+      return accessor->lock(accessor);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Unlock the container of the accessor.
+ *
+ * @param accessor The accessor.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * If the container of the @p accessor permit it and was previously
+ * locked, it will be unlocked. If @p accessor is @c NULL or if a
+ * problem occurred, #EINA_FALSE is returned, otherwise #EINA_TRUE
+ * is returned. If the container is not lockable, it will return
+ * EINA_TRUE.
+ */
+EAPI Eina_Bool
+eina_accessor_unlock(Eina_Accessor *accessor)
+{
+   EINA_MAGIC_CHECK_ACCESSOR(accessor);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(accessor, EINA_FALSE);
+
+   if (accessor->unlock)
+      return accessor->unlock(accessor);
+   return EINA_TRUE;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_array.c 
b/tests/suite/ecore/src/lib/eina_array.c
new file mode 100644
index 0000000..bd71fc9
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_array.c
@@ -0,0 +1,727 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/**
+ * @page tutorial_array_page Array Tutorial
+ *
+ * The Array data type is allow the storage of data like a C array.
+ * It is designed such that the access to its element is very fast.
+ * But the addition or removal can be done only at the end of the
+ * array. To add or remove an element at any location, the Eina
+ * @ref Eina_List_Group is the correct container is the correct one.
+ *
+ * @section tutorial_error_basic_usage Basic Usage
+ *
+ * An array must created with eina_array_new(). That function
+ * takes an integer as parameter, which is the count of pointers to
+ * add when increasing the array size. Once the array is not used
+ * anymore, it must be destroyed with eina_array_free().
+ *
+ * To append data at the end of the array, the function
+ * eina_array_push() must be used. To remove the data at the end of
+ * the array, eina_array_pop() must be used. Once the array is filled,
+ * one can check its elements by iterating over it. A while loop and
+ * eina_array_data_get() can be used, or else one can use the
+ * predefined macro EINA_ARRAY_ITER_NEXT(). To free all the elements,
+ * a while loop can be used with eina_array_count_get(). Here is an
+ * example of use:
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ * #include <string.h>
+ *
+ * #include <eina_array.h>
+ *
+ * int main(void)
+ * {
+ *     const char *strings[] = {
+ *         "first string",
+ *         "second string",
+ *         "third string",
+ *         "fourth string"
+ *     };
+ *     Eina_Array         *array;
+ *     char               *item;
+ *     Eina_Array_Iterator iterator;
+ *     unsigned int        i;
+ *
+ *     if (!eina_init())
+ *     {
+ *         printf ("Error during the initialization of eina\n");
+ *         return EXIT_FAILURE;
+ *     }
+ *
+ *     array = eina_array_new(16);
+ *     if (!array)
+ *         goto shutdown;
+ *
+ *     for (i = 0; i < 4; i++)
+ *     {
+ *         eina_array_push(array, strdup(strings[i]));
+ *     }
+ *
+ *     printf("array count: %d\n", eina_array_count_get(array));
+ *     EINA_ARRAY_ITER_NEXT(array, i, item, iterator)
+ *     {
+ *         printf("item #%d: %s\n", i, item);
+ *     }
+ *
+ *     while (eina_array_count_get(array))
+ *     {
+ *         void *data;
+ *
+ *         data = eina_array_pop(array);
+ *         free(data);
+ *     }
+ *
+ *     eina_array_free(array);
+ *     eina_shutdown();
+ *
+ *     return EXIT_SUCCESS;
+ *
+ *   shutdown:
+ *     eina_shutdown();
+ *
+ *     return EXIT_FAILURE;
+ * }
+ * @endcode
+ *
+ * To be continued
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_error.h"
+#include "eina_log.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_array.h"
+
+/*============================================================================*
+ *                                  Local                                     *
+ 
*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static const char EINA_MAGIC_ARRAY_STR[] = "Eina Array";
+static const char EINA_MAGIC_ARRAY_ITERATOR_STR[] = "Eina Array Iterator";
+static const char EINA_MAGIC_ARRAY_ACCESSOR_STR[] = "Eina Array Accessor";
+
+#define EINA_MAGIC_CHECK_ARRAY(d)                       \
+   do {                                                  \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_ARRAY)) {        \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_ARRAY); }            \
+     } while (0)
+
+#define EINA_MAGIC_CHECK_ARRAY_ITERATOR(d, ...)                 \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_ARRAY_ITERATOR))       \
+          {                                                        \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_ARRAY_ITERATOR);        \
+             return __VA_ARGS__;                                   \
+          }                                                        \
+     } while (0)
+
+#define EINA_MAGIC_CHECK_ARRAY_ACCESSOR(d, ...)                 \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_ARRAY_ACCESSOR))       \
+          {                                                        \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_ACCESSOR);              \
+             return __VA_ARGS__;                                   \
+          }                                                        \
+     } while (0)
+
+
+typedef struct _Eina_Iterator_Array Eina_Iterator_Array;
+struct _Eina_Iterator_Array
+{
+   Eina_Iterator iterator;
+
+   const Eina_Array *array;
+   unsigned int index;
+
+   EINA_MAGIC
+};
+
+typedef struct _Eina_Accessor_Array Eina_Accessor_Array;
+struct _Eina_Accessor_Array
+{
+   Eina_Accessor accessor;
+   const Eina_Array *array;
+   EINA_MAGIC
+};
+
+static int _eina_array_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_array_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_array_log_dom, __VA_ARGS__)
+
+static void        eina_array_iterator_free(Eina_Iterator_Array *it) 
EINA_ARG_NONNULL(1);
+static Eina_Array *eina_array_iterator_get_container(Eina_Iterator_Array *it) 
EINA_ARG_NONNULL(1);
+static Eina_Bool   eina_array_iterator_next(Eina_Iterator_Array *it,
+                                            void **data) EINA_ARG_NONNULL(1);
+
+static Eina_Bool   eina_array_accessor_get_at(Eina_Accessor_Array *it,
+                                              unsigned int idx,
+                                              void **data) EINA_ARG_NONNULL(1);
+static Eina_Array *eina_array_accessor_get_container(Eina_Accessor_Array *it) 
EINA_ARG_NONNULL(1);
+static void        eina_array_accessor_free(Eina_Accessor_Array *it) 
EINA_ARG_NONNULL(1);
+
+static Eina_Bool
+eina_array_iterator_next(Eina_Iterator_Array *it, void **data)
+{
+   EINA_MAGIC_CHECK_ARRAY_ITERATOR(it, EINA_FALSE);
+
+   if (!(it->index < eina_array_count_get(it->array)))
+      return EINA_FALSE;
+
+   if (data)
+      *data = eina_array_data_get(it->array, it->index);
+
+   it->index++;
+   return EINA_TRUE;
+}
+
+static Eina_Array *
+eina_array_iterator_get_container(Eina_Iterator_Array *it)
+{
+   EINA_MAGIC_CHECK_ARRAY_ITERATOR(it, NULL);
+   return (Eina_Array *)it->array;
+}
+
+static void
+eina_array_iterator_free(Eina_Iterator_Array *it)
+{
+   EINA_MAGIC_CHECK_ARRAY_ITERATOR(it);
+   MAGIC_FREE(it);
+}
+
+static Eina_Bool
+eina_array_accessor_get_at(Eina_Accessor_Array *it,
+                           unsigned int idx,
+                           void **data)
+{
+   EINA_MAGIC_CHECK_ARRAY_ACCESSOR(it, EINA_FALSE);
+
+   if (!(idx < eina_array_count_get(it->array)))
+      return EINA_FALSE;
+
+   if (data)
+      *data = eina_array_data_get(it->array, idx);
+
+   return EINA_TRUE;
+}
+
+static Eina_Array *
+eina_array_accessor_get_container(Eina_Accessor_Array *it)
+{
+   EINA_MAGIC_CHECK_ARRAY_ACCESSOR(it, NULL);
+   return (Eina_Array *)it->array;
+}
+
+static void
+eina_array_accessor_free(Eina_Accessor_Array *it)
+{
+   EINA_MAGIC_CHECK_ARRAY_ACCESSOR(it);
+   MAGIC_FREE(it);
+}
+
+EAPI Eina_Bool
+eina_array_grow(Eina_Array *array)
+{
+   void **tmp;
+   unsigned int total;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(array, EINA_FALSE);
+
+   EINA_MAGIC_CHECK_ARRAY(array);
+
+   total = array->total + array->step;
+        eina_error_set(0);
+   tmp = realloc(array->data, sizeof (void *) * total);
+   if (EINA_UNLIKELY(!tmp))
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return 0;
+     }
+
+   array->total = total;
+   array->data = tmp;
+
+   return 1;
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ *                                 Global                                     *
+ 
*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the array module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the error and magic modules or Eina. It is
+ * called by eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_array_init(void)
+{
+   _eina_array_log_dom = eina_log_domain_register("eina_array",
+                                                  EINA_LOG_COLOR_DEFAULT);
+   if (_eina_array_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_array");
+        return EINA_FALSE;
+     }
+
+#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
+   EMS(EINA_MAGIC_ARRAY);
+   EMS(EINA_MAGIC_ARRAY_ITERATOR);
+   EMS(EINA_MAGIC_ARRAY_ACCESSOR);
+#undef EMS
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the array module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the array module set up by
+ * eina_array_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_array_shutdown(void)
+{
+   eina_log_domain_unregister(_eina_array_log_dom);
+   _eina_array_log_dom = -1;
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+ *                                   API                                      *
+ 
*============================================================================*/
+
+/**
+ * @addtogroup Eina_Array_Group Array
+ *
+ * @brief These functions provide array management.
+ *
+ * The Array data type in Eina is designed to have a very fast access to
+ * its data (compared to the Eina @ref Eina_List_Group). On the other hand,
+ * data can be added or removed only at the end of the array. To insert
+ * data at any place, the Eina @ref Eina_List_Group is the correct container
+ * to use.
+ *
+ * To use the array data type, eina_init() must be called before any
+ * other array functions. When eina is no more array function is used,
+ * eina_shutdown() must be called to free all the resources.
+ *
+ * An array must be created with eina_array_new(). It allocated all
+ * the necessary data for an array. When not needed anymore, an array
+ * is freed with eina_array_free(). This function does not free any
+ * allocated memory used to store the data of each element. For that,
+ * just iterate over the array to free them. A convenient way to do
+ * that is by using #EINA_ARRAY_ITER_NEXT. An example of code is given
+ * in the description of this macro.
+ *
+ * @warning All the other functions do not check if the used array is
+ * valid or not. It's up to the user to be sure of that. It is
+ * designed like that for performance reasons.
+ *
+ * The usual features of an array are classic ones: to append an
+ * element, use eina_array_push() and to remove the last element, use
+ * eina_array_pop(). To retrieve the element at a given positin, use
+ * eina_array_data_get(). The number of elements can be retrieved with
+ * eina_array_count_get().
+ *
+ * For more information, you can look at the @ref tutorial_array_page.
+ *
+ * @{
+ */
+
+/**
+ * @brief Create a new array.
+ *
+ * @param step The count of pointers to add when increasing the array size.
+ * @return @c NULL on failure, non @c NULL otherwise.
+ *
+ * This function creates a new array. When adding an element, the array
+ * allocates @p step elements. When that buffer is full, then adding
+ * another element will increase the buffer of @p step elements again.
+ *
+ * This function return a valid array on success, or @c NULL if memory
+ * allocation fails. In that case, the error is set to
+ * #EINA_ERROR_OUT_OF_MEMORY.
+ */
+EAPI Eina_Array *
+eina_array_new(unsigned int step)
+{
+   Eina_Array *array;
+
+   eina_error_set(0);
+   array = malloc(sizeof (Eina_Array));
+   if (!array)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(array, EINA_MAGIC_ARRAY);
+
+   array->version = EINA_ARRAY_VERSION;
+   array->data = NULL;
+   array->total = 0;
+   array->count = 0;
+   array->step = step;
+
+   return array;
+}
+
+/**
+ * @brief Free an array.
+ *
+ * @param array The array to free.
+ *
+ * This function frees @p array. It calls first eina_array_flush() then
+ * free the memory of the pointer. It does not free the memory
+ * allocated for the elements of @p array. To free them, use
+ * #EINA_ARRAY_ITER_NEXT. For performance reasons, there is no check
+ * of @p array.
+ */
+EAPI void
+eina_array_free(Eina_Array *array)
+{
+   eina_array_flush(array);
+
+   EINA_SAFETY_ON_NULL_RETURN(array);
+   EINA_MAGIC_CHECK_ARRAY(array);
+   MAGIC_FREE(array);
+}
+
+/**
+ * @brief Set the step of an array.
+ *
+ * @param array The array.
+ * @param sizeof_eina_array Should be the value returned by sizeof(Eina_Array).
+ * @param step The count of pointers to add when increasing the array size.
+ *
+ * This function sets the step of @p array to @p step. For performance
+ * reasons, there is no check of @p array. If it is @c NULL or
+ * invalid, the program may crash. This function should be called when
+ * the array is not initialized.
+ */
+EAPI void
+eina_array_step_set(Eina_Array *array,
+                   unsigned int sizeof_eina_array,
+                   unsigned int step)
+{
+   EINA_SAFETY_ON_NULL_RETURN(array);
+
+   if (sizeof (Eina_Array) != sizeof_eina_array)
+     {
+       ERR("Unknow Eina_Array size ! Got %i, expected %i !\n",
+           sizeof_eina_array,
+           (int) sizeof (Eina_Array));
+       /* Force memory to zero to provide a small layer of security */
+       memset(array, 0, sizeof_eina_array);
+       return ;
+     }
+
+   array->version = EINA_ARRAY_VERSION;
+   array->data = NULL;
+   array->total = 0;
+   array->count = 0;
+   array->step = step;
+   EINA_MAGIC_SET(array, EINA_MAGIC_ARRAY);
+}
+
+/**
+ * @brief Clean an array.
+ *
+ * @param array The array to clean.
+ *
+ * This function sets the count member of @p array to 0. For
+ * performance reasons, there is no check of @p array. If it is
+ * @c NULL or invalid, the program may crash.
+ */
+EAPI void
+eina_array_clean(Eina_Array *array)
+{
+   EINA_SAFETY_ON_NULL_RETURN(array);
+   EINA_MAGIC_CHECK_ARRAY(array);
+
+   array->count = 0;
+}
+
+/**
+ * @brief Flush an array.
+ *
+ * @param array The array to flush.
+ *
+ * This function sets the count and total members of @p array to 0,
+ * frees and set to NULL its data member. For performance reasons,
+ * there is no check of @p array. If it is @c NULL or invalid, the
+ * program may crash.
+ */
+EAPI void
+eina_array_flush(Eina_Array *array)
+{
+   EINA_SAFETY_ON_NULL_RETURN(array);
+   EINA_MAGIC_CHECK_ARRAY(array);
+
+   array->count = 0;
+   array->total = 0;
+
+   if (!array->data)
+      return;
+
+   free(array->data);
+   array->data = NULL;
+}
+
+/**
+ * @brief Rebuild an array by specifying the data to keep.
+ *
+ * @param array The array.
+ * @param keep The functions which selects the data to keep.
+ * @param gdata The data to pass to the function keep.
+ * @return #EINA_TRUE on success, #EINA_FALSE oterwise.
+ *
+ * This function rebuilds @p array be specifying the elements to keep
+ * with the function @p keep. @p gdata is an additional data to pass
+ * to @p keep. For performance reasons, there is no check of @p
+ * array. If it is @c NULL or invalid, the program may crash.
+ *
+ * This function always return a valid array. If it wasn't able to
+ * remove items due to an allocation failure, it will return #EINA_FALSE
+ * and the error is set to #EINA_ERROR_OUT_OF_MEMORY.
+ */
+EAPI Eina_Bool
+eina_array_remove(Eina_Array *array, Eina_Bool (*keep)(void *data,
+                                                       void *gdata),
+                  void *gdata)
+{
+   void **tmp;
+   /* WARNING:
+      The algorithm does exit before using unitialized data. So compiler is
+      giving you a false positiv here too.
+    */
+   void *data = NULL;
+   unsigned int total = 0;
+   unsigned int limit;
+   unsigned int i;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(array, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(keep,  EINA_FALSE);
+   EINA_MAGIC_CHECK_ARRAY(array);
+
+   if (array->total == 0)
+      return EINA_TRUE;
+
+   for (i = 0; i < array->count; ++i)
+     {
+        data = eina_array_data_get(array, i);
+
+        if (keep(data, gdata) == EINA_FALSE)
+           break;
+     }
+   limit = i;
+   if (i < array->count)
+      ++i;
+
+   for (; i < array->count; ++i)
+     {
+        data = eina_array_data_get(array, i);
+
+        if (keep(data, gdata) == EINA_TRUE)
+           break;
+     }
+   /* Special case all objects that need to stay are at the beginning of the 
array. */
+   if (i == array->count)
+     {
+        array->count = limit;
+        if (array->count == 0)
+          {
+             free(array->data);
+             array->total = 0;
+             array->data = NULL;
+          }
+
+        return EINA_TRUE;
+     }
+
+        eina_error_set(0);
+   tmp = malloc(sizeof (void *) * array->total);
+   if (!tmp)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return EINA_FALSE;
+     }
+
+   memcpy(tmp, array->data, limit * sizeof(void *));
+   total = limit;
+
+   if (i < array->count)
+     {
+        tmp[total] = data;
+        total++;
+        ++i;
+     }
+
+   for (; i < array->count; ++i)
+     {
+        data = eina_array_data_get(array, i);
+
+        if (keep(data, gdata))
+          {
+             tmp[total] = data;
+             total++;
+          }
+     }
+
+   free(array->data);
+
+   /* If we do not keep any object in the array, we should have exited
+      earlier in test (i == array->count). */
+   assert(total != 0);
+
+   array->data = tmp;
+   array->count = total;
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Returned a new iterator associated to an array.
+ *
+ * @param array The array.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to
+ * @p array. If @p array is @c NULL or the count member of @p array is
+ * less or equal than 0, this function returns NULL. If the memory can
+ * not be allocated, NULL is returned and #EINA_ERROR_OUT_OF_MEMORY is
+ * set. Otherwise, a valid iterator is returned.
+ */
+EAPI Eina_Iterator *
+eina_array_iterator_new(const Eina_Array *array)
+{
+   Eina_Iterator_Array *it;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(array, NULL);
+   EINA_MAGIC_CHECK_ARRAY(array);
+
+   eina_error_set(0);
+   it = calloc(1, sizeof (Eina_Iterator_Array));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(it,            EINA_MAGIC_ARRAY_ITERATOR);
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->array = array;
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(eina_array_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         eina_array_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(eina_array_iterator_free);
+
+   return &it->iterator;
+}
+
+/**
+ * @brief Returned a new accessor associated to an array.
+ *
+ * @param array The array.
+ * @return A new accessor.
+ *
+ * This function returns a newly allocated accessor associated to
+ * @p array. If @p array is @c NULL or the count member of @p array is
+ * less or equal than 0, this function returns NULL. If the memory can
+ * not be allocated, NULL is returned and #EINA_ERROR_OUT_OF_MEMORY is
+ * set. Otherwise, a valid accessor is returned.
+ */
+EAPI Eina_Accessor *
+eina_array_accessor_new(const Eina_Array *array)
+{
+   Eina_Accessor_Array *ac;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(array, NULL);
+   EINA_MAGIC_CHECK_ARRAY(array);
+
+   eina_error_set(0);
+   ac = calloc(1, sizeof (Eina_Accessor_Array));
+   if (!ac)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(ac,            EINA_MAGIC_ARRAY_ACCESSOR);
+   EINA_MAGIC_SET(&ac->accessor, EINA_MAGIC_ACCESSOR);
+
+   ac->array = array;
+
+   ac->accessor.version = EINA_ACCESSOR_VERSION;
+   ac->accessor.get_at = FUNC_ACCESSOR_GET_AT(eina_array_accessor_get_at);
+   ac->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(
+         eina_array_accessor_get_container);
+   ac->accessor.free = FUNC_ACCESSOR_FREE(eina_array_accessor_free);
+
+   return &ac->accessor;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_benchmark.c 
b/tests/suite/ecore/src/lib/eina_benchmark.c
new file mode 100644
index 0000000..5cd3fd3
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_benchmark.c
@@ -0,0 +1,742 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/**
+ * @page tutorial_benchmark_page Benchmark Tutorial
+ *
+ * The Benchmark module allows you to write easily benchmarks
+ * framework in a project for timing critical part and detect slow
+ * parts of code. In addition it automatically creates data files of
+ * these benchmark, as well as a gnuplot file which can display the
+ * comparison curves of the benchmarks.
+ *
+ * @section tutorial_benchmark_basic_usage Basic Usage
+ *
+ * To create a basic benchmark, you have to follow these steps:
+ *
+ * @li Create a new bechmark
+ * @li Write the functions that wraps the the functions you want to
+ * bechmark.
+ * @li Register these wrappers functions.
+ * @li Run the benchmark.
+ * @li Free the memory.
+ *
+ * Here is a basic example of bechmark which creates two functions
+ * that will be run. These functions just print a message.
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ *
+ * #include <Eina.h>
+ *
+ * static
+ * void work1(int request)
+ * {
+ *   printf ("work1 in progress... Request: %d\n", request);
+ * }
+ *
+ * static
+ * void work2(int request)
+ * {
+ *   printf ("work2 in progress... Request: %d\n", request);
+ * }
+ *
+ * int main()
+ * {
+ *   Eina_Benchmark *test;
+ *   Eina_Array     *ea;
+ *
+ *   if (!eina_init())
+ *     return EXIT_FAILURE;
+ *
+ *   test = eina_benchmark_new("test", "run");
+ *   if (!test)
+ *     goto shutdown_eina;
+ *
+ *   eina_benchmark_register(test, "work-1", EINA_BENCHMARK(work1), 200, 300, 
10);
+ *   eina_benchmark_register(test, "work-2", EINA_BENCHMARK(work2), 100, 150, 
5);
+ *
+ *   ea = eina_benchmark_run(test);
+ *
+ *   eina_benchmark_free(test);
+ *   eina_shutdown();
+ *
+ *   return EXIT_SUCCESS;
+ *
+ *  shutdown_eina:
+ *   eina_shutdown();
+ *
+ *   return EXIT_FAILURE;
+ * }
+ * @endcode
+ *
+ * As "test", "run" are passed to eina_benchmark_new() and as the tests
+ * "work-1" and "work-2" are registered, the data files
+ * bench_test_run.work-1.data and bench_test_run.work-2.data will be
+ * created after the eina_benchmark_run() call. They contain four
+ * columns. The file bench_test_run.work-1.data contains for example:
+ *
+ * @code
+ * # specimen      experiment time starting time   ending time
+ * 200     23632   2852446 2876078
+ * 210     6924    2883046 2889970
+ * 220     6467    2895962 2902429
+ * 230     6508    2908271 2914779
+ * 240     6278    2920610 2926888
+ * 250     6342    2932830 2939172
+ * 260     6252    2944954 2951206
+ * 270     6463    2956978 2963441
+ * 280     6347    2969548 2975895
+ * 290     6457    2981702 2988159
+ * @endcode
+ *
+ * The first column (specimen) is the integer passed to the work1()
+ * function when the test is run. The second column (experiment time)
+ * is the time, in nanosecond, that work1() takes. The third and
+ * fourth columnd are self-explicit.
+ *
+ * You can see that the integer passed work1() starts from 200 and
+ * finishes at 290, with a step of 10. These values are computed withe
+ * last 3 values passed to eina_benchmark_register(). See the document
+ * of that function for the detailed behavior.
+ *
+ * The gnuplot file will be named bench_test_run.gnuplot. Just run:
+ *
+ * @code
+ * gnuplot bench_test_run.gnuplot
+ * @endcode
+ *
+ * to create the graphic of the comparison curves. The image file is
+ * named output_test_run.png.
+ *
+ * @section tutorial_benchmark_advanced_usage More Advanced Usage
+ *
+ * In this section, several test will be created and run. The idea is
+ * exactly the same than in the previous section, but with some basic
+ * automatic way to run all the benchmarks. The following code
+ * benchmarks some Eina converts functions, and some Eina containers
+ * types:
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ * #include <time.h>
+ *
+ * #include <Eina.h>
+ *
+ * static void bench_convert(Eina_Benchmark *bench);
+ * static void bench_container(Eina_Benchmark *bench);
+ *
+ * typedef struct _Benchmark_Case Benchmark_Case;
+ *
+ * struct _Benchmark_Case
+ * {
+ *    const char *bench_case;
+ *    void (*build)(Eina_Benchmark *bench);
+ * };
+ *
+ * static const Benchmark_Case benchmarks[] = {
+ *   { "Bench 1", bench_convert },
+ *   { "Bench 2", bench_container },
+ *   { NULL,      NULL }
+ * };
+ *
+ * static
+ * void convert1(int request)
+ * {
+ *   char tmp[128];
+ *   int i;
+ *
+ *   srand(time(NULL));
+ *
+ *   for (i = 0; i < request; ++i)
+ *     eina_convert_itoa(rand(), tmp);
+ * }
+ *
+ * static
+ * void convert2(int request)
+ * {
+ *   char tmp[128];
+ *   int i;
+ *
+ *   srand(time(NULL));
+ *
+ *   for (i = 0; i < request; ++i)
+ *     eina_convert_xtoa(rand(), tmp);
+ * }
+ *
+ * static void
+ * bench_convert(Eina_Benchmark *bench)
+ * {
+ *   eina_benchmark_register(bench, "convert-1", EINA_BENCHMARK(convert1), 
200, 400, 10);
+ *   eina_benchmark_register(bench, "convert-2", EINA_BENCHMARK(convert2), 
200, 400, 10);
+ * }
+ *
+ * static
+ * void array(int request)
+ * {
+ *   Eina_Array *array;
+ *   Eina_Array_Iterator it;
+ *   int *data;
+ *   int i;
+ *
+ *   srand(time(NULL));
+ *
+ *   array = eina_array_new(64);
+ *
+ *   for (i = 0; i < request; ++i)
+ *     {
+ *       data = (int *)malloc(sizeof(int));
+ *       if (!data) continue;
+ *       *data = rand();
+ *       eina_array_push(array, data);
+ *     }
+ *
+ *   EINA_ARRAY_ITER_NEXT(array, i, data, it)
+ *     free(data);
+ *
+ *   eina_array_free(array);
+ * }
+ *
+ * static
+ * void list(int request)
+ * {
+ *   Eina_List *l = NULL;
+ *   int *data;
+ *   int i;
+ *
+ *   srand(time(NULL));
+ *
+ *   for (i = 0; i < request; ++i)
+ *     {
+ *       data = (int *)malloc(sizeof(int));
+ *       if (!data) continue;
+ *       *data = rand();
+ *       l = eina_list_prepend(l, data);
+ *     }
+ *
+ *   while (l)
+ *     {
+ *       free(eina_list_data_get(l));
+ *       l = eina_list_remove_list(l, l);
+ *     }
+ * }
+ *
+ * static void
+ * bench_container(Eina_Benchmark *bench)
+ * {
+ *   eina_benchmark_register(bench, "array", EINA_BENCHMARK(array), 200, 300, 
10);
+ *   eina_benchmark_register(bench, "list", EINA_BENCHMARK(list), 200, 300, 
10);
+ * }
+ *
+ * int main()
+ * {
+ *   Eina_Benchmark *test;
+ *   Eina_Array     *ea;
+ *   unsigned int    i;
+ *
+ *   if (!eina_init())
+ *     return EXIT_FAILURE;
+ *
+ *   for (i = 0; benchmarks[i].bench_case != NULL; ++i)
+ *     {
+ *       test = eina_benchmark_new(benchmarks[i].bench_case, "Benchmark 
example");
+ *       if (!test)
+ *         continue;
+ *
+ *       benchmarks[i].build(test);
+ *
+ *       ea = eina_benchmark_run(test);
+ *
+ *       eina_benchmark_free(test);
+ *     }
+ *
+ *   eina_shutdown();
+ *
+ *   return EXIT_SUCCESS;
+ * }
+ * @endcode
+ *
+ * gnuplot can be used to see how are performed the convert functions
+ * together, as well as how are performed the containers. So it is now
+ * easy to see that the hexadecimal convert function is faster than
+ * the decimal one, and that arrays are faster than lists.
+ *
+ * You can improve all that by executing automatically gnuplot in your
+ * program, or integrate the Eina benchmark framework in an autotooled
+ * project. See that
+ * <a 
href="http://trac.enlightenment.org/e/wiki/AutotoolsIntegration#Benchmark";>page</a>
+ * for more informations.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_log.h"
+#include "eina_benchmark.h"
+#include "eina_inlist.h"
+#include "eina_list.h"
+#include "eina_counter.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#define EINA_BENCHMARK_FILENAME_MASK "bench_%s_%s.gnuplot"
+#define EINA_BENCHMARK_DATA_MASK "bench_%s_%s.%s.data"
+
+typedef struct _Eina_Run Eina_Run;
+struct _Eina_Run
+{
+   EINA_INLIST;
+
+   Eina_Benchmark_Specimens cb;
+   const char *name;
+   int start;
+   int end;
+   int step;
+};
+
+struct _Eina_Benchmark
+{
+   const char *name;
+   const char *run;
+
+   Eina_Inlist *runs;
+   Eina_List *names;
+};
+
+static int _eina_benchmark_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_benchmark_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_benchmark_log_dom, __VA_ARGS__)
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the benchmark module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the benchmark module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_benchmark_init(void)
+{
+   _eina_benchmark_log_dom = eina_log_domain_register("eina_benchmark",
+                                                      EINA_LOG_COLOR_DEFAULT);
+   if (_eina_benchmark_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_benchmark");
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the benchmark module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the benchmark module set up by
+ * eina_benchmark_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_benchmark_shutdown(void)
+{
+   eina_log_domain_unregister(_eina_benchmark_log_dom);
+   _eina_benchmark_log_dom = -1;
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Benchmark_Group Benchmark
+ *
+ * These functions allow you to add benchmark framework in a project
+ * for timing critical part and detect slow parts of code. It is used
+ * in Eina to compare the time used by eina, glib, evas and ecore data
+ * types.
+ *
+ * To use the benchmark module, Eina must be initialized with
+ * eina_init() and later shut down with eina_shutdown(). A benchmark
+ * is created with eina_benchmark_new() and freed with
+ * eina_benchmark_free().
+ *
+ * eina_benchmark_register() adds a test to a benchmark. That test can
+ * be run a certain amount of times. Adding more than one test to be
+ * executed allows the comparison between several parts of a program,
+ * or different implementations.
+ *
+ * eina_benchmark_run() runs all the tests registered with
+ * eina_benchmark_register(). The amount of time of each test is
+ * written in a gnuplot file.
+ *
+ * For more information, you can look at the @ref tutorial_benchmark_page.
+ *
+ * @{
+ */
+
+/**
+ * @brief Create a new array.
+ *
+ * @param name The name of the benchmark.
+ * @param run The name of the run.
+ * @return @c NULL on failure, non @c NULL otherwise.
+ *
+ * This function creates a new benchmark. @p name and @p run are used
+ * to name the gnuplot file that eina_benchmark_run() will create.
+ *
+ * This function return a valid benchmark on success, or @c NULL if
+ * memory allocation fails. In that case, the error is set to
+ * #EINA_ERROR_OUT_OF_MEMORY.
+ *
+ * When the new module is not needed anymore, use
+ * eina_benchmark_free() to free the allocated memory.
+ */
+EAPI Eina_Benchmark *
+eina_benchmark_new(const char *name, const char *run)
+{
+   Eina_Benchmark *new;
+
+        eina_error_set(0);
+   new = calloc(1, sizeof (Eina_Benchmark));
+   if (!new)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   new->name = name;
+   new->run = run;
+
+   return new;
+}
+
+/**
+ * @brief Free a benchmark object.
+ *
+ * @param bench The benchmark to free.
+ *
+ * This function removes all the benchmark tests that have been
+ * registered and frees @p bench. If @p bench is @c NULL, this
+ * function returns immediately.
+ */
+EAPI void
+eina_benchmark_free(Eina_Benchmark *bench)
+{
+   Eina_Array *names;
+
+   if (!bench)
+      return;
+
+   while (bench->runs)
+     {
+        Eina_Run *run = (Eina_Run *)bench->runs;
+
+        bench->runs = eina_inlist_remove(bench->runs, bench->runs);
+        free(run);
+     }
+
+   EINA_LIST_FREE(bench->names, names)
+   {
+      Eina_Array_Iterator it;
+      char *tmp;
+      unsigned int i;
+
+      EINA_ARRAY_ITER_NEXT(names, i, tmp, it)
+       free(tmp);
+
+      eina_array_free(names);
+   }
+
+   free(bench);
+}
+
+/**
+ * @brief Add a test to a benchmark.
+ *
+ * @param bench The benchmark.
+ * @param name The name of the test.
+ * @param bench_cb The test function to be called.
+ * @param count_start The start data to be passed to @p bench_cb.
+ * @param count_end The end data to be passed to @p bench_cb.
+ * @param count_step The step data to be passed to @p bench_cb.
+ *
+ * This function adds the test named @p name to @p benchmark. @p
+ * bench_cb is the function called when the test is executed. That
+ * test can be executed a certain amount of time. @p start, @p end and
+ * @p step define a loop with a step increment. The integer that is
+ * increasing by @p step from @p start to @p end is passed to @p
+ * bench_cb when eina_benchmark_run() is called.
+ *
+ * If @p bench is @c NULL, this function returns imediatly. If the
+ * allocation of the memory of the test to add fails, the error is set
+ * to #EINA_ERROR_OUT_OF_MEMORY.
+ */
+EAPI Eina_Bool
+eina_benchmark_register(Eina_Benchmark *bench,
+                        const char *name,
+                        Eina_Benchmark_Specimens bench_cb,
+                        int count_start,
+                        int count_end,
+                        int count_step)
+{
+   Eina_Run *run;
+
+   if (!bench)
+      return EINA_FALSE;
+
+   if (count_step == 0)
+      return EINA_FALSE;
+
+        eina_error_set(0);
+   run = calloc(1, sizeof (Eina_Run));
+   if (!run)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return EINA_FALSE;
+     }
+
+   run->cb = bench_cb;
+   run->name = name;
+   run->start = count_start;
+   run->end = count_end;
+   run->step = count_step;
+
+   bench->runs = eina_inlist_append(bench->runs, EINA_INLIST_GET(run));
+
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Run the benchmark tests that have been registered.
+ *
+ * @param bench The benchmark.
+ * @return The list of names of the test files.
+ *
+ * This function runs all the tests that as been registered with
+ * eina_benchmark_register() and save the result in a gnuplot
+ * file. The name of the file has the following format:
+ *
+ * @code
+ * bench_[name]_[run]%s.gnuplot
+ * @endcode
+ *
+ * where [name] and [run] are the values passed to
+ * eina_benchmark_new().
+ *
+ * Each registered test is executed and timed. The time is written to
+ * the gnuplot file. The number of times each test is executed is
+ * controlled by the parameters passed to eina_benchmark_register().
+ *
+ * If @p bench is @c NULL, this functions returns @c NULL
+ * immediately. Otherwise, it returns the list of the names of each
+ * test.
+ */
+EAPI Eina_Array *
+eina_benchmark_run(Eina_Benchmark *bench)
+{
+   FILE *main_script;
+   FILE *current_data;
+   Eina_Array *ea;
+   Eina_Run *run;
+   char *buffer;
+   Eina_Bool first = EINA_FALSE;
+   size_t length;
+
+   if (!bench)
+      return NULL;
+
+   length = strlen(EINA_BENCHMARK_FILENAME_MASK) + strlen(bench->name) + 
strlen(
+         bench->run);
+
+   buffer = alloca(sizeof (char) * length);
+   if (!buffer)
+      return NULL;
+
+   snprintf(buffer,
+            length,
+            EINA_BENCHMARK_FILENAME_MASK,
+            bench->name,
+            bench->run);
+
+   main_script = fopen(buffer, "w");
+   if (!main_script)
+      return NULL;
+
+   ea = eina_array_new(16);
+   if (!ea)
+     {
+        fclose(main_script);
+        return NULL;
+     }
+
+   eina_array_push(ea, strdup(buffer));
+
+   fprintf(
+      main_script,
+      "set   autoscale                        # scale axes automatically\n"
+      "unset log                              # remove any log-scaling\n"
+      "unset label                            # remove any previous labels\n"
+      "set xtic auto                          # set xtics automatically\n"
+      "set ytic auto                          # set ytics automatically\n"
+/*     "set logscale y\n" */
+      "set terminal png size 1024,768\n"
+      "set output \"output_%s_%s.png\"\n"
+      "set title \"%s %s\n"
+      "set xlabel \"tests\"\n"
+      "set ylabel \"time\"\n"
+      "plot ",
+      bench->name,
+      bench->run,
+      bench->name,
+      bench->run);
+
+   EINA_INLIST_FOREACH(bench->runs, run)
+   {
+      Eina_Counter *counter;
+      char *result;
+      size_t tmp;
+      int i;
+
+      tmp = strlen(EINA_BENCHMARK_DATA_MASK) + strlen(bench->name) + strlen(
+            bench->run) + strlen(run->name);
+      if (tmp > length)
+        {
+           buffer = alloca(sizeof (char) * tmp);
+           length = tmp;
+        }
+
+      snprintf(buffer,
+               length,
+               EINA_BENCHMARK_DATA_MASK,
+               bench->name,
+               bench->run,
+               run->name);
+
+      current_data = fopen(buffer, "w");
+      if (!current_data)
+         continue;
+
+      eina_array_push(ea, strdup(buffer));
+
+      counter = eina_counter_new(run->name);
+
+      for (i = run->start; i < run->end; i += run->step)
+        {
+           fprintf(stderr, "Run %s: %i\n", run->name, i);
+           eina_counter_start(counter);
+
+           run->cb(i);
+
+           eina_counter_stop(counter, i);
+        }
+
+      result = eina_counter_dump(counter);
+      if (result)
+        {
+           fprintf(current_data, "%s", result);
+           free(result);
+        }
+
+      eina_counter_free(counter);
+
+      fclose(current_data);
+
+      if (first == EINA_FALSE)
+         first = EINA_TRUE;
+      else
+         fprintf(main_script, ", \\\n");
+
+         fprintf(main_script,
+              "\"%s\" using 1:2 title \'%s\' with line",
+              buffer, run->name);
+   }
+
+         fprintf(main_script, "\n");
+
+         fclose(main_script);
+
+   bench->names = eina_list_append(bench->names, ea);
+
+   return ea;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_binshare.c 
b/tests/suite/ecore/src/lib/eina_binshare.c
new file mode 100644
index 0000000..3973357
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_binshare.c
@@ -0,0 +1,202 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler,
+ *                         Jorge Luis Zapata Muga,
+ *                         Cedric Bail,
+ *                         Gustavo Sverzut Barbieri
+ *                         Tom Hacohen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+
+ */
+/**
+ * @page tutorial_binshare_page Binary Share Tutorial
+ *
+ * Should call eina_binshare_init() before usage and eina_binshare_shutdown() 
after.
+ * to be written...
+ *
+ */
+
+#include "eina_share_common.h"
+#include "eina_unicode.h"
+#include "eina_private.h"
+#include "eina_binshare.h"
+
+/* The actual share */
+static Eina_Share *binshare_share;
+static const char EINA_MAGIC_BINSHARE_NODE_STR[] = "Eina Binshare Node";
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the share_common module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+EAPI Eina_Bool
+eina_binshare_init(void)
+{
+   return eina_share_common_init(&binshare_share,
+                                 EINA_MAGIC_BINSHARE_NODE,
+                                 EINA_MAGIC_BINSHARE_NODE_STR);
+}
+
+/**
+ * @internal
+ * @brief Shut down the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the share_common module set up by
+ * eina_share_common_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+EAPI Eina_Bool
+eina_binshare_shutdown(void)
+{
+   Eina_Bool ret;
+   ret = eina_share_common_shutdown(&binshare_share);
+   return ret;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+/**
+ * @addtogroup Eina_Binshare_Group Binary Share
+ *
+ * These functions allow you to store one copy of an object, and use it
+ * throughout your program.
+ *
+ * This is a method to reduce the number of duplicated objects kept in
+ * memory.
+ *
+ * For more information, you can look at the @ref tutorial_binshare_page.
+ *
+ * @{
+ */
+
+/**
+ * @brief Note that the given object has lost an instance.
+ *
+ * @param obj object The given object.
+ *
+ * This function decreases the reference counter associated to @p obj
+ * if it exists. If that counter reaches 0, the memory associated to
+ * @p obj is freed. If @p obj is NULL, the function returns
+ * immediately.
+ *
+ * Note that if the given pointer is not shared or NULL, bad things
+ * will happen, likely a segmentation fault.
+ */
+EAPI void
+eina_binshare_del(const void *obj)
+{
+   if (!obj)
+      return;
+
+   eina_share_common_del(binshare_share, obj);
+}
+
+/**
+ * @brief Retrieve an instance of an object for use in a program.
+ *
+ * @param   obj The binary object to retrieve an instance of.
+ * @param   olen The byte size
+ * @return  A pointer to an instance of the object on success.
+ *          @c NULL on failure.
+ *
+ * This function retrieves an instance of @p obj. If @p obj is
+ * @c NULL, then @c NULL is returned. If @p obj is already stored, it
+ * is just returned and its reference counter is increased. Otherwise
+ * it is added to the objects to be searched and a duplicated object
+ * of @p obj is returned.
+ *
+ * This function does not check object size, but uses the
+ * exact given size. This can be used to share part of a larger
+ * object or subobject.
+ *
+ * @see eina_binshare_add()
+ */
+EAPI const void *
+eina_binshare_add_length(const void *obj, unsigned int olen)
+{
+   return eina_share_common_add_length(binshare_share,
+                                                     obj,
+                                                     (olen) * sizeof(char),
+                                                     0);
+}
+
+/**
+ * Increment references of the given shared object.
+ *
+ * @param obj The shared object.
+ * @return    A pointer to an instance of the object on success.
+ *            @c NULL on failure.
+ *
+ * This is similar to eina_share_common_add(), but it's faster since it will
+ * avoid lookups if possible, but on the down side it requires the parameter
+ * to be shared before, in other words, it must be the return of a previous
+ * eina_binshare_add().
+ *
+ * There is no unref since this is the work of eina_binshare_del().
+ */
+EAPI const void *
+eina_binshare_ref(const void *obj)
+{
+   return eina_share_common_ref(binshare_share, obj);
+}
+
+/**
+ * @brief Note that the given object @b must be shared.
+ *
+ * @param obj the shared object to know the length. It is safe to
+ *        give NULL, in that case -1 is returned.
+ *
+ * This function is a cheap way to known the length of a shared
+ * object. Note that if the given pointer is not shared, bad
+ * things will happen, likely a segmentation fault. If in doubt, try
+ * strlen().
+ */
+EAPI int
+eina_binshare_length(const void *obj)
+{
+   return eina_share_common_length(binshare_share, obj);
+}
+
+/**
+ * @brief Dump the contents of the share_common.
+ *
+ * This function dumps all objects in the share_common to stdout with a
+ * DDD: prefix per line and a memory usage summary.
+ */
+EAPI void
+eina_binshare_dump(void)
+{
+   eina_share_common_dump(binshare_share, NULL, 0);
+}
+
+/**
+ * @}
+ */
+
diff --git a/tests/suite/ecore/src/lib/eina_chained_mempool.c 
b/tests/suite/ecore/src/lib/eina_chained_mempool.c
new file mode 100644
index 0000000..f178cac
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_chained_mempool.c
@@ -0,0 +1,351 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008-2010 Cedric BAIL, Vincent Torri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef EFL_HAVE_POSIX_THREADS
+#include <pthread.h>
+#endif
+
+#ifdef EFL_HAVE_WIN32_THREADS
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include "eina_inlist.h"
+#include "eina_error.h"
+#include "eina_module.h"
+#include "eina_mempool.h"
+#include "eina_trash.h"
+
+#include "eina_private.h"
+
+#ifdef DEBUG
+#include "eina_log.h"
+
+static int _eina_mempool_log_dom = -1;
+
+#ifdef INF
+#undef INF
+#endif
+#define INF(...) EINA_LOG_DOM_INFO(_eina_mempool_log_dom, __VA_ARGS__)
+#endif
+
+typedef struct _Chained_Mempool Chained_Mempool;
+struct _Chained_Mempool
+{
+   Eina_Inlist *first;
+   const char *name;
+   int item_alloc;
+   int pool_size;
+   int alloc_size;
+   int group_size;
+   int usage;
+#ifdef EFL_HAVE_THREADS
+# ifdef EFL_HAVE_POSIX_THREADS
+   pthread_mutex_t mutex;
+# else
+   HANDLE mutex;
+# endif
+#endif
+};
+
+typedef struct _Chained_Pool Chained_Pool;
+struct _Chained_Pool
+{
+   EINA_INLIST;
+   Eina_Trash *base;
+   int usage;
+};
+
+static inline Chained_Pool *
+_eina_chained_mp_pool_new(Chained_Mempool *pool)
+{
+   Chained_Pool *p;
+   unsigned char *ptr;
+   int i;
+
+   eina_error_set(0);
+   p = malloc(pool->alloc_size);
+   if (!p)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   ptr = (unsigned char *)p + eina_mempool_alignof(sizeof(Chained_Pool));
+   p->usage = 0;
+   p->base = NULL;
+   for (i = 0; i < pool->pool_size; ++i, ptr += pool->item_alloc)
+      eina_trash_push(&p->base, ptr);
+   return p;
+}
+
+static inline void
+_eina_chained_mp_pool_free(Chained_Pool *p)
+{
+   free(p);
+}
+
+static void *
+eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size)
+{
+   Chained_Mempool *pool = data;
+   Chained_Pool *p = NULL;
+   void *mem;
+
+#ifdef EFL_HAVE_THREADS
+# ifdef EFL_HAVE_POSIX_THREADS
+   pthread_mutex_lock(&pool->mutex);
+# else
+   WaitForSingleObject(pool->mutex, INFINITE);
+# endif
+#endif
+
+   // look 4 pool from 2nd bucket on
+   EINA_INLIST_FOREACH(pool->first, p)
+   {
+      // base is not NULL - has a free slot
+      if (p->base)
+        {
+           pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p));
+           break;
+        }
+   }
+
+   // we have reached the end of the list - no free pools
+   if (!p)
+     {
+        p = _eina_chained_mp_pool_new(pool);
+        if (!p)
+          {
+#ifdef EFL_HAVE_PTHREAD
+# ifdef EFL_HAVE_POSIX_THREADS
+             pthread_mutex_unlock(&pool->mutex);
+# else
+             ReleaseMutex(pool->mutex);
+# endif
+#endif
+             return NULL;
+          }
+
+        pool->first = eina_inlist_prepend(pool->first, EINA_INLIST_GET(p));
+     }
+
+   // Request a free pointer
+   mem = eina_trash_pop(&p->base);
+   // move to end - it just filled up
+   if (!p->base)
+      pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p));
+
+   p->usage++;
+   pool->usage++;
+
+#ifdef EFL_HAVE_THREADS
+# ifdef EFL_HAVE_POSIX_THREADS
+   pthread_mutex_unlock(&pool->mutex);
+# else
+   ReleaseMutex(pool->mutex);
+# endif
+#endif
+
+   return mem;
+}
+
+static void
+eina_chained_mempool_free(void *data, void *ptr)
+{
+   Chained_Mempool *pool = data;
+   Chained_Pool *p;
+   void *pmem;
+   int psize;
+
+   psize = pool->group_size;
+   // look 4 pool
+
+#ifdef EFL_HAVE_THREADS
+# ifdef EFL_HAVE_POSIX_THREADS
+   pthread_mutex_lock(&pool->mutex);
+# else
+   WaitForSingleObject(pool->mutex, INFINITE);
+# endif
+#endif
+
+   EINA_INLIST_FOREACH(pool->first, p)
+   {
+      // pool mem base
+      pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool));
+      // is it in pool mem?
+      if ((ptr >= pmem) &&
+          ((unsigned char *)ptr < (((unsigned char *)pmem) + psize)))
+        {
+           // freed node points to prev free node
+           eina_trash_push(&p->base, ptr);
+           // next free node is now the one we freed
+           p->usage--;
+           pool->usage--;
+           if (p->usage == 0)
+             {
+                // free bucket
+                pool->first = eina_inlist_remove(pool->first, 
EINA_INLIST_GET(p));
+                _eina_chained_mp_pool_free(p);
+             }
+           else
+              // move to front
+              pool->first = eina_inlist_promote(pool->first, 
EINA_INLIST_GET(p));
+
+           break;
+        }
+   }
+
+#ifdef EFL_HAVE_THREADS
+# ifdef EFL_HAVE_POSIX_THREADS
+   pthread_mutex_unlock(&pool->mutex);
+# else
+   ReleaseMutex(pool->mutex);
+# endif
+#endif
+}
+
+static void *
+eina_chained_mempool_realloc(__UNUSED__ void *data,
+                             __UNUSED__ void *element,
+                             __UNUSED__ unsigned int size)
+{
+   return NULL;
+}
+
+static void *
+eina_chained_mempool_init(const char *context,
+                          __UNUSED__ const char *option,
+                          va_list args)
+{
+   Chained_Mempool *mp;
+   int item_size;
+   size_t length;
+
+   length = context ? strlen(context) + 1 : 0;
+
+   mp = calloc(1, sizeof(Chained_Mempool) + length);
+   if (!mp)
+      return NULL;
+
+   item_size = va_arg(args, int);
+   mp->pool_size = va_arg(args, int);
+
+   if (length)
+     {
+        mp->name = (const char *)(mp + 1);
+        memcpy((char *)mp->name, context, length);
+     }
+
+   mp->item_alloc = eina_mempool_alignof(item_size);
+   mp->group_size = mp->item_alloc * mp->pool_size;
+   mp->alloc_size = mp->group_size + 
eina_mempool_alignof(sizeof(Chained_Pool));
+
+#ifdef EFL_HAVE_THREADS
+# ifdef EFL_HAVE_POSIX_THREADS
+   pthread_mutex_init(&mp->mutex, NULL);
+# else
+   mp->mutex = CreateMutex(NULL, FALSE, NULL);
+# endif
+#endif
+
+   return mp;
+}
+
+static void
+eina_chained_mempool_shutdown(void *data)
+{
+   Chained_Mempool *mp;
+
+   mp = (Chained_Mempool *)data;
+
+   while (mp->first)
+     {
+        Chained_Pool *p = (Chained_Pool *)mp->first;
+
+#ifdef DEBUG
+        if (p->usage > 0)
+           INF("Bad news we are destroying not an empty mempool [%s]\n",
+               mp->name);
+
+#endif
+
+        mp->first = eina_inlist_remove(mp->first, mp->first);
+        _eina_chained_mp_pool_free(p);
+     }
+
+#ifdef EFL_HAVE_THREADS
+# ifdef EFL_HAVE_POSIX_THREADS
+   pthread_mutex_destroy(&mp->mutex);
+# else
+   CloseHandle(mp->mutex);
+# endif
+#endif
+
+   free(mp);
+}
+
+static Eina_Mempool_Backend _eina_chained_mp_backend = {
+   "chained_mempool",
+   &eina_chained_mempool_init,
+   &eina_chained_mempool_free,
+   &eina_chained_mempool_malloc,
+   &eina_chained_mempool_realloc,
+   NULL,
+   NULL,
+   &eina_chained_mempool_shutdown
+};
+
+Eina_Bool chained_init(void)
+{
+#ifdef DEBUG
+   _eina_mempool_log_dom = eina_log_domain_register("eina_mempool",
+                                                    EINA_LOG_COLOR_DEFAULT);
+   if (_eina_mempool_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_mempool");
+        return EINA_FALSE;
+     }
+
+#endif
+   return eina_mempool_register(&_eina_chained_mp_backend);
+}
+
+void chained_shutdown(void)
+{
+   eina_mempool_unregister(&_eina_chained_mp_backend);
+#ifdef DEBUG
+   eina_log_domain_unregister(_eina_mempool_log_dom);
+   _eina_mempool_log_dom = -1;
+#endif
+}
+
+#ifndef EINA_STATIC_BUILD_CHAINED_POOL
+
+EINA_MODULE_INIT(chained_init);
+EINA_MODULE_SHUTDOWN(chained_shutdown);
+
+#endif /* ! EINA_STATIC_BUILD_CHAINED_POOL */
diff --git a/tests/suite/ecore/src/lib/eina_convert.c 
b/tests/suite/ecore/src/lib/eina_convert.c
new file mode 100644
index 0000000..0d75469
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_convert.c
@@ -0,0 +1,773 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric BAIL, Vincent Torri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_log.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_convert.h"
+#include "eina_fp.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static const char look_up_table[] = {'0', '1', '2', '3', '4',
+                                     '5', '6', '7', '8', '9',
+                                     'a', 'b', 'c', 'd', 'e', 'f'};
+static int _eina_convert_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_convert_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_convert_log_dom, __VA_ARGS__)
+
+#define HEXA_TO_INT(Hexa) (Hexa >= 'a') ? Hexa - 'a' + 10 : Hexa - '0'
+
+static inline void reverse(char s[], int length)
+{
+   int i, j;
+   char c;
+
+   for (i = 0, j = length - 1; i < j; i++, j--)
+     {
+        c = s[i];
+        s[i] = s[j];
+        s[j] = c;
+     }
+}
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+EAPI Eina_Error EINA_ERROR_CONVERT_P_NOT_FOUND = 0;
+EAPI Eina_Error EINA_ERROR_CONVERT_0X_NOT_FOUND = 0;
+EAPI Eina_Error EINA_ERROR_CONVERT_OUTRUN_STRING_LENGTH = 0;
+
+static const char EINA_ERROR_CONVERT_0X_NOT_FOUND_STR[] =
+   "Error during string conversion to float, First '0x' was not found.";
+static const char EINA_ERROR_CONVERT_P_NOT_FOUND_STR[] =
+   "Error during string conversion to float, First 'p' was not found.";
+static const char EINA_ERROR_CONVERT_OUTRUN_STRING_LENGTH_STR[] =
+   "Error outrun string limit during conversion string conversion to float.";
+
+/**
+ * @endcond
+ */
+
+/**
+ * @internal
+ * @brief Initialize the convert module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the convert module of Eina. It is called by
+ * eina_init().
+ *
+ * This function sets up the error module of Eina and registers the
+ * errors #EINA_ERROR_CONVERT_0X_NOT_FOUND,
+ * #EINA_ERROR_CONVERT_P_NOT_FOUND and
+ * #EINA_ERROR_CONVERT_OUTRUN_STRING_LENGTH.
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_convert_init(void)
+{
+   _eina_convert_log_dom = eina_log_domain_register("eina_convert",
+                                                    EINA_LOG_COLOR_DEFAULT);
+   if (_eina_convert_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_convert");
+        return EINA_FALSE;
+     }
+
+#define EEMR(n) n = eina_error_msg_static_register(n ## _STR)
+   EEMR(EINA_ERROR_CONVERT_0X_NOT_FOUND);
+   EEMR(EINA_ERROR_CONVERT_P_NOT_FOUND);
+   EEMR(EINA_ERROR_CONVERT_OUTRUN_STRING_LENGTH);
+#undef EEMR
+
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the convert module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the convert module set up by
+ * eina_convert_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_convert_shutdown(void)
+{
+   eina_log_domain_unregister(_eina_convert_log_dom);
+   _eina_convert_log_dom = -1;
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Convert_Group Convert
+ *
+ * These functions allow you to convert integer or real numbers to
+ * string or conversely.
+ *
+ * To use these functions, you have to call eina_init()
+ * first, and eina_shutdown() when eina is not used anymore.
+ *
+ * @section Eina_Convert_From_Integer_To_Sring Conversion from integer to 
string
+ *
+ * To convert an integer to a string in the decimal base,
+ * eina_convert_itoa() should be used. If the hexadecimal base is
+ * wanted, eina_convert_xtoa() should be used. They all need a bufffer
+ * sufficiently large to store all the cyphers.
+ *
+ * Here is an example of use:
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ *
+ * #include <Eina.h>
+ *
+ * int main(void)
+ * {
+ *    char tmp[128];
+ *
+ *    if (!eina_init())
+ *    {
+ *        printf ("Error during the initialization of eina.\n");
+ *        return EXIT_FAILURE;
+ *    }
+ *
+ *    eina_convert_itoa(45, tmp);
+ *    printf("value: %s\n", tmp);
+
+ *    eina_convert_xtoa(0xA1, tmp);
+ *    printf("value: %s\n", tmp);
+ *
+ *    eina_shutdown();
+ *
+ *    return EXIT_SUCCESS;
+ * }
+ * @endcode
+ *
+ * Compile this code with the following command:
+ *
+ * @code
+ * gcc -Wall -o test_eina_convert test_eina.c `pkg-config --cflags --libs eina`
+ * @endcode
+ *
+ * @note
+ * The alphabetical cyphers are in lower case.
+ *
+ * @section Eina_Convert_Double Conversion double / string
+ *
+ * To convert a double to a string, eina_convert_dtoa() should be
+ * used. Like with the integer functions, a buffer must be used. The
+ * resulting string ghas the following format (which is the result
+ * obtained with snprintf() and the @%a modifier):
+ *
+ * @code
+ * [-]0xh.hhhhhp[+-]e
+ * @endcode
+ *
+ * To convert a string to a double, eina_convert_atod() should be
+ * used. The format of the string must be as above. Then, the double
+ * has the following mantiss and exponent:
+ *
+ * @code
+ * mantiss  : [-]hhhhhh
+ * exponent : 2^([+-]e - 4 * n)
+ * @endcode
+ *
+ * with n being number of cypers after the point in the string
+ * format. To obtain the double number from the mantiss and exponent,
+ * use ldexp().
+ *
+ * Here is an example of use:
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ * #include <math.h>
+ *
+ * #include <Eina.h>
+ *
+ * int main(void)
+ * {
+ *    char      tmp[128];
+ *    long long int m = 0;
+ *    long int  e = 0;
+ *    double    r;
+ *
+ *    if (!eina_init())
+ *    {
+ *        printf ("Error during the initialization of eina.\n");
+ *        return EXIT_FAILURE;
+ *    }
+ *
+ *    printf("initial value : 40.56\n");
+ *    eina_convert_dtoa(40.56, tmp);
+ *    printf("result dtoa   : %s\n", tmp);
+
+ *    eina_convert_atod(tmp, 128, &m, &e);
+ *    r = ldexp((double)m, e);
+ *    printf("result atod   : %f\n", r);
+ *
+ *    eina_shutdown();
+ *
+ *    return EXIT_SUCCESS;
+ * }
+ * @endcode
+ *
+ * Compile this code with the following command:
+ *
+ * @code
+ * gcc -Wall -o test_eina_convert test_eina.c `pkg-config --cflags --libs 
eina` -lm
+ * @endcode
+ *
+ * @{
+ */
+
+/*
+ * Come from the second edition of The C Programming Language ("K&R2") on page 
64
+ */
+
+/**
+ * @brief Convert an integer number to a string in decimal base.
+ *
+ * @param n The integer to convert.
+ * @param s The buffer to store the converted integer.
+ * @return The length of the string, including the nul terminated
+ * character.
+ *
+ * This function converts @p n to a nul terminated string. The
+ * converted string is in decimal base. As no check is done, @p s must
+ * be a buffer that is sufficiently large to store the integer.
+ *
+ * The returned value is the length of the string, including the nul
+ * terminated character.
+ */
+EAPI int
+eina_convert_itoa(int n, char *s)
+{
+   int i = 0;
+   int r = 0;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(s, 0);
+
+   if (n < 0)
+     {
+        n = -n;
+        *s++ = '-';
+        r = 1;
+     }
+
+   do {
+        s[i++] = n % 10 + '0';
+     } while ((n /= 10) > 0);
+
+   s[i] = '\0';
+
+   reverse(s, i);
+
+   return i + r;
+}
+
+/**
+ * @brief Convert an integer number to a string in hexadecimal base.
+ *
+ * @param n The integer to convert.
+ * @param s The buffer to store the converted integer.
+ * @return The length of the string, including the nul terminated
+ * character.
+ *
+ * This function converts @p n to a nul terminated string. The
+ * converted string is in hexadecimal base and the alphabetical
+ * cyphers are in lower case. As no check is done, @p s must be a
+ * buffer that is sufficiently large to store the integer.
+ *
+ * The returned value is the length of the string, including the nul
+ * terminated character.
+ */
+EAPI int
+eina_convert_xtoa(unsigned int n, char *s)
+{
+   int i;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(s, 0);
+
+   i = 0;
+   do {
+        s[i++] = look_up_table[n & 0xF];
+     } while ((n >>= 4) > 0);
+
+   s[i] = '\0';
+
+   reverse(s, i);
+
+   return i;
+}
+
+/**
+ * @brief Convert a string to a double.
+ *
+ * @param src The string to convert.
+ * @param length The length of the string.
+ * @param m The mantisse.
+ * @param e The exponent.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function converts the string @p s of length @p length that
+ * represent a double in hexadecimal base to a double. It is used to
+ * replace the use of snprintf() with the \%a modifier, which is
+ * missing on some platform (like Windows (tm) or OpenBSD).
+ *
+ * The string must have the following format:
+ *
+ * @code
+ * [-]0xh.hhhhhp[+-]e
+ * @endcode
+ *
+ * where the h are the hexadecimal cyphers of the mantiss and e the
+ * exponent (a decimal number). If n is the number of cypers after the
+ * point, the returned mantiss and exponents are:
+ *
+ * @code
+ * mantiss  : [-]hhhhhh
+ * exponent : 2^([+-]e - 4 * n)
+ * @endcode
+ *
+ * The mantiss and exponent are stored in the buffers pointed
+ * respectively by @p m and @p e.
+ *
+ * If the string is invalid, the error is set to:
+ *
+ * @li #EINA_ERROR_CONVERT_0X_NOT_FOUND if no 0x is found,
+ * @li #EINA_ERROR_CONVERT_P_NOT_FOUND if no p is found,
+ * @li #EINA_ERROR_CONVERT_OUTRUN_STRING_LENGTH if @p length is not
+ * correct.
+ *
+ * In those cases, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+EAPI Eina_Bool
+eina_convert_atod(const char *src, int length, long long *m, long *e)
+{
+   const char *str = src;
+   long long mantisse;
+   long exponent;
+   int nbr_decimals = 0;
+   int sign = 1;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(src, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m,   EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(e,   EINA_FALSE);
+
+   if (length <= 0)
+      goto on_length_error;
+
+   /* Compute the mantisse. */
+   if (*str == '-')
+     {
+        sign = -1;
+        str++;
+        length--;
+     }
+
+   if (length <= 2)
+      goto on_length_error;
+
+   if (strncmp(str, "0x", 2))
+     {
+        eina_error_set(EINA_ERROR_CONVERT_0X_NOT_FOUND);
+        DBG("'0x' not found in '%s'", src);
+        return EINA_FALSE;
+     }
+
+   str += 2;
+   length -= 2;
+
+   mantisse = HEXA_TO_INT(*str);
+
+   str++;
+   length--; if (length <= 0)
+      goto on_length_error;
+
+   if (*str == '.')
+      for (str++, length--;
+           length > 0 && *str != 'p';
+           ++str, --length, ++nbr_decimals)
+        {
+           mantisse <<= 4;
+           mantisse += HEXA_TO_INT(*str);
+        }
+
+   if (sign < 0)
+      mantisse = -mantisse;
+
+   /* Compute the exponent. */
+   if (*str != 'p')
+     {
+        eina_error_set(EINA_ERROR_CONVERT_P_NOT_FOUND);
+        DBG("'p' not found in '%s'", src);
+        return EINA_FALSE;
+     }
+
+   sign = +1;
+
+   str++;
+   length--; if (length <= 0)
+      goto on_length_error;
+
+   if (strchr("-+", *str))
+     {
+        sign = (*str == '-') ? -1 : +1;
+
+        str++; length--;
+     }
+
+   for (exponent = 0; length > 0 && *str != '\0'; ++str, --length)
+     {
+        exponent *= 10;
+        exponent += *str - '0';
+     }
+
+   if (length < 0)
+      goto on_length_error;
+
+   if (sign < 0)
+      exponent = -exponent;
+
+   *m = mantisse;
+   *e = exponent - (nbr_decimals << 2);
+
+   return EINA_TRUE;
+
+on_length_error:
+   eina_error_set(EINA_ERROR_CONVERT_OUTRUN_STRING_LENGTH);
+   return EINA_FALSE;
+}
+
+/**
+ * @brief Convert a double to a string.
+ *
+ * @param d The double to convert.
+ * @param des The destination buffer to store the converted double.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function converts the double @p d to a string. The string is
+ * stored in the buffer pointed by @p des and must be sufficiently
+ * large to contain the converted double. The returned string is nul
+ * terminated and has the following format:
+ *
+ * @code
+ * [-]0xh.hhhhhp[+-]e
+ * @endcode
+ *
+ * where the h are the hexadecimal cyphers of the mantiss and e the
+ * exponent (a decimal number).
+ *
+ * The returned value is the length of the string, including the nul
+ * character.
+ */
+EAPI int
+eina_convert_dtoa(double d, char *des)
+{
+   int length = 0;
+   int p;
+   int i;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(des, EINA_FALSE);
+
+   if (d < 0.0)
+     {
+        *(des++) = '-';
+        d = -d;
+        length++;
+     }
+
+   d = frexp(d, &p);
+
+   if (p)
+     {
+        d *= 2;
+        p -= 1;
+     }
+
+   *(des++) = '0';
+   *(des++) = 'x';
+   *(des++) = look_up_table[(size_t)d];
+   *(des++) = '.';
+   length += 4;
+
+   for (i = 0; i < 16; i++, length++)
+     {
+        d -= floor(d);
+        d *= 16;
+        *(des++) = look_up_table[(size_t)d];
+     }
+
+   while (*(des - 1) == '0')
+     {
+        des--;
+        length--;
+     }
+
+   if (*(des - 1) == '.')
+     {
+        des--;
+        length--;
+     }
+
+   *(des++) = 'p';
+   if (p < 0)
+     {
+        *(des++) = '-';
+        p = -p;
+     }
+   else
+      *(des++) = '+';
+
+   length += 2;
+
+   return length + eina_convert_itoa(p, des);
+}
+
+/**
+ * @brief Convert a 32.32 fixed point number to a string.
+ *
+ * @param fp The fixed point number to convert.
+ * @param des The destination buffer to store the converted fixed point number.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function converts the 32.32 fixed point number @p fp to a
+ * string. The string is stored in the buffer pointed by @p des and
+ * must be sufficiently large to contain the converted fixed point
+ * number. The returned string is terminated and has the following
+ * format:
+ *
+ * @code
+ * [-]0xh.hhhhhp[+-]e
+ * @endcode
+ *
+ * where the h are the hexadecimal cyphers of the mantiss and e the
+ * exponent (a decimal number).
+ *
+ * The returned value is the length of the string, including the nul
+ * character.
+ *
+ * @note The code is the same than eina_convert_dtoa() except that it
+ * implements the frexp() function for fixed point numbers and does
+ * some optimisations.
+ */
+EAPI int
+eina_convert_fptoa(Eina_F32p32 fp, char *des)
+{
+   int length = 0;
+   int p = 0;
+   int i;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(des, EINA_FALSE);
+
+   if (fp == 0)
+     {
+        memcpy(des, "0x0p+0", 7);
+        return 7;
+     }
+
+   if (fp < 0)
+     {
+        *(des++) = '-';
+        fp = -fp;
+        length++;
+     }
+
+   /* fp >= 1 */
+   if (fp >= 0x0000000100000000LL)
+      while (fp >= 0x0000000100000000LL)
+        {
+           p++;
+           /* fp /= 2 */
+           fp >>= 1;
+        } /* fp < 0.5 */
+   else if (fp < 0x80000000)
+      while (fp < 0x80000000)
+        {
+           p--;
+           /* fp *= 2 */
+           fp <<= 1;
+        }
+
+   if (p)
+     {
+        p--;
+        /* fp *= 2 */
+        fp <<= 1;
+     }
+
+   *(des++) = '0';
+   *(des++) = 'x';
+   *(des++) = look_up_table[fp >> 32];
+   *(des++) = '.';
+   length += 4;
+
+   for (i = 0; i < 16; i++, length++)
+     {
+        fp &= 0x00000000ffffffffLL;
+        fp <<= 4; /* fp *= 16 */
+        *(des++) = look_up_table[fp >> 32];
+     }
+
+   while (*(des - 1) == '0')
+     {
+        des--;
+        length--;
+     }
+
+   if (*(des - 1) == '.')
+     {
+        des--;
+        length--;
+     }
+
+   *(des++) = 'p';
+   if (p < 0)
+     {
+        *(des++) = '-';
+        p = -p;
+     }
+   else
+      *(des++) = '+';
+
+   length += 2;
+
+   return length + eina_convert_itoa(p, des);
+}
+
+/**
+ * @brief Convert a string to a 32.32 fixed point number.
+ *
+ * @param src The string to convert.
+ * @param length The length of the string.
+ * @param fp The fixed point number.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function converts the string @p src of length @p length that
+ * represent a double in hexadecimal base to a 32.32 fixed point
+ * number stored in @p fp. The function always tries to convert the
+ * string with eina_convert_atod().
+ *
+ * The string must have the following format:
+ *
+ * @code
+ * [-]0xh.hhhhhp[+-]e
+ * @endcode
+ *
+ * where the h are the hexadecimal cyphers of the mantiss and e the
+ * exponent (a decimal number). If n is the number of cypers after the
+ * point, the returned mantiss and exponents are:
+ *
+ * @code
+ * mantiss  : [-]hhhhhh
+ * exponent : 2^([+-]e - 4 * n)
+ * @endcode
+ *
+ * The mantiss and exponent are stored in the buffers pointed
+ * respectively by @p m and @p e.
+ *
+ * If the string is invalid, the error is set to:
+ *
+ * @li #EINA_ERROR_CONVERT_0X_NOT_FOUND if no 0x is found,
+ * @li #EINA_ERROR_CONVERT_P_NOT_FOUND if no p is found,
+ * @li #EINA_ERROR_CONVERT_OUTRUN_STRING_LENGTH if @p length is not
+ * correct.
+ *
+ * In those cases, or if @p fp is @c NULL, #EINA_FALSE is returned,
+ * otherwise @p fp is computed and #EINA_TRUE is returned.
+ *
+ * @note The code uses eina_convert_atod() and do the correct bit
+ * shift to compute the fixed point number.
+ */
+EAPI Eina_Bool
+eina_convert_atofp(const char *src, int length, Eina_F32p32 *fp)
+{
+   long long m;
+   long e;
+
+   if (!eina_convert_atod(src, length, &m, &e))
+      return EINA_FALSE;
+
+   if (!fp)
+      return EINA_TRUE;
+
+   e += 32;
+
+   if (e > 0)
+      *fp = m << e;
+   else
+      *fp = m >> -e;
+
+   return EINA_TRUE;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_counter.c 
b/tests/suite/ecore/src/lib/eina_counter.c
new file mode 100644
index 0000000..8c430dc
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_counter.c
@@ -0,0 +1,505 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail, Vincent Torri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#ifndef _WIN32
+# include <time.h>
+#else
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+#endif /* _WIN2 */
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_inlist.h"
+#include "eina_error.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_counter.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#ifndef _WIN32
+typedef struct timespec Eina_Nano_Time;
+#else
+typedef LARGE_INTEGER Eina_Nano_Time;
+#endif
+
+typedef struct _Eina_Clock Eina_Clock;
+
+struct _Eina_Counter
+{
+   EINA_INLIST;
+
+   Eina_Inlist *clocks;
+   const char *name;
+};
+
+struct _Eina_Clock
+{
+   EINA_INLIST;
+
+   Eina_Nano_Time start;
+   Eina_Nano_Time end;
+   int specimen;
+
+   Eina_Bool valid;
+};
+
+#ifndef _WIN32
+static inline int
+_eina_counter_time_get(Eina_Nano_Time *tp)
+{
+# if defined(CLOCK_PROCESS_CPUTIME_ID)
+   return clock_gettime(CLOCK_PROCESS_CPUTIME_ID, tp);
+# elif defined(CLOCK_PROF)
+   return clock_gettime(CLOCK_PROF, tp);
+# elif defined(CLOCK_REALTIME)
+   return clock_gettime(CLOCK_REALTIME, tp);
+# else
+   return gettimeofday(tp, NULL);
+# endif
+}
+#else
+static const char EINA_ERROR_COUNTER_WINDOWS_STR[] =
+   "Change your OS, you moron !";
+static int EINA_ERROR_COUNTER_WINDOWS = 0;
+static LARGE_INTEGER _eina_counter_frequency;
+
+static inline int
+_eina_counter_time_get(Eina_Nano_Time *tp)
+{
+   return QueryPerformanceCounter(tp);
+}
+#endif /* _WIN2 */
+
+static char *
+_eina_counter_asiprintf(char *base, int *position, const char *format, ...)
+{
+   char *tmp, *result;
+   int size = 32;
+   int n;
+   va_list ap;
+
+   tmp = realloc(base, sizeof (char) * (*position + size));
+   if (!tmp)
+      return base;
+
+   result = tmp;
+
+   while (1)
+     {
+        va_start(ap, format);
+        n = vsnprintf(result + *position, size, format, ap);
+        va_end(ap);
+
+        if (n > -1 && n < size)
+          {
+             /* If we always have glibc > 2.2, we could just return *position 
+= n. */
+             *position += strlen(result + *position);
+             return result;
+          }
+
+        if (n > -1)
+           size = n + 1;
+        else
+           size <<= 1;
+
+        tmp = realloc(result, sizeof (char) * (*position + size));
+        if (!tmp)
+           return result;
+
+        result = tmp;
+     }
+}
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the eina counter internal structure.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the counter module set up by
+ * eina_counter_init(). It is called by eina_init().
+ *
+ * This function sets up the error module of Eina and only on Windows,
+ * it initializes the high precision timer. It also registers, only on
+ * Windows, the error #EINA_ERROR_COUNTER_WINDOWS. It is also called
+ * by eina_init(). It returns 0 on failure, otherwise it returns the
+ * number of times it has already been called.
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_counter_init(void)
+{
+#ifdef _WIN32
+   EINA_ERROR_COUNTER_WINDOWS = eina_error_msg_static_register(
+         EINA_ERROR_COUNTER_WINDOWS_STR);
+   if (!QueryPerformanceFrequency(&_eina_counter_frequency))
+     {
+        eina_error_set(EINA_ERROR_COUNTER_WINDOWS);
+        return EINA_FALSE;
+     }
+
+#endif /* _WIN2 */
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the counter module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the counter module set up by
+ * eina_counter_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_counter_shutdown(void)
+{
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Counter_Group Counter
+ *
+ * @brief These functions allow you to get the time spent in a part of a code.
+ *
+ * Before using the counter system, Eina must be initialized with
+ * eina_init() and later shut down with eina_shutdown(). The create a
+ * counter, use eina_counter_new(). To free it, use
+ * eina_counter_free().
+ *
+ * To time a part of a code, call eina_counter_start() just before it,
+ * and eina_counter_stop() just after it. Each time you start to time
+ * a code, a clock is added to a list. You can give a number of that
+ * clock with the second argument of eina_counter_stop(). To send all
+ * the registered clocks to a stream (like stdout, ofr a file), use
+ * eina_counter_dump().
+ *
+ * Here is a straightforward example:
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ *
+ * #include <eina_counter.h>
+ *
+ * void test_malloc(void)
+ * {
+ *    int i;
+ *
+ *    for (i = 0; i < 100000; ++i)
+ *    {
+ *       void *buf;
+ *
+ *       buf = malloc(100);
+ *       free(buf);
+ *    }
+ * }
+ *
+ * int main(void)
+ * {
+ *    Eina_Counter *counter;
+ *
+ *    if (!eina_init())
+ *    {
+ *        printf("Error during the initialization of eina\n");
+ *        return EXIT_FAILURE;
+ *    }
+ *
+ *    counter = eina_counter_new("malloc");
+ *
+ *    eina_counter_start(counter);
+ *    test_malloc();
+ *    eina_counter_stop(counter, 1);
+ *
+ *    char* result = eina_counter_dump(counter);
+ *    printf("%s", result);
+ *    free(result);
+ *
+ *    eina_counter_free(counter);
+ *    eina_shutdown();
+ *
+ *    return EXIT_SUCCESS;
+ * }
+ * @endcode
+ *
+ * Compile this code with the following commant:
+ *
+ * @verbatim
+ * gcc -Wall -o test_eina_counter test_eina.c `pkg-config --cflags --libs eina`
+ * @endverbatim
+ *
+ * The result should be something like that:
+ *
+ * @verbatim
+ * \# specimen    experiment time    starting time    ending time
+ * 1              9794125            783816           10577941
+ * @endverbatim
+ *
+ * Note that the displayed time is in nanosecond.
+ *
+ * @{
+ */
+
+/**
+ * @brief Return a counter.
+ *
+ * @param name The name of the counter.
+ *
+ * This function returns a new counter. It is characterized by @p
+ * name. If @p name is @c NULL, the function returns @c NULL
+ * immediately. If memory allocation fails, @c NULL is returned and the
+ * error is set to #EINA_ERROR_OUT_OF_MEMORY.
+ *
+ * Whe the new counter is not needed anymore, use eina_counter_free() to
+ * free the allocated memory.
+ */
+EAPI Eina_Counter *
+eina_counter_new(const char *name)
+{
+   Eina_Counter *counter;
+   size_t length;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+   length = strlen(name) + 1;
+
+        eina_error_set(0);
+   counter = calloc(1, sizeof (Eina_Counter) + length);
+   if (!counter)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   counter->name = (char *)(counter + 1);
+   memcpy((char *)counter->name, name, length);
+
+   return counter;
+}
+
+/**
+ * @brief Delete a counter.
+ *
+ * @param counter The counter to delete.
+ *
+ * This function remove the clock of @p counter from the used clocks
+ * (see eina_counter_start()) and frees the memory allocated for
+ * @p counter. If @p counter is @c NULL, the function returns
+ * immediately.
+ */
+EAPI void
+eina_counter_free(Eina_Counter *counter)
+{
+   EINA_SAFETY_ON_NULL_RETURN(counter);
+
+   while (counter->clocks)
+     {
+        Eina_Clock *clk = (Eina_Clock *)counter->clocks;
+
+        counter->clocks = eina_inlist_remove(counter->clocks, counter->clocks);
+        free(clk);
+     }
+
+        free(counter);
+}
+
+/**
+ * @brief Start the time count.
+ *
+ * @param counter The counter.
+ *
+ * This function specifies that the part of the code beginning just
+ * after its call is being to be timed, using @p counter. If
+ * @p counter is @c NULL, this function returns immediately.
+ *
+ * This function adds the clock associated to @p counter in a list. If
+ * the memory needed by that clock can not be allocated, the function
+ * returns and the error is set to #EINA_ERROR_OUT_OF_MEMORY.
+ *
+ * To stop the timing, eina_counter_stop() must be called with the
+ * same counter.
+ */
+EAPI void
+eina_counter_start(Eina_Counter *counter)
+{
+   Eina_Clock *clk;
+   Eina_Nano_Time tp;
+
+   EINA_SAFETY_ON_NULL_RETURN(counter);
+   if (_eina_counter_time_get(&tp) != 0)
+      return;
+
+        eina_error_set(0);
+   clk = calloc(1, sizeof (Eina_Clock));
+   if (!clk)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return;
+     }
+
+   counter->clocks = eina_inlist_prepend(counter->clocks, 
EINA_INLIST_GET(clk));
+
+   clk->valid = EINA_FALSE;
+   clk->start = tp;
+}
+
+/**
+ * @brief Stop the time count.
+ *
+ * @param counter The counter.
+ * @param specimen The number of the test.
+ *
+ * This function stop the timing that has been started with
+ * eina_counter_start(). @p counter must be the same than the one used
+ * with eina_counter_start(). @p specimen is the number of the
+ * test. If @p counter or its associated clock are  @c NULL, or if the
+ * time can't be retrieved the function exits.
+ */
+EAPI void
+eina_counter_stop(Eina_Counter *counter, int specimen)
+{
+   Eina_Clock *clk;
+   Eina_Nano_Time tp;
+
+   EINA_SAFETY_ON_NULL_RETURN(counter);
+   if (_eina_counter_time_get(&tp) != 0)
+      return;
+
+   clk = (Eina_Clock *)counter->clocks;
+
+   if (!clk || clk->valid == EINA_TRUE)
+      return;
+
+   clk->end = tp;
+   clk->specimen = specimen;
+   clk->valid = EINA_TRUE;
+}
+
+/**
+ * @brief Dump the result of all clocks of a counter to a stream.
+ *
+ * @return A string with a summary of the test.
+ * @param counter The counter.
+ *
+ * This function returns an malloc'd string containing the dump of
+ * all the valid clocks of @p counter.
+ * If @p counter @c NULL, the functions exits
+ * immediately. Otherwise, the output is formattted like that:
+ *
+ * @verbatim
+ * \# specimen    experiment time    starting time    ending time
+ * 1              208                120000           120208
+ * @endverbatim
+ *
+ * The unit of time is the nanosecond.
+ */
+EAPI char *
+eina_counter_dump(Eina_Counter *counter)
+{
+   Eina_Clock *clk;
+   char *result = NULL;
+   int position = 0;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(counter, NULL);
+
+   result = _eina_counter_asiprintf(
+         result,
+         &position,
+         "# specimen\texperiment time\tstarting time\tending time\n");
+   if (!result)
+      return NULL;
+
+   EINA_INLIST_REVERSE_FOREACH(counter->clocks, clk)
+   {
+      long int start;
+      long int end;
+      long int diff;
+
+      if (clk->valid == EINA_FALSE)
+         continue;
+
+#ifndef _WIN32
+      start = clk->start.tv_sec * 1000000000 + clk->start.tv_nsec;
+      end = clk->end.tv_sec * 1000000000 + clk->end.tv_nsec;
+      diff =
+         (clk->end.tv_sec -
+          clk->start.tv_sec) * 1000000000 + clk->end.tv_nsec -
+         clk->start.tv_nsec;
+#else
+      start =
+         (long int)(((long long int)clk->start.QuadPart *
+                     1000000000ll) /
+                    (long long int)_eina_counter_frequency.QuadPart);
+      end =
+         (long int)(((long long int)clk->end.QuadPart *
+                     1000000000LL) /
+                    (long long int)_eina_counter_frequency.QuadPart);
+      diff =
+         (long int)(((long long int)(clk->end.QuadPart -
+                                     clk->start.QuadPart) *
+                     1000000000LL) /
+                    (long long int)_eina_counter_frequency.QuadPart);
+#endif /* _WIN2 */
+
+      result = _eina_counter_asiprintf(result, &position,
+                                       "%i\t%li\t%li\t%li\n",
+                                       clk->specimen,
+                                       diff,
+                                       start,
+                                       end);
+   }
+
+   return result;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_cpu.c 
b/tests/suite/ecore/src/lib/eina_cpu.c
new file mode 100644
index 0000000..1ee411f
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_cpu.c
@@ -0,0 +1,208 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef EFL_HAVE_THREADS
+# ifdef _WIN32
+#  define WIN32_LEAN_AND_MEAN
+#  include <windows.h>
+# elif defined (__SUNPRO_C) || defined(__GNU__)
+#  include <unistd.h>
+# elif defined (__FreeBSD__) || defined (__OpenBSD__) || \
+   defined (__NetBSD__) || defined (__DragonFly__) || defined (__MacOSX__) || \
+   (defined (__MACH__) && defined (__APPLE__))
+#  include <unistd.h>
+#  include <sys/param.h>
+#  include <sys/sysctl.h>
+# elif defined (__linux__) || defined(__GLIBC__)
+#  define _GNU_SOURCE
+#  include <sched.h>
+# endif
+# ifdef EFL_HAVE_POSIX_THREADS
+#  include <pthread.h>
+# endif
+
+# define TH_MAX 8
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "eina_cpu.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/* FIXME this ifdefs should be replaced */
+#if defined(__i386__) || defined(__x86_64__)
+/* We save ebx and restore it to be PIC compatible */
+static inline void _x86_cpuid(int op, int *a, int *b, int *c, int *d)
+{
+   asm volatile (
+#if defined(__x86_64__)
+      "pushq %%rbx      \n\t" /* save %ebx */
+#else
+      "pushl %%ebx      \n\t" /* save %ebx */
+#endif
+      "cpuid            \n\t"
+      "movl %%ebx, %1   \n\t" /* save what cpuid just put in %ebx */
+#if defined(__x86_64__)
+      "popq %%rbx       \n\t" /* restore the old %ebx */
+#else
+      "popl %%ebx       \n\t" /* restore the old %ebx */
+#endif
+      : "=a" (*a), "=r" (*b), "=c" (*c), "=d" (*d)
+      : "a" (op)
+      : "cc");
+}
+
+static
+void _x86_simd(Eina_Cpu_Features *features)
+{
+   int a, b, c, d;
+
+   _x86_cpuid(1, &a, &b, &c, &d);
+   /*
+    * edx
+    * 18 = PN (Processor Number)
+    * 19 = CLFlush (Cache Line Flush)
+    * 23 = MMX
+    * 25 = SSE
+    * 26 = SSE2
+    * 28 = HTT (Hyper Threading)
+    * ecx
+    * 0 = SSE3
+    */
+   if ((d >> 23) & 1)
+      *features |= EINA_CPU_MMX;
+
+   if ((d >> 25) & 1)
+      *features |= EINA_CPU_SSE;
+
+   if ((d >> 26) & 1)
+      *features |= EINA_CPU_SSE2;
+
+   if (c & 1)
+      *features |= EINA_CPU_SSE3;
+}
+#endif
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/* FIXME the features checks should be called when this function is called?
+ * or make it static by doing eina_cpu_init() and return a local var
+ */
+/**
+ *
+ * @return
+ */
+EAPI Eina_Cpu_Features eina_cpu_features_get(void)
+{
+   Eina_Cpu_Features ecf = 0;
+#if defined(__i386__) || defined(__x86_64__)
+   _x86_simd(&ecf);
+#endif
+   return ecf;
+}
+
+EAPI int eina_cpu_count(void)
+{
+#ifdef EFL_HAVE_THREADS
+
+# if   defined (_WIN32)
+   SYSTEM_INFO sysinfo;
+
+   GetSystemInfo(&sysinfo);
+   return sysinfo.dwNumberOfProcessors;
+
+# elif defined (__SUNPRO_C) || defined(__GNU__)
+   /*
+    * _SC_NPROCESSORS_ONLN: number of processors that are online, that
+                            is available when sysconf is called. The number
+                            of cpu can change by admins.
+    * _SC_NPROCESSORS_CONF: maximum number of processors that are available
+                            to the current OS instance. That number can be
+                            change after a reboot.
+    * _SC_NPROCESSORS_MAX : maximum number of processors that are on the
+                            motherboard.
+    */
+   return sysconf(_SC_NPROCESSORS_ONLN);
+
+# elif defined (__FreeBSD__) || defined (__OpenBSD__) || \
+   defined (__NetBSD__) || defined (__DragonFly__) || defined (__MacOSX__) || \
+   (defined (__MACH__) && defined (__APPLE__))
+
+   int mib[4];
+   int cpus;
+   size_t len = sizeof(cpus);
+
+   mib[0] = CTL_HW;
+#ifdef HW_AVAILCPU
+   mib[1] = HW_AVAILCPU;
+#else
+   mib[1] = HW_NCPU;
+#endif
+   sysctl(mib, 2, &cpus, &len, NULL, 0);
+   if (cpus < 1)
+      cpus = 1;
+
+   return cpus;
+
+# elif defined (__linux__) || defined(__GLIBC__)
+   cpu_set_t cpu;
+   int i;
+   static int cpus = 0;
+
+   if (cpus != 0)
+      return cpus;
+
+   CPU_ZERO(&cpu);
+   if (sched_getaffinity(0, sizeof(cpu), &cpu) != 0)
+     {
+        fprintf(stderr, "[Eina] could not get cpu affinity: %s\n",
+                strerror(errno));
+        return 1;
+     }
+
+   for (i = 0; i < TH_MAX; i++)
+     {
+        if (CPU_ISSET(i, &cpu))
+           cpus = i + 1;
+        else
+           break;
+     }
+   return cpus;
+
+# else
+#  error "eina_cpu_count() error: Platform not supported"
+# endif
+#else
+   return 1;
+#endif
+}
diff --git a/tests/suite/ecore/src/lib/eina_error.c 
b/tests/suite/ecore/src/lib/eina_error.c
new file mode 100644
index 0000000..f273ca5
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_error.c
@@ -0,0 +1,463 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/**
+ * @page tutorial_error_page Error Tutorial
+ *
+ * @section tutorial_error_introduction Introduction
+ *
+ * The Eina error module provides a way to manage errors in a simple
+ * but powerful way in libraries and modules. It is also used in Eina
+ * itself. Similar to libC's @c errno and strerror() facilities, this
+ * is extensible and recommended for other libraries and applications.
+ *
+ * @section tutorial_error_registering_msg Registering messages
+ *
+ * The error module can provide a system that mimic the errno system
+ * of the C standard library. It consists in 2 parts:
+ *
+ * @li a way of registering new messages with
+ * eina_error_msg_register() and eina_error_msg_get(),
+ * @li a way of setting / getting last error message with
+ * eina_error_set() / eina_error_get().
+ *
+ * So one has to fisrt register all the error messages that a program
+ * or a lib should manage. Then, when an error can occur, use
+ * eina_error_set(), and when errors are managed, use
+ * eina_error_get(). If eina_error_set() is used to set an error, do
+ * not forget to call before eina_error_set0), to remove previous set
+ * errors.
+ *
+ * Here is an example of use:
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ *
+ * #include <eina_error.h>
+ *
+ * Eina_Error MY_ERROR_NEGATIVE;
+ * Eina_Error MY_ERROR_NULL;
+ *
+ * voi *data_new()
+ * {
+ *    eina_error_set(0);
+ *
+ *    eina_error_set(MY_ERROR_NULL);
+ *    return NULL;
+ * }
+ *
+ * int test(int n)
+ * {
+ *    eina_error_set(0);
+ *
+ *    if (n < 0)
+ *    {
+ *       eina_error_set(MY_ERROR_NEGATIVE);
+ *       return 0;
+ *    }
+ *
+ *    return 1;
+ * }
+ *
+ * int main(void)
+ * {
+ *    void *data;
+ *
+ *    if (!eina_init())
+ *    {
+ *       printf ("Error during the initialization of eina_error module\n");
+ *       return EXIT_FAILURE;
+ *    }
+ *
+ *    MY_ERROR_NEGATIVE = eina_error_msg_register("Negative number");
+ *    MY_ERROR_NULL = eina_error_msg_register("NULL pointer");
+
+ *    data = data_new();
+ *    if (!data)
+ *    {
+ *       Eina_Error err;
+ *
+ *       err = eina_error_get();
+ *       if (err)
+ *          printf("Error during memory allocation: %s\n",
+ *                 eina_error_msg_get(err));
+ *    }
+ *
+ *    if (!test(0))
+ *    {
+ *       Eina_Error err;
+ *
+ *       err = eina_error_get();
+ *       if (err)
+ *          printf("Error during test function: %s\n",
+ *                 eina_error_msg_get(err));
+ *    }
+ *
+ *    if (!test(-1))
+ *    {
+ *       Eina_Error err;
+ *
+ *       err = eina_error_get();
+ *       if (err)
+ *          printf("Error during test function: %s\n",
+ *                 eina_error_msg_get(err));
+ *    }
+ *
+ *    eina_shutdown();
+ *
+ *    return EXIT_SUCCESS;
+ * }
+ * @endcode
+ *
+ * Of course, instead of printf(), eina_log_print() can be used to
+ * have beautiful error messages.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_error.h"
+
+/* TODO
+ * + add a wrapper for assert?
+ * + add common error numbers, messages
+ * + add a calltrace of errors, not only store the last error but a list of 
them
+ * and also store the function that set it
+ */
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+typedef struct _Eina_Error_Message Eina_Error_Message;
+struct _Eina_Error_Message
+{
+   Eina_Bool string_allocated;
+   const char *string;
+};
+
+static Eina_Error_Message *_eina_errors = NULL;
+static size_t _eina_errors_count = 0;
+static size_t _eina_errors_allocated = 0;
+static Eina_Error _eina_last_error;
+
+static Eina_Error_Message *
+_eina_error_msg_alloc(void)
+{
+   size_t idx;
+
+   if (_eina_errors_count == _eina_errors_allocated)
+     {
+        void *tmp;
+        size_t size;
+
+        if (EINA_UNLIKELY(_eina_errors_allocated == 0))
+           size = 24;
+        else
+           size = _eina_errors_allocated + 8;
+
+        tmp = realloc(_eina_errors, sizeof(Eina_Error_Message) * size);
+        if (!tmp)
+           return NULL;
+
+        _eina_errors = tmp;
+        _eina_errors_allocated = size;
+     }
+
+   idx = _eina_errors_count;
+   _eina_errors_count++;
+   return _eina_errors + idx;
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+EAPI Eina_Error EINA_ERROR_OUT_OF_MEMORY = 0;
+
+static const char EINA_ERROR_OUT_OF_MEMORY_STR[] = "Out of memory";
+
+/**
+ * @endcond
+ */
+
+/**
+ * @internal
+ * @brief Initialize the error module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the error module of Eina. It is called by
+ * eina_init().
+ *
+ * This function registers the error #EINA_ERROR_OUT_OF_MEMORY.
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_error_init(void)
+{
+   /* TODO register the eina's basic errors */
+   EINA_ERROR_OUT_OF_MEMORY = eina_error_msg_static_register(
+         EINA_ERROR_OUT_OF_MEMORY_STR);
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the error module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the error module set up by
+ * eina_error_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_error_shutdown(void)
+{
+   Eina_Error_Message *eem, *eem_end;
+
+   eem = _eina_errors;
+   eem_end = eem + _eina_errors_count;
+
+   for (; eem < eem_end; eem++)
+      if (eem->string_allocated)
+         free((char *)eem->string);
+
+         free(_eina_errors);
+   _eina_errors = NULL;
+   _eina_errors_count = 0;
+   _eina_errors_allocated = 0;
+
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Error_Group Error
+ *
+ * @brief These functions provide error management for projects.
+ *
+ * To use the error system Eina must be initialized with eina_init()
+ * and later shut down with eina_shutdown(). Error codes are
+ * registered with eina_error_msg_register() and converted from
+ * identifier to original message string with eina_error_msg_get().
+ *
+ * Logging functions are not in eina_error anymore, see
+ * eina_log_print() instead.
+ *
+ * @{
+ */
+
+/**
+ * @brief Register a new error type.
+ *
+ * @param msg The description of the error. It will be duplicated using
+ *        strdup().
+ * @return The unique number identifier for this error.
+ *
+ * This function stores in a list the error message described by
+ * @p msg. The returned value is a unique identifier greater or equal
+ * than 1. The description can be retrieve later by passing to
+ * eina_error_msg_get() the returned value.
+ *
+ * @see eina_error_msg_static_register()
+ */
+EAPI Eina_Error
+eina_error_msg_register(const char *msg)
+{
+   Eina_Error_Message *eem;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, 0);
+
+   eem = _eina_error_msg_alloc();
+   if (!eem)
+      return 0;
+
+   eem->string_allocated = EINA_TRUE;
+   eem->string = strdup(msg);
+   if (!eem->string)
+     {
+        _eina_errors_count--;
+        return 0;
+     }
+
+   return _eina_errors_count; /* identifier = index + 1 (== _count). */
+}
+
+/**
+ * @brief Register a new error type, statically allocated message.
+ *
+ * @param msg The description of the error. This string will not be
+ *        duplicated and thus the given pointer should live during
+ *        usage of eina_error.
+ * @return The unique number identifier for this error.
+ *
+ * This function stores in a list the error message described by
+ * @p msg. The returned value is a unique identifier greater or equal
+ * than 1. The description can be retrieve later by passing to
+ * eina_error_msg_get() the returned value.
+ *
+ * @see eina_error_msg_register()
+ */
+EAPI Eina_Error
+eina_error_msg_static_register(const char *msg)
+{
+   Eina_Error_Message *eem;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, 0);
+
+   eem = _eina_error_msg_alloc();
+   if (!eem)
+      return 0;
+
+   eem->string_allocated = EINA_FALSE;
+   eem->string = msg;
+   return _eina_errors_count; /* identifier = index + 1 (== _count). */
+}
+
+/**
+ * @brief Change the message of an already registered message
+ *
+ * @param error The Eina_Error to change the message of
+ * @param msg The description of the error. This string will be
+ * duplicated only if the error was registered with @ref 
eina_error_msg_register
+ * otherwise it must remain intact for the duration
+ * @return EINA_TRUE if successful, EINA_FALSE on error
+ *
+ * This function modifies the message associated with @p error and changes
+ * it to @p msg.  If the error was previously registered by @ref 
eina_error_msg_static_register
+ * then the string will not be duplicated, otherwise the previous message
+ * will be freed and @p msg copied.
+ *
+ * @see eina_error_msg_register()
+ */
+EAPI Eina_Bool
+eina_error_msg_modify(Eina_Error error, const char *msg)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(msg, EINA_FALSE);
+   if (error < 1)
+      return EINA_FALSE;
+
+   if ((size_t)error > _eina_errors_count)
+      return EINA_FALSE;
+
+   if (_eina_errors[error - 1].string_allocated)
+     {
+        const char *tmp;
+
+        if (!(tmp = strdup(msg)))
+           return EINA_FALSE;
+
+        free((void *)_eina_errors[error - 1].string);
+        _eina_errors[error - 1].string = tmp;
+        return EINA_TRUE;
+     }
+
+   _eina_errors[error - 1].string = msg;
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Return the description of the given an error number.
+ *
+ * @param error The error number.
+ * @return The description of the error.
+ *
+ * This function returns the description of an error that has been
+ * registered with eina_error_msg_register(). If an incorrect error is
+ * given, then @c NULL is returned.
+ */
+EAPI const char *
+eina_error_msg_get(Eina_Error error)
+{
+   if (error < 1)
+      return NULL;
+
+   if ((size_t)error > _eina_errors_count)
+      return NULL;
+
+   return _eina_errors[error - 1].string;
+}
+
+/**
+ * @brief Return the last set error.
+ *
+ * @return The last error.
+ *
+ * This function returns the last error set by eina_error_set(). The
+ * description of the message is returned by eina_error_msg_get().
+ */
+EAPI Eina_Error
+eina_error_get(void)
+{
+   return _eina_last_error;
+}
+
+/**
+ * @brief Set the last error.
+ *
+ * @param err The error identifier.
+ *
+ * This function sets the last error identifier. The last error can be
+ * retrieved with eina_error_get().
+ */
+EAPI void
+eina_error_set(Eina_Error err)
+{
+   _eina_last_error = err;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_file.c 
b/tests/suite/ecore/src/lib/eina_file.c
new file mode 100644
index 0000000..a5c9572
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_file.c
@@ -0,0 +1,544 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Vincent Torri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifndef _WIN32
+# define _GNU_SOURCE
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <string.h>
+#include <dirent.h>
+
+#ifndef _WIN32
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <unistd.h>
+#else
+# include <Evil.h>
+#endif /* _WIN2 */
+
+#ifndef _WIN32
+# define PATH_DELIM '/'
+#else
+# define PATH_DELIM '\\'
+# define NAME_MAX MAX_PATH
+#endif
+
+#ifdef __sun
+# ifndef NAME_MAX
+#  define NAME_MAX 255
+# endif
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_file.h"
+#include "eina_stringshare.h"
+
+typedef struct _Eina_File_Iterator Eina_File_Iterator;
+struct _Eina_File_Iterator
+{
+   Eina_Iterator iterator;
+
+   DIR *dirp;
+   int length;
+
+   char dir[1];
+};
+
+static Eina_Bool
+_eina_file_ls_iterator_next(Eina_File_Iterator *it, void **data)
+{
+   struct dirent *dp;
+   char *name;
+   size_t length;
+
+   do
+     {
+        dp = readdir(it->dirp);
+        if (!dp)
+           return EINA_FALSE;
+     }
+   while ((dp->d_name[0] == '.') &&
+          ((dp->d_name[1] == '\0') ||
+           ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
+
+   length = strlen(dp->d_name);
+   name = alloca(length + 2 + it->length);
+
+   memcpy(name,                  it->dir,    it->length);
+   memcpy(name + it->length,     "/",        1);
+   memcpy(name + it->length + 1, dp->d_name, length + 1);
+
+   *data = (char *)eina_stringshare_add(name);
+   return EINA_TRUE;
+}
+
+static char *
+_eina_file_ls_iterator_container(Eina_File_Iterator *it)
+{
+   return it->dir;
+}
+
+static void
+_eina_file_ls_iterator_free(Eina_File_Iterator *it)
+{
+   closedir(it->dirp);
+
+   EINA_MAGIC_SET(&it->iterator, 0);
+   free(it);
+}
+
+typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
+struct _Eina_File_Direct_Iterator
+{
+   Eina_Iterator iterator;
+
+   DIR *dirp;
+   int length;
+
+   Eina_File_Direct_Info info;
+
+   char dir[1];
+};
+
+static Eina_Bool
+_eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
+{
+   struct dirent *dp;
+   size_t length;
+
+   do
+     {
+        dp = readdir(it->dirp);
+        if (!dp)
+           return EINA_FALSE;
+
+        length = strlen(dp->d_name);
+        if (it->info.name_start + length + 1 >= PATH_MAX)
+           continue;
+     }
+   while ((dp->d_name[0] == '.') &&
+          ((dp->d_name[1] == '\0') ||
+           ((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
+
+   memcpy(it->info.path + it->info.name_start, dp->d_name, length);
+   it->info.name_length = length;
+   it->info.path_length = it->info.name_start + length;
+   it->info.path[it->info.path_length] = '\0';
+   it->info.dirent = dp;
+
+   *data = &it->info;
+   return EINA_TRUE;
+}
+
+static char *
+_eina_file_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
+{
+   return it->dir;
+}
+
+static void
+_eina_file_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
+{
+   closedir(it->dirp);
+
+   EINA_MAGIC_SET(&it->iterator, 0);
+   free(it);
+}
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_File_Group File
+ *
+ * @brief Functions to traverse directories and split paths.
+ *
+ * @li eina_file_dir_list() list the content of a directory,
+ * recusrsively or not, and can call a callback function for eachfound
+ * file.
+ * @li eina_file_split() split a path into all the subdirectories that
+ * compose it, according to the separator of the file system.
+ *
+ * @{
+ */
+
+/**
+ * @brief List all files on the directory calling the function for every file 
found.
+ *
+ * @param dir The directory name.
+ * @param recursive Iterate recursively in the directory.
+ * @param cb The callback to be called.
+ * @param data The data to pass to the callback.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function lists all the files in @p dir. To list also all the
+ * sub directoris recursively, @p recursive must be set to #EINA_TRUE,
+ * otherwise it must be set to #EINA_FALSE. For each found file, @p cb
+ * is called and @p data is passed to it.
+ *
+ * If @p cb or @p dir are @c NULL, or if @p dir is a string of size 0,
+ * or if @p dir can not be opened, this function returns #EINA_FALSE
+ * immediately. otherwise, it returns #EINA_TRUE.
+ */
+EAPI Eina_Bool
+eina_file_dir_list(const char *dir,
+                   Eina_Bool recursive,
+                   Eina_File_Dir_List_Cb cb,
+                   void *data)
+{
+#ifndef _WIN32
+   struct dirent *de;
+   DIR *d;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cb,  EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
+
+   d = opendir(dir);
+   if (!d)
+      return EINA_FALSE;
+
+   while ((de = readdir(d)))
+     {
+        if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, ".."))
+           continue;
+
+        cb(de->d_name, dir, data);
+        /* d_type is only available on linux and bsd (_BSD_SOURCE) */
+
+        if (recursive == EINA_TRUE)
+          {
+             char *path;
+
+             path = alloca(strlen(dir) + strlen(de->d_name) + 2);
+             strcpy(path, dir);
+             strcat(path, "/");
+             strcat(path, de->d_name);
+#ifndef sun
+             if (de->d_type == DT_UNKNOWN)
+               {
+#endif
+             struct stat st;
+
+             if (stat(path, &st))
+                continue;
+
+             if (!S_ISDIR(st.st_mode))
+                continue;
+
+#ifndef sun
+          }
+        else if (de->d_type != DT_DIR)
+           continue;
+
+#endif
+
+             eina_file_dir_list(path, recursive, cb, data);
+          }
+     }
+
+   closedir(d);
+#else
+   WIN32_FIND_DATA file;
+   HANDLE hSearch;
+   char *new_dir;
+   TCHAR *tdir;
+   size_t length_dir;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cb,  EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
+
+   length_dir = strlen(dir);
+   new_dir = (char *)alloca(length_dir + 5);
+   if (!new_dir)
+      return EINA_FALSE;
+
+   memcpy(new_dir,              dir,    length_dir);
+   memcpy(new_dir + length_dir, "/*.*", 5);
+
+#ifdef UNICODE
+   tdir = evil_char_to_wchar(new_dir);
+#else
+   tdir = new_dir;
+#endif /* ! UNICODE */
+   hSearch = FindFirstFile(tdir, &file);
+#ifdef UNICODE
+   free(tdir);
+#endif /* UNICODE */
+
+   if (hSearch == INVALID_HANDLE_VALUE)
+      return EINA_FALSE;
+
+   do
+     {
+        char *filename;
+
+#ifdef UNICODE
+        filename = evil_wchar_to_char(file.cFileName);
+#else
+        filename = file.cFileName;
+#endif /* ! UNICODE */
+        if (!strcmp(filename, ".") || !strcmp(filename, ".."))
+           continue;
+
+        cb(filename, dir, data);
+
+        if (recursive == EINA_TRUE)
+          {
+             char *path;
+
+             path = alloca(strlen(dir) + strlen(filename) + 2);
+             strcpy(path, dir);
+             strcat(path, "/");
+             strcat(path, filename);
+
+             if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+                continue;
+
+             eina_file_dir_list(path, recursive, cb, data);
+          }
+
+#ifdef UNICODE
+        free(filename);
+#endif /* UNICODE */
+
+     } while (FindNextFile(hSearch, &file));
+   FindClose(hSearch);
+#endif /* _WIN32 */
+
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Split a path according to the delimiter of the filesystem.
+ *
+ * @param path The path to split.
+ * @return An array of the parts of the path to split.
+ *
+ * This function splits @p path according to the delimiter of the used
+ * filesystem. If  @p path is @c NULL or if the array can not be
+ * created, @c NULL is returned, otherwise, an array with the
+ * different parts of @p path is returned.
+ */
+EAPI Eina_Array *
+eina_file_split(char *path)
+{
+   Eina_Array *ea;
+   char *current;
+   size_t length;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   ea = eina_array_new(16);
+
+   if (!ea)
+      return NULL;
+
+   for (current = strchr(path, PATH_DELIM);
+        current;
+        path = current + 1, current = strchr(path, PATH_DELIM))
+     {
+        length = current - path;
+
+        if (length <= 0)
+           continue;
+
+        eina_array_push(ea, path);
+        *current = '\0';
+     }
+
+   if (*path != '\0')
+        eina_array_push(ea, path);
+
+   return ea;
+}
+
+/**
+ * Get an iterator to list the content of a directory.
+ *
+ * Iterators are cheap to be created and allow interruption at any
+ * iteration. At each iteration, only the next directory entry is read
+ * from the filesystem with readdir().
+ *
+ * The iterator will handle the user a stringshared value with the
+ * full path. One must call eina_stringshare_del() on it after usage
+ * to not leak!
+ *
+ * The eina_file_direct_ls() function will provide a possibly faster
+ * alternative if you need to filter the results somehow, like
+ * checking extension.
+ *
+ * The iterator will walk over '.' and '..' without returning them.
+ *
+ * @param  dir The name of the directory to list
+ * @return Return an Eina_Iterator that will walk over the files and
+ *         directory in the pointed directory. On failure it will
+ *         return NULL. The iterator emits stringshared value with the
+ *         full path and must be freed with eina_stringshare_del().
+ *
+ * @see eina_file_direct_ls()
+ */
+EAPI Eina_Iterator *
+eina_file_ls(const char *dir)
+{
+   Eina_File_Iterator *it;
+   size_t length;
+
+   if (!dir)
+      return NULL;
+
+   length = strlen(dir);
+   if (length < 1)
+      return NULL;
+
+   it = calloc(1, sizeof (Eina_File_Iterator) + length);
+   if (!it)
+      return NULL;
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->dirp = opendir(dir);
+   if (!it->dirp)
+     {
+        free(it);
+        return NULL;
+     }
+
+   memcpy(it->dir, dir, length + 1);
+   if (dir[length - 1] != '/')
+      it->length = length;
+   else
+      it->length = length - 1;
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_ls_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _eina_file_ls_iterator_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_ls_iterator_free);
+
+   return &it->iterator;
+}
+
+/**
+ * Get an iterator to list the content of a directory, with direct information.
+ *
+ * Iterators are cheap to be created and allow interruption at any
+ * iteration. At each iteration, only the next directory entry is read
+ * from the filesystem with readdir().
+ *
+ * The iterator returns the direct pointer to couple of useful information in
+ * #Eina_File_Direct_Info and that pointer should not be modified anyhow!
+ *
+ * The iterator will walk over '.' and '..' without returning them.
+ *
+ * @param  dir The name of the directory to list
+
+ * @return Return an Eina_Iterator that will walk over the files and
+ *         directory in the pointed directory. On failure it will
+ *         return NULL. The iterator emits #Eina_File_Direct_Info
+ *         pointers that could be used but not modified. The lifetime
+ *         of the returned pointer is until the next iteration and
+ *         while the iterator is live, deleting the iterator
+ *         invalidates the pointer.
+ *
+ * @see eina_file_ls()
+ */
+EAPI Eina_Iterator *
+eina_file_direct_ls(const char *dir)
+{
+   Eina_File_Direct_Iterator *it;
+   size_t length;
+
+   if (!dir)
+      return NULL;
+
+   length = strlen(dir);
+   if (length < 1)
+      return NULL;
+
+   if (length + NAME_MAX + 2 >= PATH_MAX)
+      return NULL;
+
+   it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
+   if (!it)
+      return NULL;
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->dirp = opendir(dir);
+   if (!it->dirp)
+     {
+        free(it);
+        return NULL;
+     }
+
+   memcpy(it->dir,       dir, length + 1);
+   it->length = length;
+
+   memcpy(it->info.path, dir, length);
+   if (dir[length - 1] == '/')
+      it->info.name_start = length;
+   else
+     {
+        it->info.path[length] = '/';
+        it->info.name_start = length + 1;
+     }
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_direct_ls_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _eina_file_direct_ls_iterator_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
+
+   return &it->iterator;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_fp.c 
b/tests/suite/ecore/src/lib/eina_fp.c
new file mode 100644
index 0000000..73a2df0
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_fp.c
@@ -0,0 +1,532 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <math.h>
+
+#include "eina_types.h"
+#include "eina_fp.h"
+
+#define MAX_PREC 1025
+static const Eina_F32p32 eina_trigo[MAX_PREC] =
+{
+   0x0000000100000000, 0x00000000ffffec43, 0x00000000ffffb10b,
+   0x00000000ffff4e5a, 0x00000000fffec42e, 0x00000000fffe1287,
+   0x00000000fffd3967, 0x00000000fffc38cd, 0x00000000fffb10b9,
+   0x00000000fff9c12c,
+   0x00000000fff84a25, 0x00000000fff6aba5, 0x00000000fff4e5ac,
+   0x00000000fff2f83b, 0x00000000fff0e351, 0x00000000ffeea6ef,
+   0x00000000ffec4316, 0x00000000ffe9b7c5, 0x00000000ffe704fe,
+   0x00000000ffe42ac0,
+   0x00000000ffe1290b, 0x00000000ffddffe2, 0x00000000ffdaaf43,
+   0x00000000ffd7372f, 0x00000000ffd397a8, 0x00000000ffcfd0ad,
+   0x00000000ffcbe23f, 0x00000000ffc7cc5f, 0x00000000ffc38f0d,
+   0x00000000ffbf2a4b,
+   0x00000000ffba9e17, 0x00000000ffb5ea75, 0x00000000ffb10f63,
+   0x00000000ffac0ce3, 0x00000000ffa6e2f6, 0x00000000ffa1919c,
+   0x00000000ff9c18d6, 0x00000000ff9678a6, 0x00000000ff90b10b,
+   0x00000000ff8ac208,
+   0x00000000ff84ab9c, 0x00000000ff7e6dc8, 0x00000000ff78088f,
+   0x00000000ff717bf0, 0x00000000ff6ac7ec, 0x00000000ff63ec85,
+   0x00000000ff5ce9bc, 0x00000000ff55bf92, 0x00000000ff4e6e08,
+   0x00000000ff46f51f,
+   0x00000000ff3f54d8, 0x00000000ff378d34, 0x00000000ff2f9e35,
+   0x00000000ff2787dc, 0x00000000ff1f4a2a, 0x00000000ff16e520,
+   0x00000000ff0e58c0, 0x00000000ff05a50a, 0x00000000fefcca01,
+   0x00000000fef3c7a6,
+   0x00000000feea9df9, 0x00000000fee14cfe, 0x00000000fed7d4b3,
+   0x00000000fece351d, 0x00000000fec46e3b, 0x00000000feba800f,
+   0x00000000feb06a9c, 0x00000000fea62de1, 0x00000000fe9bc9e2,
+   0x00000000fe913e9f,
+   0x00000000fe868c1b, 0x00000000fe7bb256, 0x00000000fe70b153,
+   0x00000000fe658913, 0x00000000fe5a3998, 0x00000000fe4ec2e4,
+   0x00000000fe4324f9, 0x00000000fe375fd7, 0x00000000fe2b7382,
+   0x00000000fe1f5ffa,
+   0x00000000fe132543, 0x00000000fe06c35d, 0x00000000fdfa3a4b,
+   0x00000000fded8a0e, 0x00000000fde0b2a8, 0x00000000fdd3b41c,
+   0x00000000fdc68e6c, 0x00000000fdb94199, 0x00000000fdabcda5,
+   0x00000000fd9e3294,
+   0x00000000fd907065, 0x00000000fd82871d, 0x00000000fd7476bd,
+   0x00000000fd663f46, 0x00000000fd57e0bd, 0x00000000fd495b21,
+   0x00000000fd3aae77, 0x00000000fd2bdabf, 0x00000000fd1cdffd,
+   0x00000000fd0dbe32,
+   0x00000000fcfe7562, 0x00000000fcef058e, 0x00000000fcdf6eb8,
+   0x00000000fccfb0e4, 0x00000000fcbfcc13, 0x00000000fcafc048,
+   0x00000000fc9f8d86, 0x00000000fc8f33ce, 0x00000000fc7eb325,
+   0x00000000fc6e0b8b,
+   0x00000000fc5d3d03, 0x00000000fc4c4791, 0x00000000fc3b2b37,
+   0x00000000fc29e7f7, 0x00000000fc187dd5, 0x00000000fc06ecd2,
+   0x00000000fbf534f2, 0x00000000fbe35637, 0x00000000fbd150a3,
+   0x00000000fbbf243b,
+   0x00000000fbacd100, 0x00000000fb9a56f6, 0x00000000fb87b61f,
+   0x00000000fb74ee7e, 0x00000000fb620016, 0x00000000fb4eeaea,
+   0x00000000fb3baefd, 0x00000000fb284c52, 0x00000000fb14c2eb,
+   0x00000000fb0112cd,
+   0x00000000faed3bf9, 0x00000000fad93e73, 0x00000000fac51a3f,
+   0x00000000fab0cf5e, 0x00000000fa9c5dd5, 0x00000000fa87c5a6,
+   0x00000000fa7306d5, 0x00000000fa5e2164, 0x00000000fa491558,
+   0x00000000fa33e2b3,
+   0x00000000fa1e8978, 0x00000000fa0909ab, 0x00000000f9f36350,
+   0x00000000f9dd9668, 0x00000000f9c7a2f9, 0x00000000f9b18905,
+   0x00000000f99b488f, 0x00000000f984e19c, 0x00000000f96e542e,
+   0x00000000f957a049,
+   0x00000000f940c5f1, 0x00000000f929c528, 0x00000000f9129df3,
+   0x00000000f8fb5056, 0x00000000f8e3dc53, 0x00000000f8cc41ee,
+   0x00000000f8b4812b, 0x00000000f89c9a0e, 0x00000000f8848c9b,
+   0x00000000f86c58d4,
+   0x00000000f853febe, 0x00000000f83b7e5d, 0x00000000f822d7b4,
+   0x00000000f80a0ac7, 0x00000000f7f1179a, 0x00000000f7d7fe31,
+   0x00000000f7bebe90, 0x00000000f7a558ba, 0x00000000f78bccb3,
+   0x00000000f7721a80,
+   0x00000000f7584225, 0x00000000f73e43a5, 0x00000000f7241f04,
+   0x00000000f709d446, 0x00000000f6ef6370, 0x00000000f6d4cc85,
+   0x00000000f6ba0f8a, 0x00000000f69f2c83, 0x00000000f6842374,
+   0x00000000f668f461,
+   0x00000000f64d9f4e, 0x00000000f632243f, 0x00000000f616833a,
+   0x00000000f5fabc41, 0x00000000f5decf59, 0x00000000f5c2bc87,
+   0x00000000f5a683cf, 0x00000000f58a2535, 0x00000000f56da0be,
+   0x00000000f550f66e,
+   0x00000000f5342649, 0x00000000f5173054, 0x00000000f4fa1494,
+   0x00000000f4dcd30c, 0x00000000f4bf6bc2, 0x00000000f4a1deb9,
+   0x00000000f4842bf7, 0x00000000f4665380, 0x00000000f4485559,
+   0x00000000f42a3186,
+   0x00000000f40be80c, 0x00000000f3ed78ef, 0x00000000f3cee434,
+   0x00000000f3b029e1, 0x00000000f39149f9, 0x00000000f3724482,
+   0x00000000f3531980, 0x00000000f333c8f8, 0x00000000f31452ef,
+   0x00000000f2f4b76a,
+   0x00000000f2d4f66d, 0x00000000f2b50ffe, 0x00000000f2950421,
+   0x00000000f274d2dc, 0x00000000f2547c33, 0x00000000f234002b,
+   0x00000000f2135eca, 0x00000000f1f29814, 0x00000000f1d1ac0e,
+   0x00000000f1b09abe,
+   0x00000000f18f6429, 0x00000000f16e0853, 0x00000000f14c8742,
+   0x00000000f12ae0fb, 0x00000000f1091583, 0x00000000f0e724e0,
+   0x00000000f0c50f17, 0x00000000f0a2d42c, 0x00000000f0807426,
+   0x00000000f05def09,
+   0x00000000f03b44db, 0x00000000f01875a1, 0x00000000eff58161,
+   0x00000000efd2681f, 0x00000000efaf29e2, 0x00000000ef8bc6af,
+   0x00000000ef683e8b, 0x00000000ef44917b, 0x00000000ef20bf86,
+   0x00000000eefcc8b1,
+   0x00000000eed8ad01, 0x00000000eeb46c7b, 0x00000000ee900727,
+   0x00000000ee6b7d08, 0x00000000ee46ce25, 0x00000000ee21fa83,
+   0x00000000edfd0228, 0x00000000edd7e51a, 0x00000000edb2a35f,
+   0x00000000ed8d3cfc,
+   0x00000000ed67b1f6, 0x00000000ed420255, 0x00000000ed1c2e1d,
+   0x00000000ecf63554, 0x00000000ecd01801, 0x00000000eca9d628,
+   0x00000000ec836fd1, 0x00000000ec5ce501, 0x00000000ec3635bd,
+   0x00000000ec0f620d,
+   0x00000000ebe869f5, 0x00000000ebc14d7d, 0x00000000eb9a0ca9,
+   0x00000000eb72a780, 0x00000000eb4b1e08, 0x00000000eb237047,
+   0x00000000eafb9e43, 0x00000000ead3a803, 0x00000000eaab8d8d,
+   0x00000000ea834ee6,
+   0x00000000ea5aec15, 0x00000000ea326520, 0x00000000ea09ba0d,
+   0x00000000e9e0eae4, 0x00000000e9b7f7a9, 0x00000000e98ee063,
+   0x00000000e965a51a, 0x00000000e93c45d2, 0x00000000e912c292,
+   0x00000000e8e91b61,
+   0x00000000e8bf5046, 0x00000000e8956146, 0x00000000e86b4e68,
+   0x00000000e84117b3, 0x00000000e816bd2d, 0x00000000e7ec3edc,
+   0x00000000e7c19cc8, 0x00000000e796d6f6, 0x00000000e76bed6e,
+   0x00000000e740e036,
+   0x00000000e715af54, 0x00000000e6ea5ad0, 0x00000000e6bee2af,
+   0x00000000e69346f9, 0x00000000e66787b5, 0x00000000e63ba4e9,
+   0x00000000e60f9e9b, 0x00000000e5e374d4, 0x00000000e5b72798,
+   0x00000000e58ab6f1,
+   0x00000000e55e22e3, 0x00000000e5316b76, 0x00000000e50490b1,
+   0x00000000e4d7929c, 0x00000000e4aa713c, 0x00000000e47d2c98,
+   0x00000000e44fc4b9, 0x00000000e42239a4, 0x00000000e3f48b61,
+   0x00000000e3c6b9f7,
+   0x00000000e398c56c, 0x00000000e36aadc9, 0x00000000e33c7314,
+   0x00000000e30e1554, 0x00000000e2df9490, 0x00000000e2b0f0d0,
+   0x00000000e2822a1a, 0x00000000e2534077, 0x00000000e22433ec,
+   0x00000000e1f50482,
+   0x00000000e1c5b240, 0x00000000e1963d2d, 0x00000000e166a550,
+   0x00000000e136eab0, 0x00000000e1070d56, 0x00000000e0d70d48,
+   0x00000000e0a6ea8e, 0x00000000e076a52f, 0x00000000e0463d33,
+   0x00000000e015b2a1,
+   0x00000000dfe50580, 0x00000000dfb435d9, 0x00000000df8343b2,
+   0x00000000df522f13, 0x00000000df20f804, 0x00000000deef9e8d,
+   0x00000000debe22b5, 0x00000000de8c8483, 0x00000000de5ac3ff,
+   0x00000000de28e131,
+   0x00000000ddf6dc21, 0x00000000ddc4b4d6, 0x00000000dd926b59,
+   0x00000000dd5fffb0, 0x00000000dd2d71e3, 0x00000000dcfac1fb,
+   0x00000000dcc7f000, 0x00000000dc94fbf8, 0x00000000dc61e5ec,
+   0x00000000dc2eade4,
+   0x00000000dbfb53e8, 0x00000000dbc7d7ff, 0x00000000db943a31,
+   0x00000000db607a88, 0x00000000db2c9909, 0x00000000daf895bf,
+   0x00000000dac470af, 0x00000000da9029e3, 0x00000000da5bc163,
+   0x00000000da273737,
+   0x00000000d9f28b66, 0x00000000d9bdbdf9, 0x00000000d988cef8,
+   0x00000000d953be6b, 0x00000000d91e8c5b, 0x00000000d8e938d0,
+   0x00000000d8b3c3d1, 0x00000000d87e2d67, 0x00000000d848759b,
+   0x00000000d8129c74,
+   0x00000000d7dca1fb, 0x00000000d7a68638, 0x00000000d7704934,
+   0x00000000d739eaf7, 0x00000000d7036b89, 0x00000000d6cccaf3,
+   0x00000000d696093d, 0x00000000d65f266f, 0x00000000d6282293,
+   0x00000000d5f0fdb0,
+   0x00000000d5b9b7d0, 0x00000000d58250fa, 0x00000000d54ac937,
+   0x00000000d513208f, 0x00000000d4db570c, 0x00000000d4a36cb6,
+   0x00000000d46b6195, 0x00000000d43335b3, 0x00000000d3fae917,
+   0x00000000d3c27bcb,
+   0x00000000d389edd7, 0x00000000d3513f43, 0x00000000d318701a,
+   0x00000000d2df8063, 0x00000000d2a67027, 0x00000000d26d3f6f,
+   0x00000000d233ee43, 0x00000000d1fa7cae, 0x00000000d1c0eab7,
+   0x00000000d1873867,
+   0x00000000d14d65c8, 0x00000000d11372e1, 0x00000000d0d95fbd,
+   0x00000000d09f2c64, 0x00000000d064d8df, 0x00000000d02a6537,
+   0x00000000cfefd176, 0x00000000cfb51da3, 0x00000000cf7a49c8,
+   0x00000000cf3f55ef,
+   0x00000000cf044220, 0x00000000cec90e64, 0x00000000ce8dbac5,
+   0x00000000ce52474c, 0x00000000ce16b401, 0x00000000cddb00ef,
+   0x00000000cd9f2e1e, 0x00000000cd633b97, 0x00000000cd272964,
+   0x00000000cceaf78e,
+   0x00000000ccaea61e, 0x00000000cc72351e, 0x00000000cc35a497,
+   0x00000000cbf8f492, 0x00000000cbbc2519, 0x00000000cb7f3634,
+   0x00000000cb4227ee, 0x00000000cb04fa50, 0x00000000cac7ad63,
+   0x00000000ca8a4131,
+   0x00000000ca4cb5c3, 0x00000000ca0f0b22, 0x00000000c9d14159,
+   0x00000000c9935870, 0x00000000c9555072, 0x00000000c9172967,
+   0x00000000c8d8e35a, 0x00000000c89a7e53, 0x00000000c85bfa5e,
+   0x00000000c81d5782,
+   0x00000000c7de95cb, 0x00000000c79fb541, 0x00000000c760b5ee,
+   0x00000000c72197dc, 0x00000000c6e25b15, 0x00000000c6a2ffa3,
+   0x00000000c663858f, 0x00000000c623ece2, 0x00000000c5e435a8,
+   0x00000000c5a45fe9,
+   0x00000000c5646bb0, 0x00000000c5245906, 0x00000000c4e427f6,
+   0x00000000c4a3d888, 0x00000000c4636ac8, 0x00000000c422debf,
+   0x00000000c3e23476, 0x00000000c3a16bf9, 0x00000000c3608550,
+   0x00000000c31f8087,
+   0x00000000c2de5da6, 0x00000000c29d1cb8, 0x00000000c25bbdc8,
+   0x00000000c21a40de, 0x00000000c1d8a606, 0x00000000c196ed49,
+   0x00000000c15516b2, 0x00000000c113224a, 0x00000000c0d1101d,
+   0x00000000c08ee033,
+   0x00000000c04c9297, 0x00000000c00a2754, 0x00000000bfc79e73,
+   0x00000000bf84f800, 0x00000000bf423404, 0x00000000beff5289,
+   0x00000000bebc539a, 0x00000000be793741, 0x00000000be35fd89,
+   0x00000000bdf2a67b,
+   0x00000000bdaf3223, 0x00000000bd6ba08b, 0x00000000bd27f1bc,
+   0x00000000bce425c2, 0x00000000bca03ca7, 0x00000000bc5c3676,
+   0x00000000bc181338, 0x00000000bbd3d2f9, 0x00000000bb8f75c3,
+   0x00000000bb4afba1,
+   0x00000000bb06649c, 0x00000000bac1b0c0, 0x00000000ba7ce018,
+   0x00000000ba37f2ad, 0x00000000b9f2e88b, 0x00000000b9adc1bc,
+   0x00000000b9687e4a, 0x00000000b9231e41, 0x00000000b8dda1ac,
+   0x00000000b8980894,
+   0x00000000b8525305, 0x00000000b80c8109, 0x00000000b7c692ac,
+   0x00000000b78087f7, 0x00000000b73a60f6, 0x00000000b6f41db4,
+   0x00000000b6adbe3a, 0x00000000b6674296, 0x00000000b620aad0,
+   0x00000000b5d9f6f4,
+   0x00000000b593270e, 0x00000000b54c3b27, 0x00000000b505334a,
+   0x00000000b4be0f84, 0x00000000b476cfde, 0x00000000b42f7464,
+   0x00000000b3e7fd20, 0x00000000b3a06a1e, 0x00000000b358bb69,
+   0x00000000b310f10c,
+   0x00000000b2c90b11, 0x00000000b2810985, 0x00000000b238ec71,
+   0x00000000b1f0b3e2, 0x00000000b1a85fe2, 0x00000000b15ff07c,
+   0x00000000b11765bc, 0x00000000b0cebfad, 0x00000000b085fe5a,
+   0x00000000b03d21ce,
+   0x00000000aff42a15, 0x00000000afab1739, 0x00000000af61e946,
+   0x00000000af18a048, 0x00000000aecf3c49, 0x00000000ae85bd55,
+   0x00000000ae3c2377, 0x00000000adf26ebb, 0x00000000ada89f2c,
+   0x00000000ad5eb4d5,
+   0x00000000ad14afc2, 0x00000000acca8ffd, 0x00000000ac805594,
+   0x00000000ac360090, 0x00000000abeb90fe, 0x00000000aba106e9,
+   0x00000000ab56625d, 0x00000000ab0ba364, 0x00000000aac0ca0b,
+   0x00000000aa75d65d,
+   0x00000000aa2ac865, 0x00000000a9dfa030, 0x00000000a9945dc9,
+   0x00000000a949013a, 0x00000000a8fd8a91, 0x00000000a8b1f9d8,
+   0x00000000a8664f1c, 0x00000000a81a8a68, 0x00000000a7ceabc7,
+   0x00000000a782b345,
+   0x00000000a736a0ef, 0x00000000a6ea74cf, 0x00000000a69e2ef2,
+   0x00000000a651cf63, 0x00000000a605562f, 0x00000000a5b8c360,
+   0x00000000a56c1702, 0x00000000a51f5123, 0x00000000a4d271cc,
+   0x00000000a485790b,
+   0x00000000a43866eb, 0x00000000a3eb3b77, 0x00000000a39df6bd,
+   0x00000000a35098c7, 0x00000000a30321a2, 0x00000000a2b5915a,
+   0x00000000a267e7fa, 0x00000000a21a258e, 0x00000000a1cc4a24,
+   0x00000000a17e55c5,
+   0x00000000a1304880, 0x00000000a0e2225f, 0x00000000a093e36f,
+   0x00000000a0458bbb, 0x000000009ff71b50, 0x000000009fa8923a,
+   0x000000009f59f086, 0x000000009f0b363e, 0x000000009ebc6370,
+   0x000000009e6d7827,
+   0x000000009e1e746f, 0x000000009dcf5856, 0x000000009d8023e6,
+   0x000000009d30d72d, 0x000000009ce17236, 0x000000009c91f50e,
+   0x000000009c425fc1, 0x000000009bf2b25b, 0x000000009ba2ece8,
+   0x000000009b530f76,
+   0x000000009b031a0f, 0x000000009ab30cc1, 0x000000009a62e797,
+   0x000000009a12aa9f, 0x0000000099c255e5, 0x000000009971e974,
+   0x000000009921655a, 0x0000000098d0c9a2, 0x0000000098801659,
+   0x00000000982f4b8d,
+   0x0000000097de6948, 0x00000000978d6f97, 0x00000000973c5e88,
+   0x0000000096eb3626, 0x000000009699f67f, 0x0000000096489f9e,
+   0x0000000095f73190, 0x0000000095a5ac61, 0x000000009554101f,
+   0x0000000095025cd6,
+   0x0000000094b09292, 0x00000000945eb161, 0x00000000940cb94e,
+   0x0000000093baaa66, 0x00000000936884b6, 0x000000009316484b,
+   0x0000000092c3f531, 0x0000000092718b75, 0x00000000921f0b24,
+   0x0000000091cc744b,
+   0x000000009179c6f5, 0x0000000091270331, 0x0000000090d4290a,
+   0x000000009081388e, 0x00000000902e31c8, 0x000000008fdb14c7,
+   0x000000008f87e197, 0x000000008f349845, 0x000000008ee138dd,
+   0x000000008e8dc36c,
+   0x000000008e3a3800, 0x000000008de696a5, 0x000000008d92df68,
+   0x000000008d3f1256, 0x000000008ceb2f7c, 0x000000008c9736e7,
+   0x000000008c4328a3, 0x000000008bef04bf, 0x000000008b9acb46,
+   0x000000008b467c45,
+   0x000000008af217cb, 0x000000008a9d9de3, 0x000000008a490e9b,
+   0x0000000089f469ff, 0x00000000899fb01e, 0x00000000894ae103,
+   0x0000000088f5fcbc, 0x0000000088a10357, 0x00000000884bf4df,
+   0x0000000087f6d163,
+   0x0000000087a198f0, 0x00000000874c4b92, 0x0000000086f6e956,
+   0x0000000086a1724b, 0x00000000864be67c, 0x0000000085f645f8,
+   0x0000000085a090cc, 0x00000000854ac704, 0x0000000084f4e8ad,
+   0x00000000849ef5d7,
+   0x000000008448ee8c, 0x0000000083f2d2db, 0x00000000839ca2d1,
+   0x0000000083465e7c, 0x0000000082f005e8, 0x0000000082999922,
+   0x0000000082431839, 0x0000000081ec833a, 0x000000008195da31,
+   0x00000000813f1d2d,
+   0x0000000080e84c3a, 0x0000000080916766, 0x00000000803a6ebf,
+   0x000000007fe36251, 0x000000007f8c422b, 0x000000007f350e59,
+   0x000000007eddc6ea, 0x000000007e866bea, 0x000000007e2efd67,
+   0x000000007dd77b6f,
+   0x000000007d7fe60f, 0x000000007d283d54, 0x000000007cd0814c,
+   0x000000007c78b205, 0x000000007c20cf8c, 0x000000007bc8d9ef,
+   0x000000007b70d13b, 0x000000007b18b57e, 0x000000007ac086c5,
+   0x000000007a68451f,
+   0x000000007a0ff098, 0x0000000079b7893e, 0x00000000795f0f1f,
+   0x0000000079068248, 0x0000000078ade2c8, 0x00000000785530ab,
+   0x0000000077fc6c01, 0x0000000077a394d5, 0x00000000774aab36,
+   0x0000000076f1af32,
+   0x000000007698a0d6, 0x00000000763f8030, 0x0000000075e64d4e,
+   0x00000000758d083e, 0x000000007533b10d, 0x0000000074da47c9,
+   0x000000007480cc80, 0x0000000074273f3f, 0x0000000073cda016,
+   0x000000007373ef10,
+   0x00000000731a2c3d, 0x0000000072c057aa, 0x0000000072667164,
+   0x00000000720c797a, 0x0000000071b26ffa, 0x00000000715854f2,
+   0x0000000070fe286e, 0x0000000070a3ea7e, 0x0000000070499b30,
+   0x000000006fef3a90,
+   0x000000006f94c8ae, 0x000000006f3a4596, 0x000000006edfb157,
+   0x000000006e850c00, 0x000000006e2a559d, 0x000000006dcf8e3d,
+   0x000000006d74b5ee, 0x000000006d19ccbe, 0x000000006cbed2bb,
+   0x000000006c63c7f3,
+   0x000000006c08ac74, 0x000000006bad804c, 0x000000006b524389,
+   0x000000006af6f639, 0x000000006a9b986b, 0x000000006a402a2c,
+   0x0000000069e4ab8a, 0x0000000069891c94, 0x00000000692d7d57,
+   0x0000000068d1cde3,
+   0x0000000068760e44, 0x00000000681a3e89, 0x0000000067be5ec1,
+   0x0000000067626ef9, 0x0000000067066f40, 0x0000000066aa5fa3,
+   0x00000000664e4032, 0x0000000065f210f9, 0x000000006595d209,
+   0x000000006539836d,
+   0x0000000064dd2536, 0x000000006480b770, 0x0000000064243a2b,
+   0x0000000063c7ad75, 0x00000000636b115c, 0x00000000630e65ed,
+   0x0000000062b1ab39, 0x000000006254e14c, 0x0000000061f80835,
+   0x00000000619b2002,
+   0x00000000613e28c2, 0x0000000060e12283, 0x0000000060840d54,
+   0x000000006026e943, 0x000000005fc9b65d, 0x000000005f6c74b2,
+   0x000000005f0f2450, 0x000000005eb1c545, 0x000000005e5457a0,
+   0x000000005df6db6f,
+   0x000000005d9950c0, 0x000000005d3bb7a3, 0x000000005cde1024,
+   0x000000005c805a54, 0x000000005c22963f, 0x000000005bc4c3f6,
+   0x000000005b66e385, 0x000000005b08f4fd, 0x000000005aaaf86a,
+   0x000000005a4ceddc,
+   0x0000000059eed561, 0x000000005990af08, 0x0000000059327adf,
+   0x0000000058d438f4, 0x000000005875e957, 0x0000000058178c16,
+   0x0000000057b9213f, 0x00000000575aa8e0, 0x0000000056fc230a,
+   0x00000000569d8fc9,
+   0x00000000563eef2d, 0x0000000055e04144, 0x000000005581861d,
+   0x000000005522bdc6, 0x0000000054c3e84e, 0x00000000546505c4,
+   0x0000000054061636, 0x0000000053a719b3, 0x000000005348104a,
+   0x0000000052e8fa09,
+   0x000000005289d6ff, 0x00000000522aa73a, 0x0000000051cb6aca,
+   0x00000000516c21bc, 0x00000000510ccc20, 0x0000000050ad6a05,
+   0x00000000504dfb78, 0x000000004fee808a, 0x000000004f8ef947,
+   0x000000004f2f65c0,
+   0x000000004ecfc603, 0x000000004e701a1f, 0x000000004e106222,
+   0x000000004db09e1b, 0x000000004d50ce19, 0x000000004cf0f22b,
+   0x000000004c910a5f, 0x000000004c3116c5, 0x000000004bd1176b,
+   0x000000004b710c5f,
+   0x000000004b10f5b2, 0x000000004ab0d371, 0x000000004a50a5ab,
+   0x0000000049f06c70, 0x00000000499027cd, 0x00000000492fd7d3,
+   0x0000000048cf7c8f, 0x00000000486f1611, 0x00000000480ea467,
+   0x0000000047ae27a1,
+   0x00000000474d9fcd, 0x0000000046ed0cfa, 0x00000000468c6f37,
+   0x00000000462bc693, 0x0000000045cb131c, 0x00000000456a54e3,
+   0x0000000045098bf5, 0x0000000044a8b861, 0x000000004447da37,
+   0x0000000043e6f186,
+   0x000000004385fe5c, 0x00000000432500c8, 0x0000000042c3f8d9,
+   0x000000004262e69f, 0x000000004201ca28, 0x0000000041a0a383,
+   0x00000000413f72bf, 0x0000000040de37eb, 0x00000000407cf317,
+   0x00000000401ba450,
+   0x000000003fba4ba7, 0x000000003f58e92a, 0x000000003ef77ce8,
+   0x000000003e9606f1, 0x000000003e348752, 0x000000003dd2fe1c,
+   0x000000003d716b5e, 0x000000003d0fcf25, 0x000000003cae2982,
+   0x000000003c4c7a83,
+   0x000000003beac238, 0x000000003b8900b0, 0x000000003b2735f9,
+   0x000000003ac56223, 0x000000003a63853d, 0x000000003a019f56,
+   0x00000000399fb07d, 0x00000000393db8c1, 0x0000000038dbb831,
+   0x000000003879aedd,
+   0x0000000038179cd3, 0x0000000037b58222, 0x0000000037535edb,
+   0x0000000036f1330b, 0x00000000368efec2, 0x00000000362cc20f,
+   0x0000000035ca7d02, 0x0000000035682fa9, 0x000000003505da14,
+   0x0000000034a37c51,
+   0x0000000034411671, 0x0000000033dea881, 0x00000000337c3292,
+   0x000000003319b4b3, 0x0000000032b72ef2, 0x000000003254a15e,
+   0x0000000031f20c08, 0x00000000318f6efe, 0x00000000312cca50,
+   0x0000000030ca1e0c,
+   0x0000000030676a43, 0x000000003004af02, 0x000000002fa1ec5a,
+   0x000000002f3f2259, 0x000000002edc510f, 0x000000002e79788b,
+   0x000000002e1698dc, 0x000000002db3b212, 0x000000002d50c43c,
+   0x000000002cedcf68,
+   0x000000002c8ad3a7, 0x000000002c27d108, 0x000000002bc4c799,
+   0x000000002b61b76b, 0x000000002afea08c, 0x000000002a9b830b,
+   0x000000002a385ef9, 0x0000000029d53464, 0x000000002972035b,
+   0x00000000290ecbee,
+   0x0000000028ab8e2c, 0x0000000028484a25, 0x0000000027e4ffe7,
+   0x000000002781af83, 0x00000000271e5906, 0x0000000026bafc82,
+   0x0000000026579a04, 0x0000000025f4319d, 0x000000002590c35c,
+   0x00000000252d4f4f,
+   0x0000000024c9d587, 0x0000000024665613, 0x000000002402d101,
+   0x00000000239f4662, 0x00000000233bb644, 0x0000000022d820b8,
+   0x00000000227485cc, 0x000000002210e590, 0x0000000021ad4013,
+   0x0000000021499565,
+   0x0000000020e5e594, 0x00000000208230b1, 0x00000000201e76ca,
+   0x000000001fbab7ef, 0x000000001f56f430, 0x000000001ef32b9b,
+   0x000000001e8f5e41, 0x000000001e2b8c30, 0x000000001dc7b578,
+   0x000000001d63da29,
+   0x000000001cfffa51, 0x000000001c9c1600, 0x000000001c382d46,
+   0x000000001bd44032, 0x000000001b704ed3, 0x000000001b0c5939,
+   0x000000001aa85f74, 0x000000001a446191, 0x0000000019e05fa2,
+   0x00000000197c59b5,
+   0x0000000019184fdb, 0x0000000018b44221, 0x0000000018503098,
+   0x0000000017ec1b50, 0x0000000017880257, 0x000000001723e5bd,
+   0x0000000016bfc591, 0x00000000165ba1e4, 0x0000000015f77ac3,
+   0x0000000015935040,
+   0x00000000152f2269, 0x0000000014caf14d, 0x000000001466bcfd,
+   0x0000000014028587, 0x00000000139e4afb, 0x00000000133a0d69,
+   0x0000000012d5cce0, 0x000000001271896f, 0x00000000120d4326,
+   0x0000000011a8fa15,
+   0x000000001144ae4a, 0x0000000010e05fd6, 0x00000000107c0ec7,
+   0x000000001017bb2d, 0x000000000fb36519, 0x000000000f4f0c98,
+   0x000000000eeab1bb, 0x000000000e865491, 0x000000000e21f52a,
+   0x000000000dbd9395,
+   0x000000000d592fe1, 0x000000000cf4ca1f, 0x000000000c90625c,
+   0x000000000c2bf8aa, 0x000000000bc78d18, 0x000000000b631fb4,
+   0x000000000afeb08f, 0x000000000a9a3fb8, 0x000000000a35cd3e,
+   0x0000000009d15931,
+   0x00000000096ce3a1, 0x0000000009086c9c, 0x0000000008a3f433,
+   0x00000000083f7a75, 0x0000000007daff71, 0x0000000007768337,
+   0x00000000071205d6, 0x0000000006ad875f, 0x00000000064907df,
+   0x0000000005e48768,
+   0x0000000005800608, 0x00000000051b83cf, 0x0000000004b700cc,
+   0x0000000004527d0f, 0x0000000003edf8a7, 0x00000000038973a4,
+   0x000000000324ee16, 0x0000000002c0680b, 0x00000000025be194,
+   0x0000000001f75ac0,
+   0x000000000192d39e, 0x00000000012e4c3e, 0x0000000000c9c4af,
+   0x0000000000653d02, 0x0000000000000000
+};
+
+EAPI Eina_F32p32
+eina_f32p32_cos(Eina_F32p32 a)
+{
+   Eina_F32p32 F32P32_2PI;
+   Eina_F32p32 F32P32_PI2;
+   Eina_F32p32 F32P32_3PI2;
+   Eina_F32p32 remainder_2PI;
+   Eina_F32p32 remainder_PI;
+   Eina_F32p32 interpol;
+   Eina_F32p32 result;
+   int idx;
+   int index2;
+
+   F32P32_2PI = EINA_F32P32_PI << 1;
+   F32P32_PI2 = EINA_F32P32_PI >> 1;
+   F32P32_3PI2 = EINA_F32P32_PI + F32P32_PI2;
+
+   /* Take advantage of cosinus symetrie. */
+   a = eina_fp32p32_llabs(a);
+
+   /* Find table entry in 0 to PI / 2 */
+   remainder_PI = a - (a / EINA_F32P32_PI) * EINA_F32P32_PI;
+
+   /* Find which case from 0 to 2 * PI */
+   remainder_2PI = a - (a / F32P32_2PI) * F32P32_2PI;
+
+   interpol = eina_f32p32_div(eina_f32p32_scale(remainder_PI, MAX_PREC * 2),
+                              EINA_F32P32_PI);
+   idx = eina_f32p32_int_to(interpol);
+   if (idx >= MAX_PREC)
+      idx = 2 * MAX_PREC - (idx - 1);
+
+   index2 = idx + 1;
+   if (index2 == MAX_PREC)
+      index2 = idx - 1;
+
+   result = eina_f32p32_add(eina_trigo[idx],
+                            eina_f32p32_mul(eina_f32p32_sub(eina_trigo[idx],
+                                                            
eina_trigo[index2]),
+                                            (Eina_F32p32)eina_f32p32_fracc_get(
+                                               interpol)));
+
+   if (0 <= remainder_2PI && remainder_2PI < F32P32_PI2)
+      return result;
+   else if (F32P32_PI2 <= remainder_2PI && remainder_2PI < EINA_F32P32_PI)
+      return -result;
+   else if (EINA_F32P32_PI <= remainder_2PI && remainder_2PI < F32P32_3PI2)
+      return -result;
+   else /*  if (F32P32_3PI2 <= remainder_2PI) */
+      return result;
+}
+
+EAPI Eina_F32p32
+eina_f32p32_sin(Eina_F32p32 a)
+{
+   Eina_F32p32 F32P32_2PI;
+   Eina_F32p32 F32P32_PI2;
+   Eina_F32p32 F32P32_3PI2;
+   Eina_F32p32 remainder_2PI;
+   Eina_F32p32 remainder_PI;
+   Eina_F32p32 interpol;
+   Eina_F32p32 result;
+   int idx;
+   int index2;
+
+   F32P32_2PI = EINA_F32P32_PI << 1;
+   F32P32_PI2 = EINA_F32P32_PI >> 1;
+   F32P32_3PI2 = EINA_F32P32_PI + F32P32_PI2;
+
+   /* We only have a table for cosinus, but sin(a) = cos(pi / 2 - a) */
+   a = eina_f32p32_sub(F32P32_PI2, a);
+
+   /* Take advantage of cosinus symetrie. */
+   a = eina_fp32p32_llabs(a);
+
+   /* Find table entry in 0 to PI / 2 */
+   remainder_PI = a - (a / EINA_F32P32_PI) * EINA_F32P32_PI;
+
+   /* Find which case from 0 to 2 * PI */
+   remainder_2PI = a - (a / F32P32_2PI) * F32P32_2PI;
+
+   interpol = eina_f32p32_div(eina_f32p32_scale(remainder_PI, MAX_PREC * 2),
+                              EINA_F32P32_PI);
+   idx = eina_f32p32_int_to(interpol);
+   if (idx >= MAX_PREC)
+      idx = 2 * MAX_PREC - (idx + 1);
+
+   index2 = idx + 1;
+   if (index2 == MAX_PREC)
+      index2 = idx - 1;
+
+   result = eina_f32p32_add(eina_trigo[idx],
+                            eina_f32p32_mul(eina_f32p32_sub(eina_trigo[idx],
+                                                            
eina_trigo[index2]),
+                                            (Eina_F32p32)eina_f32p32_fracc_get(
+                                               interpol)));
+
+   if (0 <= remainder_2PI && remainder_2PI < F32P32_PI2)
+      return result;
+   else if (F32P32_PI2 <= remainder_2PI && remainder_2PI < EINA_F32P32_PI)
+      return -result;
+   else if (EINA_F32P32_PI <= remainder_2PI && remainder_2PI < F32P32_3PI2)
+      return -result;
+   else /* if (F32P32_3PI2 <= remainder_2PI) */
+      return result;
+}
+
diff --git a/tests/suite/ecore/src/lib/eina_hamster.c 
b/tests/suite/ecore/src/lib/eina_hamster.c
new file mode 100644
index 0000000..2f68777
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_hamster.c
@@ -0,0 +1,128 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "eina_config.h"
+#include "eina_types.h"
+#include "eina_hamster.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+const char *_eina_hamster_time = __TIME__;
+const char *_eina_hamster_date = __DATE__;
+static int _eina_hamsters = -1;
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Hamster_Group Hamster
+ *
+ * @brief These functions provide hamster calls.
+ *
+ * @{
+ */
+
+/**
+ * @brief Get the hamster count.
+ *
+ * @return The number of available hamsters.
+ *
+ * This function returns how many hamsters you have.
+ */
+EAPI int
+eina_hamster_count(void)
+{
+   if (_eina_hamsters < 0)
+     {
+        int hrs = 0, min = 0, sec = 0;
+        char mon[8] = "";
+        int monnum = 0, day = 0, year = 0;
+        int fields;
+
+        fields = sscanf(_eina_hamster_time, "%02i:%02i:%02i", &hrs, &min, 
&sec);
+        if (fields == 3)
+          {
+             _eina_hamsters = (hrs * 60) + min;
+             fields = sscanf(_eina_hamster_date, "%s %i %i", mon, &day, &year);
+             if (fields == 3)
+               {
+                  int i;
+                  const char *mons[] =
+                  {
+                     "Jan",
+                     "Feb",
+                     "Mar",
+                     "Apr",
+                     "May",
+                     "Jun",
+                     "Jul",
+                     "Aug",
+                     "Sep",
+                     "Oct",
+                     "Nov",
+                     "Dec"
+                  };
+
+                  for (i = 0; i < 12; i++)
+                    {
+                       if (!strcmp(mon, mons[i]))
+                         {
+                            monnum = i + 1;
+                            break;
+                         }
+                    }
+                  // alloc 60 for mins, 24 for hrs
+                  // alloc 1-31 (32) for days, 1-12 (13) for months
+                  // use year as-is, for 31 bits (signed) this gives us up to
+                  // 3584 years, which is good enough imho. - 1500 years from
+                  // now or so. :)
+                  _eina_hamsters +=
+                     (day + (monnum * 32) + (13 * 32 * year)) * (24 * 60);
+               }
+          }
+     }
+
+   // format: [rest - year][0-12 - month][0-31 - day][0-23 - hrs][0-59 - sec]
+   return _eina_hamsters;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_hash.c 
b/tests/suite/ecore/src/lib/eina_hash.c
new file mode 100644
index 0000000..4c5f533
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_hash.c
@@ -0,0 +1,1933 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Gustavo Sverzut Barbieri,
+ *                         Vincent Torri, Jorge Luis Zapata Muga, Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef _MSC_VER
+# include <Evil.h>
+#else
+# include <stdint.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_rbtree.h"
+#include "eina_error.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_hash.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#define EINA_MAGIC_CHECK_HASH(d)                                        \
+   do {                                                                  \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_HASH)) {                         \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_HASH); }                            
 \
+     } while(0)
+
+#define EINA_MAGIC_CHECK_HASH_ITERATOR(d, ...)                          \
+   do {                                                                  \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_HASH_ITERATOR))                \
+          {                                                                  \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_HASH_ITERATOR);                 \
+             return __VA_ARGS__;                                               
    \
+          }                                                                  \
+     } while(0)
+
+#define EINA_HASH_BUCKET_SIZE 8
+#define EINA_HASH_SMALL_BUCKET_SIZE 5
+
+#define EINA_HASH_RBTREE_MASK 0xFFF
+
+typedef struct _Eina_Hash_Head Eina_Hash_Head;
+typedef struct _Eina_Hash_Element Eina_Hash_Element;
+typedef struct _Eina_Hash_Foreach_Data Eina_Hash_Foreach_Data;
+typedef struct _Eina_Iterator_Hash Eina_Iterator_Hash;
+typedef struct _Eina_Hash_Each Eina_Hash_Each;
+
+struct _Eina_Hash
+{
+   Eina_Key_Length key_length_cb;
+   Eina_Key_Cmp key_cmp_cb;
+   Eina_Key_Hash key_hash_cb;
+   Eina_Free_Cb data_free_cb;
+
+   Eina_Rbtree **buckets;
+   int size;
+   int mask;
+
+   int population;
+
+   EINA_MAGIC
+};
+
+struct _Eina_Hash_Head
+{
+   EINA_RBTREE;
+   int hash;
+
+   Eina_Rbtree *head;
+};
+
+struct _Eina_Hash_Element
+{
+   EINA_RBTREE;
+   Eina_Hash_Tuple tuple;
+   Eina_Bool begin : 1;
+};
+
+struct _Eina_Hash_Foreach_Data
+{
+   Eina_Hash_Foreach cb;
+   const void *fdata;
+};
+
+typedef void *(*Eina_Iterator_Get_Content_Callback)(Eina_Iterator_Hash *it);
+#define FUNC_ITERATOR_GET_CONTENT(Function) 
((Eina_Iterator_Get_Content_Callback)Function)
+
+struct _Eina_Iterator_Hash
+{
+   Eina_Iterator iterator;
+
+   Eina_Iterator_Get_Content_Callback get_content;
+   const Eina_Hash *hash;
+
+   Eina_Iterator *current;
+   Eina_Iterator *list;
+   Eina_Hash_Head *hash_head;
+   Eina_Hash_Element *hash_element;
+   int bucket;
+
+   int index;
+
+   EINA_MAGIC
+};
+
+struct _Eina_Hash_Each
+{
+   Eina_Hash_Head *hash_head;
+   const Eina_Hash_Element *hash_element;
+   const void *data;
+};
+
+#undef get16bits
+#if (defined(__GNUC__) && defined(__i386__)) || defined(__WATCOMC__) \
+   || defined(_MSC_VER) || defined (__BORLANDC__) || defined (__TURBOC__)
+# define get16bits(d) (*((const uint16_t *)(d)))
+#endif
+
+#if !defined (get16bits)
+# define get16bits(d) ((((uint32_t)(((const uint8_t *)(d))[1])) << 8) \
+                       + (uint32_t)(((const uint8_t *)(d))[0]))
+#endif
+
+static inline int
+_eina_hash_hash_rbtree_cmp_hash(const Eina_Hash_Head *hash_head,
+                                const int *hash,
+                                __UNUSED__ int key_length,
+                                __UNUSED__ void *data)
+{
+   return hash_head->hash - *hash;
+}
+
+static Eina_Rbtree_Direction
+_eina_hash_hash_rbtree_cmp_node(const Eina_Hash_Head *left,
+                                const Eina_Hash_Head *right,
+                                __UNUSED__ void *data)
+{
+   if (left->hash - right->hash < 0)
+      return EINA_RBTREE_LEFT;
+
+   return EINA_RBTREE_RIGHT;
+}
+
+static inline int
+_eina_hash_key_rbtree_cmp_key_data(const Eina_Hash_Element *hash_element,
+                                   const Eina_Hash_Tuple *tuple,
+                                   __UNUSED__ unsigned int key_length,
+                                   Eina_Key_Cmp cmp)
+{
+   int result;
+
+   result = cmp(hash_element->tuple.key,
+                hash_element->tuple.key_length,
+                tuple->key,
+                tuple->key_length);
+
+   if (result == 0 && tuple->data && tuple->data != hash_element->tuple.data)
+      return 1;
+
+   return result;
+}
+
+static Eina_Rbtree_Direction
+_eina_hash_key_rbtree_cmp_node(const Eina_Hash_Element *left,
+                               const Eina_Hash_Element *right,
+                               Eina_Key_Cmp cmp)
+{
+   int result;
+
+   result = cmp(left->tuple.key, left->tuple.key_length,
+                right->tuple.key, right->tuple.key_length);
+
+   if (result < 0)
+      return EINA_RBTREE_LEFT;
+
+   return EINA_RBTREE_RIGHT;
+}
+
+static inline Eina_Bool
+eina_hash_add_alloc_by_hash(Eina_Hash *hash,
+                            const void *key, int key_length, int alloc_length,
+                            int key_hash,
+                            const void *data)
+{
+   Eina_Hash_Element *new_hash_element = NULL;
+   Eina_Hash_Head *hash_head;
+   Eina_Error error = 0;
+   int hash_num;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,  EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   error = EINA_ERROR_OUT_OF_MEMORY;
+
+   /* Apply eina mask to hash. */
+   hash_num = key_hash & hash->mask;
+   key_hash &= EINA_HASH_RBTREE_MASK;
+
+   if (!hash->buckets)
+     {
+        hash->buckets = calloc(sizeof (Eina_Rbtree *), hash->size);
+        if (!hash->buckets) goto on_error;
+
+        hash_head = NULL;
+     }
+   else
+      /* Look up for head node. */
+      hash_head = (Eina_Hash_Head 
*)eina_rbtree_inline_lookup(hash->buckets[hash_num],
+                                                              &key_hash, 0,
+                                                              
EINA_RBTREE_CMP_KEY_CB(_eina_hash_hash_rbtree_cmp_hash),
+                                                              NULL);
+
+   if (!hash_head)
+     {
+        /* If not found allocate it and an element. */
+        hash_head = malloc(sizeof(Eina_Hash_Head) + sizeof(Eina_Hash_Element) 
+ alloc_length);
+        if (!hash_head)
+           goto on_error;
+
+        hash_head->hash = key_hash;
+        hash_head->head = NULL;
+
+        hash->buckets[hash_num] =
+           eina_rbtree_inline_insert(hash->buckets[hash_num], 
EINA_RBTREE_GET(hash_head),
+                                     EINA_RBTREE_CMP_NODE_CB(
+                                        _eina_hash_hash_rbtree_cmp_node), 
NULL);
+
+        new_hash_element = (Eina_Hash_Element *)(hash_head + 1);
+        new_hash_element->begin = EINA_TRUE;
+     }
+
+   if (!new_hash_element)
+     {
+        /*
+           Alloc a new element
+           (No more lookup as we expect to support more than one item for one 
key).
+         */
+        new_hash_element = malloc(sizeof (Eina_Hash_Element) + alloc_length);
+        if (!new_hash_element)
+           goto on_error;
+
+        new_hash_element->begin = EINA_FALSE;
+     }
+
+   /* Setup the element */
+   new_hash_element->tuple.key_length = key_length;
+   new_hash_element->tuple.data = (void *)data;
+   if (alloc_length > 0)
+     {
+        new_hash_element->tuple.key = (char *)(new_hash_element + 1);
+        memcpy((char *)new_hash_element->tuple.key, key, alloc_length);
+     }
+   else
+      new_hash_element->tuple.key = key;
+
+   /* add the new element to the hash. */
+   hash_head->head = eina_rbtree_inline_insert(hash_head->head, 
EINA_RBTREE_GET(new_hash_element),
+                                        EINA_RBTREE_CMP_NODE_CB(
+                                           _eina_hash_key_rbtree_cmp_node),
+                                        (const void *)hash->key_cmp_cb);
+   hash->population++;
+   return EINA_TRUE;
+
+on_error:
+   eina_error_set(error);
+   return EINA_FALSE;
+}
+
+static Eina_Bool
+_eina_hash_rbtree_each(__UNUSED__ const Eina_Rbtree *container,
+                       const Eina_Hash_Head *hash_head,
+                       Eina_Hash_Each *data)
+{
+   Eina_Iterator *it;
+   Eina_Hash_Element *hash_element;
+   Eina_Bool found = EINA_TRUE;
+
+   it = eina_rbtree_iterator_prefix(hash_head->head);
+   EINA_ITERATOR_FOREACH(it, hash_element)
+   {
+      if (hash_element->tuple.data == data->data)
+        {
+           data->hash_element = hash_element;
+           data->hash_head = (Eina_Hash_Head *)hash_head;
+           found = EINA_FALSE;
+           break;
+        }
+   }
+
+   eina_iterator_free(it);
+   return found;
+}
+
+static inline Eina_Hash_Element *
+_eina_hash_find_by_hash(const Eina_Hash *hash,
+                        Eina_Hash_Tuple *tuple,
+                        int key_hash,
+                        Eina_Hash_Head **hash_head)
+{
+   Eina_Hash_Element *hash_element;
+   int rb_hash = key_hash & EINA_HASH_RBTREE_MASK;
+
+   key_hash &= hash->mask;
+
+   if (!hash->buckets)
+      return NULL;
+
+   *hash_head = (Eina_Hash_Head 
*)eina_rbtree_inline_lookup(hash->buckets[key_hash],
+                                                     &rb_hash, 0,
+                                                     EINA_RBTREE_CMP_KEY_CB(
+                                                        
_eina_hash_hash_rbtree_cmp_hash),
+                                                     NULL);
+   if (!*hash_head)
+      return NULL;
+
+   hash_element = (Eina_Hash_Element 
*)eina_rbtree_inline_lookup((*hash_head)->head,
+                                                  tuple, 0,
+                                                     EINA_RBTREE_CMP_KEY_CB(
+                                                     
_eina_hash_key_rbtree_cmp_key_data),
+                                                  (const void *)hash->
+                                                  key_cmp_cb);
+
+   return hash_element;
+}
+
+static inline Eina_Hash_Element *
+_eina_hash_find_by_data(const Eina_Hash *hash,
+                        const void *data,
+                        int *key_hash,
+                        Eina_Hash_Head **hash_head)
+{
+   Eina_Hash_Each each;
+   Eina_Iterator *it;
+   int hash_num;
+
+   if (!hash->buckets)
+      return NULL;
+
+   each.hash_element = NULL;
+   each.data = data;
+
+   for (hash_num = 0; hash_num < hash->size; hash_num++)
+     {
+        if (!hash->buckets[hash_num])
+           continue;
+
+        it = eina_rbtree_iterator_prefix(hash->buckets[hash_num]);
+        eina_iterator_foreach(it, EINA_EACH_CB(_eina_hash_rbtree_each), &each);
+        eina_iterator_free(it);
+
+        if (each.hash_element)
+          {
+             *key_hash = hash_num;
+             *hash_head = each.hash_head;
+             return (Eina_Hash_Element *)each.hash_element;
+          }
+     }
+
+   return NULL;
+}
+
+static void
+_eina_hash_el_free(Eina_Hash_Element *hash_element, Eina_Hash *hash)
+{
+   if (hash->data_free_cb)
+      hash->data_free_cb(hash_element->tuple.data);
+
+   if (hash_element->begin == EINA_FALSE)
+      free(hash_element);
+}
+
+static void
+_eina_hash_head_free(Eina_Hash_Head *hash_head, Eina_Hash *hash)
+{
+   eina_rbtree_delete(hash_head->head, 
EINA_RBTREE_FREE_CB(_eina_hash_el_free), hash);
+   free(hash_head);
+}
+
+static Eina_Bool
+_eina_hash_del_by_hash_el(Eina_Hash *hash,
+                          Eina_Hash_Element *hash_element,
+                          Eina_Hash_Head *hash_head,
+                          int key_hash)
+{
+   hash_head->head = eina_rbtree_inline_remove(hash_head->head, 
EINA_RBTREE_GET(
+                                           hash_element), 
EINA_RBTREE_CMP_NODE_CB(
+                                           _eina_hash_key_rbtree_cmp_node),
+                                        (const void *)hash->key_cmp_cb);
+   _eina_hash_el_free(hash_element, hash);
+
+   if (!hash_head->head)
+     {
+        key_hash &= hash->mask;
+
+        hash->buckets[key_hash] =
+           eina_rbtree_inline_remove(hash->buckets[key_hash], EINA_RBTREE_GET(
+                                        hash_head),
+                                     EINA_RBTREE_CMP_NODE_CB(
+                                        _eina_hash_hash_rbtree_cmp_node), 
NULL);
+        free(hash_head);
+     }
+
+   hash->population--;
+   if (hash->population == 0)
+     {
+        free(hash->buckets);
+        hash->buckets = NULL;
+     }
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+_eina_hash_del_by_key_hash(Eina_Hash *hash,
+                           const void *key,
+                           int key_length,
+                           int key_hash,
+                           const void *data)
+{
+   Eina_Hash_Element *hash_element;
+   Eina_Hash_Head *hash_head;
+   Eina_Hash_Tuple tuple;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,  EINA_FALSE);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   if (!hash->buckets)
+      return EINA_FALSE;
+
+   tuple.key = (void *)key;
+   tuple.key_length = key_length;
+   tuple.data = (void *)data;
+
+   hash_element = _eina_hash_find_by_hash(hash, &tuple, key_hash, &hash_head);
+   if (!hash_element)
+      return EINA_FALSE;
+
+   return _eina_hash_del_by_hash_el(hash, hash_element, hash_head, key_hash);
+}
+
+static Eina_Bool
+_eina_hash_del_by_key(Eina_Hash *hash, const void *key, const void *data)
+{
+   int key_length, key_hash;
+
+   EINA_MAGIC_CHECK_HASH(hash);
+   if (!hash)
+      return EINA_FALSE;
+
+   if (!key)
+      return EINA_FALSE;
+
+   if (!hash->buckets)
+      return EINA_FALSE;
+
+   key_length = hash->key_length_cb ? hash->key_length_cb(key) : 0;
+   key_hash = hash->key_hash_cb(key, key_length);
+   return _eina_hash_del_by_key_hash(hash, key, key_length, key_hash, data);
+}
+
+static unsigned int
+_eina_string_key_length(const char *key)
+{
+   if (!key)
+      return 0;
+
+   return (int)strlen(key) + 1;
+}
+
+static int
+_eina_string_key_cmp(const char *key1, __UNUSED__ int key1_length,
+                     const char *key2, __UNUSED__ int key2_length)
+{
+   return strcmp(key1, key2);
+}
+
+static int
+_eina_stringshared_key_cmp(const char *key1, __UNUSED__ int key1_length,
+                           const char *key2, __UNUSED__ int key2_length)
+{
+   return key1 - key2;
+}
+
+static unsigned int
+_eina_int32_key_length(__UNUSED__ const uint32_t *key)
+{
+   return 4;
+}
+
+static int
+_eina_int32_key_cmp(const uint32_t *key1, __UNUSED__ int key1_length,
+                    const uint32_t *key2, __UNUSED__ int key2_length)
+{
+   return *key1 - *key2;
+}
+
+static unsigned int
+_eina_int64_key_length(__UNUSED__ const uint32_t *key)
+{
+   return 8;
+}
+
+static int
+_eina_int64_key_cmp(const uint64_t *key1, __UNUSED__ int key1_length,
+                    const uint64_t *key2, __UNUSED__ int key2_length)
+{
+   return *key1 - *key2;
+}
+
+static Eina_Bool
+_eina_foreach_cb(const Eina_Hash *hash,
+                 Eina_Hash_Tuple *data,
+                 Eina_Hash_Foreach_Data *fdata)
+{
+   return fdata->cb((Eina_Hash *)hash,
+                    data->key,
+                    data->data,
+                    (void *)fdata->fdata);
+}
+
+static void *
+_eina_hash_iterator_data_get_content(Eina_Iterator_Hash *it)
+{
+   Eina_Hash_Element *stuff;
+
+   EINA_MAGIC_CHECK_HASH_ITERATOR(it, NULL);
+
+   stuff = it->hash_element;
+
+   if (!stuff)
+      return NULL;
+
+   return stuff->tuple.data;
+}
+
+static void *
+_eina_hash_iterator_key_get_content(Eina_Iterator_Hash *it)
+{
+   Eina_Hash_Element *stuff;
+
+   EINA_MAGIC_CHECK_HASH_ITERATOR(it, NULL);
+
+   stuff = it->hash_element;
+
+   if (!stuff)
+      return NULL;
+
+   return (void *)stuff->tuple.key;
+}
+
+static Eina_Hash_Tuple *
+_eina_hash_iterator_tuple_get_content(Eina_Iterator_Hash *it)
+{
+   Eina_Hash_Element *stuff;
+
+   EINA_MAGIC_CHECK_HASH_ITERATOR(it, NULL);
+
+   stuff = it->hash_element;
+
+   if (!stuff)
+      return NULL;
+
+   return &stuff->tuple;
+}
+
+static Eina_Bool
+_eina_hash_iterator_next(Eina_Iterator_Hash *it, void **data)
+{
+   Eina_Bool ok;
+   int bucket;
+
+   if (!(it->index < it->hash->population))
+      return EINA_FALSE;
+
+   if (!it->current)
+     {
+        ok = EINA_FALSE;
+        bucket = 0;
+        it->index = -1;
+     }
+   else
+     {
+        ok = eina_iterator_next(it->list, (void **)&it->hash_element);
+        if (!ok)
+          {
+                  eina_iterator_free(it->list);
+             it->list = NULL;
+
+             ok = eina_iterator_next(it->current, (void **)&it->hash_head);
+             if (!ok)
+               {
+                  eina_iterator_free(it->current);
+                  it->current = NULL;
+                  it->bucket++;
+               }
+             else
+               {
+                  it->list = eina_rbtree_iterator_prefix(it->hash_head->head);
+                  ok = eina_iterator_next(it->list, (void 
**)&it->hash_element);
+               }
+          }
+
+        bucket = it->bucket;
+     }
+
+   if (ok == EINA_FALSE)
+     {
+        while (bucket < it->hash->size)
+          {
+             if (it->hash->buckets[bucket])
+               {
+                  it->current =
+                     eina_rbtree_iterator_prefix(it->hash->buckets[bucket]);
+                  ok = eina_iterator_next(it->current, (void 
**)&it->hash_head);
+                  if (ok)
+                     break;
+
+                  eina_iterator_free(it->current);
+                  it->current = NULL;
+               }
+
+             ++bucket;
+          }
+        if (it->list)
+                  eina_iterator_free(it->list);
+
+        it->list = eina_rbtree_iterator_prefix(it->hash_head->head);
+        ok = eina_iterator_next(it->list, (void **)&it->hash_element);
+        if (bucket == it->hash->size)
+           ok = EINA_FALSE;
+     }
+
+   it->index++;
+   it->bucket = bucket;
+
+   if (ok)
+      *data = it->get_content(it);
+
+   return ok;
+}
+
+static void *
+_eina_hash_iterator_get_container(Eina_Iterator_Hash *it)
+{
+      EINA_MAGIC_CHECK_HASH_ITERATOR(it, NULL);
+   return (void *)it->hash;
+}
+
+static void
+_eina_hash_iterator_free(Eina_Iterator_Hash *it)
+{
+      EINA_MAGIC_CHECK_HASH_ITERATOR(it);
+   if (it->current)
+      eina_iterator_free(it->current);
+
+   if (it->list)
+      eina_iterator_free(it->list);
+
+      free(it);
+}
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Hash_Group Hash Table
+ *
+ * @brief give a small description here : what it is for, what it does
+ * , etc...
+ *
+ * Hash API. Give some hints about the use (functions that must be
+ * used like init / shutdown), general use, etc... Give also a link to
+ * tutorial below.
+ *
+ * @section hashtable_algo Algorithm
+ *
+ * Give here the algorithm used in the implementation
+ *
+ * @section hashtable_perf Performance
+ *
+ * Give some hints about performance if it is possible, and an image !
+ *
+ * @section hashtable_tutorial Tutorial
+ *
+ * Here is a fantastic tutorial about our hash table
+ *
+ * @{
+ */
+
+/**
+ * @brief Create a new hash table.
+ *
+ * @param key_length_cb The function called when getting the size of the key.
+ * @param key_cmp_cb The function called when comparing the keys.
+ * @param key_hash_cb The function called when getting the values.
+ * @param data_free_cb The function called when the hash table is freed.
+ * @param buckets_power_size The size of the buckets.
+ * @return The new hash table.
+ *
+ * This function create a new hash table using user-defined callbacks
+ * to manage the hash table. On failure, @c NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. If @p key_cmp_cb or @pkey_hash_cb
+ * are @c NULL, @c NULL is returned. If @p buckets_power_size is
+ * smaller or equal than 2, or if it is greater or equal than 17,
+ * @c NULL is returned.
+ *
+ * Pre-defined functions are available to create a hash table. See
+ * eina_hash_string_djb2_new(), eina_hash_string_superfast_new(),
+ * eina_hash_string_small_new(), eina_hash_int32_new(),
+ * eina_hash_int64_new(), eina_hash_pointer_new() and
+ * eina_hash_stringshared_new().
+ */
+EAPI Eina_Hash *
+eina_hash_new(Eina_Key_Length key_length_cb,
+              Eina_Key_Cmp key_cmp_cb,
+              Eina_Key_Hash key_hash_cb,
+              Eina_Free_Cb data_free_cb,
+              int buckets_power_size)
+{
+   /* FIXME: Use mempool. */
+   Eina_Hash *new;
+
+   eina_error_set(0);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key_cmp_cb,  NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key_hash_cb, NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(buckets_power_size < 3,  NULL);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(buckets_power_size > 16, NULL);
+
+   new = malloc(sizeof (Eina_Hash));
+   if (!new)
+      goto on_error;
+
+   EINA_MAGIC_SET(new, EINA_MAGIC_HASH);
+   
+   new->key_length_cb = key_length_cb;
+   new->key_cmp_cb = key_cmp_cb;
+   new->key_hash_cb = key_hash_cb;
+   new->data_free_cb = data_free_cb;
+   new->buckets = NULL;
+   new->population = 0;
+
+   new->size = 1 << buckets_power_size;
+   new->mask = new->size - 1;
+
+   return new;
+
+on_error:
+   eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+   return NULL;
+}
+
+/**
+ * @brief Create a new hash table using the djb2 algorithm.
+ *
+ * @param data_free_cb The function called when the hash table is freed.
+ * @return The new hash table.
+ *
+ * This function create a new hash table using the djb2 algorithm for
+ * table management and strcmp() to compare the keys. Values can then
+ * be looked up with pointers other than the original key pointer that
+ * was used to add values. On failure, this function returns @c NULL.
+ * @p data_free_cb is a callback called when the hash table is
+ * freed. @c NULL can be passed as callback.
+ */
+EAPI Eina_Hash *
+eina_hash_string_djb2_new(Eina_Free_Cb data_free_cb)
+{
+   return eina_hash_new(EINA_KEY_LENGTH(_eina_string_key_length),
+                        EINA_KEY_CMP(_eina_string_key_cmp),
+                        EINA_KEY_HASH(eina_hash_djb2),
+                        data_free_cb,
+                        EINA_HASH_BUCKET_SIZE);
+}
+
+/**
+ * @brief Create a new hash table for use with strings.
+ *
+ * @param data_free_cb The function called when the hash table is freed.
+ * @return The new hash table.
+ *
+ * This function create a new hash table using the superfast algorithm
+ * for table management and strcmp() to compare the keys. Values can
+ * then be looked up with pointers other than the original key pointer
+ * that was used to add values. On failure, this function returns
+ * @c NULL. @p data_free_cb is a callback called when the hash table is
+ * freed. @c NULL can be passed as callback. 
+ */
+EAPI Eina_Hash *
+eina_hash_string_superfast_new(Eina_Free_Cb data_free_cb)
+{
+   return eina_hash_new(EINA_KEY_LENGTH(_eina_string_key_length),
+                        EINA_KEY_CMP(_eina_string_key_cmp),
+                        EINA_KEY_HASH(eina_hash_superfast),
+                        data_free_cb,
+                        EINA_HASH_BUCKET_SIZE);
+}
+
+/**
+ * @brief Create a new hash table for use with strings with small bucket size.
+ *
+ * @param data_free_cb  The function called when the hash table is freed.
+ * @return  The new hash table.
+ *
+ * This function create a new hash table using the superfast algorithm
+ * for table management and strcmp() to compare the keys, but with a
+ * smaller bucket size (compared to eina_hash_string_superfast_new())
+ * which will minimize the memory used by the returned hash
+ * table. Values can then be looked up with pointers other than the
+ * original key pointer that was used to add values. On failure, this
+ * function returns @c NULL. @p data_free_cb is a callback called when
+ * the hash table is freed. @c NULL can be passed as callback.
+ */
+EAPI Eina_Hash *
+eina_hash_string_small_new(Eina_Free_Cb data_free_cb)
+{
+   return eina_hash_new(EINA_KEY_LENGTH(_eina_string_key_length),
+                        EINA_KEY_CMP(_eina_string_key_cmp),
+                        EINA_KEY_HASH(eina_hash_superfast),
+                        data_free_cb,
+                        EINA_HASH_SMALL_BUCKET_SIZE);
+}
+
+/**
+ * @brief Create a new hash table for use with 32bit integers.
+ *
+ * @param data_free_cb  The function called when the hash table is freed.
+ * @return  The new hash table.
+ *
+ * This function create a new hash table using the int32 algorithm for
+ * table management and dereferenced pointers to compare the
+ * keys. Values can then be looked up with pointers other than the
+ * original key pointer that was used to add values. This method may
+ * appear to be able to match string keys, actually it only matches
+ * the first character. On failure, this function returns @c NULL.
+ * @p data_free_cb is a callback called when the hash table is freed.
+ * @c NULL can be passed as callback.
+ */
+EAPI Eina_Hash *
+eina_hash_int32_new(Eina_Free_Cb data_free_cb)
+{
+   return eina_hash_new(EINA_KEY_LENGTH(_eina_int32_key_length),
+                        EINA_KEY_CMP(_eina_int32_key_cmp),
+                        EINA_KEY_HASH(eina_hash_int32),
+                        data_free_cb,
+                        EINA_HASH_BUCKET_SIZE);
+}
+
+/**
+ * @brief Create a new hash table for use with 64bit integers.
+ *
+ * @param data_free_cb  The function called when the hash table is freed.
+ * @return  The new hash table.
+ *
+ * This function create a new hash table using the int64 algorithm for
+ * table management and dereferenced pointers to compare the
+ * keys. Values can then be looked up with pointers other than the
+ * original key pointer that was used to add values. This method may
+ * appear to be able to match string keys, actually it only matches
+ * the first character. On failure, this function returns @c NULL.
+ * @p data_free_cb is a callback called when the hash table is freed.
+ * @c NULL can be passed as callback.
+ */
+EAPI Eina_Hash *
+eina_hash_int64_new(Eina_Free_Cb data_free_cb)
+{
+   return eina_hash_new(EINA_KEY_LENGTH(_eina_int64_key_length),
+                        EINA_KEY_CMP(_eina_int64_key_cmp),
+                        EINA_KEY_HASH(eina_hash_int64),
+                        data_free_cb,
+                        EINA_HASH_BUCKET_SIZE);
+}
+
+/**
+ * @brief Create a new hash table for use with pointers.
+ *
+ * @param data_free_cb  The function called when the hash table is freed.
+ * @return  The new hash table.
+ *
+ * This function create a new hash table using the int64 algorithm for
+ * table management and dereferenced pointers to compare the
+ * keys. Values can then be looked up with pointers other than the
+ * original key pointer that was used to add values. This method may
+ * appear to be able to match string keys, actually it only matches
+ * the first character. On failure, this function returns @c NULL.
+ * @p data_free_cb is a callback called when the hash table is freed.
+ * @c NULL can be passed as callback.
+ */
+EAPI Eina_Hash *
+eina_hash_pointer_new(Eina_Free_Cb data_free_cb)
+{
+#ifdef __LP64__
+   return eina_hash_new(EINA_KEY_LENGTH(_eina_int64_key_length),
+                        EINA_KEY_CMP(_eina_int64_key_cmp),
+                        EINA_KEY_HASH(eina_hash_int64),
+                        data_free_cb,
+                        EINA_HASH_BUCKET_SIZE);
+#else
+   return eina_hash_new(EINA_KEY_LENGTH(_eina_int32_key_length),
+                        EINA_KEY_CMP(_eina_int32_key_cmp),
+                        EINA_KEY_HASH(eina_hash_int32),
+                        data_free_cb,
+                        EINA_HASH_BUCKET_SIZE);
+#endif
+}
+
+/**
+ * @brief Create a new hash table optimized for stringshared values.
+ *
+ * @param data_free_cb  The function called when the hash table is freed.
+ * @return  The new hash table.
+ *
+ * This function create a new hash table optimized for stringshared
+ * values. Values CAN NOT be looked up with pointers not
+ * equal to the original key pointer that was used to add a value. On failure, 
this function returns @c NULL.
+ * @p data_free_cb is a callback called when the hash table is freed.
+ * @c NULL can be passed as callback.
+ *
+ * Excerpt of code that will NOT work with this type of hash:
+ *
+ * @code
+ * extern Eina_Hash *hash;
+ * extern const char *value;
+ * const char *a = eina_stringshare_add("key");
+ *
+ * eina_hash_add(hash, a, value);
+ * eina_hash_find(hash, "key")
+ * @endcode
+ */
+EAPI Eina_Hash *
+eina_hash_stringshared_new(Eina_Free_Cb data_free_cb)
+{
+   return eina_hash_new(NULL,
+                        EINA_KEY_CMP(_eina_stringshared_key_cmp),
+                        EINA_KEY_HASH(eina_hash_superfast),
+                        data_free_cb,
+                        EINA_HASH_BUCKET_SIZE);
+}
+
+/**
+ * @brief Returns the number of entries in the given hash table.
+ *
+ * @param hash The given hash table.
+ * @return The number of entries in the hash table.
+ *
+ * This function returns the number of entries in @p hash, or 0 on
+ * error. If @p hash is @c NULL, 0 is returned.
+ */
+EAPI int
+eina_hash_population(const Eina_Hash *hash)
+{
+   if (!hash)
+      return 0;
+
+   EINA_MAGIC_CHECK_HASH(hash);
+   return hash->population;
+}
+
+/**
+ * Free the given hash table resources.
+ *
+ * @param hash The hash table to be freed.
+ *
+ * This function frees up all the memory allocated to storing @p hash,
+ * and call the free callback if it has been passed to the hash table
+ * at creation time. If no free callback has been passed, any entries
+ * in the table that the program has no more pointers for elsewhere
+ * may now be lost, so this should only be called if the program has
+ * already freed any allocated data in the hash table or has the
+ * pointers for data in the table stored elsewhere as well. If @p hash
+ * is @c NULL, the function returns immediately.
+ *
+ * Example:
+ * @code
+ * extern Eina_Hash *hash;
+ *
+ * eina_hash_free(hash);
+ * hash = NULL;
+ * @endcode
+ */
+EAPI void
+eina_hash_free(Eina_Hash *hash)
+{
+   int i;
+
+   EINA_MAGIC_CHECK_HASH(hash);
+   EINA_SAFETY_ON_NULL_RETURN(hash);
+
+   if (hash->buckets)
+     {
+        for (i = 0; i < hash->size; i++)
+           eina_rbtree_delete(hash->buckets[i], 
EINA_RBTREE_FREE_CB(_eina_hash_head_free), hash);
+        free(hash->buckets);
+     }
+   free(hash);
+}
+
+/**
+ * Free the given hash table buckets resources.
+ *
+ * @param hash The hash table whose buckets have to be freed.
+ *
+ * This function frees up all the memory allocated to storing the
+ * buckets of @p hash, and call the free callback on all hash table
+ * buckets if it has been passed to the hash table at creation time,
+ * then frees the buckets. If no free callback has been passed, no
+ * buckets value will be freed. If @p hash is @c NULL, the function
+ * returns immediately.
+ */
+EAPI void
+eina_hash_free_buckets(Eina_Hash *hash)
+{
+   int i;
+
+   EINA_MAGIC_CHECK_HASH(hash);
+   EINA_SAFETY_ON_NULL_RETURN(hash);
+
+   if (hash->buckets)
+     {
+        for (i = 0; i < hash->size; i++)
+           eina_rbtree_delete(hash->buckets[i],
+                              EINA_RBTREE_FREE_CB(_eina_hash_head_free), hash);
+        free(hash->buckets);
+        hash->buckets = NULL;
+        hash->population = 0;
+     }
+}
+
+/**
+ * @brief Add an entry to the given hash table.
+ *
+ * @param hash The given hash table.
+ * @param key A unique key.
+ * @param key_length The length of the key.
+ * @param key_hash The hash that will always match key.
+ * @param data The data to associate with the string given by the key.
+ * @return #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * This function adds @p key to @p hash. @p hash, @p key and @p data
+ * can be @c NULL, in that case #EINA_FALSE is returned. @p key is
+ * expected to be a unique string within the hash table. Otherwise,
+ * one cannot be sure which inserted data pointer will be accessed
+ * with @ref eina_hash_find, and removed with @ref eina_hash_del. Do
+ * not forget to count '\\0' for string when setting the value of
+ * @p key_length. @p key_hash is expected to always match
+ * @p key. Otherwise, one cannot be sure to find it again with @ref
+ * eina_hash_find_by_hash. Key strings are case sensitive. If an error
+ * occurs, eina_error_get() should be used to determine if an
+ * allocation error occurred during this function. This function
+ * returns #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ */
+EAPI Eina_Bool
+eina_hash_add_by_hash(Eina_Hash  *hash,
+                      const void *key,
+                      int         key_length,
+                      int         key_hash,
+                      const void *data)
+{
+   return eina_hash_add_alloc_by_hash(hash,
+                                     key,
+                                      key_length,
+                                      key_length,
+                                      key_hash,
+                                      data);
+}
+
+/**
+ * @brief Add an entry to the given hash table and do not duplicate the string 
key.
+ *
+ * @param hash The given hash table.  Can be @c NULL.
+ * @param key A unique key.  Can be @c NULL.
+ * @param key_length Should be the length of @p key (don't forget to count 
'\\0' for string).
+ * @param key_hash The hash that will always match key.
+ * @param data Data to associate with the string given by @p key.
+ * @return #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * This function adds @p key to @p hash. @p hash, @p key and @p data
+ * can be @c NULL, in that case #EINA_FALSE is returned. @p key is
+ * expected to be a unique string within the hash table. Otherwise,
+ * one cannot be sure which inserted data pointer will be accessed
+ * with @ref eina_hash_find, and removed with @ref eina_hash_del. This
+ * function does not make a copy of @p key so it must be a string
+ * constant or stored elsewhere (in the object being added). Do
+ * not forget to count '\\0' for string when setting the value of
+ * @p key_length. @p key_hash is expected to always match
+ * @p key. Otherwise, one cannot be sure to find it again with @ref
+ * eina_hash_find_by_hash. Key strings are case sensitive. If an error
+ * occurs, eina_error_get() should be used to determine if an
+ * allocation error occurred during this function. This function
+ * returns #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ */
+EAPI Eina_Bool
+eina_hash_direct_add_by_hash(Eina_Hash  *hash,
+                             const void *key,
+                             int         key_length,
+                             int         key_hash,
+                             const void *data)
+{
+   return eina_hash_add_alloc_by_hash(hash, key, key_length, 0, key_hash, 
data);
+}
+
+/**
+ * @brief Add an entry to the given hash table.
+ *
+ * @param hash The given hash table.
+ * @param key A unique key.
+ * @param data Data to associate with the string given by @p key.
+ * @return #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * This function adds @p key to @p hash. @p hash, @p key and @p data
+ * can be @c NULL, in that case #EINA_FALSE is returned. @p key is
+ * expected to be unique within the hash table. Key uniqueness varies
+ * depending on the type of @p hash: a stringshared @ref Eina_Hash
+ * need only have unique pointers for keys, but the strings in the
+ * pointers may be identical. All other hash types require the strings
+ * themselves to be unique. Failure to use sufficient uniqueness will
+ * result in unexpected results when inserting data pointers accessed
+ * with eina_hash_find(), and removed with eina_hash_del(). Key
+ * strings are case sensitive. If an error occurs, eina_error_get()
+ * should be used to determine if an allocation error occurred during
+ * this function. This function returns #EINA_FALSE if an error
+ * occurred, #EINA_TRUE otherwise.
+ */
+EAPI Eina_Bool
+eina_hash_add(Eina_Hash *hash, const void *key, const void *data)
+{
+   unsigned int key_length;
+   int key_hash;
+
+   EINA_MAGIC_CHECK_HASH(hash);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash,              EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash->key_hash_cb, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,               EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data,              EINA_FALSE);
+
+   key_length = hash->key_length_cb ? hash->key_length_cb(key) : 0;
+   key_hash = hash->key_hash_cb(key, key_length);
+
+   return eina_hash_add_alloc_by_hash(hash, key, key_length, key_length, 
key_hash, data);
+}
+
+/**
+ * @brief Add an entry to the given hash table without duplicating the string 
key.
+ *
+ * @param hash The given hash table.  Can be @c NULL.
+ * @param key A unique key.  Can be @c NULL.
+ * @param data Data to associate with the string given by @p key.
+ * @return #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * This function adds @p key to @p hash. @p hash, @p key and @p data
+ * can be @c NULL, in that case #EINA_FALSE is returned. @p key is
+ * expected to be unique within the hash table. Key uniqueness varies
+ * depending on the type of @p hash: a stringshared @ref Eina_Hash
+ * need only have unique pointers for keys, but the strings in the
+ * pointers may be identical. All other hash types require the strings
+ * themselves to be unique. Failure to use sufficient uniqueness will
+ * result in unexpected results when inserting data pointers accessed
+ * with eina_hash_find(), and removed with eina_hash_del(). This
+ * function does not make a copy of @p key, so it must be a string
+ * constant or stored elsewhere ( in the object being added). Key
+ * strings are case sensitive. If an error occurs, eina_error_get()
+ * should be used to determine if an allocation error occurred during
+ * this function. This function returns #EINA_FALSE if an error
+ * occurred, #EINA_TRUE otherwise.
+ */
+EAPI Eina_Bool
+eina_hash_direct_add(Eina_Hash *hash, const void *key, const void *data)
+{
+   int key_length;
+   int key_hash;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash,              EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash->key_hash_cb, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,               EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data,              EINA_FALSE);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   key_length = hash->key_length_cb ? hash->key_length_cb(key) : 0;
+   key_hash = hash->key_hash_cb(key, key_length);
+
+   return eina_hash_add_alloc_by_hash(hash, key, key_length, 0, key_hash, 
data);
+}
+
+/**
+ * @brief Remove the entry identified by a key and a key hash from the given 
hash table.
+ *
+ * @param hash The given hash table.
+ * @param key The key.
+ * @param key_length The length of the key.
+ * @param key_hash The hash that always match the key.
+ * @return #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * This function removes the entry identified by @p key and
+ * @p key_hash from @p hash. If a free function was given to the
+ * callback on creation, it will be called for the data being
+ * deleted. Do not forget to count '\\0' for string when setting the
+ * value of @p key_length. If @p hash or @p key are @c NULL, the
+ * functions returns immediately #EINA_FALSE. This function returns
+ * #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * @note if you don't have the key_hash, use eina_hash_del_by_key() instead.
+ * @note if you don't have the key, use eina_hash_del_by_data() instead.
+ */
+EAPI Eina_Bool
+eina_hash_del_by_key_hash(Eina_Hash *hash,
+                          const void *key,
+                          int key_length,
+                          int key_hash)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,  EINA_FALSE);
+
+   return _eina_hash_del_by_key_hash(hash, key, key_length, key_hash, NULL);
+}
+
+/**
+ * @brief Remove the entry identified by a key from the given hash table.
+ *
+ * This version will calculate key length and hash by using functions
+ * provided to hash creation function.
+ *
+ * @param hash The given hash table.
+ * @param key  The key.
+ * @return #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * This function removes the entry identified by @p key from @p
+ * hash. The key length and hash will be calculated automatically by
+ * using functiond provided to has creation function. If a free
+ * function was given to the callback on creation, it will be called
+ * for the data being deleted. If @p hash or @p key are @c NULL, the
+ * functions returns immediately #EINA_FALSE. This function returns
+ * #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * @note if you already have the key_hash, use eina_hash_del_by_key_hash() 
instead.
+ * @note if you don't have the key, use eina_hash_del_by_data() instead.
+ */
+EAPI Eina_Bool
+eina_hash_del_by_key(Eina_Hash *hash, const void *key)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,  EINA_FALSE);
+
+   return _eina_hash_del_by_key(hash, key, NULL);
+}
+
+/**
+ * @brief Remove the entry identified by a data from the given hash table.
+ *
+ * This version is slow since there is no quick access to nodes based on data.
+ *
+ * @param hash The given hash table.
+ * @param data The data value to search and remove.
+ * @return #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *          thing goes fine.
+ *
+ * This function removes the entry identified by @p data from @p
+ * hash. If a free function was given to the callback on creation, it
+ * will be called for the data being deleted. If @p hash or @p data
+ * are @c NULL, the functions returns immediately #EINA_FALSE. This
+ * function returns #EINA_FALSE if an error occurred, #EINA_TRUE
+ * otherwise.
+ *
+ * @note if you already have the key, use eina_hash_del_by_key() or 
eina_hash_del_by_key_hash() instead.
+ */
+EAPI Eina_Bool
+eina_hash_del_by_data(Eina_Hash *hash, const void *data)
+{
+   Eina_Hash_Element *hash_element;
+   Eina_Hash_Head *hash_head;
+   int key_hash;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, EINA_FALSE);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   hash_element = _eina_hash_find_by_data(hash, data, &key_hash, &hash_head);
+   if (!hash_element)
+      goto error;
+
+   if (hash_element->tuple.data != data)
+      goto error;
+
+   return _eina_hash_del_by_hash_el(hash, hash_element, hash_head, key_hash);
+
+error:
+   return EINA_FALSE;
+}
+
+/**
+ * @brief Remove the entry identified by a key and a key hash or a
+ * data from the given hash table.
+ *
+ * If @p key is @c NULL, then @p data is used to find a match to
+ * remove.
+ *
+ * @param hash The given hash table.
+ * @param key The key.
+ * @param key_length The length of the key.
+ * @param key_hash The hash that always match the key.
+ * @param data The data pointer to remove if the key is @c NULL.
+ * @return #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * This function removes the entry identified by @p key and
+ * @p key_hash, or @p data, from @p hash. If a free function was given to
+ * the  callback on creation, it will be called for the data being
+ * deleted. If @p hash is @c NULL, the functions returns immediately
+ * #EINA_FALSE. If @p key is @c NULL, then @p key_hash and @p key_hash
+ * are ignored and @p data is used to find a match to remove,
+ * otherwise @p key and @p key_hash are used and @p data is not
+ * required and can be @c NULL. Do not forget to count '\\0' for
+ * string when setting the value of @p key_length. This function
+ * returns #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * @note if you know you already have the key, use eina_hash_del_by_key_hash(),
+ *       if you know you don't have the key, use eina_hash_del_by_data()
+ *       directly.
+ */
+EAPI Eina_Bool
+eina_hash_del_by_hash(Eina_Hash *hash,
+                      const void *key,
+                      int key_length,
+                      int key_hash,
+                      const void *data)
+{
+   Eina_Bool ret;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, EINA_FALSE);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   if (key)
+      ret = _eina_hash_del_by_key_hash(hash, key, key_length, key_hash, data);
+   else
+      ret = eina_hash_del_by_data(hash, data);
+
+   return ret;
+}
+
+/**
+ * @brief Remove the entry identified by a key or a data from the given
+ * hash table.
+ *
+ * @param hash The given hash table.
+ * @param key  The key.
+ * @param data The data pointer to remove if the key is @c NULL.
+ * @return #EINA_FALSE if an error occurred, #EINA_TRUE otherwise.
+ *
+ * This function removes the entry identified by @p key or @p data
+ * from @p hash. If a free function was given to the
+ * callback on creation, it will be called for the data being
+ * deleted. If @p hash is @c NULL, the functions returns immediately
+ * #EINA_FALSE. If @p key is @c NULL, then @p data is used to find the a
+ * match to remove, otherwise @p key is used and @p data is not
+ * required and can be @c NULL. This function returns #EINA_FALSE if
+ * an error occurred, #EINA_TRUE otherwise.
+ *
+ * @note if you know you already have the key, use
+ *       eina_hash_del_by_key() or eina_hash_del_by_key_hash(). If you
+ *       know you don't have the key, use eina_hash_del_by_data()
+ *       directly.
+ */
+EAPI Eina_Bool
+eina_hash_del(Eina_Hash *hash, const void *key, const void *data)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, EINA_FALSE);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   if (!key)
+     return eina_hash_del_by_data(hash, data);
+
+   return _eina_hash_del_by_key(hash, key, data);
+}
+
+/**
+ * @brief Retrieve a specific entry in the given hash table.
+ *
+ * @param hash The given hash table.
+ * @param key The key of the entry to find.
+ * @param key_length The length of the key.
+ * @param key_hash The hash that always match the key
+ * @return The data pointer for the stored entry on success, @c NULL
+ * otherwise.
+ *
+ * This function retrieves the entry associated to @p key of length
+ * @p key_length in @p hash. @p key_hash is the hash that always match
+ * @p key. It is ignored if @p key is @c NULL. Do not forget to count
+ * '\\0' for string when setting the value of @p key_length. If
+ * @p hash is @c NULL, this function returns immediately @c NULL. This
+ * function returns the data pointer on success, @c NULL otherwise.
+ */
+EAPI void *
+eina_hash_find_by_hash(const Eina_Hash *hash,
+                       const void *key,
+                       int key_length,
+                       int key_hash)
+{
+   Eina_Hash_Head *hash_head;
+   Eina_Hash_Element *hash_element;
+   Eina_Hash_Tuple tuple;
+
+   if (!hash)
+      return NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   tuple.key = key;
+   tuple.key_length = key_length;
+   tuple.data = NULL;
+
+   hash_element = _eina_hash_find_by_hash(hash, &tuple, key_hash, &hash_head);
+   if (hash_element)
+      return hash_element->tuple.data;
+
+   return NULL;
+}
+
+/**
+ * @brief Retrieve a specific entry in the given hash table.
+ *
+ * @param hash The given hash table.
+ * @param key The key of the entry to find.
+ * @return The data pointer for the stored entry on success, @c NULL
+ * otherwise.
+ *
+ * This function retrieves the entry associated to @p key in
+ * @p hash. If @p hash is @c NULL, this function returns immediately
+ * @c NULL. This function returns the data pointer on success, @c NULL
+ * otherwise.
+ */
+EAPI void *
+eina_hash_find(const Eina_Hash *hash, const void *key)
+{
+   int key_length;
+   int hash_num;
+
+   if (!hash)
+      return NULL;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash->key_hash_cb, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,               NULL);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   key_length = hash->key_length_cb ? hash->key_length_cb(key) : 0;
+   hash_num = hash->key_hash_cb(key, key_length);
+
+   return eina_hash_find_by_hash(hash, key, key_length, hash_num);
+}
+
+/**
+ * @brief Modify the entry pointer at the specified key and returns
+ * the old entry.
+ *
+ * @param hash The given hash table.
+ * @param key The key of the entry to modify.
+ * @param key_length Should be the length of @p key (don't forget to count 
'\\0' for string).
+ * @param key_hash The hash that always match the key. Ignored if @p key is @c 
NULL.
+ * @param data The data to replace the old entry, if it exists.
+ * @return The data pointer for the old stored entry, or @c NULL if not
+ *          found. If an existing entry is not found, nothing is added to the
+ *          hash.
+ */
+EAPI void *
+eina_hash_modify_by_hash(Eina_Hash *hash,
+                         const void *key,
+                         int key_length,
+                         int key_hash,
+                         const void *data)
+{
+   Eina_Hash_Head *hash_head;
+   Eina_Hash_Element *hash_element;
+   void *old_data = NULL;
+   Eina_Hash_Tuple tuple;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,  NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data, NULL);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   tuple.key = key;
+   tuple.key_length = key_length;
+   tuple.data = NULL;
+
+   hash_element = _eina_hash_find_by_hash(hash, &tuple, key_hash, &hash_head);
+   if (hash_element)
+     {
+        old_data = hash_element->tuple.data;
+        hash_element->tuple.data = (void *)data;
+     }
+
+   return old_data;
+}
+
+/**
+ * @brief Modify the entry pointer at the specified key and return the
+ * old entry or add the entry if not found.
+ *
+ * @param hash The given hash table.
+ * @param key The key of the entry to modify.
+ * @param data The data to replace the old entry
+ * @return The data pointer for the old stored entry, or @c NULL
+ * otherwise.
+ *
+ * This function modifies the data of @p key with @p data in @p
+ * hash. If no entry is found, @p data is added to @p hash with the
+ * key @p key. On success this function returns the old entry,
+ * otherwise it returns @c NULL. To check for errors, use
+ * eina_error_get().
+ */
+EAPI void *
+eina_hash_set(Eina_Hash *hash, const void *key, const void *data)
+{
+   Eina_Hash_Tuple tuple;
+   Eina_Hash_Head *hash_head;
+   Eina_Hash_Element *hash_element;
+   int key_length;
+   int key_hash;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash,              NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash->key_hash_cb, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,               NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data,              NULL);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   key_length = hash->key_length_cb ? hash->key_length_cb(key) : 0;
+   key_hash = hash->key_hash_cb(key, key_length);
+
+   tuple.key = key;
+   tuple.key_length = key_length;
+   tuple.data = NULL;
+
+   hash_element = _eina_hash_find_by_hash(hash, &tuple, key_hash, &hash_head);
+   if (hash_element)
+     {
+        void *old_data = NULL;
+
+        old_data = hash_element->tuple.data;
+        hash_element->tuple.data = (void *)data;
+        return old_data;
+     }
+
+   eina_hash_add_alloc_by_hash(hash,
+                               key,
+                               key_length,
+                               key_length,
+                               key_hash,
+                               data);
+   return NULL;
+}
+/**
+ * @brief Modify the entry pointer at the specified key and return the old 
entry.
+ * @param hash The given hash table.
+ * @param key The key of the entry to modify.
+ * @param data The data to replace the old entry.
+ * @return The data pointer for the old stored entry on success, or
+ * @c NULL otherwise.
+ *
+ * This function modifies the data of @p key with @p data in @p
+ * hash. If no entry is found, nothing is added to @p hash. On success
+ * this function returns the old entry, otherwise it returns @c NULL.
+ */
+EAPI void *
+eina_hash_modify(Eina_Hash *hash, const void *key, const void *data)
+{
+   int key_length;
+   int hash_num;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash,              NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash->key_hash_cb, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(key,               NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data,              NULL);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   key_length = hash->key_length_cb ? hash->key_length_cb(key) : 0;
+   hash_num = hash->key_hash_cb(key, key_length);
+
+   return eina_hash_modify_by_hash(hash, key, key_length, hash_num, data);
+}
+
+/**
+ * @brief Change the key associated with a data without triggering the
+ * free callback.
+ *
+ * @param hash    The given hash table.
+ * @param old_key The current key associated with the data
+ * @param new_key The new key to associate data with
+ * @return EINA_FALSE in any case but success, EINA_TRUE on success.
+ *
+ * This function allows for the move of data from one key to another,
+ * but does not call the Eina_Free_Cb associated with the hash table
+ * when destroying the old key.
+ */
+EAPI Eina_Bool
+eina_hash_move(Eina_Hash *hash, const void *old_key, const void *new_key)
+{
+   Eina_Free_Cb hash_free_cb;
+   const void *data;
+   Eina_Bool result = EINA_FALSE;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash,              EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash->key_hash_cb, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(old_key,           EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(new_key,           EINA_FALSE);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   data = eina_hash_find(hash, old_key);
+   if (!data) goto error;
+
+   hash_free_cb = hash->data_free_cb;
+   hash->data_free_cb = NULL;
+
+   eina_hash_del(hash, old_key, data);
+   result = eina_hash_add(hash, new_key, data);
+
+   hash->data_free_cb = hash_free_cb;
+
+error:
+   return result;
+}
+
+/*============================================================================*
+*                                Iterator                                    *
+*============================================================================*/
+
+/**
+ * @brief Call a function on every member stored in the hash table
+ *
+ * @param hash The hash table whose members will be walked
+ * @param func The function to call on each parameter
+ * @param fdata The data pointer to pass to the function being called
+ *
+ * This function goes through every entry in the hash table @p hash and calls
+ * the function @p func on each member. The function should @b not modify the
+ * hash table contents if it returns 1. @b If the hash table contents are
+ * modified by this function or the function wishes to stop processing it must
+ * return 0, otherwise return 1 to keep processing.
+ *
+ * Example:
+ * @code
+ * extern Eina_Hash *hash;
+ *
+ * Eina_Bool hash_fn(const Eina_Hash *hash, const void *key, void *data, void 
*fdata)
+ * {
+ *   printf("Func data: %s, Hash entry: %s / %p\n", fdata, (const char *)key, 
data);
+ *   return 1;
+ * }
+ *
+ * int main(int argc, char **argv)
+ * {
+ *   char *hash_fn_data;
+ *
+ *   hash_fn_data = strdup("Hello World");
+ *   eina_hash_foreach(hash, hash_fn, hash_fn_data);
+ *   free(hash_fn_data);
+ * }
+ * @endcode
+ */
+EAPI void
+eina_hash_foreach(const Eina_Hash *hash,
+                  Eina_Hash_Foreach func,
+                  const void *fdata)
+{
+   Eina_Iterator *it;
+   Eina_Hash_Foreach_Data foreach;
+
+   EINA_MAGIC_CHECK_HASH(hash);
+   EINA_SAFETY_ON_NULL_RETURN(hash);
+   EINA_SAFETY_ON_NULL_RETURN(func);
+
+   foreach.cb = func;
+   foreach.fdata = fdata;
+
+   it = eina_hash_iterator_tuple_new(hash);
+   if (!it)
+      return;
+   eina_iterator_foreach(it, EINA_EACH_CB(_eina_foreach_cb), &foreach);
+
+   eina_iterator_free(it);
+}
+
+/**
+ * @brief Returned a new iterator associated to hash data.
+ *
+ * @param hash The hash.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to
+ * @p hash. If @p hash is not populated, this function still returns a
+ * valid iterator that will always return false on
+ * eina_iterator_next(), thus keeping API sane.
+ *
+ * If the memory can not be allocated, @c NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
+ * returned.
+ *
+ * @warning if the hash structure changes then the iterator becomes
+ * invalid. That is, if you add or remove items this iterator behavior
+ * is undefined and your program may crash.
+ */
+EAPI Eina_Iterator *
+eina_hash_iterator_data_new(const Eina_Hash *hash)
+{
+   Eina_Iterator_Hash *it;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, NULL);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   eina_error_set(0);
+   it = calloc(1, sizeof (Eina_Iterator_Hash));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   it->hash = hash;
+   it->get_content = 
FUNC_ITERATOR_GET_CONTENT(_eina_hash_iterator_data_get_content);
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_hash_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _eina_hash_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_hash_iterator_free);
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+   EINA_MAGIC_SET(it,            EINA_MAGIC_HASH_ITERATOR);
+
+   return &it->iterator;
+}
+
+/**
+ * @brief Returned a new iterator associated to hash keys.
+ *
+ * @param hash The hash.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to @p
+ * hash. If @p hash is not populated, this function still returns a
+ * valid iterator that will always return false on
+ * eina_iterator_next(), thus keeping API sane.
+ *
+ * If the memory can not be allocated, NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
+ * returned.
+ *
+ * @warning if the hash structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove items this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_hash_iterator_key_new(const Eina_Hash *hash)
+{
+   Eina_Iterator_Hash *it;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, NULL);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   eina_error_set(0);
+   it = calloc(1, sizeof (Eina_Iterator_Hash));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   it->hash = hash;
+   it->get_content = FUNC_ITERATOR_GET_CONTENT(
+         _eina_hash_iterator_key_get_content);
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_hash_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _eina_hash_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_hash_iterator_free);
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+   EINA_MAGIC_SET(it,            EINA_MAGIC_HASH_ITERATOR);
+
+   return &it->iterator;
+}
+
+/**
+ * @brief Returned a new iterator associated to hash keys and data.
+ *
+ * @param hash The hash.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to @p
+ * hash. If @p hash is not populated, this function still returns a
+ * valid iterator that will always return false on
+ * eina_iterator_next(), thus keeping API sane.
+ *
+ * If the memory can not be allocated, NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
+ * returned.
+ *
+ * @note iterator data will provide values as Eina_Hash_Tuple that should not
+ *   be modified!
+ *
+ * @warning if the hash structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove items this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_hash_iterator_tuple_new(const Eina_Hash *hash)
+{
+   Eina_Iterator_Hash *it;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(hash, NULL);
+   EINA_MAGIC_CHECK_HASH(hash);
+
+   eina_error_set(0);
+   it = calloc(1, sizeof (Eina_Iterator_Hash));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   it->hash = hash;
+   it->get_content = FUNC_ITERATOR_GET_CONTENT(
+         _eina_hash_iterator_tuple_get_content);
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_hash_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _eina_hash_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_hash_iterator_free);
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+   EINA_MAGIC_SET(it,            EINA_MAGIC_HASH_ITERATOR);
+
+   return &it->iterator;
+}
+
+/* Common hash functions */
+
+/* Paul Hsieh (http://www.azillionmonkeys.com/qed/hash.html)
+   used by WebCore (http://webkit.org/blog/8/hashtables-part-2/) */
+EAPI int
+eina_hash_superfast(const char *key, int len)
+{
+   int hash = len, tmp;
+   int rem;
+
+   rem = len & 3;
+   len >>= 2;
+
+   /* Main loop */
+   for (; len > 0; len--)
+     {
+        hash += get16bits(key);
+        tmp = (get16bits(key + 2) << 11) ^ hash;
+        hash = (hash << 16) ^ tmp;
+        key += 2 * sizeof (uint16_t);
+        hash += hash >> 11;
+     }
+
+   /* Handle end cases */
+   switch (rem)
+     {
+      case 3:
+         hash += get16bits(key);
+         hash ^= hash << 16;
+         hash ^= key[sizeof (uint16_t)] << 18;
+         hash += hash >> 11;
+         break;
+
+      case 2:
+         hash += get16bits(key);
+         hash ^= hash << 11;
+         hash += hash >> 17;
+         break;
+
+      case 1:
+         hash += *key;
+         hash ^= hash << 10;
+         hash += hash >> 1;
+     }
+
+   /* Force "avalanching" of final 127 bits */
+   hash ^= hash << 3;
+   hash += hash >> 5;
+   hash ^= hash << 4;
+   hash += hash >> 17;
+   hash ^= hash << 25;
+   hash += hash >> 6;
+
+   return hash;
+}
+
+/**
+ * @}
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_inlist.c 
b/tests/suite/ecore/src/lib/eina_inlist.c
new file mode 100644
index 0000000..9ebc623
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_inlist.c
@@ -0,0 +1,693 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Vincent Torri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_error.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_inlist.h"
+
+/* FIXME: TODO please, refactor this :) */
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+typedef struct _Eina_Iterator_Inlist Eina_Iterator_Inlist;
+typedef struct _Eina_Accessor_Inlist Eina_Accessor_Inlist;
+
+struct _Eina_Iterator_Inlist
+{
+   Eina_Iterator iterator;
+   const Eina_Inlist *head;
+   const Eina_Inlist *current;
+};
+
+struct _Eina_Accessor_Inlist
+{
+   Eina_Accessor accessor;
+
+   const Eina_Inlist *head;
+   const Eina_Inlist *current;
+
+   unsigned int index;
+};
+
+static Eina_Bool
+eina_inlist_iterator_next(Eina_Iterator_Inlist *it, void **data) {
+   if (!it->current)
+      return EINA_FALSE;
+
+   if (data)
+      *data = (void *)it->current;
+
+   it->current = it->current->next;
+
+   return EINA_TRUE;
+}
+
+static Eina_Inlist *
+eina_inlist_iterator_get_container(Eina_Iterator_Inlist *it) {
+   return (Eina_Inlist *)it->head;
+}
+
+static void
+eina_inlist_iterator_free(Eina_Iterator_Inlist *it) {
+   free(it);
+}
+
+static Eina_Bool
+eina_inlist_accessor_get_at(Eina_Accessor_Inlist *it,
+                            unsigned int idx,
+                            void **data) {
+   const Eina_Inlist *over;
+   unsigned int middle;
+   unsigned int i;
+
+   if (it->index == idx)
+      over = it->current;
+   else if (idx > it->index)
+      /* Looking after current. */
+      for (i = it->index, over = it->current;
+           i < idx && over;
+           ++i, over = over->next)
+         ;
+   else
+     {
+        middle = it->index >> 1;
+
+        if (idx > middle)
+           /* Looking backward from current. */
+           for (i = it->index, over = it->current;
+                i > idx && over;
+                --i, over = over->prev)
+              ;
+        else
+           /* Looking from the start. */
+           for (i = 0, over = it->head;
+                i < idx && over;
+                ++i, over = over->next)
+              ;
+     }
+
+   if (!over)
+      return EINA_FALSE;
+
+   it->current = over;
+   it->index = idx;
+
+   if (data)
+      *data = (void *)over;
+
+   return EINA_TRUE;
+}
+
+static Eina_Inlist *
+eina_inlist_accessor_get_container(Eina_Accessor_Inlist *it) {
+   return (Eina_Inlist *)it->head;
+}
+
+static void
+eina_inlist_accessor_free(Eina_Accessor_Inlist *it) {
+   free(it);
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Inline_List_Group Inline List
+ *
+ * @brief These functions provide inline list management.
+ *
+ * Inline lists mean its nodes pointers are part of same memory as
+ * data. This has the benefit of framenting memory less and avoiding
+ * @c node->data indirection, but has the drawback of elements only
+ * being able to be part of one single inlist at same time. But it is
+ * possible to have inlist nodes to be part of regular lists created
+ * with eina_list_append() or eina_list_prepend().
+ *
+ * Inline lists have its purposes, but if you don't know them go with
+ * regular lists instead.
+ *
+ * @code
+ * #include <Eina.h>
+ * #include <stdio.h>
+ *
+ * int
+ * main(void)
+ * {
+ *    struct my_struct {
+ *       EINA_INLIST;
+ *       int a, b;
+ *    } *d, *cur;
+ *    Eina_Inlist *list, *itr;
+ *
+ *    eina_init();
+ *
+ *    d = malloc(sizeof(*d));
+ *    d->a = 1;
+ *    d->b = 10;
+ *    list = eina_inlist_append(NULL, EINA_INLIST_GET(d));
+ *
+ *    d = malloc(sizeof(*d));
+ *    d->a = 2;
+ *    d->b = 20;
+ *    list = eina_inlist_append(list, EINA_INLIST_GET(d));
+ *
+ *    d = malloc(sizeof(*d));
+ *    d->a = 3;
+ *    d->b = 30;
+ *    list = eina_inlist_prepend(list, EINA_INLIST_GET(d));
+ *
+ *    printf("list=%p\n", list);
+ *    EINA_INLIST_FOREACH(list, cur)
+ *      printf("\ta=%d, b=%d\n", cur->a, cur->b);
+ *
+ *    list = eina_inlist_remove(list, EINA_INLIST_GET(d));
+ *    free(d);
+ *    printf("list=%p\n", list);
+ *    for (itr = list; itr != NULL; itr = itr->next)
+ *      {
+ *  cur = EINA_INLIST_CONTAINER_GET(itr, struct my_struct);
+ *  printf("\ta=%d, b=%d\n", cur->a, cur->b);
+ *      }
+ *
+ *    while (list)
+ *      {
+ *  Eina_Inlist *aux = list;
+ *  list = eina_inlist_remove(list, list);
+ *  free(aux);
+ *      }
+ *
+ *    eina_shutdown();
+ *
+ *    return 0;
+ * }
+ * @endcode
+ *
+ * @{
+ */
+
+/**
+ * Add a new node to end of list.
+ *
+ * @note this code is meant to be fast, appends are O(1) and do not
+ *       walk @a list anyhow.
+ *
+ * @note @a new_l is considered to be in no list. If it was in another
+ *       list before, please eina_inlist_remove() it before adding. No
+ *       check of @a new_l prev and next pointers is done, so it' safe
+ *       to have them uninitialized.
+ *
+ * @param list existing list head or NULL to create a new list.
+ * @param new_l new list node, must not be NULL.
+ *
+ * @return the new list head. Use it and not given @a list anymore.
+ */
+EAPI Eina_Inlist *
+eina_inlist_append(Eina_Inlist *list, Eina_Inlist *new_l)
+{
+   Eina_Inlist *l;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
+
+   new_l->next = NULL;
+   if (!list)
+     {
+        new_l->prev = NULL;
+        new_l->last = new_l;
+        return new_l;
+     }
+
+   if (list->last)
+      l = list->last;
+   else
+      for (l = list; (l) && (l->next); l = l->next)
+         ;
+
+   l->next = new_l;
+   new_l->prev = l;
+   list->last = new_l;
+   return list;
+}
+
+/**
+ * Add a new node to beginning of list.
+ *
+ * @note this code is meant to be fast, prepends are O(1) and do not
+ *       walk @a list anyhow.
+ *
+ * @note @a new_l is considered to be in no list. If it was in another
+ *       list before, please eina_inlist_remove() it before adding. No
+ *       check of @a new_l prev and next pointers is done, so it' safe
+ *       to have them uninitialized.
+ *
+ * @param list existing list head or NULL to create a new list.
+ * @param new_l new list node, must not be NULL.
+ *
+ * @return the new list head. Use it and not given @a list anymore.
+ */
+EAPI Eina_Inlist *
+eina_inlist_prepend(Eina_Inlist *list, Eina_Inlist *new_l)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
+
+   new_l->prev = NULL;
+   if (!list)
+     {
+        new_l->next = NULL;
+        new_l->last = new_l;
+        return new_l;
+     }
+
+   new_l->next = list;
+   list->prev = new_l;
+   new_l->last = list->last;
+   list->last = NULL;
+   return new_l;
+}
+
+/**
+ * Add a new node after the given relative item in list.
+ *
+ * @note this code is meant to be fast, appends are O(1) and do not
+ *       walk @a list anyhow.
+ *
+ * @note @a new_l is considered to be in no list. If it was in another
+ *       list before, please eina_inlist_remove() it before adding. No
+ *       check of @a new_l prev and next pointers is done, so it' safe
+ *       to have them uninitialized.
+ *
+ * @note @a relative is considered to be inside @a list, no checks are
+ *       done to confirm that and giving nodes from different lists
+ *       will lead to problems. Giving NULL @a relative is the same as
+ *       eina_list_append().
+ *
+ * @param list existing list head or NULL to create a new list.
+ * @param new_l new list node, must not be NULL.
+ * @param relative reference node, @a new_l will be added after it.
+ *
+ * @return the new list head. Use it and not given @a list anymore.
+ */
+EAPI Eina_Inlist *
+eina_inlist_append_relative(Eina_Inlist *list,
+                            Eina_Inlist *new_l,
+                            Eina_Inlist *relative)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
+
+   if (relative)
+     {
+        if (relative->next)
+          {
+             new_l->next = relative->next;
+             relative->next->prev = new_l;
+          }
+        else
+           new_l->next = NULL;
+
+        relative->next = new_l;
+        new_l->prev = relative;
+        if (!new_l->next)
+           list->last = new_l;
+
+        return list;
+     }
+
+   return eina_inlist_append(list, new_l);
+}
+
+/**
+ * Add a new node before the given relative item in list.
+ *
+ * @note this code is meant to be fast, prepends are O(1) and do not
+ *       walk @a list anyhow.
+ *
+ * @note @a new_l is considered to be in no list. If it was in another
+ *       list before, please eina_inlist_remove() it before adding. No
+ *       check of @a new_l prev and next pointers is done, so it' safe
+ *       to have them uninitialized.
+ *
+ * @note @a relative is considered to be inside @a list, no checks are
+ *       done to confirm that and giving nodes from different lists
+ *       will lead to problems. Giving NULL @a relative is the same as
+ *       eina_list_prepend().
+ *
+ * @param list existing list head or NULL to create a new list.
+ * @param new_l new list node, must not be NULL.
+ * @param relative reference node, @a new_l will be added before it.
+ *
+ * @return the new list head. Use it and not given @a list anymore.
+ */
+EAPI Eina_Inlist *
+eina_inlist_prepend_relative(Eina_Inlist *list,
+                             Eina_Inlist *new_l,
+                             Eina_Inlist *relative)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(new_l, list);
+
+   if (relative)
+     {
+        new_l->prev = relative->prev;
+        new_l->next = relative;
+        relative->prev = new_l;
+        if (new_l->prev)
+          {
+             new_l->prev->next = new_l;
+             /* new_l->next could not be NULL, as it was set to 'relative' */
+             assert(new_l->next);
+             return list;
+          }
+        else
+          {
+             /* new_l->next could not be NULL, as it was set to 'relative' */
+             assert(new_l->next);
+
+             new_l->last = list->last;
+             list->last = NULL;
+             return new_l;
+          }
+     }
+
+   return eina_inlist_prepend(list, new_l);
+}
+
+/**
+ * Remove node from list.
+ *
+ * @note this code is meant to be fast, removals are O(1) and do not
+ *       walk @a list anyhow.
+ *
+ * @note @a item is considered to be inside @a list, no checks are
+ *       done to confirm that and giving nodes from different lists
+ *       will lead to problems, specially if @a item is the head since
+ *       it will be different from @a list and the wrong new head will
+ *       be returned.
+ *
+ * @param list existing list head, must not be NULL.
+ * @param item existing list node, must not be NULL.
+ *
+ * @return the new list head. Use it and not given @a list anymore.
+ */
+EAPI Eina_Inlist *
+eina_inlist_remove(Eina_Inlist *list, Eina_Inlist *item)
+{
+   Eina_Inlist *return_l;
+
+   /* checkme */
+   EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL
+      ((item != list) && (!item->prev) && (!item->next), list);
+
+   if (item->next)
+      item->next->prev = item->prev;
+
+   if (item->prev)
+     {
+        item->prev->next = item->next;
+        return_l = list;
+     }
+   else
+     {
+        return_l = item->next;
+        if (return_l)
+           return_l->last = list->last;
+     }
+
+   if (item == list->last)
+      list->last = item->prev;
+
+   item->next = NULL;
+   item->prev = NULL;
+   return return_l;
+}
+
+/**
+ * Move existing node to beginning of list.
+ *
+ * @note this code is meant to be fast, promotion is O(1) and do not
+ *       walk @a list anyhow.
+ *
+ * @note @a item is considered to be inside @a list, no checks are
+ *       done to confirm that and giving nodes from different lists
+ *       will lead to problems.
+ *
+ * @param list existing list head or NULL to create a new list.
+ * @param item list node to move to beginning (head), must not be NULL.
+ *
+ * @return the new list head. Use it and not given @a list anymore.
+ */
+EAPI Eina_Inlist *
+eina_inlist_promote(Eina_Inlist *list, Eina_Inlist *item)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
+
+   if (item == list)
+      return list;
+
+   if (item->next)
+      item->next->prev = item->prev;
+
+   item->prev->next = item->next;
+
+   if (list->last == item)
+      list->last = item->prev;
+
+   item->next = list;
+   item->prev = NULL;
+   item->last = list->last;
+
+   list->prev = item;
+   list->last = NULL;
+
+   return item;
+}
+
+/**
+ * Move existing node to end of list.
+ *
+ * @note this code is meant to be fast, demoting is O(1) and do not
+ *       walk @a list anyhow.
+ *
+ * @note @a item is considered to be inside @a list, no checks are
+ *       done to confirm that and giving nodes from different lists
+ *       will lead to problems.
+ *
+ * @param list existing list head or NULL to create a new list.
+ * @param item list node to move to end (tail), must not be NULL.
+ *
+ * @return the new list head. Use it and not given @a list anymore.
+ */
+EAPI Eina_Inlist *
+eina_inlist_demote(Eina_Inlist *list, Eina_Inlist *item)
+{
+   Eina_Inlist *l;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(list, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(item, list);
+
+   if (list->last == item)
+      return list;
+
+   if (!list->last)
+     {
+        for (l = list; l->next; l = l->next)
+           ;
+        list->last = l;
+     }
+
+   l = list;
+   if (item->prev)
+      item->prev->next = item->next;
+   else
+      l = item->next;
+
+   item->next->prev = item->prev;
+
+   list->last->next = item;
+   item->prev = list->last;
+   item->next = NULL;
+
+   l->last = item;
+   return l;
+}
+
+/**
+ * Find given node in list, returns itself if found, NULL if not.
+ *
+ * @warning this is an expensive call and have O(n) cost, possibly
+ *    walking the whole list.
+ *
+ * @param list existing list to search @a item in, must not be NULL.
+ * @param item what to search for, must not be NULL.
+ *
+ * @return @a item if found, NULL if not.
+ */
+EAPI Eina_Inlist *
+eina_inlist_find(Eina_Inlist *list, Eina_Inlist *item)
+{
+   Eina_Inlist *l;
+
+   for (l = list; l; l = l->next) {
+        if (l == item)
+           return item;
+     }
+   return NULL;
+}
+
+/**
+ * @brief Get the count of the number of items in a list.
+ *
+ * @param list The list whose count to return.
+ * @return The number of members in the list.
+ *
+ * This function returns how many members @p list contains. If the
+ * list is @c NULL, 0 is returned.
+ *
+ * @warning This is an order-N operation and so the time will depend
+ *    on the number of elements on the list, that is, it might become
+ *    slow for big lists!
+ */
+EAPI unsigned int
+eina_inlist_count(const Eina_Inlist *list)
+{
+   const Eina_Inlist *l;
+   unsigned int i = 0;
+
+   for (l = list; l; l = l->next)
+      i++;
+
+   return i;
+}
+
+/**
+ * @brief Returned a new iterator associated to a list.
+ *
+ * @param list The list.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to @p
+ * list. If @p list is @c NULL or the count member of @p list is less
+ * or equal than 0, this function still returns a valid iterator that
+ * will always return false on eina_iterator_next(), thus keeping API
+ * sane.
+ *
+ * If the memory can not be allocated, NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
+ * returned.
+ *
+ * @warning if the list structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove nodes this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_inlist_iterator_new(const Eina_Inlist *list)
+{
+   Eina_Iterator_Inlist *it;
+
+   eina_error_set(0);
+   it = calloc(1, sizeof (Eina_Iterator_Inlist));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   it->head = list;
+   it->current = list;
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(eina_inlist_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         eina_inlist_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(eina_inlist_iterator_free);
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   return &it->iterator;
+}
+
+/**
+ * @brief Returned a new accessor associated to a list.
+ *
+ * @param list The list.
+ * @return A new accessor.
+ *
+ * This function returns a newly allocated accessor associated to
+ * @p list. If @p list is @c NULL or the count member of @p list is
+ * less or equal than 0, this function returns NULL. If the memory can
+ * not be allocated, NULL is returned and #EINA_ERROR_OUT_OF_MEMORY is
+ * set. Otherwise, a valid accessor is returned.
+ */
+EAPI Eina_Accessor *
+eina_inlist_accessor_new(const Eina_Inlist *list)
+{
+   Eina_Accessor_Inlist *ac;
+
+        eina_error_set(0);
+   ac = calloc(1, sizeof (Eina_Accessor_Inlist));
+   if (!ac)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   ac->head = list;
+   ac->current = list;
+   ac->index = 0;
+
+   ac->accessor.version = EINA_ACCESSOR_VERSION;
+   ac->accessor.get_at = FUNC_ACCESSOR_GET_AT(eina_inlist_accessor_get_at);
+   ac->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(
+         eina_inlist_accessor_get_container);
+   ac->accessor.free = FUNC_ACCESSOR_FREE(eina_inlist_accessor_free);
+
+   EINA_MAGIC_SET(&ac->accessor, EINA_MAGIC_ACCESSOR);
+
+   return &ac->accessor;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_iterator.c 
b/tests/suite/ecore/src/lib/eina_iterator.c
new file mode 100644
index 0000000..66dbbf4
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_iterator.c
@@ -0,0 +1,260 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_iterator.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static const char EINA_MAGIC_ITERATOR_STR[] = "Eina Iterator";
+
+#define EINA_MAGIC_CHECK_ITERATOR(d)                            \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_ITERATOR)) {              \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_ITERATOR); }                  \
+     } while(0)
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the iterator module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the iterator module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_iterator_init(void)
+{
+   return eina_magic_string_set(EINA_MAGIC_ITERATOR, EINA_MAGIC_ITERATOR_STR);
+}
+
+/**
+ * @internal
+ * @brief Shut down the iterator module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the iterator module set up by
+ * eina_iterator_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_iterator_shutdown(void)
+{
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Iterator_Group Iterator Functions
+ *
+ * @brief These functions manage iterators on containers.
+ *
+ * These functions allow to access elements of a container in a
+ * generic way, without knowing which container is used (a bit like
+ * iterators in the C++ STL). Iterators only allows sequential access
+ * (that is, from an element to the next one). For random access, see
+ * @ref Eina_Accessor_Group.
+ *
+ * An iterator is created from container data types, so no creation
+ * function is available here. An iterator is deleted with
+ * eina_iterator_free(). To get the data and iterate, use
+ * eina_iterator_next(). To call a function on all the elements of a
+ * container, use eina_iterator_foreach().
+ *
+ * @{
+ */
+
+/**
+ * @brief Free an iterator.
+ *
+ * @param iterator The iterator to free.
+ *
+ * This function frees @p iterator if it is not @c NULL;
+ */
+EAPI void
+eina_iterator_free(Eina_Iterator *iterator)
+{
+   EINA_MAGIC_CHECK_ITERATOR(iterator);
+   EINA_SAFETY_ON_NULL_RETURN(iterator);
+   EINA_SAFETY_ON_NULL_RETURN(iterator->free);
+   iterator->free(iterator);
+}
+
+/**
+ * @brief Return the container of an iterator.
+ *
+ * @param iterator The iterator.
+ * @return The container which created the iterator.
+ *
+ * This function returns the container which created @p iterator. If
+ * @p iterator is @c NULL, this function returns @c NULL.
+ */
+EAPI void *
+eina_iterator_container_get(Eina_Iterator *iterator)
+{
+   EINA_MAGIC_CHECK_ITERATOR(iterator);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iterator,                NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iterator->get_container, NULL);
+   return iterator->get_container(iterator);
+}
+
+/**
+ * @brief Return the value of the current element and go to the next one.
+ *
+ * @param iterator The iterator.
+ * @param data The data of the element.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function returns the value of the current element pointed by
+ * @p iterator in @p data, then goes to the next element. If @p
+ * iterator is @c NULL or if a problem occurred, #EINA_FALSE is
+ * returned, otherwise #EINA_TRUE is returned.
+ */
+EAPI Eina_Bool
+eina_iterator_next(Eina_Iterator *iterator, void **data)
+{
+   if (!iterator)
+      return EINA_FALSE;
+
+   EINA_MAGIC_CHECK_ITERATOR(iterator);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iterator,       EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iterator->next, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(data,           EINA_FALSE);
+   return iterator->next(iterator, data);
+}
+
+/**
+ * @brief Iterate over the container and execute a callback on each element.
+ *
+ * @param iterator The iterator.
+ * @param cb The callback called on each iteration.
+ * @param fdata The data passed to the callback.
+ *
+ * This function iterates over the elements pointed by @p iterator,
+ * beginning from the current element. For Each element, the callback
+ * @p cb is called with the data @p fdata. If @p iterator is @c NULL,
+ * the function returns immediately. Also, if @p cb returns @c
+ * EINA_FALSE, the iteration stops at that point.
+ */
+EAPI void
+eina_iterator_foreach(Eina_Iterator *iterator,
+                      Eina_Each_Cb cb,
+                      const void *fdata)
+{
+   const void *container;
+   void *data;
+
+   EINA_MAGIC_CHECK_ITERATOR(iterator);
+   EINA_SAFETY_ON_NULL_RETURN(iterator);
+   EINA_SAFETY_ON_NULL_RETURN(iterator->get_container);
+   EINA_SAFETY_ON_NULL_RETURN(iterator->next);
+   EINA_SAFETY_ON_NULL_RETURN(cb);
+
+   if (!eina_iterator_lock(iterator)) return ;
+
+   container = iterator->get_container(iterator);
+   while (iterator->next(iterator, &data) == EINA_TRUE) {
+        if (cb(container, data, (void *)fdata) != EINA_TRUE)
+          goto on_exit;
+     }
+
+ on_exit:
+   (void) eina_iterator_unlock(iterator);
+}
+
+/**
+ * @brief Lock the container of the iterator.
+ *
+ * @param iterator The iterator.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * If the container of the @p iterator permit it, it will be locked.
+ * If @p iterator is @c NULL or if a problem occurred, #EINA_FALSE is
+ * returned, otherwise #EINA_TRUE is returned. If the container
+ * is not lockable, it will return EINA_TRUE.
+ */
+EAPI Eina_Bool
+eina_iterator_lock(Eina_Iterator *iterator)
+{
+   EINA_MAGIC_CHECK_ITERATOR(iterator);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, EINA_FALSE);
+
+   if (iterator->lock)
+      return iterator->lock(iterator);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Unlock the container of the iterator.
+ *
+ * @param iterator The iterator.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * If the container of the @p iterator permit it and was previously
+ * locked, it will be unlocked. If @p iterator is @c NULL or if a
+ * problem occurred, #EINA_FALSE is returned, otherwise #EINA_TRUE
+ * is returned. If the container is not lockable, it will return
+ * EINA_TRUE.
+ */
+EAPI Eina_Bool
+eina_iterator_unlock(Eina_Iterator *iterator)
+{
+   EINA_MAGIC_CHECK_ITERATOR(iterator);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(iterator, EINA_FALSE);
+
+   if (iterator->unlock)
+      return iterator->unlock(iterator);
+   return EINA_TRUE;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_lalloc.c 
b/tests/suite/ecore/src/lib/eina_lalloc.c
new file mode 100644
index 0000000..b1e62b7
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_lalloc.c
@@ -0,0 +1,158 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_lalloc.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+struct _Eina_Lalloc
+{
+   void *data;
+   int num_allocated;
+   int num_elements;
+   int acc;
+   Eina_Lalloc_Alloc alloc_cb;
+   Eina_Lalloc_Free free_cb;
+};
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Lalloc_Group Lazy allocator
+ *
+ * @{
+ */
+
+EAPI Eina_Lalloc *eina_lalloc_new(void *data,
+                                  Eina_Lalloc_Alloc alloc_cb,
+                                  Eina_Lalloc_Free free_cb,
+                                  int num_init)
+{
+   Eina_Lalloc *a;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(alloc_cb, NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(free_cb,  NULL);
+
+   a = calloc(1, sizeof(Eina_Lalloc));
+   a->data = data;
+   a->alloc_cb = alloc_cb;
+   a->free_cb = free_cb;
+   if (num_init > 0)
+     {
+        a->num_allocated = num_init;
+        a->alloc_cb(a->data, a->num_allocated);
+     }
+
+   return a;
+}
+
+EAPI void eina_lalloc_free(Eina_Lalloc *a)
+{
+   EINA_SAFETY_ON_NULL_RETURN(a);
+   EINA_SAFETY_ON_NULL_RETURN(a->free_cb);
+   a->free_cb(a->data);
+   free(a);
+}
+
+EAPI Eina_Bool eina_lalloc_element_add(Eina_Lalloc *a)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(a,           EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(a->alloc_cb, EINA_FALSE);
+
+   if (a->num_elements == a->num_allocated)
+     {
+        if (a->alloc_cb(a->data, (1 << a->acc)) == EINA_TRUE)
+          {
+             a->num_allocated = (1 << a->acc);
+             a->acc++;
+          }
+        else
+           return EINA_FALSE;
+     }
+
+   a->num_elements++;
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool eina_lalloc_elements_add(Eina_Lalloc *a, int num)
+{
+   int tmp;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(a,           EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(a->alloc_cb, EINA_FALSE);
+
+   tmp = a->num_elements + num;
+   if (tmp > a->num_allocated)
+     {
+        int allocated;
+        int acc;
+
+        allocated = a->num_allocated;
+        acc = a->acc;
+
+        while (tmp > allocated)
+          {
+             allocated = (1 << acc);
+             acc++;
+          }
+
+        if (a->alloc_cb(a->data, allocated) == EINA_TRUE)
+          {
+             a->num_allocated = allocated;
+             a->acc = acc;
+          }
+        else
+           return EINA_FALSE;
+     }
+
+   a->num_elements += num;
+
+   return EINA_TRUE;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_list.c 
b/tests/suite/ecore/src/lib/eina_list.c
new file mode 100644
index 0000000..e301476
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_list.c
@@ -0,0 +1,2184 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Gustavo Sverzut Barbieri, Tilman 
Sauerbeck,
+ *                         Vincent Torri, Cedric Bail, Jorge Luis Zapata Muga,
+ *                         Corey Donohoe, Arnaud de Turckheim, Alexandre 
Becoulet
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (C) 2004 ncn
+ * Copyright (C) 2006 Sebastian Dransfeld
+ * Copyright (C) 2007 Christopher Michael
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a 
copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies of the Software and its Copyright notices. In addition publicly
+ *  documented acknowledgment must be given that this software has been used 
if no
+ *  source code of this software is made available publicly. This includes
+ *  acknowledgments in either Copyright notices, Manuals, Publicity and 
Marketing
+ *  documents or any documentation provided with any product containing this
+ *  software. This License does not apply to any software that links to the
+ *  libraries provided by this software (statically or dynamically), but only 
to
+ *  the software provided.
+
+ *  Please see the OLD-COPYING.PLAIN for a plain-english explanation of this 
notice
+ *  and it's intent.
+
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/**
+ * @page tutorial_list_page List Tutorial
+ *
+ * to be written...
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_error.h"
+#include "eina_log.h"
+#include "eina_mempool.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_list.h"
+
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static const char EINA_MAGIC_LIST_STR[] = "Eina List";
+static const char EINA_MAGIC_LIST_ITERATOR_STR[] = "Eina List Iterator";
+static const char EINA_MAGIC_LIST_ACCESSOR_STR[] = "Eina List Accessor";
+static const char EINA_MAGIC_LIST_ACCOUNTING_STR[] = "Eina List Accounting";
+
+
+#define EINA_MAGIC_CHECK_LIST(d, ...)                           \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_LIST))                  \
+          {                                                           \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_LIST);                    \
+             return __VA_ARGS__;                                     \
+          }                                                           \
+     } while(0)
+
+#define EINA_MAGIC_CHECK_LIST_ITERATOR(d, ...)                  \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_LIST_ITERATOR))         \
+          {                                                           \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_LIST_ITERATOR);           \
+             return __VA_ARGS__;                                     \
+          }                                                           \
+     } while(0)
+
+#define EINA_MAGIC_CHECK_LIST_ACCESSOR(d, ...)                  \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_LIST_ACCESSOR))         \
+          {                                                           \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_LIST_ACCESSOR);           \
+             return __VA_ARGS__;                                     \
+          }                                                           \
+     } while(0)
+
+#define EINA_MAGIC_CHECK_LIST_ACCOUNTING(d)                     \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_LIST_ACCOUNTING))       \
+          {                                                           \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_LIST_ACCOUNTING);         \
+             return;                                                 \
+          }                                                           \
+     } while(0)
+
+#define EINA_LIST_SORT_STACK_SIZE 32
+
+typedef struct _Eina_Iterator_List Eina_Iterator_List;
+typedef struct _Eina_Accessor_List Eina_Accessor_List;
+
+struct _Eina_Iterator_List
+{
+   Eina_Iterator iterator;
+
+   const Eina_List *head;
+   const Eina_List *current;
+
+   EINA_MAGIC
+};
+
+struct _Eina_Accessor_List
+{
+   Eina_Accessor accessor;
+
+   const Eina_List *head;
+   const Eina_List *current;
+
+   unsigned int index;
+
+   EINA_MAGIC
+};
+
+static Eina_Mempool *_eina_list_mp = NULL;
+static Eina_Mempool *_eina_list_accounting_mp = NULL;
+static int _eina_list_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_list_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_list_log_dom, __VA_ARGS__)
+
+static inline Eina_List_Accounting *
+_eina_list_mempool_accounting_new(__UNUSED__ Eina_List *list)
+{
+   Eina_List_Accounting *tmp;
+
+   tmp =
+      eina_mempool_malloc(_eina_list_accounting_mp,
+                          sizeof (Eina_List_Accounting));
+   if (!tmp)
+      return NULL;
+
+   EINA_MAGIC_SET(tmp, EINA_MAGIC_LIST_ACCOUNTING);
+
+   return tmp;
+}
+static inline void
+_eina_list_mempool_accounting_free(Eina_List_Accounting *accounting)
+{
+   EINA_MAGIC_CHECK_LIST_ACCOUNTING(accounting);
+
+   EINA_MAGIC_SET(accounting, EINA_MAGIC_NONE);
+   eina_mempool_free(_eina_list_accounting_mp, accounting);
+}
+
+static inline Eina_List *
+_eina_list_mempool_list_new(__UNUSED__ Eina_List *list)
+{
+   Eina_List *tmp;
+
+   tmp = eina_mempool_malloc(_eina_list_mp, sizeof (Eina_List));
+   if (!tmp)
+      return NULL;
+
+   EINA_MAGIC_SET(tmp, EINA_MAGIC_LIST);
+
+   return tmp;
+}
+static inline void
+_eina_list_mempool_list_free(Eina_List *list)
+{
+   EINA_MAGIC_CHECK_LIST(list);
+
+   list->accounting->count--;
+   if (list->accounting->count == 0)
+      _eina_list_mempool_accounting_free(list->accounting);
+
+   EINA_MAGIC_SET(list, EINA_MAGIC_NONE);
+   eina_mempool_free(_eina_list_mp, list);
+}
+
+static Eina_List *
+_eina_list_setup_accounting(Eina_List *list)
+{
+   EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   list->accounting = _eina_list_mempool_accounting_new(list);
+   if (!list->accounting)
+      goto on_error;
+
+   list->accounting->last = list;
+   list->accounting->count = 1;
+
+   return list;
+
+on_error:
+   _eina_list_mempool_list_free(list);
+   return NULL;
+}
+
+static inline void
+_eina_list_update_accounting(Eina_List *list, Eina_List *new_list)
+{
+   EINA_MAGIC_CHECK_LIST(list);
+   EINA_MAGIC_CHECK_LIST(new_list);
+
+   list->accounting->count++;
+   new_list->accounting = list->accounting;
+}
+
+#if 0
+static Eina_Mempool2 _eina_list_mempool =
+{
+   sizeof(Eina_List),
+   320,
+   0, NULL, NULL
+};
+static Eina_Mempool2 _eina_list_accounting_mempool =
+{
+   sizeof(Eina_List_Accounting),
+   80,
+   0, NULL, NULL
+};
+#endif
+
+static Eina_Bool
+eina_list_iterator_next(Eina_Iterator_List *it, void **data)
+{
+   EINA_MAGIC_CHECK_LIST_ITERATOR(it, EINA_FALSE);
+
+   if (!it->current)
+      return EINA_FALSE;
+
+   *data = eina_list_data_get(it->current);
+
+   it->current = eina_list_next(it->current);
+
+   return EINA_TRUE;
+}
+
+static Eina_Bool
+eina_list_iterator_prev(Eina_Iterator_List *it, void **data)
+{
+   EINA_MAGIC_CHECK_LIST_ITERATOR(it, EINA_FALSE);
+
+   if (!it->current)
+      return EINA_FALSE;
+
+   *data = eina_list_data_get(it->current);
+
+   it->current = eina_list_prev(it->current);
+
+   return EINA_TRUE;
+}
+
+static Eina_List *
+eina_list_iterator_get_container(Eina_Iterator_List *it)
+{
+   EINA_MAGIC_CHECK_LIST_ITERATOR(it, NULL);
+
+   return (Eina_List *)it->head;
+}
+
+static void
+eina_list_iterator_free(Eina_Iterator_List *it)
+{
+   EINA_MAGIC_CHECK_LIST_ITERATOR(it);
+
+   MAGIC_FREE(it);
+}
+
+static Eina_Bool
+eina_list_accessor_get_at(Eina_Accessor_List *it, unsigned int idx, void 
**data)
+{
+   const Eina_List *over;
+   unsigned int middle;
+   unsigned int i;
+
+   EINA_MAGIC_CHECK_LIST_ACCESSOR(it, EINA_FALSE);
+
+   if (idx >= eina_list_count(it->head))
+      return EINA_FALSE;
+
+   if (it->index == idx)
+      over = it->current;
+   else if (idx > it->index)
+     {
+        /* After current position. */
+        middle = ((eina_list_count(it->head) - it->index) >> 1) + it->index;
+
+        if (idx > middle)
+           /* Go backward from the end. */
+           for (i = eina_list_count(it->head) - 1,
+                over = eina_list_last(it->head);
+                i > idx && over;
+                --i, over = eina_list_prev(over))
+              ;
+        else
+           /* Go forward from current. */
+           for (i = it->index, over = it->current;
+                i < idx && over;
+                ++i, over = eina_list_next(over))
+              ;
+     }
+   else
+     {
+        /* Before current position. */
+        middle = it->index >> 1;
+
+        if (idx > middle)
+           /* Go backward from current. */
+           for (i = it->index, over = it->current;
+                i > idx && over;
+                --i, over = eina_list_prev(over))
+              ;
+        else
+           /* Go forward from start. */
+           for (i = 0, over = it->head;
+                i < idx && over;
+                ++i, over = eina_list_next(over))
+              ;
+     }
+
+   if (!over)
+      return EINA_FALSE;
+
+   it->current = over;
+   it->index = idx;
+
+   *data = eina_list_data_get(it->current);
+   return EINA_TRUE;
+}
+
+static Eina_List *
+eina_list_accessor_get_container(Eina_Accessor_List *it)
+{
+   EINA_MAGIC_CHECK_LIST_ACCESSOR(it, NULL);
+
+   return (Eina_List *)it->head;
+}
+
+static void
+eina_list_accessor_free(Eina_Accessor_List *it)
+{
+   EINA_MAGIC_CHECK_LIST_ACCESSOR(it);
+
+   MAGIC_FREE(it);
+}
+
+static Eina_List *
+eina_list_sort_rebuild_prev(Eina_List *list)
+{
+   Eina_List *prev = NULL;
+
+   EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   for (; list; list = list->next)
+     {
+        list->prev = prev;
+        prev = list;
+     }
+
+   return prev;
+}
+
+static Eina_List *
+eina_list_sort_merge(Eina_List *a, Eina_List *b, Eina_Compare_Cb func)
+{
+   Eina_List *first, *last;
+
+   if (func(a->data, b->data) < 0)
+      a = (last = first = a)->next;
+   else
+      b = (last = first = b)->next;
+
+   while (a && b)
+      if (func(a->data, b->data) < 0)
+         a = (last = last->next = a)->next;
+      else
+         b = (last = last->next = b)->next;
+
+   last->next = a ? a : b;
+
+   return first;
+}
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the list module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the list module of Eina. It is called by
+ * eina_init().
+ *
+ * This function creates mempool to speed up list node and accounting
+ * management, using EINA_MEMPOOL environment variable if it is set to
+ * choose the memory pool type to use.
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_list_init(void)
+{
+   const char *choice, *tmp;
+
+   _eina_list_log_dom = eina_log_domain_register("eina_list",
+                                                 EINA_LOG_COLOR_DEFAULT);
+   if (_eina_list_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_list");
+        return EINA_FALSE;
+     }
+
+#ifdef EINA_DEFAULT_MEMPOOL
+   choice = "pass_through";
+#else
+   choice = "chained_mempool";
+#endif
+   tmp = getenv("EINA_MEMPOOL");
+   if (tmp && tmp[0])
+      choice = tmp;
+
+   _eina_list_mp = eina_mempool_add
+         (choice, "list", NULL, sizeof(Eina_List), 320);
+   if (!_eina_list_mp)
+     {
+        ERR("ERROR: Mempool for list cannot be allocated in list init.");
+        goto on_init_fail;
+     }
+
+   _eina_list_accounting_mp = eina_mempool_add
+         (choice, "list_accounting", NULL, sizeof(Eina_List_Accounting), 80);
+   if (!_eina_list_accounting_mp)
+     {
+        ERR(
+           "ERROR: Mempool for list accounting cannot be allocated in list 
init.");
+        eina_mempool_del(_eina_list_mp);
+        goto on_init_fail;
+     }
+
+#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
+   EMS(EINA_MAGIC_LIST);
+   EMS(EINA_MAGIC_LIST_ITERATOR);
+   EMS(EINA_MAGIC_LIST_ACCESSOR);
+   EMS(EINA_MAGIC_LIST_ACCOUNTING);
+#undef EMS
+
+   return EINA_TRUE;
+
+on_init_fail:
+   eina_log_domain_unregister(_eina_list_log_dom);
+   _eina_list_log_dom = -1;
+   return EINA_FALSE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the list module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the list module set up by
+ * eina_list_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_list_shutdown(void)
+{
+   eina_mempool_del(_eina_list_accounting_mp);
+   eina_mempool_del(_eina_list_mp);
+
+   eina_log_domain_unregister(_eina_list_log_dom);
+   _eina_list_log_dom = -1;
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_List_Group List
+ *
+ * @brief These functions provide double linked list management.
+ *
+ * For more information, you can look at the @ref tutorial_list_page.
+ *
+ * @{
+ */
+
+/**
+ * @brief Append the given data to the given linked list.
+ *
+ * @param list The given list.
+ * @param data The data to append.
+ * @return A list pointer.
+ *
+ * This function appends @p data to @p list. If @p list is @c NULL, a
+ * new list is returned. On success, a new list pointer that should be
+ * used in place of the one given to this function is
+ * returned. Otherwise, the old pointer is returned.
+ *
+ * The following example code demonstrates how to ensure that the
+ * given data has been successfully appended.
+ *
+ * @code
+ * Eina_List *list = NULL;
+ * extern void *my_data;
+ *
+ * list = eina_list_append(list, my_data);
+ * if (eina_error_get())
+ *   {
+ *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
+ *     exit(-1);
+ *   }
+ * @endcode
+ */
+EAPI Eina_List *
+eina_list_append(Eina_List *list, const void *data)
+{
+   Eina_List *l, *new_l;
+
+   eina_error_set(0);
+   new_l = _eina_list_mempool_list_new(list);
+   if (!new_l)
+      return list;
+
+   new_l->next = NULL;
+   new_l->data = (void *)data;
+   if (!list)
+     {
+        new_l->prev = NULL;
+        return _eina_list_setup_accounting(new_l);
+     }
+
+   EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   l = list->accounting->last;
+   list->accounting->last = new_l;
+
+   l->next = new_l;
+   new_l->prev = l;
+
+   _eina_list_update_accounting(list, new_l);
+   return list;
+}
+
+/**
+ * @brief Prepends the given data to the given linked list.
+ *
+ * @param list The given list.
+ * @param data The data to prepend.
+ * @return A list pointer.
+ *
+ * This function prepends @p data to @p list. If @p list is @c NULL, a
+ * new list is returned. On success, a new list pointer that should be
+ * used in place of the one given to this function is
+ * returned. Otherwise, the old pointer is returned.
+ *
+ * The following example code demonstrates how to ensure that the
+ * given data has been successfully prepended.
+ *
+ * Example:
+ * @code
+ * Eina_List *list = NULL;
+ * extern void *my_data;
+ *
+ * list = eina_list_prepend(list, my_data);
+ * if (eina_error_get())
+ *   {
+ *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
+ *     exit(-1);
+ *   }
+ * @endcode
+ */
+EAPI Eina_List *
+eina_list_prepend(Eina_List *list, const void *data)
+{
+   Eina_List *new_l;
+
+   eina_error_set(0);
+   new_l = _eina_list_mempool_list_new(list);
+   if (!new_l)
+      return list;
+
+   new_l->prev = NULL;
+   new_l->next = list;
+   new_l->data = (void *)data;
+
+   if (!list)
+      return _eina_list_setup_accounting(new_l);
+
+   EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   list->prev = new_l;
+
+   _eina_list_update_accounting(list, new_l);
+
+   return new_l;
+}
+
+/**
+ * @brief Insert the given data into the given linked list after the specified 
data.
+ *
+ * @param list The given linked list.
+ * @param data The data to insert.
+ * @param relative The data to insert after.
+ * @return A list pointer.
+ *
+ * This function inserts @p data to @p list after @p relative. If
+ * @p relative is not in the list, @p data is appended to the end of
+ * the list.  If @p list is @c NULL, a  new list is returned. If there
+ * are multiple instances of @p relative in the list, @p data is
+ * inserted after the first instance.On success, a new list pointer
+ * that should be used in place of the one given to this function is
+ * returned. Otherwise, the old pointer is returned.
+ *
+ * The following example code demonstrates how to ensure that the
+ * given data has been successfully inserted.
+ *
+ * @code
+ * Eina_List *list = NULL;
+ * extern void *my_data;
+ * extern void *relative_member;
+ *
+ * list = eina_list_append(list, relative_member);
+ * if (eina_error_get())
+ *   {
+ *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
+ *     exit(-1);
+ *   }
+ * list = eina_list_append_relative(list, my_data, relative_member);
+ * if (eina_error_get())
+ *   {
+ *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
+ *     exit(-1);
+ *   }
+ * @endcode
+ */
+EAPI Eina_List *
+eina_list_append_relative(Eina_List *list,
+                          const void *data,
+                          const void *relative)
+{
+   Eina_List *l;
+   void *list_data;
+
+   if (list)
+      EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   EINA_LIST_FOREACH(list, l, list_data)
+   {
+      if (list_data == relative)
+         return eina_list_append_relative_list(list, data, l);
+   }
+
+   return eina_list_append(list, data);
+}
+
+/**
+ * @brief Append a list node to a linked list after the specified member
+ *
+ * @param list The given linked list.
+ * @param data The data to insert.
+ * @param relative The list node to insert after.
+ * @return A list pointer.
+ *
+ * This function inserts @p data to @p list after the list node
+ * @p relative. If @p list or @p relative are @c NULL, @p data is just
+ * appended to @p list using eina_list_append(). If @p list is
+ * @c NULL, a  new list is returned. If there are multiple instances
+ * of @p relative in the list, @p data is inserted after the first
+ * instance. On success, a new list pointer that should be used in
+ * place of the one given to this function is returned. Otherwise, the
+ * old pointer is returned.
+ */
+EAPI Eina_List *
+eina_list_append_relative_list(Eina_List *list,
+                               const void *data,
+                               Eina_List *relative)
+{
+   Eina_List *new_l;
+
+   if ((!list) || (!relative))
+      return eina_list_append(list, data);
+
+   eina_error_set(0);
+   new_l = _eina_list_mempool_list_new(list);
+   if (!new_l)
+      return list;
+
+   EINA_MAGIC_CHECK_LIST(relative, NULL);
+   new_l->next = relative->next;
+   new_l->data = (void *)data;
+
+   if (relative->next)
+      relative->next->prev = new_l;
+
+   relative->next = new_l;
+   new_l->prev = relative;
+
+   _eina_list_update_accounting(list, new_l);
+
+   if (!new_l->next)
+      new_l->accounting->last = new_l;
+
+   return list;
+}
+
+/**
+ * @brief Prepend a data pointer to a linked list before the specified member
+ *
+ * @param list The given linked list.
+ * @param data The data to insert.
+ * @param relative The data to insert before.
+ * @return A list pointer.
+ *
+ * This function inserts @p data to @p list before @p relative. If
+ * @p relative is not in the list, @p data is prepended to the list
+ * with eina_list_prepend(). If @p list is @c NULL, a  new list is
+ * returned. If there are multiple instances of @p relative in the
+ * list, @p data is inserted before the first instance. On success, a
+ * new list pointer that should be used in place of the one given to
+ * this function is returned. Otherwise, the old pointer is returned.
+ *
+ * The following code example demonstrates how to ensure that the
+ * given data has been successfully inserted.
+ *
+ * @code
+ * Eina_List *list = NULL;
+ * extern void *my_data;
+ * extern void *relative_member;
+ *
+ * list = eina_list_append(list, relative_member);
+ * if (eina_error_get_error())
+ *   {
+ *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
+ *     exit(-1);
+ *   }
+ * list = eina_list_prepend_relative(list, my_data, relative_member);
+ * if (eina_error_get())
+ *   {
+ *     fprintf(stderr, "ERROR: Memory is low. List allocation failed.\n");
+ *     exit(-1);
+ *   }
+ * @endcode
+ */
+EAPI Eina_List *
+eina_list_prepend_relative(Eina_List *list,
+                           const void *data,
+                           const void *relative)
+{
+   Eina_List *l;
+   void *list_data;
+
+   if (list)
+      EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   EINA_LIST_FOREACH(list, l, list_data)
+   {
+      if (list_data == relative)
+         return eina_list_prepend_relative_list(list, data, l);
+   }
+   return eina_list_prepend(list, data);
+}
+
+/**
+ * @brief Prepend a list node to a linked list before the specified member
+ *
+ * @param list The given linked list.
+ * @param data The data to insert.
+ * @param relative The list node to insert before.
+ * @return A list pointer.
+ *
+ * This function inserts @p data to @p list before the list node
+ * @p relative. If @p list or @p relative are @c NULL, @p data is just
+ * prepended to @p list using eina_list_prepend(). If @p list is
+ * @c NULL, a  new list is returned. If there are multiple instances
+ * of @p relative in the list, @p data is inserted before the first
+ * instance. On success, a new list pointer that should be used in
+ * place of the one given to this function is returned. Otherwise, the
+ * old pointer is returned.
+ */
+EAPI Eina_List *
+eina_list_prepend_relative_list(Eina_List *list,
+                                const void *data,
+                                Eina_List *relative)
+{
+   Eina_List *new_l;
+
+   if ((!list) || (!relative))
+      return eina_list_prepend(list, data);
+
+   eina_error_set(0);
+   new_l = _eina_list_mempool_list_new(list);
+   if (!new_l)
+      return list;
+
+   EINA_MAGIC_CHECK_LIST(relative, NULL);
+
+   new_l->prev = relative->prev;
+   new_l->next = relative;
+   new_l->data = (void *)data;
+
+   if (relative->prev)
+      relative->prev->next = new_l;
+
+   relative->prev = new_l;
+
+   _eina_list_update_accounting(list, new_l);
+
+   if (new_l->prev)
+      return list;
+
+   return new_l;
+}
+
+/**
+ * @brief Insert a new node into a sorted list.
+ *
+ * @param list The given linked list, @b must be sorted.
+ * @param func The function called for the sort.
+ * @param data The data to insert sorted.
+ * @return A list pointer.
+ *
+ * This function inserts values into a linked list assuming it was
+ * sorted and the result will be sorted. If @p list is @c NULLL, a new
+ * list is returned. On success, a new list pointer that should be
+ * used in place of the one given to this function is
+ * returned. Otherwise, the old pointer is returned. See eina_error_get().
+ *
+ * @note O(log2(n)) comparisons (calls to @p func) average/worst case
+ * performance as it uses eina_list_search_sorted_near_list() and thus
+ * is bounded to that. As said in eina_list_search_sorted_near_list(),
+ * lists do not have O(1) access time, so walking to the correct node
+ * can be costly, consider worst case to be almost O(n) pointer
+ * dereference (list walk).
+ */
+EAPI Eina_List *
+eina_list_sorted_insert(Eina_List *list, Eina_Compare_Cb func, const void 
*data)
+{
+   Eina_List *lnear;
+   int cmp;
+
+   if (!list)
+      return eina_list_append(NULL, data);
+
+   lnear = eina_list_search_sorted_near_list(list, func, data, &cmp);
+   if (cmp < 0)
+      return eina_list_append_relative_list(list, data, lnear);
+   else
+      return eina_list_prepend_relative_list(list, data, lnear);
+}
+
+/**
+ * @brief Remove the first instance of the specified data from the given list.
+ *
+ * @param list The given list.
+ * @param data The specified data.
+ * @return A list pointer.
+ *
+ * This function removes the first instance of @p data from
+ * @p list. If the specified data is not in the given list (tihis
+ * include the case where @p data is @c NULL), nothing is done. If
+ * @p list is @c NULL, @c NULL is returned, otherwise a new list
+ * pointer that should be used in place of the one passed to this
+ * function.
+ */
+EAPI Eina_List *
+eina_list_remove(Eina_List *list, const void *data)
+{
+   Eina_List *l;
+
+   if (list)
+        EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   l = eina_list_data_find_list(list, data);
+   return eina_list_remove_list(list, l);
+}
+
+/**
+ * @brief Remove the specified data.
+ *
+ * @param list The given linked list.
+ * @param remove_list The list node which is to be removed.
+ * @return A list pointer.
+ *
+ * This function removes the list node @p remove_list from @p list and
+ * frees the list node structure @p remove_list. If @p list is
+ * @c NULL, this function returns @c NULL. If @p remove_list is
+ * @c NULL, it returns @p list, otherwise, a new list pointer that
+ * should be used in place of the one passed to this function.
+ *
+ * The following code gives an example (notice we use EINA_LIST_FOREACH
+ * instead of EINA_LIST_FOREACH_SAFE because we stop the loop after
+ * removing the current node).
+ *
+ * @code
+ * extern Eina_List *list;
+ * Eina_List *l;
+ * extern void *my_data;
+ * void *data
+ *
+ * EINA_LIST_FOREACH(list, l, data)
+ *   {
+ *     if (data == my_data)
+ *       {
+ *         list = eina_list_remove_list(list, l);
+ *         break;
+ *       }
+ *   }
+ * @endcode
+ */
+EAPI Eina_List *
+eina_list_remove_list(Eina_List *list, Eina_List *remove_list)
+{
+   Eina_List *return_l;
+
+   if (!list)
+      return NULL;
+
+   if (!remove_list)
+      return list;
+
+        EINA_MAGIC_CHECK_LIST(remove_list, NULL);
+
+   if (remove_list->next)
+      remove_list->next->prev = remove_list->prev;
+
+   if (remove_list->prev)
+     {
+        remove_list->prev->next = remove_list->next;
+        return_l = list;
+     }
+   else
+      return_l = remove_list->next;
+
+   if (remove_list == remove_list->accounting->last)
+     {
+        EINA_MAGIC_CHECK_LIST(list, NULL);
+        list->accounting->last = remove_list->prev;
+     }
+
+   _eina_list_mempool_list_free(remove_list);
+   return return_l;
+}
+
+/**
+ * @brief Free an entire list and all the nodes, ignoring the data contained.
+
+ * @param list The list to free
+ * @return A NULL pointer
+ *
+ * This function frees all the nodes of @p list. It does not free the
+ * data of the nodes. To free them, use #EINA_LIST_FREE.
+ */
+EAPI Eina_List *
+eina_list_free(Eina_List *list)
+{
+   Eina_List *l, *free_l;
+
+   if (!list)
+      return NULL;
+
+   EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   for (l = list; l; )
+     {
+        free_l = l;
+        l = l->next;
+
+        _eina_list_mempool_list_free(free_l);
+     }
+
+   return NULL;
+}
+
+/**
+ * @brief Move the specified data to the head of the list.
+ *
+ * @param list The list handle to move the data.
+ * @param move_list The list node to move.
+ * @return A new list handle to replace the old one
+ *
+ * This function move @p move_list to the front of @p list. If list is
+ * @c NULL, @c NULL is returned. If @p move_list is @c NULL,
+ * @p list is returned. Otherwise, a new list pointer that should be
+ * used in place of the one passed to this function.
+ *
+ * Example:
+ * @code
+ * extern Eina_List *list;
+ * Eina_List *l;
+ * extern void *my_data;
+ * void *data;
+ *
+ * EINA_LIST_FOREACH(list, l, data)
+ *   {
+ *     if (data == my_data)
+ *       {
+ *         list = eina_list_promote_list(list, l);
+ *         break;
+ *       }
+ *   }
+ * @endcode
+ */
+EAPI Eina_List *
+eina_list_promote_list(Eina_List *list, Eina_List *move_list)
+{
+   if (!list)
+      return NULL;
+
+   if (!move_list)
+     {
+        return list; /* Promoting head to be head. */
+
+     }
+
+   if (move_list == list)
+      return list;
+
+   if (move_list->next == list)
+      return move_list;
+
+      EINA_MAGIC_CHECK_LIST(list,      NULL);
+      EINA_MAGIC_CHECK_LIST(move_list, NULL);
+
+   /* Remove the promoted item from the list. */
+   if (!move_list->prev)
+      move_list->next->prev = NULL;
+   else
+     {
+        move_list->prev->next = move_list->next;
+        if (move_list == list->accounting->last)
+           list->accounting->last = move_list->prev;
+        else
+           move_list->next->prev = move_list->prev;
+     }
+
+   /* Add the promoted item in the list. */
+   move_list->next = list;
+   move_list->prev = list->prev;
+   list->prev = move_list;
+   if (move_list->prev)
+      move_list->prev->next = move_list;
+
+   return move_list;
+}
+
+/**
+ * @brief Move the specified data to the tail of the list.
+ *
+ * @param list The list handle to move the data.
+ * @param move_list The list node to move.
+ * @return A new list handle to replace the old one
+ *
+ * This function move @p move_list to the back of @p list. If list is
+ * @c NULL, @c NULL is returned. If @p move_list is @c NULL,
+ * @p list is returned. Otherwise, a new list pointer that should be
+ * used in place of the one passed to this function.
+ *
+ * Example:
+ * @code
+ * extern Eina_List *list;
+ * Eina_List *l;
+ * extern void *my_data;
+ * void *data;
+ *
+ * EINA_LIST_FOREACH(list, l, data)
+ *   {
+ *     if (data == my_data)
+ *       {
+ *         list = eina_list_demote_list(list, l);
+ *         break;
+ *       }
+ *   }
+ * @endcode
+ */
+EAPI Eina_List *
+eina_list_demote_list(Eina_List *list, Eina_List *move_list)
+{
+   if (!list)
+      return NULL;
+
+   if (!move_list)
+     {
+        return list; /* Demoting tail to be tail. */
+
+     }
+
+   if (move_list == list->accounting->last)
+      return list;
+
+      EINA_MAGIC_CHECK_LIST(list,      NULL);
+      EINA_MAGIC_CHECK_LIST(move_list, NULL);
+
+   /* Update pointer list if necessary. */
+   if (list == move_list)
+     {
+        list = move_list->next; /* Remove the demoted item from the list. */
+
+     }
+
+   if (move_list->prev)
+      move_list->prev->next = move_list->next;
+
+   move_list->next->prev = move_list->prev;
+   /* Add the demoted item in the list. */
+   move_list->prev = list->accounting->last;
+   move_list->prev->next = move_list;
+   move_list->next = NULL;
+   list->accounting->last = move_list;
+
+   return list;
+}
+
+/**
+ * @brief Find a member of a list and return the member.
+ *
+ * @param list The list to search for a data.
+ * @param data The data pointer to find in the list.
+ * @return The found member data pointer if foun, @c NULL otherwise.
+ *
+ * This function searches in @p list from beginning to end for the
+ * first member whose data pointer is @p data. If it is found, @p data
+ * will be returned, otherwise NULL will be returned.
+ *
+ * Example:
+ * @code
+ * extern Eina_List *list;
+ * extern void *my_data;
+ *
+ * if (eina_list_data_find(list, my_data) == my_data)
+ *   {
+ *     printf("Found member %p\n", my_data);
+ *   }
+ * @endcode
+ */
+EAPI void *
+eina_list_data_find(const Eina_List *list, const void *data)
+{
+   if (eina_list_data_find_list(list, data))
+      return (void *)data;
+
+   return NULL;
+}
+
+/**
+ * @brief Find a member of a list and return the list node containing that 
member.
+ *
+ * @param list The list to search for data.
+ * @param data The data pointer to find in the list.
+ * @return The found members list node on success, @c NULL otherwise.
+ *
+ * This function searches in @p list from beginning to end for the
+ * first member whose data pointer is @p data. If it is found, the
+ * list node containing the specified member is returned, otherwise
+ * @c NULL is returned.
+ */
+EAPI Eina_List *
+eina_list_data_find_list(const Eina_List *list, const void *data)
+{
+   const Eina_List *l;
+   void *list_data;
+
+   if (list)
+      EINA_MAGIC_CHECK_LIST(list, NULL);
+
+      EINA_LIST_FOREACH(list, l, list_data)
+   {
+      if (list_data == data)
+         return (Eina_List *)l;
+   }
+
+   return NULL;
+}
+
+/**
+ * @brief Get the nth member's data pointer in a list.
+ *
+ * @param list The list to get the specified member number from.
+ * @param n The number of the element (0 being the first).
+ * @return The data pointer stored in the specified element.
+ *
+ * This function returns the data pointer of element number @p n, in
+ * the @p list. The first element in the array is element number 0. If
+ * the element number @p n does not exist, @c NULL is
+ * returned. Otherwise, the data of the found element is returned.
+ */
+EAPI void *
+eina_list_nth(const Eina_List *list, unsigned int n)
+{
+   Eina_List *l;
+
+   l = eina_list_nth_list(list, n);
+   return l ? l->data : NULL;
+}
+
+/**
+ * @brief Get the nth member's list node in a list.
+ *
+ * @param list The list to get the specfied member number from.
+ * @param n The number of the element (0 being the first).
+ * @return The list node stored in the numbered element.
+ *
+ * This function returns the list node of element number @p n, in
+ * @ list. The first element in the array is element number 0. If the
+ * element number @p n does not exist or @p list is @c NULL or @p n is
+ * greater than the count of elements in @p list minus 1, @c NULL is
+ * returned. Otherwise the list node stored in the numbered element is
+ * returned.
+ */
+EAPI Eina_List *
+eina_list_nth_list(const Eina_List *list, unsigned int n)
+{
+   const Eina_List *l;
+   unsigned int i;
+
+   if (list)
+      EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   /* check for non-existing nodes */
+   if ((!list) || (n > (list->accounting->count - 1)))
+      return NULL;
+
+   /* if the node is in the 2nd half of the list, search from the end
+    * else, search from the beginning.
+    */
+   if (n > (list->accounting->count / 2))
+      for (i = list->accounting->count - 1,
+           l = list->accounting->last;
+           l;
+           l = l->prev, i--)
+        {
+           if (i == n)
+              return (Eina_List *)l;
+        }
+   else
+      for (i = 0, l = list; l; l = l->next, i++)
+        {
+           if (i == n)
+              return (Eina_List *)l;
+        }
+
+   abort();
+}
+
+/**
+ * @brief Reverse all the elements in the list.
+ *
+ * @param list The list to reverse.
+ * @return The list head after it has been reversed.
+ *
+ * This function reverses the order of all elements in @p list, so the
+ * last member is now first, and so on. If @p list is @c NULL, this
+ * functon returns @c NULL.
+ *
+ * @note @b in-place: this will change the given list, so you should
+ * now point to the new list head that is returned by this function.
+ *
+ * @see eina_list_reverse_clone()
+ * @see eina_list_iterator_reversed_new()
+ */
+EAPI Eina_List *
+eina_list_reverse(Eina_List *list)
+{
+   Eina_List *l1, *l2;
+
+   if (!list)
+      return NULL;
+
+   EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   l1 = list;
+   l2 = list->accounting->last;
+   while (l1 != l2)
+     {
+        void *data;
+
+        data = l1->data;
+        l1->data = l2->data;
+        l2->data = data;
+        l1 = l1->next;
+        if (l1 == l2)
+           break;
+
+        l2 = l2->prev;
+     }
+
+   return list;
+}
+
+/**
+ * @brief Clone (copy) all the elements in the list in reverse order.
+ *
+ * @param list The list to reverse.
+ * @return The new list that has been reversed.
+ *
+ * This function reverses the order of all elements in @p list, so the
+ * last member is now first, and so on. If @p list is @c NULL, this
+ * functon returns @c NULL. This returns a copy of the given list.
+ *
+ * @note @b copy: this will copy the list and you should then
+ * eina_list_free() when it is not required anymore.
+ *
+ * @see eina_list_reverse()
+ * @see eina_list_clone()
+ */
+EAPI Eina_List *
+eina_list_reverse_clone(const Eina_List *list)
+{
+   const Eina_List *l;
+   Eina_List *lclone;
+   void *data;
+
+   if (!list)
+      return NULL;
+
+   EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   lclone = NULL;
+   EINA_LIST_FOREACH(list, l, data)
+   lclone = eina_list_prepend(lclone, data);
+
+   return lclone;
+}
+
+/**
+ * @brief Clone (copy) all the elements in the list in exact order.
+ *
+ * @param list The list to clone.
+ * @return The new list that has been cloned.
+ *
+ * This function clone in order of all elements in @p list. If @p list
+ * is @c NULL, this functon returns @c NULL. This returns a copy of
+ * the given list.
+ *
+ * @note @b copy: this will copy the list and you should then
+ * eina_list_free() when it is not required anymore.
+ *
+ * @see eina_list_reverse_clone()
+ */
+EAPI Eina_List *
+eina_list_clone(const Eina_List *list)
+{
+   const Eina_List *l;
+   Eina_List *lclone;
+   void *data;
+
+   if (!list)
+      return NULL;
+
+   EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   lclone = NULL;
+   EINA_LIST_FOREACH(list, l, data)
+   lclone = eina_list_append(lclone, data);
+
+   return lclone;
+}
+
+/**
+ * @brief Sort a list according to the ordering func will return.
+ *
+ * @param list The list handle to sort.
+ * @param size The length of the list to sort.
+ * @param func A function pointer that can handle comparing the list data
+ * nodes.
+ * @return the new head of list.
+ *
+ * This function sorts @p list. @p size if the number of the first
+ * element to sort. If @p size is 0 or greater than the number of
+ * elements in @p list, all the elements are sorted. @p func is used to
+ * compare two elements of @p list. If @p list or @p func are @c NULL,
+ * this function returns @c NULL.
+ *
+ * @note @b in-place: this will change the given list, so you should
+ * now point to the new list head that is returned by this function.
+ *
+ * @note worst case is O(n * log2(n)) comparisons (calls to func()),
+ * O(n) comparisons average case. That means that for 1,000,000 list
+ * elements, sort will usually do 1,000,000 comparisons, but may do up
+ * to 20,000,000.
+ *
+ * Example:
+ * @code
+ * int
+ * sort_cb(const void *d1, const void *d2)
+ * {
+ *    const char *txt = NULL;
+ *    const char *txt2 = NULL;
+ *
+ *    if(!d1) return(1);
+ *    if(!d2) return(-1);
+ *
+ *    return(strcmp((const char*)d1, (const char*)d2));
+ * }
+ * extern Eina_List *list;
+ *
+ * list = eina_list_sort(list, eina_list_count(list), sort_cb);
+ * @endcode
+ */
+EAPI Eina_List *
+eina_list_sort(Eina_List *list, unsigned int size, Eina_Compare_Cb func)
+{
+   unsigned int i = 0;
+   unsigned int n = 0;
+   Eina_List *tail = list;
+   Eina_List *unsort = NULL;
+   Eina_List *stack[EINA_LIST_SORT_STACK_SIZE];
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(func, list);
+   if (!list)
+      return NULL;
+
+   EINA_MAGIC_CHECK_LIST(list, NULL);
+
+   /* if the caller specified an invalid size, sort the whole list */
+   if ((size == 0) ||
+       (size > list->accounting->count))
+      size = list->accounting->count;
+
+   if (size != list->accounting->count)
+     {
+        unsort = eina_list_nth_list(list, size);
+        if (unsort)
+           unsort->prev->next = NULL;
+     }
+
+   while (tail)
+     {
+        unsigned int idx, tmp;
+
+        Eina_List *a = tail;
+        Eina_List *b = tail->next;
+
+        if (!b)
+          {
+             stack[i++] = a;
+             break;
+          }
+
+        tail = b->next;
+
+        if (func(a->data, b->data) < 0)
+           ((stack[i++] = a)->next = b)->next = 0;
+        else
+           ((stack[i++] = b)->next = a)->next = 0;
+
+        tmp = n++;
+        for (idx = n ^ tmp; idx &= idx - 1; i--)
+           stack[i - 2] = eina_list_sort_merge(stack[i - 2], stack[i - 1], 
func);
+     }
+
+   while (i-- > 1)
+      stack[i - 1] = eina_list_sort_merge(stack[i - 1], stack[i], func);
+
+   list = stack[0];
+   tail = eina_list_sort_rebuild_prev(list);
+
+   if (unsort)
+     {
+        tail->next = unsort;
+        unsort->prev = tail;
+     }
+   else
+      list->accounting->last = tail;
+
+   return list;
+}
+
+/**
+ * @brief Merge two list.
+ *
+ * @param left Head list to merge.
+ * @param right Tail list to merge.
+ * @return A new merged list.
+ *
+ * This function put right at the end of left and return the head.
+ *
+ * Both left and right does not exist anymore after the merge.
+ *
+ * @note merge cost is O(n), being @b n the size of the smallest
+ * list. This is due the need to fix accounting of that segment,
+ * making count and last access O(1).
+ */
+EAPI Eina_List *
+eina_list_merge(Eina_List *left, Eina_List *right)
+{
+   unsigned int n_left, n_right;
+
+   if (!left)
+      return right;
+
+   if (!right)
+      return left;
+
+   left->accounting->last->next = right;
+   right->prev = left->accounting->last;
+
+   n_left = left->accounting->count;
+   n_right = right->accounting->count;
+
+   if (n_left >= n_right)
+     {
+        Eina_List *itr = right;
+        left->accounting->last = right->accounting->last;
+        left->accounting->count += n_right;
+
+        _eina_list_mempool_accounting_free(right->accounting);
+
+        do
+          {
+             itr->accounting = left->accounting;
+             itr = itr->next;
+          }
+        while (itr);
+     }
+   else
+     {
+        Eina_List *itr = left->accounting->last;
+        right->accounting->count += n_left;
+
+        _eina_list_mempool_accounting_free(left->accounting);
+
+        do
+          {
+             itr->accounting = right->accounting;
+             itr = itr->prev;
+          }
+        while (itr);
+     }
+
+   return left;
+}
+
+
+/**
+ * @brief Split a list into 2 lists.
+ *
+ * @param list List to split.
+ * @param relative The list will be split after @p relative.
+ * @param right The head of the new right list.
+ * @return The new left list
+ *
+ * This function split @p list into two lists ( left and right ) after the 
node @p relative. @p Relative
+ * will become the last node of the left list. If @p list or @p right are NULL 
list is returns.
+ * If @p relative is NULL right is set to @p list and NULL is returns.
+ * If @p relative is the last node of @p list list is returns and @p right is 
set to NULL.
+ *
+ * list does not exist anymore after the split.
+ *
+ */
+EAPI Eina_List *
+eina_list_split_list(Eina_List *list, Eina_List *relative, Eina_List **right)
+{
+   Eina_List *next;
+   Eina_List *itr;
+
+   if(!right)
+      return list;
+
+   *right = NULL;
+
+   if (!list)
+      return NULL;
+
+   if (!relative)
+     {
+        *right = list;
+        return NULL;
+     }
+
+   if (relative == eina_list_last(list))
+      return list;
+
+   next = eina_list_next(relative);
+   next->prev = NULL;
+   next->accounting = _eina_list_mempool_accounting_new(next);
+   next->accounting->last = list->accounting->last;
+   *right = next;
+
+   itr = next;
+   do
+     {
+        itr->accounting = next->accounting;
+        next->accounting->count++;
+        itr = itr->next;
+     }
+   while (itr);
+
+   relative->next = NULL;
+   list->accounting->last = relative;
+   list->accounting->count = list->accounting->count - next->accounting->count;
+
+   return list;
+}
+
+/**
+ * @brief Merge two sorted list according to the ordering func will return.
+ *
+ * @param left First list to merge.
+ * @param right Second list to merge.
+ * @param func A function pointer that can handle comparing the list data
+ * nodes.
+ * @return A new sorted list.
+ *
+ * This function compare the head of @p left and @p right, and choose the
+ * smallest one to be head of the returned list. It will continue this process
+ * for all entry of both list.
+ *
+ * Both left and right does not exist anymore after the merge.
+ * If @p func is NULL, it will return NULL.
+ *
+ * Example:
+ * @code
+ * int
+ * sort_cb(void *d1, void *d2)
+ * {
+ *   const char *txt = NULL;
+ *    const char *txt2 = NULL;
+ *
+ *    if(!d1) return(1);
+ *    if(!d2) return(-1);
+ *
+ *    return(strcmp((const char*)d1, (const char*)d2));
+ * }
+ * extern Eina_List *sorted1;
+ * extern Eina_List *sorted2;
+ *
+ * list = eina_list_sorted_merge(sorted1, sorted2, sort_cb);
+ * @endcode
+ */
+EAPI Eina_List *
+eina_list_sorted_merge(Eina_List *left, Eina_List *right, Eina_Compare_Cb func)
+{
+   Eina_List *ret;
+   Eina_List *current;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(func, NULL);
+
+   if (!left)
+      return right;
+
+   if (!right)
+      return left;
+
+   if (func(left->data, right->data) < 0)
+     {
+        ret = left;
+        current = left;
+        left = left->next;
+        ret->accounting->count += right->accounting->count;
+
+        _eina_list_mempool_accounting_free(right->accounting);
+     }
+   else
+     {
+        ret = right;
+        current = right;
+        right = right->next;
+        ret->accounting->count += left->accounting->count;
+
+        _eina_list_mempool_accounting_free(left->accounting);
+     }
+
+   while (left && right)
+     {
+        if (func(left->data, right->data) < 0)
+          {
+             current->next = left;
+             left->prev = current;
+             left = left->next;
+          }
+        else
+          {
+             current->next = right;
+             right->prev = current;
+             right = right->next;
+          }
+
+        current = current->next;
+        current->accounting = ret->accounting;
+     }
+
+   if (left)
+     {
+        current->next = left;
+        left->prev = current;
+        current->accounting = ret->accounting;
+     }
+
+   if (right)
+     {
+        current->next = right;
+        right->prev = current;
+        current->accounting = ret->accounting;
+     }
+
+   while (current->next)
+     {
+        current = current->next;
+        current->accounting = ret->accounting;
+     }
+
+   ret->accounting->last = current;
+
+   return ret;
+}
+
+/**
+ * @brief Returns node nearest to data is in the sorted list.
+ *
+ * @param list The list to search for data, @b must be sorted.
+ * @param func A function pointer that can handle comparing the list data 
nodes.
+ * @param data reference value to search.
+ * @param result_cmp if provided returns the result of
+ * func(node->data, data) node being the last (returned) node. If node
+ * was found (exact match), then it is 0. If returned node is smaller
+ * than requested data, it is less than 0 and if it's bigger it's
+ * greater than 0. It is the last value returned by func().
+ * @return the nearest node, NULL if not found.
+ *
+ * This can be used to check if some value is inside the list and get
+ * the nearest container node in this case. It should be used when list is
+ * known to be sorted as it will do binary search for results.
+ *
+ * Example: imagine user gives a string, you check if it's in the list
+ * before duplicating its contents, otherwise you want to insert it
+ * sorted. In this case you get the result of this function and either
+ * append or prepend the value.
+ *
+ * @note O(log2(n)) average/worst case performance, for 1,000,000
+ * elements it will do a maximum of 20 comparisons. This is much
+ * faster than the 1,000,000 comparisons made naively walking the list
+ * from head to tail, so depending on the number of searches and
+ * insertions, it may be worth to eina_list_sort() the list and do the
+ * searches later. As lists do not have O(1) access time, walking to
+ * the correct node can be costly, consider worst case to be almost
+ * O(n) pointer dereference (list walk).
+ *
+ * @see eina_list_search_sorted_list()
+ * @see eina_list_sort()
+ * @see eina_list_sorted_merge()
+ */
+EAPI Eina_List *
+eina_list_search_sorted_near_list(const Eina_List *list,
+                                  Eina_Compare_Cb func,
+                                  const void *data,
+                                  int *result_cmp)
+{
+   const Eina_List *ct;
+   unsigned int inf, sup, cur;
+   int cmp;
+
+   if (!list)
+     {
+        if (result_cmp)
+           *result_cmp = 0;
+
+        return NULL;
+     }
+
+   if (list->accounting->count == 1)
+     {
+        if (result_cmp)
+           *result_cmp = func(list->data, data);
+
+        return (Eina_List *)list;
+     }
+
+   /* list walk is expensive, do quick check: tail */
+   ct = list->accounting->last;
+   cmp = func(ct->data, data);
+   if (cmp <= 0)
+      goto end;
+
+   /* list walk is expensive, do quick check: head */
+   ct = list;
+   cmp = func(ct->data, data);
+   if (cmp >= 0)
+      goto end;
+
+   /* inclusive bounds */
+   inf = 1;
+   sup = list->accounting->count - 2;
+   cur = 1;
+   ct = list->next;
+
+   /* no loop, just compare if comparison value is important to caller */
+   if (inf > sup)
+     {
+        if (result_cmp)
+           cmp = func(ct->data, data);
+
+        goto end;
+     }
+
+   while (inf <= sup)
+     {
+        unsigned int tmp = cur;
+        cur = inf + ((sup - inf) >> 1);
+        if      (tmp < cur)
+           for (; tmp != cur; tmp++, ct = ct->next) ;
+        else if (tmp > cur)
+           for (; tmp != cur; tmp--, ct = ct->prev) ;
+
+        cmp = func(ct->data, data);
+        if (cmp == 0)
+           break;
+        else if (cmp < 0)
+           inf = cur + 1;
+        else if (cmp > 0)
+          {
+             if (cur > 0)
+                sup = cur - 1;
+             else
+                break;
+          }
+        else
+           break;
+     }
+
+end:
+   if (result_cmp)
+      *result_cmp = cmp;
+
+   return (Eina_List *)ct;
+}
+
+/**
+ * @brief Returns node if data is in the sorted list.
+ *
+ * @param list The list to search for data, @b must be sorted.
+ * @param func A function pointer that can handle comparing the list data 
nodes.
+ * @param data reference value to search.
+ * @return the node if func(node->data, data) == 0, NULL if not found.
+ *
+ * This can be used to check if some value is inside the list and get
+ * the container node in this case. It should be used when list is
+ * known to be sorted as it will do binary search for results.
+ *
+ * Example: imagine user gives a string, you check if it's in the list
+ * before duplicating its contents.
+ *
+ * @note O(log2(n)) average/worst case performance, for 1,000,000
+ * elements it will do a maximum of 20 comparisons. This is much
+ * faster than the 1,000,000 comparisons made by
+ * eina_list_search_unsorted_list(), so depending on the number of
+ * searches and insertions, it may be worth to eina_list_sort() the
+ * list and do the searches later. As said in
+ * eina_list_search_sorted_near_list(), lists do not have O(1) access
+ * time, so walking to the correct node can be costly, consider worst
+ * case to be almost O(n) pointer dereference (list walk).
+ *
+ * @see eina_list_search_sorted()
+ * @see eina_list_sort()
+ * @see eina_list_sorted_merge()
+ * @see eina_list_search_unsorted_list()
+ * @see eina_list_search_sorted_near_list()
+ */
+EAPI Eina_List *
+eina_list_search_sorted_list(const Eina_List *list,
+                             Eina_Compare_Cb func,
+                             const void *data)
+{
+   Eina_List *lnear;
+   int cmp;
+
+   lnear = eina_list_search_sorted_near_list(list, func, data, &cmp);
+   if (!lnear)
+      return NULL;
+
+   if (cmp == 0)
+      return lnear;
+
+   return NULL;
+}
+
+
+/**
+ * @brief Returns node data if it is in the sorted list.
+ *
+ * @param list The list to search for data, @b must be sorted.
+ * @param func A function pointer that can handle comparing the list data 
nodes.
+ * @param data reference value to search.
+ * @return the node value (@c node->data) if func(node->data, data) == 0,
+ * NULL if not found.
+ *
+ * This can be used to check if some value is inside the list and get
+ * the existing instance in this case. It should be used when list is
+ * known to be sorted as it will do binary search for results.
+ *
+ * Example: imagine user gives a string, you check if it's in the list
+ * before duplicating its contents.
+ *
+ * @note O(log2(n)) average/worst case performance, for 1,000,000
+ * elements it will do a maximum of 20 comparisons. This is much
+ * faster than the 1,000,000 comparisons made by
+ * eina_list_search_unsorted(), so depending on the number of
+ * searches and insertions, it may be worth to eina_list_sort() the
+ * list and do the searches later. As said in
+ * eina_list_search_sorted_near_list(), lists do not have O(1) access
+ * time, so walking to the correct node can be costly, consider worst
+ * case to be almost O(n) pointer dereference (list walk).
+ *
+ * @see eina_list_search_sorted_list()
+ * @see eina_list_sort()
+ * @see eina_list_sorted_merge()
+ * @see eina_list_search_unsorted_list()
+ */
+EAPI void *
+eina_list_search_sorted(const Eina_List *list,
+                        Eina_Compare_Cb func,
+                        const void *data)
+{
+   return eina_list_data_get(eina_list_search_sorted_list(list, func, data));
+}
+
+/**
+ * @brief Returns node if data is in the unsorted list.
+ *
+ * @param list The list to search for data, may be unsorted.
+ * @param func A function pointer that can handle comparing the list data 
nodes.
+ * @param data reference value to search.
+ * @return the node if func(node->data, data) == 0, NULL if not found.
+ *
+ * This can be used to check if some value is inside the list and get
+ * the container node in this case.
+ *
+ * Example: imagine user gives a string, you check if it's in the list
+ * before duplicating its contents.
+ *
+ * @note this is expensive and may walk the whole list, it's order-N,
+ * that is for 1,000,000 elements list it may walk and compare
+ * 1,000,000 nodes.
+ *
+ * @see eina_list_search_sorted_list()
+ * @see eina_list_search_unsorted()
+ */
+EAPI Eina_List *
+eina_list_search_unsorted_list(const Eina_List *list,
+                               Eina_Compare_Cb func,
+                               const void *data)
+{
+   const Eina_List *l;
+   void *d;
+
+   EINA_LIST_FOREACH(list, l, d)
+   {
+      if (!func(d, data))
+         return (Eina_List *)l;
+   }
+   return NULL;
+}
+
+/**
+ * @brief Returns node data if it is in the unsorted list.
+ *
+ * @param list The list to search for data, may be unsorted.
+ * @param func A function pointer that can handle comparing the list data 
nodes.
+ * @param data reference value to search.
+ * @return the node value (@c node->data) if func(node->data, data) == 0,
+ * NULL if not found.
+ *
+ * This can be used to check if some value is inside the list and get
+ * the existing instance in this case.
+ *
+ * Example: imagine user gives a string, you check if it's in the list
+ * before duplicating its contents.
+ *
+ * @note this is expensive and may walk the whole list, it's order-N,
+ * that is for 1,000,000 elements list it may walk and compare
+ * 1,000,000 nodes.
+ *
+ * @see eina_list_search_sorted()
+ * @see eina_list_search_unsorted_list()
+ */
+EAPI void *
+eina_list_search_unsorted(const Eina_List *list,
+                          Eina_Compare_Cb func,
+                          const void *data)
+{
+   return eina_list_data_get(eina_list_search_unsorted_list(list, func, data));
+}
+
+
+/**
+ * @brief Returned a new iterator associated to a list.
+ *
+ * @param list The list.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to @p
+ * list. If @p list is @c NULL or the count member of @p list is less
+ * or equal than 0, this function still returns a valid iterator that
+ * will always return false on eina_iterator_next(), thus keeping API
+ * sane.
+ *
+ * If the memory can not be allocated, NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
+ * returned.
+ *
+ * @warning if the list structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove nodes this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_list_iterator_new(const Eina_List *list)
+{
+   Eina_Iterator_List *it;
+
+   eina_error_set(0);
+   it = calloc(1, sizeof (Eina_Iterator_List));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(it,            EINA_MAGIC_LIST_ITERATOR);
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->head = list;
+   it->current = list;
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(eina_list_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         eina_list_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(eina_list_iterator_free);
+
+   return &it->iterator;
+}
+
+/**
+ * @brief Returned a new reversed iterator associated to a list.
+ *
+ * @param list The list.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to @p
+ * list. If @p list is @c NULL or the count member of @p list is less
+ * or equal than 0, this function still returns a valid iterator that
+ * will always return false on eina_iterator_next(), thus keeping API
+ * sane.
+ *
+ * Unlike eina_list_iterator_new(), this will walk the list backwards.
+ *
+ * If the memory can not be allocated, NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
+ * returned.
+ *
+ * @warning if the list structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove nodes this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_list_iterator_reversed_new(const Eina_List *list)
+{
+   Eina_Iterator_List *it;
+
+        eina_error_set(0);
+   it = calloc(1, sizeof (Eina_Iterator_List));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(it,            EINA_MAGIC_LIST_ITERATOR);
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->head = eina_list_last(list);
+   it->current = it->head;
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(eina_list_iterator_prev);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         eina_list_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(eina_list_iterator_free);
+
+   return &it->iterator;
+}
+
+/**
+ * @brief Returned a new accessor associated to a list.
+ *
+ * @param list The list.
+ * @return A new accessor.
+ *
+ * This function returns a newly allocated accessor associated to
+ * @p list. If @p list is @c NULL or the count member of @p list is
+ * less or equal than 0, this function returns NULL. If the memory can
+ * not be allocated, NULL is returned and #EINA_ERROR_OUT_OF_MEMORY is
+ * set. Otherwise, a valid accessor is returned.
+ */
+EAPI Eina_Accessor *
+eina_list_accessor_new(const Eina_List *list)
+{
+   Eina_Accessor_List *ac;
+
+        eina_error_set(0);
+   ac = calloc(1, sizeof (Eina_Accessor_List));
+   if (!ac)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(ac,            EINA_MAGIC_LIST_ACCESSOR);
+   EINA_MAGIC_SET(&ac->accessor, EINA_MAGIC_ACCESSOR);
+
+   ac->head = list;
+   ac->current = list;
+   ac->index = 0;
+
+   ac->accessor.version = EINA_ACCESSOR_VERSION;
+   ac->accessor.get_at = FUNC_ACCESSOR_GET_AT(eina_list_accessor_get_at);
+   ac->accessor.get_container = FUNC_ACCESSOR_GET_CONTAINER(
+         eina_list_accessor_get_container);
+   ac->accessor.free = FUNC_ACCESSOR_FREE(eina_list_accessor_free);
+
+   return &ac->accessor;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_log.c 
b/tests/suite/ecore/src/lib/eina_log.c
new file mode 100644
index 0000000..aa9b781
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_log.c
@@ -0,0 +1,2483 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2009 Jorge Luis Zapata Muga, Cedric Bail, Andre Dieb
+ * Martins
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/**
+ * @page tutorial_log_page Log Tutorial
+ *
+ * @section tutorial_log_introduction Introduction
+ *
+ * The Eina Log module provides logging facilities for libraries and
+ * applications. It provides colored logging, basic logging levels (error,
+ * warning, debug, info, critical) and loggers - called logging domains -
+ * which will be covered on next sections.
+ *
+ * @section tutorial_log_basic_usage Basic Usage
+ *
+ * Log messages can be displayed using the following macros:
+ *
+ * @li EINA_LOG_ERR(),
+ * @li EINA_LOG_INFO(),
+ * @li EINA_LOG_WARN(),
+ * @li EINA_LOG_DBG().
+ *
+ * Here is an example:
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ *
+ * #include <Eina.h>
+ *
+ * void test(int i)
+ * {
+ *    EINA_LOG_DBG("Entering test");
+ *
+ *    if (i < 0)
+ *    {
+ *        EINA_LOG_ERR("Argument is negative");
+ *        return;
+ *    }
+ *
+ *    EINA_LOG_INFO("argument non negative");
+ *
+ *    EINA_LOG_DBG("Exiting test");
+ * }
+ *
+ * int main(void)
+ * {
+ *    if (!eina_init())
+ *    {
+ *        printf("log during the initialization of Eina_Log module\n");
+ *        return EXIT_FAILURE;
+ *    }
+ *
+ *    test(-1);
+ *    test(0);
+ *
+ *    eina_shutdown();
+ *
+ *    return EXIT_SUCCESS;
+ * }
+ * @endcode
+ *
+ * If you compiled Eina without debug mode, execution will yield only one log
+ * message, which is "argument is negative".
+ *
+ * Here we introduce the concept of logging domains (or loggers), which might
+ * already be familiar to readers. It is basically a way to separate a set of
+ * log messages into a context (e.g. a module) and provide a way of controlling
+ * this set as a whole.
+ *
+ * For example, suppose you have 3 different modules on your application and 
you
+ * want to get logging only from one of them (e.g. create some sort of filter).
+ * For achieving that, all you need to do is create a logging domain for each
+ * module so that all logging inside a module can be considered as a whole.
+ *
+ * Logging domains are specified by a name, color applied to the name and the
+ * level. The first two (name and color) are set through code, that is, inside
+ * your application/module/library.
+ *
+ * The level is used for controlling which messages should appear. It
+ * specifies the lowest level that should be displayed (e.g. a message
+ * with level 11 being logged on a domain with level set to 10 would be
+ * displayed, while a message with level 9 wouldn't).
+ *
+ * The domain level is set during runtime (in contrast with the name and
+ * color) through the environment variable EINA_LOG_LEVELS. This variable
+ * expects a list in the form domain_name1:level1,domain_name2:level2,... . For
+ * example:
+ *
+ * @code
+ *
+ * EINA_LOG_LEVELS=mymodule1:5,mymodule2:2,mymodule3:0 ./myapp
+ *
+ * @endcode
+ *
+ * This line would set mymodule1 level to 5, mymodule2 level to 2 and mymodule3
+ * level to 0.
+ *
+ *
+ * There's also a global logger to which EINA_LOG_(ERR, DBG, INFO, CRIT, WARN)
+ * macros do log on. It is a logger that is created internally by Eina Log with
+ * an empty name and can be used for general logging (where logging domains do
+ * not apply).
+ *
+ * Since this global logger doesn't have a name, you can't set its level 
through
+ * EINA_LOG_LEVELS variable. Here we introduce a second environment variable
+ * that is a bit more special: EINA_LOG_LEVEL.
+ *
+ * This variable specifies the level of the global logging domain and the level
+ * of domains that haven't been set through EINA_LOG_LEVELS. Here's an example:
+ *
+ * @code
+ *
+ * EINA_LOG_LEVEL=3 EINA_LOG_LEVELS=module1:10,module3:2 ./myapp
+ *
+ * @endcode
+ *
+ * Supposing you have modules named "module1", "module2" and "module3", this
+ * line would result in module1 with level 10, module2 with level 3 and module3
+ * with level 2. Note that module2's level wasn't specified, so it's level is
+ * set to the global level. This way we can easily apply filters to multiple
+ * domains with only one parameter (EINA_LOG_LEVEL=num).
+ *
+ * The global level (EINA_LOG_LEVEL) can also be set through code, using
+ * eina_log_level_set() function.
+ *
+ *
+ * While developing your libraries or applications, you may notice that
+ * EINA_LOG_DOM_(ERR, DBG, INFO, CRIT, WARN) macros also print out
+ * messages from eina itself. Here we introduce another environment variable
+ * that is a bit more special: EINA_LOG_LEVELS_GLOB.
+ *
+ * This variable allows you to disable the logging of any/all code in eina 
itself.
+ * This is useful when developing your libraries or applications so that you 
can
+ * see your own domain's messages easier without having to sift through a lot 
of
+ * internal eina debug messages. Here's an example:
+ *
+ * @code
+ *
+ * EINA_LOG_LEVEL=3 EINA_LOG_LEVELS_GLOB=eina_*:0 ./myapp
+ *
+ * @endcode
+ *
+ * This will disable eina_log output from all internal eina code thus allowing
+ * you to see your own domain messages easier.
+ *
+ * @section tutorial_log_advanced_display Advanced usage of print callbacks
+ *
+ * The log module allows the user to change the way
+ * eina_log_print() displays the messages. It suffices to pass to
+ * eina_log_print_cb_set() the function used to display the
+ * message. That  function must be of type #Eina_Log_Print_Cb. As a
+ * custom data can be passed to that callback, powerful display
+ * messages can be displayed.
+ *
+ * It is suggested to not use __FILE__, __FUNCTION__ or __LINE__ when
+ * writing that callback, but when defining macros (like
+ * EINA_LOG_ERR() and other macros).
+ *
+ * Here is an example of custom callback, whose behavior can be
+ * changed at runtime:
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ *
+ * #include <eina_log.h>
+ *
+ * #define log(fmt, ...)                                    \
+ *    eina_log_print(EINA_LOG_LEVEL_ERR, __FILE__, __FUNCTION__, __LINE__, 
fmt, ##__VA_ARGS__)
+ *
+ * typedef struct _Data Data;
+ *
+ * struct _Data
+ * {
+ *    int to_stderr;
+ * };
+ *
+ * void print_cb(const Eina_Log_Domain *domain,
+ *               Eina_Log_Level level,
+ *               const char *file,
+ *               const char *fnc,
+ *               int line,
+ *               const char *fmt,
+ *               void *data,
+ *               va_list args)
+ * {
+ *    Data *d;
+ *    FILE *output;
+ *    char *str;
+ *
+ *    d = (Data *)data;
+ *    if (d->to_stderr)
+ *    {
+ *       output = stderr;
+ *       str = "stderr";
+ *    }
+ *    else
+ *    {
+ *       output = stdout;
+ *       str = "stdout";
+ *    }
+ *
+ *    fprintf(output, "%s:%s:%s (%d) %s: ",
+ *            domain->domain_str, file, fnc, line, str);
+ *    vfprintf(output, fmt, args);
+ *    putc('\n', output);
+ * }
+ *
+ * void test(Data *data, int i)
+ * {
+ *    if (i < 0)
+ *       data->to_stderr = 0;
+ *    else
+ *       data->to_stderr = 1;
+ *
+ *    log("log message...");
+ * }
+ *
+ * int main(void)
+ * {
+ *    Data data;
+ *
+ *    if (!eina_init())
+ *    {
+ *       printf("log during the initialization of Eina_Log module\n");
+ *       return EXIT_FAILURE;
+ *    }
+ *
+ *    eina_log_print_cb_set(print_cb, &data);
+ *
+ *    test(&data, -1);
+ *    test(&data, 0);
+ *
+ *    eina_shutdown();
+ *
+ *    return EXIT_SUCCESS;
+ * }
+ * @endcode
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+#include <assert.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#ifdef EFL_HAVE_POSIX_THREADS
+# include <pthread.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_inlist.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_log.h"
+
+/* TODO
+ * + printing logs to stdout or stderr can be implemented
+ * using a queue, useful for multiple threads printing
+ * + add a wrapper for assert?
+ */
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#define EINA_LOG_ENV_ABORT "EINA_LOG_ABORT"
+#define EINA_LOG_ENV_ABORT_LEVEL "EINA_LOG_ABORT_LEVEL"
+#define EINA_LOG_ENV_LEVEL "EINA_LOG_LEVEL"
+#define EINA_LOG_ENV_LEVELS "EINA_LOG_LEVELS"
+#define EINA_LOG_ENV_LEVELS_GLOB "EINA_LOG_LEVELS_GLOB"
+#define EINA_LOG_ENV_COLOR_DISABLE "EINA_LOG_COLOR_DISABLE"
+#define EINA_LOG_ENV_FILE_DISABLE "EINA_LOG_FILE_DISABLE"
+#define EINA_LOG_ENV_FUNCTION_DISABLE "EINA_LOG_FUNCTION_DISABLE"
+
+
+// Structure for storing domain level settings passed from the command line
+// that will be matched with application-defined domains.
+typedef struct _Eina_Log_Domain_Level_Pending Eina_Log_Domain_Level_Pending;
+struct _Eina_Log_Domain_Level_Pending
+{
+   EINA_INLIST;
+   unsigned int level;
+   size_t namelen;
+   char name[];
+};
+
+/*
+ * List of levels for domains set by the user before the domains are 
registered,
+ * updates the domain levels on the first log and clears itself.
+ */
+static Eina_Inlist *_pending_list = NULL;
+static Eina_Inlist *_glob_list = NULL;
+
+// Disable color flag (can be changed through the env var
+// EINA_LOG_ENV_COLOR_DISABLE).
+static Eina_Bool _disable_color = EINA_FALSE;
+static Eina_Bool _disable_file = EINA_FALSE;
+static Eina_Bool _disable_function = EINA_FALSE;
+static Eina_Bool _abort_on_critical = EINA_FALSE;
+static int _abort_level_on_critical = EINA_LOG_LEVEL_CRITICAL;
+
+#ifdef EFL_HAVE_THREADS
+
+static Eina_Bool _threads_enabled = EINA_FALSE;
+
+# ifdef EFL_HAVE_POSIX_THREADS
+
+typedef pthread_t Thread;
+
+static pthread_t _main_thread;
+
+#  define SELF() pthread_self()
+#  define IS_MAIN(t)  pthread_equal(t, _main_thread)
+#  define IS_OTHER(t) EINA_UNLIKELY(!IS_MAIN(t))
+#  define CHECK_MAIN(...)                                         \
+   do {                                                           \
+      if (!IS_MAIN(pthread_self())) {                             \
+         fprintf(stderr,                                          \
+                 "ERR: not main thread! current=%lu, main=%lu\n", \
+                 (unsigned long)pthread_self(),                   \
+                 (unsigned long)_main_thread);                    \
+         return __VA_ARGS__;                                      \
+      }                                                           \
+   } while (0)
+
+#  ifdef EFL_HAVE_POSIX_THREADS_SPINLOCK
+
+static pthread_spinlock_t _log_lock;
+#   define LOG_LOCK()                                                  \
+   if (_threads_enabled)                                               \
+         do {                                                          \
+            if (0) {                                                   \
+               fprintf(stderr, "+++LOG LOG_LOCKED!   [%s, %lu]\n",     \
+                       __FUNCTION__, (unsigned long)pthread_self()); } \
+            if (EINA_UNLIKELY(_threads_enabled)) {                     \
+               pthread_spin_lock(&_log_lock); }                        \
+         } while (0)
+#   define LOG_UNLOCK()                                                \
+   if (_threads_enabled)                                               \
+         do {                                                          \
+            if (EINA_UNLIKELY(_threads_enabled)) {                     \
+               pthread_spin_unlock(&_log_lock); }                      \
+            if (0) {                                                   \
+               fprintf(stderr,                                         \
+                       "---LOG LOG_UNLOCKED! [%s, %lu]\n",             \
+                       __FUNCTION__, (unsigned long)pthread_self()); } \
+         } while (0)
+#   define INIT() pthread_spin_init(&_log_lock, PTHREAD_PROCESS_PRIVATE)
+#   define SHUTDOWN() pthread_spin_destroy(&_log_lock)
+
+#  else /* ! EFL_HAVE_POSIX_THREADS_SPINLOCK */
+
+static pthread_mutex_t _log_mutex = PTHREAD_MUTEX_INITIALIZER;
+#   define LOG_LOCK() if(_threads_enabled) {pthread_mutex_lock(&_log_mutex); }
+#   define LOG_UNLOCK() if(_threads_enabled) 
{pthread_mutex_unlock(&_log_mutex); }
+#   define INIT() (1)
+#   define SHUTDOWN() do {} while (0)
+
+#  endif /* ! EFL_HAVE_POSIX_THREADS_SPINLOCK */
+
+# else /* EFL_HAVE_WIN32_THREADS */
+
+typedef DWORD Thread;
+
+static DWORD _main_thread;
+
+#  define SELF() GetCurrentThreadId()
+#  define IS_MAIN(t)  (t == _main_thread)
+#  define IS_OTHER(t) EINA_UNLIKELY(!IS_MAIN(t))
+#  define CHECK_MAIN(...)                                         \
+   do {                                                           \
+      if (!IS_MAIN(GetCurrentThreadId())) {                       \
+         fprintf(stderr,                                          \
+                 "ERR: not main thread! current=%lu, main=%lu\n", \
+                 GetCurrentThreadId(), _main_thread);             \
+         return __VA_ARGS__;                                      \
+      }                                                           \
+   } while (0)
+
+static HANDLE _log_mutex = NULL;
+
+#  define LOG_LOCK() if(_threads_enabled) WaitForSingleObject(_log_mutex, 
INFINITE)
+#  define LOG_UNLOCK() if(_threads_enabled) ReleaseMutex(_log_mutex)
+#  define INIT() ((_log_mutex = CreateMutex(NULL, FALSE, NULL)) ? 1 : 0)
+#  define SHUTDOWN()  if (_log_mutex) CloseHandle(_log_mutex)
+
+# endif /* EFL_HAVE_WIN32_THREADS */
+
+#else /* ! EFL_HAVE_THREADS */
+
+# define LOG_LOCK() do {} while (0)
+# define LOG_UNLOCK() do {} while (0)
+# define IS_MAIN(t)  (1)
+# define IS_OTHER(t) (0)
+# define CHECK_MAIN(...) do {} while (0)
+# define INIT() (1)
+# define SHUTDOWN() do {} while (0)
+
+#endif /* ! EFL_HAVE_THREADS */
+
+
+// List of domains registered
+static Eina_Log_Domain *_log_domains = NULL;
+static unsigned int _log_domains_count = 0;
+static size_t _log_domains_allocated = 0;
+
+// Default function for printing on domains
+static Eina_Log_Print_Cb _print_cb = eina_log_print_cb_stderr;
+static void *_print_cb_data = NULL;
+
+#ifdef DEBUG
+static Eina_Log_Level _log_level = EINA_LOG_LEVEL_DBG;
+#elif DEBUG_CRITICAL
+static Eina_Log_Level _log_level = EINA_LOG_LEVEL_CRITICAL;
+#else
+static Eina_Log_Level _log_level = EINA_LOG_LEVEL_ERR;
+#endif
+
+/* NOTE: if you change this, also change:
+ *   eina_log_print_level_name_get()
+ *   eina_log_print_level_name_color_get()
+ */
+static const char *_names[] = {
+   "CRI",
+   "ERR",
+   "WRN",
+   "INF",
+   "DBG",
+};
+
+#ifdef _WIN32
+static int
+eina_log_win32_color_get(const char *domain_str)
+{
+   char *str;
+   char *tmp;
+   char *tmp2;
+   int code = -1;
+   int lighted = 0;
+   int ret = 0;
+
+   str = strdup(domain_str);
+   if (!str)
+      return 0;
+
+   /* this should not append */
+   if (str[0] != '\033')
+     {
+        free(str);
+        return 0;
+     }
+
+   /* we skip the first char and the [ */
+   tmp = tmp2 = str + 2;
+   while (*tmp != 'm')
+     {
+        if (*tmp == ';')
+          {
+             *tmp = '\0';
+             code = atol(tmp2);
+             tmp++;
+             tmp2 = tmp;
+          }
+
+        tmp++;
+     }
+   *tmp = '\0';
+   if (code < 0)
+      code = atol(tmp2);
+   else
+      lighted = atol(tmp2);
+
+   free(str);
+
+   if (code < lighted)
+     {
+        int c;
+
+        c = code;
+        code = lighted;
+        lighted = c;
+     }
+
+   if (lighted)
+      ret = FOREGROUND_INTENSITY;
+
+   if (code == 31)
+      ret |= FOREGROUND_RED;
+   else if (code == 32)
+      ret |= FOREGROUND_GREEN;
+   else if (code == 33)
+      ret |= FOREGROUND_RED | FOREGROUND_GREEN;
+   else if (code == 34)
+      ret |= FOREGROUND_BLUE;
+   else if (code == 36)
+      ret |= FOREGROUND_GREEN | FOREGROUND_BLUE;
+   else if (code == 37)
+      ret |= FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
+
+   return ret;
+}
+#endif
+
+static inline void
+eina_log_print_level_name_get(int level, const char **p_name)
+{
+   static char buf[4];
+   /* NOTE: if you change this, also change
+    *    eina_log_print_level_name_color_get()
+    *    eina_log_level_name_get() (at eina_inline_log.x)
+    */
+   if (EINA_UNLIKELY(level < 0))
+     {
+        snprintf(buf, sizeof(buf), "%03d", level);
+        *p_name = buf;
+     }
+   else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
+     {
+        snprintf(buf, sizeof(buf), "%03d", level);
+        *p_name = buf;
+     }
+   else
+      *p_name = _names[level];
+}
+
+#ifdef _WIN32
+static inline void
+eina_log_print_level_name_color_get(int level,
+                                    const char **p_name,
+                                    int *p_color)
+{
+   static char buf[4];
+   /* NOTE: if you change this, also change:
+    *   eina_log_print_level_name_get()
+    */
+   if (EINA_UNLIKELY(level < 0))
+     {
+        snprintf(buf, sizeof(buf), "%03d", level);
+        *p_name = buf;
+     }
+   else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
+     {
+        snprintf(buf, sizeof(buf), "%03d", level);
+        *p_name = buf;
+     }
+   else
+      *p_name = _names[level];
+
+   *p_color = eina_log_win32_color_get(eina_log_level_color_get(level));
+}
+#else
+static inline void
+eina_log_print_level_name_color_get(int level,
+                                    const char **p_name,
+                                    const char **p_color)
+{
+   static char buf[4];
+   /* NOTE: if you change this, also change:
+    *   eina_log_print_level_name_get()
+    */
+   if (EINA_UNLIKELY(level < 0))
+     {
+        snprintf(buf, sizeof(buf), "%03d", level);
+        *p_name = buf;
+     }
+   else if (EINA_UNLIKELY(level >= EINA_LOG_LEVELS))
+     {
+        snprintf(buf, sizeof(buf), "%03d", level);
+        *p_name = buf;
+     }
+   else
+      *p_name = _names[level];
+
+   *p_color = eina_log_level_color_get(level);
+}
+#endif
+
+#define DECLARE_LEVEL_NAME(level) const char *name; \
+   eina_log_print_level_name_get(level, &name)
+#ifdef _WIN32
+# define DECLARE_LEVEL_NAME_COLOR(level) const char *name; int color; \
+   eina_log_print_level_name_color_get(level, &name, &color)
+#else
+# define DECLARE_LEVEL_NAME_COLOR(level) const char *name, *color; \
+   eina_log_print_level_name_color_get(level, &name, &color)
+#endif
+
+/** No threads, No color */
+static void
+eina_log_print_prefix_NOthreads_NOcolor_file_func(FILE *fp,
+                                                  const Eina_Log_Domain *d,
+                                                  Eina_Log_Level level,
+                                                  const char *file,
+                                                  const char *fnc,
+                                                  int line)
+{
+   DECLARE_LEVEL_NAME(level);
+   fprintf(fp, "%s:%s %s:%d %s() ", name, d->domain_str, file, line, fnc);
+}
+
+static void
+eina_log_print_prefix_NOthreads_NOcolor_NOfile_func(FILE *fp,
+                                                    const Eina_Log_Domain *d,
+                                                    Eina_Log_Level level,
+                                                    const char *file 
__UNUSED__,
+                                                    const char *fnc,
+                                                    int line __UNUSED__)
+{
+   DECLARE_LEVEL_NAME(level);
+   fprintf(fp, "%s:%s %s() ", name, d->domain_str, fnc);
+}
+
+static void
+eina_log_print_prefix_NOthreads_NOcolor_file_NOfunc(FILE *fp,
+                                                    const Eina_Log_Domain *d,
+                                                    Eina_Log_Level level,
+                                                    const char *file,
+                                                    const char *fnc __UNUSED__,
+                                                    int line)
+{
+   DECLARE_LEVEL_NAME(level);
+   fprintf(fp, "%s:%s %s:%d ", name, d->domain_str, file, line);
+}
+
+/* No threads, color */
+static void
+eina_log_print_prefix_NOthreads_color_file_func(FILE *fp,
+                                                const Eina_Log_Domain *d,
+                                                Eina_Log_Level level,
+                                                const char *file,
+                                                const char *fnc,
+                                                int line)
+{
+   DECLARE_LEVEL_NAME_COLOR(level);
+#ifdef _WIN32
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           color);
+   fprintf(fp, "%s", name);
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           FOREGROUND_RED | FOREGROUND_GREEN | 
FOREGROUND_BLUE);
+   fprintf(fp, ":");
+   SetConsoleTextAttribute(GetStdHandle(
+                              STD_OUTPUT_HANDLE),
+                           eina_log_win32_color_get(d->domain_str));
+   fprintf(fp, "%s", d->name);
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           FOREGROUND_RED | FOREGROUND_GREEN | 
FOREGROUND_BLUE);
+   fprintf(fp, " %s:%d ", file, line);
+   SetConsoleTextAttribute(GetStdHandle(
+                              STD_OUTPUT_HANDLE),
+                           FOREGROUND_INTENSITY | FOREGROUND_RED |
+                           FOREGROUND_GREEN | FOREGROUND_BLUE);
+   fprintf(fp, "%s()", fnc);
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           FOREGROUND_RED | FOREGROUND_GREEN | 
FOREGROUND_BLUE);
+   fprintf(fp, " ");
+#else
+   fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s %s:%d "
+           EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
+           color, name, d->domain_str, file, line, fnc);
+#endif
+}
+
+static void
+eina_log_print_prefix_NOthreads_color_NOfile_func(FILE *fp,
+                                                  const Eina_Log_Domain *d,
+                                                  Eina_Log_Level level,
+                                                  const char *file __UNUSED__,
+                                                  const char *fnc,
+                                                  int line __UNUSED__)
+{
+   DECLARE_LEVEL_NAME_COLOR(level);
+#ifdef _WIN32
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           color);
+   fprintf(fp, "%s", name);
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           FOREGROUND_RED | FOREGROUND_GREEN | 
FOREGROUND_BLUE);
+   fprintf(fp, ":");
+   SetConsoleTextAttribute(GetStdHandle(
+                              STD_OUTPUT_HANDLE),
+                           eina_log_win32_color_get(d->domain_str));
+   fprintf(fp, "%s", d->name);
+   SetConsoleTextAttribute(GetStdHandle(
+                              STD_OUTPUT_HANDLE),
+                           FOREGROUND_INTENSITY | FOREGROUND_RED |
+                           FOREGROUND_GREEN | FOREGROUND_BLUE);
+   fprintf(fp, "%s()", fnc);
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           FOREGROUND_RED | FOREGROUND_GREEN | 
FOREGROUND_BLUE);
+   fprintf(fp, " ");
+#else
+   fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s "
+           EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
+           color, name, d->domain_str, fnc);
+#endif
+}
+
+static void
+eina_log_print_prefix_NOthreads_color_file_NOfunc(FILE *fp,
+                                                  const Eina_Log_Domain *d,
+                                                  Eina_Log_Level level,
+                                                  const char *file,
+                                                  const char *fnc __UNUSED__,
+                                                  int line)
+{
+   DECLARE_LEVEL_NAME_COLOR(level);
+#ifdef _WIN32
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           color);
+   fprintf(fp, "%s", name);
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           FOREGROUND_RED | FOREGROUND_GREEN | 
FOREGROUND_BLUE);
+   fprintf(fp, ":");
+   SetConsoleTextAttribute(GetStdHandle(
+                              STD_OUTPUT_HANDLE),
+                           eina_log_win32_color_get(d->domain_str));
+   fprintf(fp, "%s", d->name);
+   SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                           FOREGROUND_RED | FOREGROUND_GREEN | 
FOREGROUND_BLUE);
+   fprintf(fp, " %s:%d ", file, line);
+#else
+   fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s %s:%d ",
+           color, name, d->domain_str, file, line);
+#endif
+}
+
+/** threads, No color */
+#ifdef EFL_HAVE_THREADS
+static void
+eina_log_print_prefix_threads_NOcolor_file_func(FILE *fp,
+                                                const Eina_Log_Domain *d,
+                                                Eina_Log_Level level,
+                                                const char *file,
+                                                const char *fnc,
+                                                int line)
+{
+   Thread cur;
+
+   DECLARE_LEVEL_NAME(level);
+   cur = SELF();
+   if (IS_OTHER(cur))
+     {
+        fprintf(fp, "%s:%s[T:%lu] %s:%d %s() ",
+                name, d->domain_str, (unsigned long)cur, file, line, fnc);
+        return;
+     }
+
+        fprintf(fp, "%s:%s %s:%d %s() ", name, d->domain_str, file, line, fnc);
+}
+
+static void
+eina_log_print_prefix_threads_NOcolor_NOfile_func(FILE *fp,
+                                                  const Eina_Log_Domain *d,
+                                                  Eina_Log_Level level,
+                                                  const char *file __UNUSED__,
+                                                  const char *fnc,
+                                                  int line __UNUSED__)
+{
+   Thread cur;
+
+   DECLARE_LEVEL_NAME(level);
+   cur = SELF();
+   if (IS_OTHER(cur))
+     {
+        fprintf(fp, "%s:%s[T:%lu] %s() ",
+                name, d->domain_str, (unsigned long)cur, fnc);
+        return;
+     }
+
+        fprintf(fp, "%s:%s %s() ", name, d->domain_str, fnc);
+}
+
+static void
+eina_log_print_prefix_threads_NOcolor_file_NOfunc(FILE *fp,
+                                                  const Eina_Log_Domain *d,
+                                                  Eina_Log_Level level,
+                                                  const char *file,
+                                                  const char *fnc __UNUSED__,
+                                                  int line)
+{
+   Thread cur;
+
+   DECLARE_LEVEL_NAME(level);
+   cur = SELF();
+   if (IS_OTHER(cur))
+     {
+        fprintf(fp, "%s:%s[T:%lu] %s:%d ",
+                name, d->domain_str, (unsigned long)cur, file, line);
+        return;
+     }
+
+        fprintf(fp, "%s:%s %s:%d ", name, d->domain_str, file, line);
+}
+
+/* threads, color */
+static void
+eina_log_print_prefix_threads_color_file_func(FILE *fp,
+                                              const Eina_Log_Domain *d,
+                                              Eina_Log_Level level,
+                                              const char *file,
+                                              const char *fnc,
+                                              int line)
+{
+   Thread cur;
+
+   DECLARE_LEVEL_NAME_COLOR(level);
+   cur = SELF();
+   if (IS_OTHER(cur))
+     {
+# ifdef _WIN32
+        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                                color);
+        fprintf(fp, "%s", name);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, ":");
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                eina_log_win32_color_get(d->domain_str));
+        fprintf(fp, "%s[T:", d->name);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, "[T:");
+        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                                FOREGROUND_GREEN | FOREGROUND_BLUE);
+        fprintf(fp, "%lu", (unsigned long)cur);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, "] %s:%d ", file, line);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_INTENSITY | FOREGROUND_RED |
+                                FOREGROUND_GREEN | FOREGROUND_BLUE);
+        fprintf(fp, "%s()", fnc);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, " ");
+# else
+        fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s[T:"
+                EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] %s:%d "
+                EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
+                color, name, d->domain_str, (unsigned long)cur, file,
+               line, fnc);
+# endif
+        return;
+     }
+
+# ifdef _WIN32
+   eina_log_print_prefix_NOthreads_color_file_func(fp,
+                                                   d,
+                                                   level,
+                                                   file,
+                                                   fnc,
+                                                   line);
+# else
+   fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s %s:%d "
+           EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
+           color, name, d->domain_str, file, line, fnc);
+# endif
+}
+
+static void
+eina_log_print_prefix_threads_color_NOfile_func(FILE *fp,
+                                                const Eina_Log_Domain *d,
+                                                Eina_Log_Level level,
+                                                const char *file __UNUSED__,
+                                                const char *fnc,
+                                                int line __UNUSED__)
+{
+   Thread cur;
+
+   DECLARE_LEVEL_NAME_COLOR(level);
+   cur = SELF();
+   if (IS_OTHER(cur))
+     {
+# ifdef _WIN32
+        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                                color);
+        fprintf(fp, "%s", name);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, ":");
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                eina_log_win32_color_get(d->domain_str));
+        fprintf(fp, "%s[T:", d->name);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, "[T:");
+        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                                FOREGROUND_GREEN | FOREGROUND_BLUE);
+        fprintf(fp, "%lu", (unsigned long)cur);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_INTENSITY | FOREGROUND_RED |
+                                FOREGROUND_GREEN | FOREGROUND_BLUE);
+        fprintf(fp, "%s()", fnc);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, " ");
+# else
+        fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s[T:"
+                EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] "
+                EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
+                color, name, d->domain_str, (unsigned long)cur, fnc);
+# endif
+        return;
+     }
+
+# ifdef _WIN32
+   eina_log_print_prefix_NOthreads_color_NOfile_func(fp,
+                                                     d,
+                                                     level,
+                                                     file,
+                                                     fnc,
+                                                     line);
+# else
+   fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s "
+           EINA_COLOR_HIGH "%s()" EINA_COLOR_RESET " ",
+           color, name, d->domain_str, fnc);
+# endif
+}
+
+static void
+eina_log_print_prefix_threads_color_file_NOfunc(FILE *fp,
+                                                const Eina_Log_Domain *d,
+                                                Eina_Log_Level level,
+                                                const char *file,
+                                                const char *fnc __UNUSED__,
+                                                int line)
+{
+   Thread cur;
+
+   DECLARE_LEVEL_NAME_COLOR(level);
+   cur = SELF();
+   if (IS_OTHER(cur))
+     {
+# ifdef _WIN32
+        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                                color);
+        fprintf(fp, "%s", name);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, ":");
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                eina_log_win32_color_get(d->domain_str));
+        fprintf(fp, "%s[T:", d->name);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, "[T:");
+        SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),
+                                FOREGROUND_GREEN | FOREGROUND_BLUE);
+        fprintf(fp, "%lu", (unsigned long)cur);
+        SetConsoleTextAttribute(GetStdHandle(
+                                   STD_OUTPUT_HANDLE),
+                                FOREGROUND_RED | FOREGROUND_GREEN |
+                                FOREGROUND_BLUE);
+        fprintf(fp, "] %s:%d ", file, line);
+# else
+        fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s[T:"
+                EINA_COLOR_ORANGE "%lu" EINA_COLOR_RESET "] %s:%d ",
+                color, name, d->domain_str, (unsigned long)cur, file, line);
+# endif
+        return;
+     }
+
+# ifdef _WIN32
+   eina_log_print_prefix_NOthreads_color_file_NOfunc(fp,
+                                                     d,
+                                                     level,
+                                                     file,
+                                                     fnc,
+                                                     line);
+# else
+        fprintf(fp, "%s%s" EINA_COLOR_RESET ":%s %s:%d ",
+           color, name, d->domain_str, file, line);
+# endif
+}
+#endif /* EFL_HAVE_THREADS */
+
+static void (*_eina_log_print_prefix)(FILE *fp, const Eina_Log_Domain *d,
+                                      Eina_Log_Level level, const char *file,
+                                      const char *fnc,
+                                      int line) =
+   eina_log_print_prefix_NOthreads_color_file_func;
+
+static inline void
+eina_log_print_prefix_update(void)
+{
+   if (_disable_file && _disable_function)
+     {
+        fprintf(stderr, "ERROR: cannot have " EINA_LOG_ENV_FILE_DISABLE " and "
+                EINA_LOG_ENV_FUNCTION_DISABLE " set at the same time, will "
+                                              "just disable function.\n");
+        _disable_file = 0;
+     }
+
+#define S(NOthread, NOcolor, NOfile, NOfunc) \
+   _eina_log_print_prefix = \
+      eina_log_print_prefix_ ## NOthread ## threads_ ## NOcolor ## color_ ## \
+      NOfile \
+      ## file_ ## NOfunc ## func
+
+#ifdef EFL_HAVE_THREADS
+   if (_threads_enabled)
+     {
+        if (_disable_color)
+          {
+             if (_disable_file)
+                S(,NO,NO,);
+             else if (_disable_function)
+                S(,NO,,NO);
+             else
+                S(,NO,,);
+          }
+        else
+          {
+             if (_disable_file)
+                S(,,NO,);
+             else if (_disable_function)
+                S(,,,NO);
+             else
+                S(,,,);
+          }
+
+        return;
+     }
+
+#endif
+
+   if (_disable_color)
+     {
+        if (_disable_file)
+                S(NO,NO,NO,);
+        else if (_disable_function)
+                S(NO,NO,,NO);
+        else
+                S(NO,NO,,);
+     }
+   else
+     {
+        if (_disable_file)
+                S(NO,,NO,);
+        else if (_disable_function)
+                S(NO,,,NO);
+        else
+                S(NO,,,);
+     }
+
+#undef S
+}
+
+/*
+ * Creates a colored domain name string.
+ */
+static const char *
+eina_log_domain_str_get(const char *name, const char *color)
+{
+   const char *d;
+
+   if (color)
+     {
+        size_t name_len;
+        size_t color_len;
+
+        name_len = strlen(name);
+        color_len = strlen(color);
+        d =
+           malloc(sizeof(char) *
+                  (color_len + name_len + strlen(EINA_COLOR_RESET) + 1));
+        if (!d)
+           return NULL;
+
+               memcpy((char *)d,                          color, color_len);
+               memcpy((char *)(d + color_len),            name,  name_len);
+               memcpy((char *)(d + color_len + name_len), EINA_COLOR_RESET,
+               strlen(EINA_COLOR_RESET));
+        ((char *)d)[color_len + name_len + strlen(EINA_COLOR_RESET)] = '\0';
+     }
+   else
+      d = strdup(name);
+
+   return d;
+}
+
+/*
+ * Setups a new logging domain to the name and color specified. Note that this
+ * constructor acts upon an pre-allocated object.
+ */
+static Eina_Log_Domain *
+eina_log_domain_new(Eina_Log_Domain *d, const char *name, const char *color)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(d,    NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+
+   d->level = EINA_LOG_LEVEL_UNKNOWN;
+   d->deleted = EINA_FALSE;
+
+   if (name)
+     {
+        if ((color) && (!_disable_color))
+           d->domain_str = eina_log_domain_str_get(name, color);
+        else
+           d->domain_str = eina_log_domain_str_get(name, NULL);
+
+        d->name = strdup(name);
+        d->namelen = strlen(name);
+     }
+   else
+     {
+        d->domain_str = NULL;
+        d->name = NULL;
+        d->namelen = 0;
+     }
+
+   return d;
+}
+
+/*
+ * Frees internal strings of a log domain, keeping the log domain itself as a
+ * slot for next domain registers.
+ */
+static void
+eina_log_domain_free(Eina_Log_Domain *d)
+{
+   EINA_SAFETY_ON_NULL_RETURN(d);
+
+   if (d->domain_str)
+      free((char *)d->domain_str);
+
+   if (d->name)
+      free((char *)d->name);
+}
+
+/*
+ * Parses domain levels passed through the env var.
+ */
+static void
+eina_log_domain_parse_pendings(void)
+{
+   const char *start;
+
+   if (!(start = getenv(EINA_LOG_ENV_LEVELS)))
+      return;
+
+   // name1:level1,name2:level2,name3:level3,...
+   while (1)
+     {
+        Eina_Log_Domain_Level_Pending *p;
+        char *end = NULL;
+        char *tmp = NULL;
+        long int level;
+
+        end = strchr(start, ':');
+        if (!end)
+           break;
+
+        // Parse level, keep going if failed
+        level = strtol((char *)(end + 1), &tmp, 10);
+        if (tmp == (end + 1))
+           goto parse_end;
+
+        // Parse name
+        p = malloc(sizeof(Eina_Log_Domain_Level_Pending) + end - start + 1);
+        if (!p)
+           break;
+
+        p->namelen = end - start;
+        memcpy((char *)p->name, start, end - start);
+        ((char *)p->name)[end - start] = '\0';
+        p->level = level;
+
+        _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(p));
+
+parse_end:
+        start = strchr(tmp, ',');
+        if (start)
+           start++;
+        else
+           break;
+     }
+}
+
+static void
+eina_log_domain_parse_pending_globs(void)
+{
+   const char *start;
+
+   if (!(start = getenv(EINA_LOG_ENV_LEVELS_GLOB)))
+      return;
+
+   // name1:level1,name2:level2,name3:level3,...
+   while (1)
+     {
+        Eina_Log_Domain_Level_Pending *p;
+        char *end = NULL;
+        char *tmp = NULL;
+        long int level;
+
+        end = strchr(start, ':');
+        if (!end)
+           break;
+
+        // Parse level, keep going if failed
+        level = strtol((char *)(end + 1), &tmp, 10);
+        if (tmp == (end + 1))
+           goto parse_end;
+
+        // Parse name
+        p = malloc(sizeof(Eina_Log_Domain_Level_Pending) + end - start + 1);
+        if (!p)
+           break;
+
+        p->namelen = 0; /* not that useful */
+        memcpy((char *)p->name, start, end - start);
+        ((char *)p->name)[end - start] = '\0';
+        p->level = level;
+
+        _glob_list = eina_inlist_append(_glob_list, EINA_INLIST_GET(p));
+
+parse_end:
+        start = strchr(tmp, ',');
+        if (start)
+           start++;
+        else
+           break;
+     }
+}
+
+static inline int
+eina_log_domain_register_unlocked(const char *name, const char *color)
+{
+   Eina_Log_Domain_Level_Pending *pending = NULL;
+   size_t namelen;
+   unsigned int i;
+
+   for (i = 0; i < _log_domains_count; i++)
+     {
+        if (_log_domains[i].deleted)
+          {
+             // Found a flagged slot, free domain_str and replace slot
+             eina_log_domain_new(&_log_domains[i], name, color);
+             goto finish_register;
+          }
+     }
+
+   if (_log_domains_count >= _log_domains_allocated)
+     {
+        Eina_Log_Domain *tmp;
+        size_t size;
+
+        if (!_log_domains)
+           // special case for init, eina itself will allocate a dozen of 
domains
+           size = 24;
+        else
+           // grow 8 buckets to minimize reallocs
+           size = _log_domains_allocated + 8;
+
+        tmp = realloc(_log_domains, sizeof(Eina_Log_Domain) * size);
+
+        if (tmp)
+          {
+             // Success!
+             _log_domains = tmp;
+             _log_domains_allocated = size;
+          }
+        else
+           return -1;
+     }
+
+   // Use an allocated slot
+             eina_log_domain_new(&_log_domains[i], name, color);
+   _log_domains_count++;
+
+finish_register:
+   namelen = _log_domains[i].namelen;
+
+   EINA_INLIST_FOREACH(_pending_list, pending)
+   {
+      if ((namelen == pending->namelen) && (strcmp(pending->name, name) == 0))
+        {
+           _log_domains[i].level = pending->level;
+           _pending_list =
+              eina_inlist_remove(_pending_list, EINA_INLIST_GET(pending));
+           free(pending);
+           break;
+        }
+   }
+
+   if (_log_domains[i].level == EINA_LOG_LEVEL_UNKNOWN)
+     {
+        EINA_INLIST_FOREACH(_glob_list, pending)
+        {
+           if (!fnmatch(pending->name, name, 0))
+             {
+                _log_domains[i].level = pending->level;
+                break;
+             }
+        }
+     }
+
+   // Check if level is still UNKNOWN, set it to global
+   if (_log_domains[i].level == EINA_LOG_LEVEL_UNKNOWN)
+      _log_domains[i].level = _log_level;
+
+   return i;
+}
+
+static inline Eina_Bool
+eina_log_term_color_supported(const char *term)
+{
+   const char *tail;
+
+   if (!term)
+      return EINA_FALSE;
+
+   tail = term + 1;
+   switch (term[0])
+     {
+      /* list of known to support color terminals,
+       * take from gentoo's portage.
+       */
+
+      case 'x': /* xterm and xterm-color */
+         return ((strncmp(tail, "term", sizeof("term") - 1) == 0) &&
+                 ((tail[sizeof("term") - 1] == '\0') ||
+                  (strcmp(tail + sizeof("term") - 1, "-color") == 0)));
+
+      case 'E': /* Eterm */
+      case 'a': /* aterm */
+      case 'k': /* kterm */
+         return (strcmp(tail, "term") == 0);
+
+      case 'r': /* xrvt or rxvt-unicode */
+         return ((strncmp(tail, "xvt", sizeof("xvt") - 1) == 0) &&
+                 ((tail[sizeof("xvt") - 1] == '\0') ||
+                  (strcmp(tail + sizeof("xvt") - 1, "-unicode") == 0)));
+
+      case 's': /* screen */
+         return (strcmp(tail, "creen") == 0);
+
+      case 'g': /* gnome */
+         return (strcmp(tail, "nome") == 0);
+
+      case 'i': /* interix */
+         return (strcmp(tail, "nterix") == 0);
+
+      default:
+         return EINA_FALSE;
+     }
+}
+
+static inline void
+eina_log_domain_unregister_unlocked(int domain)
+{
+   Eina_Log_Domain *d;
+
+   if ((unsigned int)domain >= _log_domains_count)
+      return;
+
+   d = &_log_domains[domain];
+   eina_log_domain_free(d);
+   d->deleted = 1;
+}
+
+static inline void
+eina_log_print_unlocked(int domain,
+                        Eina_Log_Level level,
+                        const char *file,
+                        const char *fnc,
+                        int line,
+                        const char *fmt,
+                        va_list args)
+{
+   Eina_Log_Domain *d;
+
+#ifdef EINA_SAFETY_CHECKS
+   if (EINA_UNLIKELY((unsigned int)domain >= _log_domains_count) ||
+       EINA_UNLIKELY(domain < 0))
+     {
+        if (file && fnc && fmt)
+           fprintf(
+              stderr,
+              "CRI: %s:%d %s() eina_log_print() unknown domain %d, original 
message format '%s'\n",
+              file,
+              line,
+              fnc,
+              domain,
+              fmt);
+        else
+           fprintf(
+              stderr,
+              "CRI: eina_log_print() unknown domain %d, original message 
format '%s'\n",
+              domain,
+              fmt ? fmt : "");
+
+        if (_abort_on_critical)
+           abort();
+
+        return;
+     }
+
+#endif
+   d = _log_domains + domain;
+#ifdef EINA_SAFETY_CHECKS
+   if (EINA_UNLIKELY(d->deleted))
+     {
+           fprintf(stderr,
+                "ERR: eina_log_print() domain %d is deleted\n",
+                domain);
+        return;
+     }
+
+#endif
+
+   if (level > d->level)
+      return;
+
+#ifdef _WIN32
+   {
+      char *wfmt;
+      char *tmp;
+
+      wfmt = strdup(fmt);
+      if (!wfmt)
+        {
+           fprintf(stderr, "ERR: %s: can not allocate memory\n", __FUNCTION__);
+           return;
+        }
+
+      tmp = wfmt;
+      while (strchr(tmp, "%"))
+        {
+           tmp++;
+           if (*tmp == 'z')
+              *tmp = 'I';
+        }
+      _print_cb(d, level, file, fnc, line, wfmt, _print_cb_data, args);
+      free(wfmt);
+   }
+#else
+   _print_cb(d, level, file, fnc, line, fmt, _print_cb_data, args);
+#endif
+
+   if (EINA_UNLIKELY(_abort_on_critical) &&
+       EINA_UNLIKELY(level <= _abort_level_on_critical))
+      abort();
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the log module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the log module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ *
+ * @warning Not-MT: just call this function from main thread! The
+ *          place where this function was called the first time is
+ *          considered the main thread.
+ */
+Eina_Bool
+eina_log_init(void)
+{
+   const char *level, *tmp;
+   int color_disable;
+
+   assert((sizeof(_names) / sizeof(_names[0])) == EINA_LOG_LEVELS);
+
+   if ((tmp = getenv(EINA_LOG_ENV_COLOR_DISABLE)))
+      color_disable = atoi(tmp);
+   else
+      color_disable = -1;
+
+   /* Check if color is explicitly disabled */
+   if (color_disable == 1)
+      _disable_color = EINA_TRUE;
+
+#ifndef _WIN32
+   /* color was not explicitly disabled or enabled, guess it */
+   else if (color_disable == -1)
+     {
+        if (!eina_log_term_color_supported(getenv("TERM")))
+           _disable_color = EINA_TRUE;
+        else
+          {
+             /* if not a terminal, but redirected to a file, disable color */
+             int fd;
+
+             if (_print_cb == eina_log_print_cb_stderr)
+                fd = STDERR_FILENO;
+             else if (_print_cb == eina_log_print_cb_stdout)
+                fd = STDOUT_FILENO;
+             else
+                fd = -1;
+
+             if ((fd >= 0) && (!isatty(fd)))
+                _disable_color = EINA_TRUE;
+          }
+     }
+#endif
+
+   if ((tmp = getenv(EINA_LOG_ENV_FILE_DISABLE)) && (atoi(tmp) == 1))
+      _disable_file = EINA_TRUE;
+
+   if ((tmp = getenv(EINA_LOG_ENV_FUNCTION_DISABLE)) && (atoi(tmp) == 1))
+      _disable_function = EINA_TRUE;
+
+   if ((tmp = getenv(EINA_LOG_ENV_ABORT)) && (atoi(tmp) == 1))
+      _abort_on_critical = EINA_TRUE;
+
+   if ((tmp = getenv(EINA_LOG_ENV_ABORT_LEVEL)))
+      _abort_level_on_critical = atoi(tmp);
+
+   eina_log_print_prefix_update();
+
+   // Global log level
+   if ((level = getenv(EINA_LOG_ENV_LEVEL)))
+      _log_level = atoi(level);
+
+   // Register UNKNOWN domain, the default logger
+   EINA_LOG_DOMAIN_GLOBAL = eina_log_domain_register("", NULL);
+
+   if (EINA_LOG_DOMAIN_GLOBAL < 0)
+     {
+        fprintf(stderr, "Failed to create global logging domain.\n");
+        return EINA_FALSE;
+     }
+
+   // Parse pending domains passed through EINA_LOG_LEVELS_GLOB
+   eina_log_domain_parse_pending_globs();
+
+   // Parse pending domains passed through EINA_LOG_LEVELS
+   eina_log_domain_parse_pendings();
+
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the log module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the log module set up by
+ * eina_log_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ *
+ * @warning Not-MT: just call this function from main thread! The
+ *          place where eina_log_init() (eina_init()) was called the
+ *          first time is considered the main thread.
+ */
+Eina_Bool
+eina_log_shutdown(void)
+{
+   Eina_Inlist *tmp;
+
+   while (_log_domains_count--)
+     {
+        if (_log_domains[_log_domains_count].deleted)
+           continue;
+
+        eina_log_domain_free(&_log_domains[_log_domains_count]);
+     }
+
+        free(_log_domains);
+
+   _log_domains = NULL;
+   _log_domains_count = 0;
+   _log_domains_allocated = 0;
+
+   while (_glob_list)
+     {
+        tmp = _glob_list;
+        _glob_list = _glob_list->next;
+        free(tmp);
+     }
+
+   while (_pending_list)
+     {
+        tmp = _pending_list;
+        _pending_list = _pending_list->next;
+        free(tmp);
+     }
+
+   return EINA_TRUE;
+}
+
+#ifdef EFL_HAVE_THREADS
+
+/**
+ * @internal
+ * @brief Activate the log mutex.
+ *
+ * This function activate the mutex in the eina log module. It is called by
+ * eina_threads_init().
+ *
+ * @see eina_threads_init()
+ */
+void
+eina_log_threads_init(void)
+{
+   _main_thread = SELF();
+   if (INIT())
+      _threads_enabled = EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the log mutex.
+ *
+ * This function shuts down the mutex in the log module.
+ * It is called by eina_threads_shutdown().
+ *
+ * @see eina_threads_shutdown()
+ */
+void
+eina_log_threads_shutdown(void)
+{
+   CHECK_MAIN();
+   SHUTDOWN();
+   _threads_enabled = EINA_FALSE;
+}
+
+#endif
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Log_Group Log
+ *
+ * @brief Full-featured logging system.
+ *
+ * Eina provides eina_log_print(), a standard function to manage all
+ * logging messages. This function may be called directly or using the
+ * helper macros such as EINA_LOG_DBG(), EINA_LOG_ERR() or those that
+ * take a specific domain as argument EINA_LOG_DOM_DBG(),
+ * EINA_LOG_DOM_ERR().  Internally, eina_log_print() will call the
+ * function defined with eina_log_print_cb_set(), that defaults to
+ * eina_log_print_cb_stderr(), but may be changed to do whatever you
+ * need, such as networking or syslog logging.
+ *
+ * The logging system is thread safe once initialized with
+ * eina_log_threads_enable(). The thread that calls this function
+ * first is considered "main thread" and other threads will have their
+ * thread id (pthread_self()) printed in the log message so it is easy
+ * to detect from where it is coming.
+ *
+ * Log domains is the Eina way to differentiate messages. There might
+ * be different domains to represent different modules, different
+ * feature-set, different categories and so on. Filtering can be
+ * applied to domain names by means of @c EINA_LOG_LEVELS environment
+ * variable or eina_log_domain_level_set().
+ *
+ * The different logging levels serve to customize the amount of
+ * debugging one want to take and may be used to automatically call
+ * abort() once some given level message is printed. This is
+ * controlled by environment variable @c EINA_LOG_ABORT and the level
+ * to be considered critical with @c EINA_LOG_ABORT_LEVEL. These can
+ * be changed with eina_log_abort_on_critical_set() and
+ * eina_log_abort_on_critical_level_set().
+ *
+ * The default maximum level to print is defined by environment
+ * variable @c EINA_LOG_LEVEL, but may be set per-domain with @c
+ * EINA_LOG_LEVELS. It will default to #EINA_LOG_ERR. This can be
+ * changed with eina_log_level_set().
+ *
+ * To use the log system Eina must be initialized with eina_init() and
+ * later shut down with eina_shutdown(). Here is a straightforward
+ * example:
+ *
+ * @code
+ * #include <stdlib.h>
+ * #include <stdio.h>
+ *
+ * #include <eina_log.h>
+ *
+ * void test_warn(void)
+ * {
+ *    EINA_LOG_WARN("Here is a warning message");
+ * }
+ *
+ * int main(void)
+ * {
+ *    if (!eina_init())
+ *    {
+ *        printf("log during the initialization of Eina_Log module\n");
+ *        return EXIT_FAILURE;
+ *    }
+ *
+ *    test_warn();
+ *
+ *    eina_shutdown();
+ *
+ *    return EXIT_SUCCESS;
+ * }
+ * @endcode
+ *
+ * Compile this code with the following command:
+ *
+ * @code
+ * gcc -Wall -o test_Eina_Log test_eina.c `pkg-config --cflags --libs eina`
+ * @endcode
+ *
+ * Now execute the program with:
+ *
+ * @code
+ * EINA_LOG_LEVEL=2 ./test_eina_log
+ * @endcode
+ *
+ * You should see a message displayed in the terminal.
+ *
+ * For more information, you can look at the @ref tutorial_log_page.
+ *
+ * @{
+ */
+
+
+/**
+ * @cond LOCAL
+ */
+
+EAPI int EINA_LOG_DOMAIN_GLOBAL = 0;
+
+/**
+ * @endcond
+ */
+
+
+/**
+ * Enable logging module to handle threads.
+ *
+ * There is no disable option on purpose, if it is enabled, there is
+ * no way back until you call the last eina_shutdown().
+ *
+ * There is no function to retrieve if threads are enabled as one is
+ * not supposed to know this from outside.
+ *
+ * After this call is executed at least once, if Eina was compiled
+ * with threads support then logging will lock around debug messages
+ * and threads that are not the main thread will have its identifier
+ * printed.
+ *
+ * The main thread is considered the thread where the first
+ * eina_init() was called.
+ */
+EAPI void
+eina_log_threads_enable(void)
+{
+#ifdef EFL_HAVE_THREADS
+   _threads_enabled = 1;
+   eina_log_print_prefix_update();
+#endif
+}
+
+/**
+ * Sets logging method to use.
+ *
+ * @param cb The callback to call when printing a log.
+ * @param data The data to pass to the callback.
+ *
+ * By default, eina_log_print_cb_stderr() is used.
+ *
+ * @note MT: safe to call from any thread.
+ *
+ * @note MT: given function @a cb will be called protected by mutex.
+ *       This means you're safe from other calls but you should never
+ *       call eina_log_print(), directly or indirectly.
+ */
+EAPI void
+eina_log_print_cb_set(Eina_Log_Print_Cb cb, void *data)
+{
+   LOG_LOCK();
+   _print_cb = cb;
+   _print_cb_data = data;
+   eina_log_print_prefix_update();
+   LOG_UNLOCK();
+}
+
+/**
+ * @brief Set the default log level.
+ *
+ * @param level The log level.
+ *
+ * This function sets the log level @p level. It is used in
+ * eina_log_print().
+ *
+ * @note this is initially set to envvar EINA_LOG_LEVEL by eina_init().
+ *
+ * @see eina_log_level_get()
+ */
+EAPI void
+eina_log_level_set(int level)
+{
+   _log_level = level;
+   if (EINA_LIKELY((EINA_LOG_DOMAIN_GLOBAL >= 0) &&
+                   ((unsigned int)EINA_LOG_DOMAIN_GLOBAL < 
_log_domains_count)))
+      _log_domains[EINA_LOG_DOMAIN_GLOBAL].level = level;
+}
+
+/**
+ * @brief Get the default log level.
+ *
+ * @return the log level that limits eina_log_print().
+ *
+ * @see eina_log_level_set()
+ */
+EAPI int
+eina_log_level_get(void)
+{
+   return _log_level;
+}
+
+/**
+ * Checks if current thread is the main thread.
+ *
+ * @return #EINA_TRUE if threads were enabled and the current thread
+ *         is the one that called eina_log_threads_init(). If there is
+ *         no thread support (compiled with --disable-pthreads) or
+ *         they were not enabled, then #EINA_TRUE is also
+ *         returned. The only case where #EINA_FALSE is returned is
+ *         when threads were successfully enabled but the current
+ *         thread is not the main (one that called
+ *         eina_log_threads_init()).
+ */
+EAPI Eina_Bool
+eina_log_main_thread_check(void)
+{
+#ifdef EFL_HAVE_THREADS
+   return ((!_threads_enabled) || IS_MAIN(SELF()));
+#else
+   return EINA_TRUE;
+#endif
+}
+
+/**
+ * @brief Set if color logging should be disabled.
+ *
+ * @param disabled if #EINA_TRUE, color logging should be disabled.
+ *
+ * @note this is initially set to envvar EINA_LOG_COLOR_DISABLE by eina_init().
+ *
+ * @see eina_log_color_disable_get()
+ */
+EAPI void
+eina_log_color_disable_set(Eina_Bool disabled)
+{
+   _disable_color = disabled;
+}
+
+/**
+ * @brief Get if color logging should be disabled.
+ *
+ * @return if #EINA_TRUE, color logging should be disabled.
+ *
+ * @see eina_log_color_disable_set()
+ */
+EAPI Eina_Bool
+eina_log_color_disable_get(void)
+{
+   return _disable_color;
+}
+
+/**
+ * @brief Set if originating file name logging should be disabled.
+ *
+ * @param disabled if #EINA_TRUE, file name logging should be disabled.
+ *
+ * @note this is initially set to envvar EINA_LOG_FILE_DISABLE by eina_init().
+ *
+ * @see eina_log_file_disable_get()
+ */
+EAPI void
+eina_log_file_disable_set(Eina_Bool disabled)
+{
+   _disable_file = disabled;
+}
+
+/**
+ * @brief Get if originating file name logging should be disabled.
+ *
+ * @return if #EINA_TRUE, file name logging should be disabled.
+ *
+ * @see eina_log_file_disable_set()
+ */
+EAPI Eina_Bool
+eina_log_file_disable_get(void)
+{
+   return _disable_file;
+}
+
+/**
+ * @brief Set if originating function name logging should be disabled.
+ *
+ * @param disabled if #EINA_TRUE, function name logging should be disabled.
+ *
+ * @note this is initially set to envvar EINA_LOG_FUNCTION_DISABLE by
+ *       eina_init().
+ *
+ * @see eina_log_function_disable_get()
+ */
+EAPI void
+eina_log_function_disable_set(Eina_Bool disabled)
+{
+   _disable_function = disabled;
+}
+
+/**
+ * @brief Get if originating function name logging should be disabled.
+ *
+ * @return if #EINA_TRUE, function name logging should be disabled.
+ *
+ * @see eina_log_function_disable_set()
+ */
+EAPI Eina_Bool
+eina_log_function_disable_get(void)
+{
+   return _disable_function;
+}
+
+/**
+ * @brief Set if critical messages should abort the program.
+ *
+ * @param abort_on_critical if #EINA_TRUE, messages with level equal
+ *        or smaller than eina_log_abort_on_critical_level_get() will
+ *        abort the program.
+ *
+ * @note this is initially set to envvar EINA_LOG_ABORT by
+ *       eina_init().
+ *
+ * @see eina_log_abort_on_critical_get()
+ * @see eina_log_abort_on_critical_level_set()
+ */
+EAPI void
+eina_log_abort_on_critical_set(Eina_Bool abort_on_critical)
+{
+   _abort_on_critical = abort_on_critical;
+}
+
+/**
+ * @brief Get if critical messages should abort the program.
+ *
+ * @return if #EINA_TRUE, any messages with level equal or smaller
+ *         than eina_log_abort_on_critical_level_get() will abort the
+ *         program.
+ *
+ * @see eina_log_abort_on_critical_set()
+ * @see eina_log_abort_on_critical_level_set()
+ */
+EAPI Eina_Bool
+eina_log_abort_on_critical_get(void)
+{
+   return _abort_on_critical;
+}
+
+/**
+ * @brief Set level that triggers abort if abort-on-critical is set.
+ *
+ * @param critical_level levels equal or smaller than the given value
+ *        will trigger program abortion if
+ *        eina_log_abort_on_critical_get() returns #EINA_TRUE.
+ *
+ * @note this is initially set to envvar EINA_LOG_ABORT_LEVEL by
+ *       eina_init().
+ *
+ * @see eina_log_abort_on_critical_level_get()
+ * @see eina_log_abort_on_critical_get()
+ */
+EAPI void
+eina_log_abort_on_critical_level_set(int critical_level)
+{
+   _abort_level_on_critical = critical_level;
+}
+
+/**
+ * @brief Get level that triggers abort if abort-on-critical is set.
+ *
+ * @return critical level equal or smaller than value will trigger
+ *        program abortion if eina_log_abort_on_critical_get() returns
+ *        #EINA_TRUE.
+ *
+ * @see eina_log_abort_on_critical_level_set()
+ * @see eina_log_abort_on_critical_get()
+ */
+EAPI int
+eina_log_abort_on_critical_level_get(void)
+{
+   return _abort_level_on_critical;
+}
+
+/**
+ * @param name Domain name
+ * @param color Color of the domain name
+ *
+ * @return Domain index that will be used as the DOMAIN parameter on log
+ *         macros. A negative return value means an log occurred.
+ *
+ * @note MT: safe to call from any thread.
+ */
+EAPI int
+eina_log_domain_register(const char *name, const char *color)
+{
+   int r;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, -1);
+
+   LOG_LOCK();
+   r = eina_log_domain_register_unlocked(name, color);
+   LOG_UNLOCK();
+   return r;
+}
+
+/**
+ * Forget about a logging domain registered by eina_log_domain_register()
+ *
+ * @param domain domain identifier as reported by eina_log_domain_register(),
+ *        must be >= 0.
+ *
+ * @note MT: safe to call from any thread.
+ */
+EAPI void
+eina_log_domain_unregister(int domain)
+{
+   EINA_SAFETY_ON_FALSE_RETURN(domain >= 0);
+   LOG_LOCK();
+   eina_log_domain_unregister_unlocked(domain);
+   LOG_UNLOCK();
+}
+
+/**
+ * Set the domain level given its name.
+ *
+ * This call has the same effect as setting
+ * EINA_LOG_LEVELS=&lt;@p domain_name&gt;:&lt;@p level&gt;
+ *
+ * @param domain_name domain name to change the level. It may be of a
+ *        still not registered domain. If the domain is not registered
+ *        yet, it will be saved as a pending set and applied upon
+ *        registration.
+ * @param level level to use to limit eina_log_print() for given domain.
+ */
+EAPI void
+eina_log_domain_level_set(const char *domain_name, int level)
+{
+   Eina_Log_Domain_Level_Pending *pending;
+   size_t namelen;
+   unsigned int i;
+
+   EINA_SAFETY_ON_NULL_RETURN(domain_name);
+
+   namelen = strlen(domain_name);
+
+   for (i = 0; i < _log_domains_count; i++)
+     {
+        if (_log_domains[i].deleted)
+           continue;
+
+        if ((namelen != _log_domains[i].namelen) ||
+            (strcmp(_log_domains[i].name, domain_name) != 0))
+           continue;
+
+        _log_domains[i].level = level;
+        return;
+     }
+
+   EINA_INLIST_FOREACH(_pending_list, pending)
+   {
+      if ((namelen == pending->namelen) &&
+          (strcmp(pending->name, domain_name) == 0))
+        {
+           pending->level = level;
+           return;
+        }
+   }
+
+   pending = malloc(sizeof(Eina_Log_Domain_Level_Pending) + namelen + 1);
+   if (!pending)
+      return;
+
+   pending->level = level;
+   pending->namelen = namelen;
+   memcpy(pending->name, domain_name, namelen + 1);
+
+   _pending_list = eina_inlist_append(_pending_list, EINA_INLIST_GET(pending));
+}
+
+/**
+ * Get the domain level given its name.
+ *
+ * @param domain_name domain name to retrieve the level. It may be of
+ *        a still not registered domain. If the domain is not
+ *        registered yet, but there is a pending value, either from
+ *        eina_log_domain_level_set(),EINA_LOG_LEVELS environment
+ *        variable or from EINA_LOG_LEVELS_GLOB, these are
+ *        returned. If nothing else was found, then the global/default
+ *        level (eina_log_level_get()) is returned.
+ *
+ * @return level to use to limit eina_log_print() for given
+ *         domain. On error (@p domain_name == NULL),
+ *         EINA_LOG_LEVEL_UNKNOWN is returned.
+ *
+ * @see eina_log_domain_level_set()
+ * @see eina_log_domain_registered_level_get()
+ */
+EAPI int
+eina_log_domain_level_get(const char *domain_name)
+{
+   Eina_Log_Domain_Level_Pending *pending;
+   size_t namelen;
+   unsigned int i;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(domain_name, EINA_LOG_LEVEL_UNKNOWN);
+
+   namelen = strlen(domain_name);
+
+   for (i = 0; i < _log_domains_count; i++)
+     {
+        if (_log_domains[i].deleted)
+           continue;
+
+        if ((namelen != _log_domains[i].namelen) ||
+            (strcmp(_log_domains[i].name, domain_name) != 0))
+           continue;
+
+        return _log_domains[i].level;
+     }
+
+   EINA_INLIST_FOREACH(_pending_list, pending)
+   {
+      if ((namelen == pending->namelen) &&
+          (strcmp(pending->name, domain_name) == 0))
+         return pending->level;
+   }
+
+   EINA_INLIST_FOREACH(_glob_list, pending)
+   {
+      if (!fnmatch(pending->name, domain_name, 0))
+         return pending->level;
+   }
+
+   return _log_level;
+}
+
+/**
+ * Get the domain level given its identifier.
+ *
+ * @param domain identifier, so it must be previously registered with
+ *        eina_log_domain_register(). It's a much faster version of
+ *        eina_log_domain_level_get(), but relies on domain being
+ *        present.
+ *
+ * @return level to use to limit eina_log_print() for given domain. On
+ *         error EINA_LOG_LEVEL_UNKNOWN is returned.
+ */
+EAPI int
+eina_log_domain_registered_level_get(int domain)
+{
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(domain >= 0, EINA_LOG_LEVEL_UNKNOWN);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL((unsigned int)domain < _log_domains_count,
+                                   EINA_LOG_LEVEL_UNKNOWN);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(_log_domains[domain].deleted,
+                                  EINA_LOG_LEVEL_UNKNOWN);
+   return _log_domains[domain].level;
+}
+
+/**
+ * Default logging method, this will output to standard error stream.
+ *
+ * This method will colorize output based on domain provided color and
+ * message logging level.
+ *
+ * To disable color, set environment variable
+ * EINA_LOG_COLOR_DISABLE=1. To enable color, even if directing to a
+ * file or when using a non-supported color terminal, use
+ * EINA_LOG_COLOR_DISABLE=0. If EINA_LOG_COLOR_DISABLE is unset (or
+ * -1), then Eina will disable color if terminal ($TERM) is
+ * unsupported or if redirecting to a file.
+
+   . Similarly, to disable file and line
+ * information, set EINA_LOG_FILE_DISABLE=1 or
+ * EINA_LOG_FUNCTION_DISABLE=1 to avoid function name in output. It is
+ * not acceptable to have both EINA_LOG_FILE_DISABLE and
+ * EINA_LOG_FUNCTION_DISABLE at the same time, in this case just
+ * EINA_LOG_FUNCTION_DISABLE will be considered and file information
+ * will be printed anyways.
+ *
+ * @note MT: if threads are enabled, this function is called within locks.
+ * @note MT: Threads different from main thread will have thread id
+ *       appended to domain name.
+ */
+EAPI void
+eina_log_print_cb_stderr(const Eina_Log_Domain *d,
+                         Eina_Log_Level level,
+                         const char *file,
+                         const char *fnc,
+                         int line,
+                         const char *fmt,
+                         __UNUSED__ void *data,
+                         va_list args)
+{
+   _eina_log_print_prefix(stderr, d, level, file, fnc, line);
+   vfprintf(stderr, fmt, args);
+   putc('\n', stderr);
+}
+
+/**
+ * Alternative logging method, this will output to standard output stream.
+ *
+ * @param d The domain.
+ * @param level The level.
+ * @param file The file which is logged.
+ * @param fnc The function which is logged.
+ * @param line The line which is logged.
+ * @param fmt The ouptut format to use.
+ * @param data Not used.
+ * @param args The arguments needed by the format.
+ *
+ * This method will colorize output based on domain provided color and
+ * message logging level. To disable color, set environment variable
+ * EINA_LOG_COLOR_DISABLE=1. Similarly, to disable file and line
+ * information, set EINA_LOG_FILE_DISABLE=1 or
+ * EINA_LOG_FUNCTION_DISABLE=1 to avoid function name in output. It is
+ * not acceptable to have both EINA_LOG_FILE_DISABLE and
+ * EINA_LOG_FUNCTION_DISABLE at the same time, in this case just
+ * EINA_LOG_FUNCTION_DISABLE will be considered and file information
+ * will be printed anyways.
+ *
+ * @note MT: if threads are enabled, this function is called within locks.
+ * @note MT: Threads different from main thread will have thread id
+ *       appended to domain name.
+ */
+EAPI void
+eina_log_print_cb_stdout(const Eina_Log_Domain *d,
+                         Eina_Log_Level level,
+                         const char *file,
+                         const char *fnc,
+                         int line,
+                         const char *fmt,
+                         __UNUSED__ void *data,
+                         va_list args)
+{
+   _eina_log_print_prefix(stdout, d, level, file, fnc, line);
+   vprintf(fmt, args);
+   putchar('\n');
+}
+
+/**
+ * Alternative logging method, this will output to given file stream.
+ *
+ * @param d The domain.
+ * @param level Not used.
+ * @param file The file which is logged.
+ * @param fnc The function which is logged.
+ * @param line The line which is logged.
+ * @param fmt The ouptut format to use.
+ * @param data The file which will store the output (as a FILE *).
+ * @param args The arguments needed by the format.
+ *
+ * This method will never output color.
+ *
+ * @note MT: if threads are enabled, this function is called within locks.
+ * @note MT: Threads different from main thread will have thread id
+ *       appended to domain name.
+ */
+EAPI void
+eina_log_print_cb_file(const Eina_Log_Domain *d,
+                       __UNUSED__ Eina_Log_Level level,
+                       const char *file,
+                       const char *fnc,
+                       int line,
+                       const char *fmt,
+                       void *data,
+                       va_list args)
+{
+   FILE *f = data;
+#ifdef EFL_HAVE_THREADS
+   if (_threads_enabled)
+     {
+        Thread cur;
+
+        cur = SELF();
+        if (IS_OTHER(cur))
+          {
+             fprintf(f, "%s[T:%lu] %s:%d %s() ", d->name, (unsigned long)cur,
+               file, line, fnc);
+             goto end;
+          }
+     }
+
+#endif
+             fprintf(f, "%s %s:%d %s() ", d->name, file, line, fnc);
+#ifdef EFL_HAVE_THREADS
+end:
+#endif
+   vfprintf(f, fmt, args);
+   putc('\n', f);
+}
+
+/**
+ * Print out log message using given domain and level.
+ *
+ * @note Usually you'll not use this function directly but the helper
+ *       macros EINA_LOG(), EINA_LOG_DOM_CRIT(), EINA_LOG_CRIT() and
+ *       so on. See eina_log.h
+ *
+ * @param domain logging domain to use or @c EINA_LOG_DOMAIN_GLOBAL if
+ *        you registered none. It is recommended that modules and
+ *        applications have their own logging domain.
+ * @param level message level, those with level greater than user
+ *        specified value (eina_log_level_set() or environment
+ *        variables EINA_LOG_LEVEL, EINA_LOG_LEVELS) will be ignored.
+ * @param file filename that originated the call, must @b not be @c NULL.
+ * @param fnc function that originated the call, must @b not be @c NULL.
+ * @param line originating line in @a file.
+ * @param fmt printf-like format to use. Should not provide trailing
+ *        '\n' as it is automatically included.
+ *
+ * @note MT: this function may be called from different threads if
+ *       eina_log_threads_enable() was called before.
+ */
+EAPI void
+eina_log_print(int domain, Eina_Log_Level level, const char *file,
+               const char *fnc, int line, const char *fmt, ...)
+{
+   va_list args;
+
+#ifdef EINA_SAFETY_CHECKS
+   if (EINA_UNLIKELY(!file))
+     {
+        fputs("ERR: eina_log_print() file == NULL\n", stderr);
+        return;
+     }
+
+   if (EINA_UNLIKELY(!fnc))
+     {
+        fputs("ERR: eina_log_print() fnc == NULL\n", stderr);
+        return;
+     }
+
+   if (EINA_UNLIKELY(!fmt))
+     {
+        fputs("ERR: eina_log_print() fmt == NULL\n", stderr);
+        return;
+     }
+
+#endif
+   va_start(args, fmt);
+   LOG_LOCK();
+   eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args);
+   LOG_UNLOCK();
+   va_end(args);
+}
+
+/**
+ * Print out log message using given domain and level.
+ *
+ * @note Usually you'll not use this function directly but the helper
+ *       macros EINA_LOG(), EINA_LOG_DOM_CRIT(), EINA_LOG_CRIT() and
+ *       so on. See eina_log.h
+ *
+ * @param domain logging domain to use or @c EINA_LOG_DOMAIN_GLOBAL if
+ *        you registered none. It is recommended that modules and
+ *        applications have their own logging domain.
+ * @param level message level, those with level greater than user
+ *        specified value (eina_log_level_set() or environment
+ *        variables EINA_LOG_LEVEL, EINA_LOG_LEVELS) will be ignored.
+ * @param file filename that originated the call, must @b not be @c NULL.
+ * @param fnc function that originated the call, must @b not be @c NULL.
+ * @param line originating line in @a file.
+ * @param fmt printf-like format to use. Should not provide trailing
+ *        '\n' as it is automatically included.
+ * @param args the arguments needed by the format.
+ *
+ * @note MT: this function may be called from different threads if
+ *       eina_log_threads_enable() was called before.
+ *
+ * @see eina_log_print()
+ */
+EAPI void
+eina_log_vprint(int domain, Eina_Log_Level level, const char *file,
+                const char *fnc, int line, const char *fmt, va_list args)
+{
+#ifdef EINA_SAFETY_CHECKS
+   if (EINA_UNLIKELY(!file))
+     {
+        fputs("ERR: eina_log_print() file == NULL\n", stderr);
+        return;
+     }
+
+   if (EINA_UNLIKELY(!fnc))
+     {
+        fputs("ERR: eina_log_print() fnc == NULL\n", stderr);
+        return;
+     }
+
+   if (EINA_UNLIKELY(!fmt))
+     {
+        fputs("ERR: eina_log_print() fmt == NULL\n", stderr);
+        return;
+     }
+
+#endif
+   LOG_LOCK();
+   eina_log_print_unlocked(domain, level, file, fnc, line, fmt, args);
+   LOG_UNLOCK();
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_magic.c 
b/tests/suite/ecore/src/lib/eina_magic.c
new file mode 100644
index 0000000..83cd247
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_magic.c
@@ -0,0 +1,487 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_error.h"
+#include "eina_log.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_magic.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+typedef struct _Eina_Magic_String Eina_Magic_String;
+struct _Eina_Magic_String
+{
+   Eina_Magic magic;
+   Eina_Bool string_allocated;
+   const char *string;
+};
+
+static int _eina_magic_string_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_magic_string_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_magic_string_log_dom, __VA_ARGS__)
+
+static Eina_Magic_String *_eina_magic_strings = NULL;
+static size_t _eina_magic_strings_count = 0;
+static size_t _eina_magic_strings_allocated = 0;
+static Eina_Bool _eina_magic_strings_dirty = 0;
+
+static int
+_eina_magic_strings_sort_cmp(const void *p1, const void *p2)
+{
+   const Eina_Magic_String *a = p1, *b = p2;
+   return a->magic - b->magic;
+}
+
+static int
+_eina_magic_strings_find_cmp(const void *p1, const void *p2)
+{
+   Eina_Magic a = (long)p1;
+   const Eina_Magic_String *b = p2;
+   return a - b->magic;
+}
+
+static Eina_Magic_String *
+_eina_magic_strings_alloc(void)
+{
+   size_t idx;
+
+   if (_eina_magic_strings_count == _eina_magic_strings_allocated)
+     {
+        void *tmp;
+        size_t size;
+
+        if (EINA_UNLIKELY(_eina_magic_strings_allocated == 0))
+           size = 48;
+        else
+           size = _eina_magic_strings_allocated + 16;
+
+        tmp = realloc(_eina_magic_strings, sizeof(Eina_Magic_String) * size);
+        if (!tmp)
+          {
+#ifdef _WIN32
+             ERR("could not realloc magic_strings from %Iu to %Iu buckets.",
+#else
+             ERR("could not realloc magic_strings from %zu to %zu buckets.",
+#endif
+                 _eina_magic_strings_allocated, size);
+             return NULL;
+          }
+
+        _eina_magic_strings = tmp;
+        _eina_magic_strings_allocated = size;
+     }
+
+   idx = _eina_magic_strings_count;
+   _eina_magic_strings_count++;
+   return _eina_magic_strings + idx;
+}
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the magic string module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the magic string module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_magic_string_init(void)
+{
+   _eina_magic_string_log_dom = eina_log_domain_register
+         ("eina_magic_string", EINA_LOG_COLOR_DEFAULT);
+   if (_eina_magic_string_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_magic_string");
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the magic string module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the magic string module set up by
+ * eina_magic string_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_magic_string_shutdown(void)
+{
+   Eina_Magic_String *ems, *ems_end;
+
+   ems = _eina_magic_strings;
+   ems_end = ems + _eina_magic_strings_count;
+
+   for (; ems < ems_end; ems++)
+      if (ems->string_allocated)
+         free((char *)ems->string);
+
+         free(_eina_magic_strings);
+   _eina_magic_strings = NULL;
+   _eina_magic_strings_count = 0;
+   _eina_magic_strings_allocated = 0;
+
+   eina_log_domain_unregister(_eina_magic_string_log_dom);
+   _eina_magic_string_log_dom = -1;
+
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Magic_Group Magic
+ *
+ * @brief These functions provide runtime type-checking (magic checks)
+ * management for projects.
+ *
+ * C is a weak statically typed language, in other words, it will just
+ * check for types during compile time and any cast will make the
+ * compiler believe the type is correct.
+ *
+ * In real world projects we often need to deal with casts, either
+ * explicit or implicit by means of @c void*. We also need to resort
+ * to casts when doing inheritance in C, as seen in the example below:
+ *
+ * @code
+ * struct base {
+ *    int id;
+ *    char *name;
+ * };
+ * int base_id_get(struct base *ptr) {
+ *    return ptr->id;
+ * }
+ *
+ * struct subtype {
+ *    struct base base;
+ *    time_t date;
+ * };
+ * @endcode
+ *
+ * It is perfectly valid to use @c {struct subtype} blobs for functions
+ * that expect @c {struct base}, since the fields will have the same
+ * offset (as base member is the first, at offset 0). We could give
+ * the functions the @c {&subtype->base} and avoid the cast, but often
+ * we just cast.
+ *
+ * In any case, we might be safe and check if the given pointer is
+ * actually of the expected type. We can do so by using eina_magic,
+ * that is nothing more than attaching an unique type identifier to
+ * the members and check for it elsewhere.
+ *
+ * @code
+ * #define BASE_MAGIC 0x12345
+ * #define SUBTYPE_MAGIC 0x3333
+ * struct base {
+ *    int id;
+ *    char *name;
+ *    EINA_MAGIC;
+ * };
+ * int base_id_get(struct base *ptr) {
+ *    if (!EINA_MAGIC_CHECK(ptr, BASE_MAGIC)) {
+ *       EINA_MAGIC_FAIL(ptr, BASE_MAGIC);
+ *       return -1;
+ *    }
+ *    return ptr->id;
+ * }
+ * void base_free(struct base *ptr) {
+ *    if (!EINA_MAGIC_CHECK(ptr, BASE_MAGIC)) {
+ *       EINA_MAGIC_FAIL(ptr, BASE_MAGIC);
+ *       return;
+ *    }
+ *    EINA_MAGIC_SET(ptr, EINA_MAGIC_NONE);
+ *    free(ptr->name);
+ *    free(ptr);
+ * }
+ * struct base *base_new(int id, const char *name) {
+ *    struct base *ptr = malloc(sizeof(struct base));
+ *    EINA_MAGIC_SET(ptr, BASE_MAGIC);
+ *    ptr->id = id;
+ *    ptr->name = strdup(name);
+ * }
+ *
+ * struct subtype {
+ *    struct base base;
+ *    EINA_MAGIC;
+ *    time_t date;
+ * };
+ *
+ * int my_init(void) {
+ *    eina_init();
+ *    eina_magic_string_set(BASE_MAGIC, "base type");
+ *    eina_magic_string_set(SUBTYPE_MAGIC, "subtype");
+ * }
+ * @endcode
+ *
+ * This code also shows that it is a good practice to set magic to
+ * #EINA_MAGIC_NONE before freeing pointer. Sometimes the pointers are
+ * in pages that are still live in memory, so kernel will not send
+ * SEGV signal to the process and it may go unnoticed that you're
+ * using already freed pointers. By setting them to #EINA_MAGIC_NONE
+ * you avoid using the bogus pointer any further and gets a nice error
+ * message.
+ *
+ * @{
+ */
+
+/**
+ * @brief Return the string associated to the given magic identifier.
+ *
+ * @param magic The magic identifier.
+ * @return The string associated to the identifier.
+ *
+ * This function returns the string associated to @p magic. If none
+ * are found, the this function still returns non @c NULL, in this
+ * case an identifier such as "(none)", "(undefined)" or
+ * "(unknown)". The returned value must not be freed.
+ *
+ * The following identifiers may be returned whenever magic is
+ * invalid, with their meanings:
+ *
+ *   - (none): no magic was registered exists at all.
+ *   - (undefined): magic was registered and found, but no string associated.
+ *   - (unknown): magic was not found in the registry.
+ */
+EAPI const char *
+eina_magic_string_get(Eina_Magic magic)
+{
+   Eina_Magic_String *ems;
+
+   if (!_eina_magic_strings)
+      return "(none)";
+
+   if (_eina_magic_strings_dirty)
+     {
+        qsort(_eina_magic_strings, _eina_magic_strings_count,
+              sizeof(Eina_Magic_String), _eina_magic_strings_sort_cmp);
+        _eina_magic_strings_dirty = 0;
+     }
+
+   ems = bsearch((void *)(long)magic, _eina_magic_strings,
+                 _eina_magic_strings_count, sizeof(Eina_Magic_String),
+                 _eina_magic_strings_find_cmp);
+   if (ems)
+      return ems->string ? ems->string : "(undefined)";
+
+   return "(unknown)";
+}
+
+/**
+ * @brief Set the string associated to the given magic identifier.
+ *
+ * @param magic The magic identifier.
+ * @param magic_name The string associated to the identifier, must not
+ *        be @c NULL.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets the string @p magic_name to @p magic. It is not
+ * checked if number or string are already set, then you might end
+ * with duplicates in that case.
+ *
+ * @see eina_magic_string_static_set()
+ */
+EAPI Eina_Bool
+eina_magic_string_set(Eina_Magic magic, const char *magic_name)
+{
+   Eina_Magic_String *ems;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(magic_name, EINA_FALSE);
+
+   ems = _eina_magic_strings_alloc();
+   if (!ems)
+      return EINA_FALSE;
+
+   ems->magic = magic;
+   ems->string_allocated = EINA_TRUE;
+   ems->string = strdup(magic_name);
+   if (!ems->string)
+   {
+      ERR("could not allocate string '%s'", magic_name);
+      _eina_magic_strings_count--;
+      return EINA_FALSE;
+   }
+
+   _eina_magic_strings_dirty = 1;
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Set the string associated to the given magic identifier.
+ *
+ * @param magic The magic identifier.
+ * @param magic_name The string associated to the identifier, must not be
+ *        @c NULL, it will not be duplcated, just referenced thus it must
+ *        be live during magic number usage.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets the string @p magic_name to @p magic. It is not
+ * checked if number or string are already set, then you might end
+ * with duplicates in that case.
+ *
+ * @see eina_magic_string_set()
+ */
+EAPI Eina_Bool
+eina_magic_string_static_set(Eina_Magic magic, const char *magic_name)
+{
+   Eina_Magic_String *ems;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(magic_name, EINA_FALSE);
+
+   ems = _eina_magic_strings_alloc();
+   if (!ems)
+      return EINA_FALSE;
+
+   ems->magic = magic;
+   ems->string_allocated = EINA_FALSE;
+   ems->string = magic_name;
+
+   _eina_magic_strings_dirty = 1;
+   return EINA_TRUE;
+}
+
+#ifdef eina_magic_fail
+# undef eina_magic_fail
+#endif
+
+/**
+ * @brief Display a message or abort is a magic check failed.
+ *
+ * @param d The checked data pointer.
+ * @param m The magic identifer to check.
+ * @param req_m The requested magic identifier to check.
+ * @param file The file in which the magic check failed.
+ * @param fnc The function in which the magic check failed.
+ * @param line The line at which the magic check failed.
+ *
+ * This function displays an error message if a magic check has
+ * failed, using the following logic in the following order:
+ * @li If @p d is @c NULL, a message warns about a @c NULL pointer.
+ * @li Otherwise, if @p m is equal to #EINA_MAGIC_NONE, a message
+ * warns about a handle that was already freed.
+ * @li Otherwise, if @p m is equal to @p req_m, a message warns about
+ * a handle that is of wrong type.
+ * @li Otherwise, a message warns you about ab-using that function...
+ *
+ * If the environment variable EINA_ERROR_ABORT is set, abort() is
+ * called and the program stops. It is useful for debugging programs
+ * with gdb.
+ */
+EAPI void
+eina_magic_fail(void *d,
+                Eina_Magic m,
+                Eina_Magic req_m,
+                const char *file,
+                const char *fnc,
+                int line)
+{
+   if (!d)
+      eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
+                     file, fnc, line,
+                     "*** Eina Magic Check Failed !!!\n"
+                     "    Input handle pointer is NULL !\n"
+                     "*** NAUGHTY PROGRAMMER!!!\n"
+                     "*** SPANK SPANK SPANK!!!\n"
+                     "*** Now go fix your code. Tut tut tut!\n"
+                     "\n");
+   else
+   if (m == EINA_MAGIC_NONE)
+      eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
+                     file, fnc, line,
+                     "*** Eina Magic Check Failed !!!\n"
+                     "    Input handle has already been freed!\n"
+                     "*** NAUGHTY PROGRAMMER!!!\n"
+                     "*** SPANK SPANK SPANK!!!\n"
+                     "*** Now go fix your code. Tut tut tut!\n"
+                     "\n");
+   else
+   if (m != req_m)
+      eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
+                     file, fnc, line,
+                     "*** Eina Magic Check Failed !!!\n"
+                     "    Input handle is wrong type\n"
+                     "    Expected: %08x - %s\n"
+                     "    Supplied: %08x - %s\n"
+                     "*** NAUGHTY PROGRAMMER!!!\n"
+                     "*** SPANK SPANK SPANK!!!\n"
+                     "*** Now go fix your code. Tut tut tut!\n"
+                     "\n",
+                     req_m, eina_magic_string_get(req_m),
+                     m, eina_magic_string_get(m));
+   else
+      eina_log_print(EINA_LOG_DOMAIN_GLOBAL, EINA_LOG_LEVEL_CRITICAL,
+                     file, fnc, line,
+                     "*** Eina Magic Check Failed !!!\n"
+                     "    Why did you call me !\n"
+                     "*** NAUGHTY PROGRAMMER!!!\n"
+                     "*** SPANK SPANK SPANK!!!\n"
+                     "*** Now go fix your code. Tut tut tut!\n"
+                     "\n");
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_main.c 
b/tests/suite/ecore/src/lib/eina_main.c
new file mode 100644
index 0000000..ceae398
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_main.c
@@ -0,0 +1,377 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#ifdef EFL_HAVE_POSIX_THREADS
+# include <pthread.h>
+#endif
+
+#ifdef EFL_HAVE_WIN32_THREADS
+# define WIN32_LEAN_AND_MEAN
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_types.h"
+#include "eina_main.h"
+#include "eina_error.h"
+#include "eina_log.h"
+#include "eina_hash.h"
+#include "eina_binshare.h"
+#include "eina_stringshare.h"
+#include "eina_ustringshare.h"
+#include "eina_list.h"
+#include "eina_matrixsparse.h"
+#include "eina_array.h"
+#include "eina_counter.h"
+#include "eina_benchmark.h"
+#include "eina_magic.h"
+#include "eina_rectangle.h"
+#include "eina_safety_checks.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static Eina_Version _version = { VMAJ, VMIN, VMIC, VREV };
+
+static int _eina_main_count = 0;
+#ifdef EFL_HAVE_THREADS
+static int _eina_main_thread_count = 0;
+#endif
+static int _eina_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_log_dom, __VA_ARGS__)
+
+#ifdef EFL_HAVE_THREADS
+static Eina_Bool _threads_activated = EINA_FALSE;
+# ifdef EFL_HAVE_POSIX_THREADS
+static pthread_mutex_t _mutex = PTHREAD_MUTEX_INITIALIZER;
+#  define LOCK() if(_threads_activated) pthread_mutex_lock(&_mutex)
+#  define UNLOCK() if(_threads_activated) pthread_mutex_unlock(&_mutex)
+#  define UNLOCK_FORCE() pthread_mutex_unlock(&_mutex)
+# else /* EFL_HAVE_WIN32_THREADS */
+static HANDLE _mutex = NULL;
+#  define LOCK() if(_threads_activated) WaitForSingleObject(_mutex, INFINITE)
+#  define UNLOCK() if(_threads_activated) ReleaseMutex(_mutex)
+#  define UNLOCK_FORCE() ReleaseMutex(_mutex)
+# endif
+#else
+# define LOCK() do {} while (0)
+# define UNLOCK() do {} while (0)
+# define UNLOCK_FORCE() do {} while (0)
+#endif
+
+/* place module init/shutdown functions here to avoid other modules
+ * calling them by mistake.
+ */
+#define S(x) extern Eina_Bool eina_ ## x ## _init(void); \
+   extern Eina_Bool eina_ ## x ## _shutdown(void)
+   S(log);
+   S(error);
+   S(safety_checks);
+   S(magic_string);
+   S(iterator);
+   S(accessor);
+   S(array);
+   S(module);
+   S(mempool);
+   S(list);
+   S(binshare);
+   S(stringshare);
+   S(ustringshare);
+   S(matrixsparse);
+   S(convert);
+   S(counter);
+   S(benchmark);
+   S(rectangle);
+   S(strbuf);
+   S(ustrbuf);
+   S(quadtree);
+#undef S
+
+struct eina_desc_setup
+{
+   const char *name;
+   Eina_Bool (*init)(void);
+   Eina_Bool (*shutdown)(void);
+};
+
+static const struct eina_desc_setup _eina_desc_setup[] = {
+#define S(x) {# x, eina_ ## x ## _init, eina_ ## x ## _shutdown}
+   /* log is a special case as it needs printf */
+   S(error),
+   S(safety_checks),
+   S(magic_string),
+   S(iterator),
+   S(accessor),
+   S(array),
+   S(module),
+   S(mempool),
+   S(list),
+   S(binshare),
+   S(stringshare),
+   S(ustringshare),
+   S(matrixsparse),
+   S(convert),
+   S(counter),
+   S(benchmark),
+   S(rectangle),
+   S(strbuf),
+   S(ustrbuf),
+   S(quadtree)
+#undef S
+};
+static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) /
+   sizeof(_eina_desc_setup[0]);
+
+static void
+_eina_shutdown_from_desc(const struct eina_desc_setup *itr)
+{
+   for (itr--; itr >= _eina_desc_setup; itr--)
+     {
+        if (!itr->shutdown())
+           ERR("Problems shutting down eina module '%s', ignored.", itr->name);
+     }
+
+   eina_log_domain_unregister(_eina_log_dom);
+   _eina_log_dom = -1;
+   eina_log_shutdown();
+}
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Main_Group Main
+ *
+ * @brief These functions provide general initialisation and shut down
+ * functions.
+ *
+ * @{
+ */
+
+/**
+ * @var eina_version
+ * @brief Eina version (defined at configuration time)
+ */
+EAPI Eina_Version *eina_version = &_version;
+
+/**
+ * @brief Initialize the Eina library.
+ *
+ * @return 1 or greater on success, 0 on error.
+ *
+ * This function sets up all the eina modules. It returns 0 on
+ * failure (that is, when one of the module fails to initialize),
+ * otherwise it returns the number of times it has already been
+ * called.
+ *
+ * When Eina is not used anymore, call eina_shutdown() to shut down
+ * the Eina library.
+ */
+EAPI int
+eina_init(void)
+{
+   const struct eina_desc_setup *itr, *itr_end;
+
+   if (EINA_LIKELY(_eina_main_count > 0))
+      return ++_eina_main_count;
+
+   if (!eina_log_init())
+     {
+        fprintf(stderr, "Could not initialize eina logging system.\n");
+        return 0;
+     }
+
+   _eina_log_dom = eina_log_domain_register("eina", EINA_LOG_COLOR_DEFAULT);
+   if (_eina_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina");
+        eina_log_shutdown();
+        return 0;
+     }
+
+   itr = _eina_desc_setup;
+   itr_end = itr + _eina_desc_setup_len;
+   for (; itr < itr_end; itr++)
+     {
+        if (!itr->init())
+          {
+             ERR("Could not initialize eina module '%s'.", itr->name);
+             _eina_shutdown_from_desc(itr);
+             return 0;
+          }
+     }
+
+   _eina_main_count = 1;
+   return 1;
+}
+
+/**
+ * @brief Shut down the Eina library.
+ *
+ * @return 0 when all the modules is completely shut down, 1 or
+ * greater otherwise.
+ *
+ * This function shuts down the Eina library. It returns 0 when it has
+ * been called the same number of times than eina_init(). In that case
+ * it shut down all the Eina modules.
+ *
+ * Once this function succeeds (that is, @c 0 is returned), you must
+ * not call any of the Eina function anymore. You must call
+ * eina_init() again to use the Eina functions again.
+ */
+EAPI int
+eina_shutdown(void)
+{
+   _eina_main_count--;
+   if (EINA_UNLIKELY(_eina_main_count == 0))
+             _eina_shutdown_from_desc(_eina_desc_setup + _eina_desc_setup_len);
+
+   return _eina_main_count;
+}
+
+
+/**
+ * @brief Initialize the mutexes of the Eina library.
+ *
+ * @return 1 or greater on success, 0 on error.
+ *
+ * This function sets up all the mutexes in all eina modules. It returns 0 on
+ * failure (that is, when one of the module fails to initialize),
+ * otherwise it returns the number of times it has already been
+ * called.
+ *
+ * When the mutexes are not used anymore, call eina_threads_shutdown() to shut 
down
+ * the mutexes.
+ */
+EAPI int
+eina_threads_init(void)
+{
+#ifdef EFL_HAVE_THREADS
+   int ret;
+
+# ifdef EFL_HAVE_WIN32_THREADS
+   if (!_mutex)
+      _mutex = CreateMutex(NULL, FALSE, NULL);
+
+   if (!_mutex)
+      return 0;
+
+# endif
+
+   LOCK();
+   ++_eina_main_thread_count;
+   ret = _eina_main_thread_count;
+
+   if(_eina_main_thread_count > 1)
+     {
+        UNLOCK();
+        return ret;
+     }
+
+   eina_share_common_threads_init();
+   eina_log_threads_init();
+   _threads_activated = EINA_TRUE;
+
+   return ret;
+#else
+   return 0;
+#endif
+}
+
+/**
+ * @brief Shut down mutexes in the Eina library.
+ *
+ * @return 0 when all mutexes are completely shut down, 1 or
+ * greater otherwise.
+ *
+ * This function shuts down the mutexes in the Eina library. It returns 0 when 
it has
+ * been called the same number of times than eina_threads_init(). In that case
+ * it shut down all the mutexes.
+ *
+ * Once this function succeeds (that is, @c 0 is returned), you must
+ * not call any of the Eina function in a thread anymore. You must call
+ * eina_threads_init() again to use the Eina functions in a thread again.
+ */
+EAPI int
+eina_threads_shutdown(void)
+{
+#ifdef EFL_HAVE_THREADS
+   int ret;
+
+   LOCK();
+   ret = --_eina_main_thread_count;
+   if(_eina_main_thread_count > 0)
+     {
+        UNLOCK();
+        return ret;
+     }
+
+   eina_share_common_threads_shutdown();
+   eina_log_threads_shutdown();
+
+   _threads_activated = EINA_FALSE;
+
+   UNLOCK_FORCE();
+
+# ifdef EFL_HAVE_WIN32_THREADS
+   if (_mutex)
+      CloseHandle(_mutex);
+
+# endif
+
+   return ret;
+#else
+   return 0;
+#endif
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_matrixsparse.c 
b/tests/suite/ecore/src/lib/eina_matrixsparse.c
new file mode 100644
index 0000000..e19f24a
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_matrixsparse.c
@@ -0,0 +1,1692 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2009 Gustavo Sverzut Barbieri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+/**
+ * @page tutorial_matrixsparse_page Sparse Matrix Tutorial
+ *
+ * to be written...
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_error.h"
+#include "eina_log.h"
+#include "eina_magic.h"
+#include "eina_mempool.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_matrixsparse.h"
+
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static const char EINA_MAGIC_MATRIXSPARSE_STR[] = "Eina Matrixsparse";
+static const char EINA_MAGIC_MATRIXSPARSE_ROW_STR[] = "Eina Matrixsparse Row";
+static const char EINA_MAGIC_MATRIXSPARSE_CELL_STR[] = "Eina Matrixsparse 
Cell";
+static const char EINA_MAGIC_MATRIXSPARSE_ITERATOR_STR[] =
+   "Eina Matrixsparse Iterator";
+static const char EINA_MAGIC_MATRIXSPARSE_ROW_ACCESSOR_STR[] =
+   "Eina Matrixsparse Row Accessor";
+static const char EINA_MAGIC_MATRIXSPARSE_ROW_ITERATOR_STR[] =
+   "Eina Matrixsparse Row Iterator";
+static const char EINA_MAGIC_MATRIXSPARSE_CELL_ACCESSOR_STR[] =
+   "Eina Matrixsparse Cell Accessor";
+static const char EINA_MAGIC_MATRIXSPARSE_CELL_ITERATOR_STR[] =
+   "Eina Matrixsparse Cell Iterator";
+
+
+#define EINA_MAGIC_CHECK_MATRIXSPARSE(d, ...)           \
+   do {                                                  \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_MATRIXSPARSE)) \
+          {                                                \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_MATRIXSPARSE);  \
+             return __VA_ARGS__;                           \
+          }                                                \
+     } while(0)
+
+#define EINA_MAGIC_CHECK_MATRIXSPARSE_ROW(d, ...)               \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_MATRIXSPARSE_ROW))     \
+          {                                                        \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_MATRIXSPARSE_ROW);      \
+             return __VA_ARGS__;                                   \
+          }                                                        \
+     } while(0)
+
+#define EINA_MAGIC_CHECK_MATRIXSPARSE_CELL(d, ...)              \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_MATRIXSPARSE_CELL))    \
+          {                                                        \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_MATRIXSPARSE_CELL);     \
+             return __VA_ARGS__;                                   \
+          }                                                        \
+     } while(0)
+
+#define EINA_MAGIC_CHECK_MATRIXSPARSE_ITERATOR(d, ...)                  \
+   do {                                                                  \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_MATRIXSPARSE_ITERATOR))        \
+          {                                                                \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_MATRIXSPARSE_ITERATOR);         \
+             return __VA_ARGS__;                                           \
+          }                                                                \
+     } while(0)
+
+struct _Eina_Matrixsparse_Cell
+{
+   Eina_Matrixsparse_Cell *next;
+   Eina_Matrixsparse_Cell *prev;
+
+   void *data;
+   unsigned long col;
+
+   Eina_Matrixsparse_Row *parent;
+
+   EINA_MAGIC
+};
+
+struct _Eina_Matrixsparse_Row
+{
+   Eina_Matrixsparse_Row *next;
+   Eina_Matrixsparse_Row *prev;
+
+   Eina_Matrixsparse_Cell *cols;
+   Eina_Matrixsparse_Cell *last_col;
+   Eina_Matrixsparse_Cell *last_used; /* fast sequential access */
+   unsigned long row;
+
+   Eina_Matrixsparse *parent;
+
+   EINA_MAGIC
+};
+
+struct _Eina_Matrixsparse
+{
+   Eina_Matrixsparse_Row *rows;
+   Eina_Matrixsparse_Row *last_row;
+   Eina_Matrixsparse_Row *last_used; /* fast sequential access */
+
+   struct
+   {
+      unsigned long rows;
+      unsigned long cols;
+   } size;
+
+   struct
+   {
+      void (*func)(void *user_data, void *cell_data);
+      void *user_data;
+   } free;
+
+   EINA_MAGIC
+};
+
+typedef struct _Eina_Matrixsparse_Iterator Eina_Matrixsparse_Iterator;
+typedef struct _Eina_Matrixsparse_Iterator_Complete
+Eina_Matrixsparse_Iterator_Complete;
+
+struct _Eina_Matrixsparse_Iterator
+{
+   Eina_Iterator iterator;
+
+   const Eina_Matrixsparse *m;
+   struct
+   {
+      const Eina_Matrixsparse_Row *row;
+      const Eina_Matrixsparse_Cell *col;
+   } ref;
+
+   EINA_MAGIC
+};
+
+struct _Eina_Matrixsparse_Iterator_Complete
+{
+   Eina_Iterator iterator;
+
+   const Eina_Matrixsparse *m;
+   struct
+   {
+      const Eina_Matrixsparse_Row *row;
+      const Eina_Matrixsparse_Cell *col;
+   } ref;
+
+   struct
+   {
+      unsigned long row, col;
+   } idx;
+
+   struct
+   {
+      Eina_Matrixsparse_Row row;
+      Eina_Matrixsparse_Cell col;
+   } dummy;
+
+   EINA_MAGIC
+};
+
+/**
+ * @todo Eina_Matrixsparse_Row_Iterator: iterator over rows in matrix
+ * @todo Eina_Matrixsparse_Row_Accessor: accessor over rows in matrix
+ * @todo Eina_Matrixsparse_Cell_Iterator: iterator over cells in row
+ * @todo Eina_Matrixsparse_Cell_Accessor: accessor over cells in row
+ */
+
+static int _eina_matrixsparse_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_matrixsparse_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_matrixsparse_log_dom, __VA_ARGS__)
+
+static Eina_Mempool *_eina_matrixsparse_cell_mp = NULL;
+static Eina_Mempool *_eina_matrixsparse_row_mp = NULL;
+
+static inline void
+_eina_matrixsparse_cell_free(Eina_Matrixsparse_Cell *c, void (*free_func)(
+                                void *,
+                                void *), void *user_data)
+{
+   if (free_func)
+      free_func(user_data, c->data);
+
+   EINA_MAGIC_SET(c, EINA_MAGIC_NONE);
+   eina_mempool_free(_eina_matrixsparse_cell_mp, c);
+}
+
+static inline void
+_eina_matrixsparse_cell_unlink(Eina_Matrixsparse_Cell *c)
+{
+   Eina_Matrixsparse_Row *r = c->parent;
+
+   if (r->last_used == c)
+     {
+        if (c->next)
+           r->last_used = c->next;
+        else
+           r->last_used = c->prev;
+     }
+
+   if (r->last_col == c)
+      r->last_col = c->prev;
+
+   if (r->cols == c)
+      r->cols = c->next;
+
+   if (c->next && c->prev)
+     {
+        c->next->prev = c->prev;
+        c->prev->next = c->next;
+     }
+   else if (c->next)
+      c->next->prev = NULL;
+   else if (c->prev)
+      c->prev->next = NULL;
+}
+
+static inline void
+_eina_matrixsparse_row_cells_free(Eina_Matrixsparse_Row *r, void (*free_func)(
+                                     void *,
+                                     void *), void *user_data)
+{
+   Eina_Matrixsparse_Cell *c = r->cols;
+   while (c)
+     {
+        Eina_Matrixsparse_Cell *c_aux = c;
+        c = c->next;
+        _eina_matrixsparse_cell_free(c_aux, free_func, user_data);
+     }
+}
+
+static inline void
+_eina_matrixsparse_row_free(Eina_Matrixsparse_Row *r, void (*free_func)(void *,
+                                                                        void 
*),
+                            void *user_data)
+{
+   _eina_matrixsparse_row_cells_free(r, free_func, user_data);
+   EINA_MAGIC_SET(r, EINA_MAGIC_NONE);
+   eina_mempool_free(_eina_matrixsparse_row_mp, r);
+}
+
+static inline void
+_eina_matrixsparse_row_unlink(Eina_Matrixsparse_Row *r)
+{
+   Eina_Matrixsparse *m = r->parent;
+
+   if (m->last_used == r)
+     {
+        if (r->next)
+           m->last_used = r->next;
+        else
+           m->last_used = r->prev;
+     }
+
+   if (m->last_row == r)
+      m->last_row = r->prev;
+
+   if (m->rows == r)
+      m->rows = r->next;
+
+   if (r->next && r->prev)
+     {
+        r->next->prev = r->prev;
+        r->prev->next = r->next;
+     }
+   else if (r->next)
+      r->next->prev = NULL;
+   else if (r->prev)
+      r->prev->next = NULL;
+}
+
+static inline void
+_eina_matrixsparse_row_find_parms_get(const Eina_Matrixsparse *m,
+                                      unsigned long row,
+                                      Eina_Matrixsparse_Row **p_r,
+                                      int *p_dir)
+{
+   Eina_Matrixsparse_Row *r;
+   unsigned long dist;
+   int dir;
+
+   dist = row - m->rows->row;
+   r = m->rows;
+   dir = 1;
+   if (dist > m->last_row->row - row)
+     {
+        dist = m->last_row->row - row;
+        r = m->last_row;
+        dir = -1;
+     }
+
+   if (m->last_used)
+     {
+        if (m->last_used->row < row)
+          {
+             if (dist > row - m->last_used->row)
+               {
+/*      dist = row = m->last_used->row; */
+                  r = m->last_used;
+                  dir = 1;
+               }
+          }
+        else if (dist > m->last_used->row - row)
+          {
+/*      dist = m->last_used->row - row; */
+             r = m->last_used;
+             dir = -1;
+          }
+     }
+
+   *p_r = r;
+   *p_dir = dir;
+}
+
+static inline void
+_eina_matrixsparse_row_cell_find_parms_get(const Eina_Matrixsparse_Row *r,
+                                           unsigned long col,
+                                           Eina_Matrixsparse_Cell **p_c,
+                                           int *p_dir)
+{
+   Eina_Matrixsparse_Cell *c;
+   unsigned long dist;
+   int dir;
+
+   dist = col - r->cols->col;
+   c = r->cols;
+   dir = 1;
+   if (dist > r->last_col->col - col)
+     {
+        dist = r->last_col->col - col;
+        c = r->last_col;
+        dir = -1;
+     }
+
+   if (r->last_used)
+     {
+        if (r->last_used->col < col)
+          {
+             if (dist > col - r->last_used->col)
+               {
+/*      dist = col = r->last_used->col; */
+                  c = r->last_used;
+                  dir = 1;
+               }
+          }
+        else if (dist > r->last_used->col - col)
+          {
+/*      dist = r->last_used->col - col; */
+             c = r->last_used;
+             dir = -1;
+          }
+     }
+
+   *p_c = c;
+   *p_dir = dir;
+}
+
+static inline Eina_Matrixsparse_Row *
+_eina_matrixsparse_row_idx_get(const Eina_Matrixsparse *m, unsigned long row)
+{
+   Eina_Matrixsparse_Row *r;
+   int dir;
+
+   if (!m->rows)
+      return NULL;
+
+   if      (m->rows->row == row)
+      return m->rows;
+   else if (m->rows->row > row)
+      return NULL;
+
+   if      (m->last_row->row == row)
+      return m->last_row;
+   else if (m->last_row->row < row)
+      return NULL;
+
+   if ((m->last_used) && (m->last_used->row == row))
+      return m->last_used;
+
+   _eina_matrixsparse_row_find_parms_get(m, row, &r, &dir);
+   assert(dir != 0);
+   if (dir > 0)
+     {
+        for (; r; r = r->next)
+           if (r->row == row)
+             {
+                ((Eina_Matrixsparse *)m)->last_used = r;
+                return r;
+             }
+           else if (r->row > row)
+              return NULL;
+
+     }
+   else if (dir < 0)
+     {
+        for (; r; r = r->prev)
+          if (r->row == row)
+            {
+               ((Eina_Matrixsparse *)m)->last_used = r;
+               return r;
+            }
+          else if (r->row < row)
+            return NULL;
+     }
+
+   return NULL;
+}
+
+static inline Eina_Matrixsparse_Cell *
+_eina_matrixsparse_row_cell_idx_get(const Eina_Matrixsparse_Row *r,
+                                    unsigned long col)
+{
+   Eina_Matrixsparse_Cell *c;
+   int dir;
+
+   if (!r->cols)
+      return NULL;
+
+   if      (r->cols->col == col)
+      return r->cols;
+   else if (r->cols->col > col)
+      return NULL;
+
+   if      (r->last_col->col == col)
+      return r->last_col;
+   else if (r->last_col->col < col)
+      return NULL;
+
+   if ((r->last_used) && (r->last_used->col == col))
+      return r->last_used;
+
+   _eina_matrixsparse_row_cell_find_parms_get(r, col, &c, &dir);
+   assert(dir != 0);
+   if (dir > 0)
+     {
+        for (; r; c = c->next)
+           if (c->col == col)
+             {
+                ((Eina_Matrixsparse_Row *)r)->last_used = c;
+                return c;
+             }
+           else if (c->col > col)
+              return NULL;
+
+     }
+   else if (dir < 0)
+     {
+        for (; r; c = c->prev)
+          if (c->col == col)
+            {
+               ((Eina_Matrixsparse_Row *)r)->last_used = c;
+               return c;
+            }
+          else if (c->col < col)
+            return NULL;
+     }
+
+   return NULL;
+}
+
+static inline Eina_Matrixsparse_Cell *
+_eina_matrixsparse_cell_idx_get(const Eina_Matrixsparse *m,
+                                unsigned long row,
+                                unsigned long col)
+{
+   Eina_Matrixsparse_Row *r = _eina_matrixsparse_row_idx_get(m, row);
+   if (!r)
+      return NULL;
+
+   return _eina_matrixsparse_row_cell_idx_get(r, col);
+}
+
+static inline void
+_eina_matrixsparse_row_idx_siblings_find(const Eina_Matrixsparse *m,
+                                         unsigned long row,
+                                         Eina_Matrixsparse_Row **p_prev,
+                                         Eina_Matrixsparse_Row **p_next)
+{
+   Eina_Matrixsparse_Row *r;
+   int dir;
+
+   _eina_matrixsparse_row_find_parms_get(m, row, &r, &dir);
+        assert(dir != 0);
+   if (dir > 0)
+     {
+        for (; r; r = r->next)
+           if (r->row > row)
+              break;
+
+        assert(r != NULL);
+        *p_prev = r->prev;
+        *p_next = r;
+     }
+   else if (dir < 0)
+     {
+        for (; r; r = r->prev)
+           if (r->row < row)
+              break;
+
+        assert(r != NULL);
+        *p_prev = r;
+        *p_next = r->next;
+     }
+}
+
+static inline void
+_eina_matrixsparse_row_cell_idx_siblings_find(const Eina_Matrixsparse_Row *r,
+                                              unsigned long col,
+                                              Eina_Matrixsparse_Cell **p_prev,
+                                              Eina_Matrixsparse_Cell **p_next)
+{
+   Eina_Matrixsparse_Cell *c;
+   int dir;
+
+   _eina_matrixsparse_row_cell_find_parms_get(r, col, &c, &dir);
+        assert(dir != 0);
+   if (dir > 0)
+     {
+        for (; c; c = c->next)
+           if (c->col > col)
+              break;
+
+        assert(c != NULL);
+        *p_prev = c->prev;
+        *p_next = c;
+     }
+   else if (dir < 0)
+     {
+        for (; c; c = c->prev)
+           if (c->col < col)
+              break;
+
+        assert(c != NULL);
+        *p_prev = c;
+        *p_next = c->next;
+     }
+}
+
+static inline Eina_Matrixsparse_Row *
+_eina_matrixsparse_row_idx_add(Eina_Matrixsparse *m, unsigned long row)
+{
+   Eina_Matrixsparse_Row *r = eina_mempool_malloc
+         (_eina_matrixsparse_row_mp, sizeof(Eina_Matrixsparse_Row));
+   if (!r)
+      return NULL;
+
+   if (!m->rows)
+     {
+        r->prev = NULL;
+        r->next = NULL;
+        m->rows = r;
+        m->last_row = r;
+     }
+   else if (row < m->rows->row)
+     {
+        r->prev = NULL;
+        r->next = m->rows;
+        m->rows->prev = r;
+        m->rows = r;
+     }
+   else if (row > m->last_row->row)
+     {
+        r->prev = m->last_row;
+        m->last_row->next = r;
+        r->next = NULL;
+        m->last_row = r;
+     }
+   else
+     {
+        Eina_Matrixsparse_Row *prev = NULL, *next = NULL;
+        _eina_matrixsparse_row_idx_siblings_find(m, row, &prev, &next);
+        assert(prev != NULL);
+        assert(next != NULL);
+        r->prev = prev;
+        r->next = next;
+        prev->next = r;
+        next->prev = r;
+     }
+
+   r->cols = NULL;
+   r->last_col = NULL;
+   r->last_used = NULL;
+   r->row = row;
+   r->parent = m;
+   EINA_MAGIC_SET(r, EINA_MAGIC_MATRIXSPARSE_ROW);
+   m->last_used = r;
+   return r;
+}
+
+static inline Eina_Matrixsparse_Cell *
+_eina_matrixsparse_row_cell_idx_add(Eina_Matrixsparse_Row *r,
+                                    unsigned long col,
+                                    const void *data)
+{
+   Eina_Matrixsparse_Cell *c = eina_mempool_malloc
+         (_eina_matrixsparse_cell_mp, sizeof(Eina_Matrixsparse_Cell));
+   if (!c)
+      return NULL;
+
+   if (!r->cols)
+     {
+        c->prev = NULL;
+        c->next = NULL;
+        r->cols = c;
+        r->last_col = c;
+     }
+   else if (col < r->cols->col)
+     {
+        c->prev = NULL;
+        c->next = r->cols;
+        r->cols->prev = c;
+        r->cols = c;
+     }
+   else if (col > r->last_col->col)
+     {
+        c->prev = r->last_col;
+        r->last_col->next = c;
+        c->next = NULL;
+        r->last_col = c;
+     }
+   else
+     {
+        Eina_Matrixsparse_Cell *prev = NULL, *next = NULL;
+        _eina_matrixsparse_row_cell_idx_siblings_find(r, col, &prev, &next);
+        assert(prev != NULL);
+        assert(next != NULL);
+        c->prev = prev;
+        c->next = next;
+        prev->next = c;
+        next->prev = c;
+     }
+
+   c->data = (void *)data;
+   c->col = col;
+   c->parent = r;
+   EINA_MAGIC_SET(c, EINA_MAGIC_MATRIXSPARSE_CELL);
+   r->last_used = c;
+   return c;
+}
+
+static inline Eina_Bool
+_eina_matrixsparse_cell_idx_add(Eina_Matrixsparse *m,
+                                unsigned long row,
+                                unsigned long col,
+                                const void *data)
+{
+   Eina_Matrixsparse_Row *r = _eina_matrixsparse_row_idx_get(m, row);
+   if (!r)
+      r = _eina_matrixsparse_row_idx_add(m, row);
+
+   if (!r)
+      return 0;
+
+   if (_eina_matrixsparse_row_cell_idx_add(r, col, data))
+      return 1;
+
+   if (r->cols)
+      return 0;
+
+   _eina_matrixsparse_row_unlink(r);
+   _eina_matrixsparse_row_free(r, m->free.func, m->free.user_data);
+   return 0;
+}
+
+/*============================================================================*
+*                Iterators                                    *
+*============================================================================*/
+static Eina_Bool
+_eina_matrixsparse_iterator_next(Eina_Matrixsparse_Iterator *it, void **data)
+{
+   EINA_MAGIC_CHECK_MATRIXSPARSE_ITERATOR(it, EINA_FALSE);
+
+   /* do not touch it->idx */
+
+   if (!it->ref.col)
+      return 0;
+
+   *data = (Eina_Matrixsparse_Cell *)it->ref.col;
+
+   it->ref.col = it->ref.col->next;
+   if (!it->ref.col)
+     {
+        it->ref.row = it->ref.row->next;
+        if (it->ref.row)
+           it->ref.col = it->ref.row->cols;
+     }
+
+   return 1;
+}
+
+static Eina_Matrixsparse *
+_eina_matrixsparse_iterator_get_container(Eina_Matrixsparse_Iterator *it)
+{
+   EINA_MAGIC_CHECK_MATRIXSPARSE_ITERATOR(it, NULL);
+   return (Eina_Matrixsparse *)it->m;
+}
+
+static void
+_eina_matrixsparse_iterator_free(Eina_Matrixsparse_Iterator *it)
+{
+   EINA_MAGIC_CHECK_MATRIXSPARSE_ITERATOR(it);
+   EINA_MAGIC_SET(it,            EINA_MAGIC_NONE);
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_NONE);
+   free(it);
+}
+
+static Eina_Bool
+_eina_matrixsparse_iterator_complete_next(
+   Eina_Matrixsparse_Iterator_Complete *it,
+   void **data)
+{
+   EINA_MAGIC_CHECK_MATRIXSPARSE_ITERATOR(it, EINA_FALSE);
+
+   if (it->idx.row >= it->m->size.rows)
+      return 0;
+
+   if (it->dummy.col.data)
+      ERR("Last iterator call changed dummy cell!");
+
+   if ((it->ref.col) &&
+       (it->ref.col->col == it->idx.col) &&
+       (it->ref.row->row == it->idx.row))
+     {
+        *data = (Eina_Matrixsparse_Cell *)it->ref.col;
+        it->ref.col = it->ref.col->next;
+        if (!it->ref.col)
+          {
+             it->ref.row = it->ref.row->next;
+             if (it->ref.row)
+                it->ref.col = it->ref.row->cols;
+          }
+     }
+   else
+     {
+        it->dummy.col.data = NULL;
+        it->dummy.col.col = it->idx.col;
+        it->dummy.row.row = it->idx.row;
+        *data = &it->dummy.col;
+     }
+
+   it->idx.col++;
+   if (it->idx.col == it->m->size.cols)
+     {
+        it->idx.col = 0;
+        it->idx.row++;
+     }
+
+   return 1;
+}
+
+static Eina_Matrixsparse *
+_eina_matrixsparse_iterator_complete_get_container(
+   Eina_Matrixsparse_Iterator_Complete *it)
+{
+      EINA_MAGIC_CHECK_MATRIXSPARSE_ITERATOR(it, NULL);
+   return (Eina_Matrixsparse *)it->m;
+}
+
+static void
+_eina_matrixsparse_iterator_complete_free(
+   Eina_Matrixsparse_Iterator_Complete *it)
+{
+      EINA_MAGIC_CHECK_MATRIXSPARSE_ITERATOR(it);
+
+   if (it->dummy.col.data)
+      ERR("Last iterator call changed dummy cell!");
+
+   EINA_MAGIC_SET(it,            EINA_MAGIC_NONE);
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_NONE);
+   free(it);
+}
+
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the matrixsparse module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the matrixsparse module of Eina. It is called by
+ * eina_init().
+ *
+ * This function creates mempool to speed up matrix rows and cells
+ * management, using EINA_MEMPOOL environment variable if it is set to
+ * choose the memory pool type to use.
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_matrixsparse_init(void)
+{
+   const char *choice, *tmp;
+
+   _eina_matrixsparse_log_dom = eina_log_domain_register("eina_matrixsparse",
+                                                         
EINA_LOG_COLOR_DEFAULT);
+   if (_eina_matrixsparse_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_matrixsparse");
+        return EINA_FALSE;
+     }
+
+#ifdef EINA_DEFAULT_MEMPOOL
+   choice = "pass_through";
+#else
+   choice = "chained_mempool";
+#endif
+   tmp = getenv("EINA_MEMPOOL");
+   if (tmp && tmp[0])
+      choice = tmp;
+
+   _eina_matrixsparse_cell_mp = eina_mempool_add
+         (choice,
+         "matrixsparse_cell",
+         NULL,
+         sizeof (Eina_Matrixsparse_Cell),
+         120);
+   if (!_eina_matrixsparse_cell_mp)
+     {
+        ERR(
+           "Mempool for matrixsparse_cell cannot be allocated in matrixsparse 
init.");
+        goto on_init_fail;
+     }
+
+   _eina_matrixsparse_row_mp = eina_mempool_add
+         (choice, "matrixsparse_row", NULL, sizeof (Eina_Matrixsparse_Row), 
120);
+   if (!_eina_matrixsparse_row_mp)
+     {
+        ERR(
+           "Mempool for matrixsparse_row cannot be allocated in matrixsparse 
init.");
+        goto on_init_fail;
+     }
+
+#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
+   EMS(EINA_MAGIC_MATRIXSPARSE);
+   EMS(EINA_MAGIC_MATRIXSPARSE_ROW);
+   EMS(EINA_MAGIC_MATRIXSPARSE_CELL);
+   EMS(EINA_MAGIC_MATRIXSPARSE_ITERATOR);
+   EMS(EINA_MAGIC_MATRIXSPARSE_ROW_ACCESSOR);
+   EMS(EINA_MAGIC_MATRIXSPARSE_ROW_ITERATOR);
+   EMS(EINA_MAGIC_MATRIXSPARSE_CELL_ACCESSOR);
+   EMS(EINA_MAGIC_MATRIXSPARSE_CELL_ITERATOR);
+#undef EMS
+
+   return EINA_TRUE;
+
+on_init_fail:
+   eina_log_domain_unregister(_eina_matrixsparse_log_dom);
+   _eina_matrixsparse_log_dom = -1;
+   return EINA_FALSE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the matrixsparse module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the matrixsparse module set up by
+ * eina_matrixsparse_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_matrixsparse_shutdown(void)
+{
+   eina_mempool_del(_eina_matrixsparse_row_mp);
+   eina_mempool_del(_eina_matrixsparse_cell_mp);
+
+   eina_log_domain_unregister(_eina_matrixsparse_log_dom);
+   _eina_matrixsparse_log_dom = -1;
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Matrixsparse_Group Sparse Matrix
+ *
+ * @brief These functions provide matrix sparse management.
+ *
+ * For more information, you can look at the @ref tutorial_matrixsparse_page.
+ *
+ * @{
+ */
+
+/**
+ * @brief Create a new Sparse Matrix.
+ *
+ * @param rows number of rows in matrix. Operations with rows greater than this
+ *        value will fail.
+ * @param cols number of columns in matrix. Operations with columns greater
+ *        than this value will fail.
+ * @param free_func used to delete cell data contents, used by
+ *        eina_matrixsparse_free(), eina_matrixsparse_size_set(),
+ *        eina_matrixsparse_row_idx_clear(),
+ *        eina_matrixsparse_column_idx_clear(),
+ *        eina_matrixsparse_cell_idx_clear() and possible others.
+ * @param user_data given to @a free_func as first parameter.
+ *
+ * @return newly allocated matrix or NULL if allocation failed and eina_error
+ *         is set.
+ */
+EAPI Eina_Matrixsparse *
+eina_matrixsparse_new(unsigned long rows, unsigned long cols, void 
(*free_func)(
+                         void *user_data,
+                         void *cell_data), const void *user_data)
+{
+   Eina_Matrixsparse *m;
+
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(rows > 0, NULL);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(cols > 0, NULL);
+
+   m = malloc(sizeof(Eina_Matrixsparse));
+   if (!m)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(m, EINA_MAGIC_MATRIXSPARSE);
+   
+   m->rows = NULL;
+   m->last_row = NULL;
+   m->last_used = NULL;
+
+   m->size.rows = rows;
+   m->size.cols = cols;
+   m->free.func = free_func;
+   m->free.user_data = (void *)user_data;
+
+   eina_error_set(0);
+   return m;
+}
+
+/**
+ * @brief Free resources allocated to Sparse Matrix.
+ *
+ * @param m The Sparse Matrix instance to free, must @b not be @c NULL.
+ */
+EAPI void
+eina_matrixsparse_free(Eina_Matrixsparse *m)
+{
+   void (*free_func)(void *, void *);
+   void *user_data;
+
+   Eina_Matrixsparse_Row *r;
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m);
+
+   free_func = m->free.func;
+   user_data = m->free.user_data;
+
+   r = m->rows;
+   while (r)
+     {
+        Eina_Matrixsparse_Row *r_aux = r;
+        r = r->next;
+        _eina_matrixsparse_row_free(r_aux, free_func, user_data);
+     }
+
+   EINA_MAGIC_SET(m, EINA_MAGIC_NONE);
+   free(m);
+}
+
+/**
+ * @brief Get the current size of Sparse Matrix.
+ *
+ * The given parameters are guaranteed to be set if they're not NULL,
+ * even if this function fails (ie: @a m is not a valid matrix instance).
+ *
+ * @param m the sparse matrix to operate on.
+ * @param rows returns the number of rows, may be NULL. If @a m is invalid,
+ *        returned value is zero, otherwise it's a positive integer.
+ * @param cols returns the number of columns, may be NULL. If @a m is
+ *        invalid, returned value is zero, otherwise it's a positive integer.
+ */
+EAPI void
+eina_matrixsparse_size_get(const Eina_Matrixsparse *m,
+                           unsigned long *rows,
+                           unsigned long *cols)
+{
+   if (rows)
+      *rows = 0;
+
+   if (cols)
+      *cols = 0;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m);
+   if (rows)
+      *rows = m->size.rows;
+
+   if (cols)
+      *cols = m->size.cols;
+}
+
+/**
+ * @brief Resize the Sparse Matrix.
+ *
+ * This will resize the sparse matrix, possibly freeing cells on rows
+ * and columns that will cease to exist.
+ *
+ * @param m the sparse matrix to operate on.
+ * @param rows the new number of rows, must be greater than zero.
+ * @param cols the new number of columns, must be greater than zero.
+ * @return 1 on success, 0 on failure.
+ *
+ * @warning cells, rows or columns are not reference counted and thus
+ *     after this call any reference might be invalid if instance were
+ *     freed.
+ */
+EAPI Eina_Bool
+eina_matrixsparse_size_set(Eina_Matrixsparse *m,
+                           unsigned long rows,
+                           unsigned long cols)
+{
+   Eina_Bool update_last_used_row;
+   Eina_Matrixsparse_Row *r;
+   void (*free_func)(void *, void *);
+   void *user_data;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(rows > 0, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(cols > 0, 0);
+
+   if ((rows == m->size.rows) && (cols == m->size.cols))
+      return 1;
+
+   update_last_used_row = ((m->last_used) && (m->last_used->row >= rows));
+   free_func = m->free.func;
+   user_data = m->free.user_data;
+
+   r = m->last_row;
+   while (r && r->row >= rows)
+     {
+        Eina_Matrixsparse_Row *r_aux = r;
+        r = r->prev;
+        _eina_matrixsparse_row_free(r_aux, free_func, user_data);
+     }
+   if (!r)
+     {
+        m->last_row = NULL;
+        m->rows = NULL;
+     }
+   else if (r != m->last_row)
+     {
+        r->next = NULL;
+        m->last_row = r;
+     }
+
+   if (update_last_used_row)
+      m->last_used = m->last_row;
+
+   r = m->rows;
+   while (r)
+     {
+        Eina_Matrixsparse_Cell *c = r->last_col;
+        Eina_Bool update_last_used_col;
+        update_last_used_col = ((r->last_used) && (r->last_used->col >= cols));
+        while (c && c->col >= cols)
+          {
+             Eina_Matrixsparse_Cell *c_aux = c;
+             c = c->prev;
+             _eina_matrixsparse_cell_free(c_aux, free_func, user_data);
+          }
+        if (!c)
+          {
+             Eina_Matrixsparse_Row *r_aux = r;
+             r->cols = NULL;
+             r->last_col = NULL;
+             if (r->next)
+                r->next->prev = r->prev;
+             else
+                m->last_row = r->prev;
+
+             if (r->prev)
+                r->prev->next = r->next;
+             else
+                m->rows = r->next;
+
+             r = r->next;
+             _eina_matrixsparse_row_free(r_aux, free_func, user_data);
+          }
+        else
+          {
+             if (c != r->last_col)
+               {
+                  c->next = NULL;
+                  r->last_col = c;
+               }
+
+             if (update_last_used_col)
+                r->last_used = r->last_col;
+
+             r = r->next;
+          }
+     }
+
+   update_last_used_row = 0;
+   if (m->last_used)
+     {
+        if (m->last_row)
+           update_last_used_row = m->last_used->row > m->last_row->row;
+        else
+           update_last_used_row = 1;
+     }
+
+   if (update_last_used_row)
+      m->last_used = m->last_row;
+
+   m->size.rows = rows;
+   m->size.cols = cols;
+   return 1;
+}
+
+/**
+ * Get the cell reference inside Sparse Matrix.
+ *
+ * @param m the sparse matrix to operate on.
+ * @param row the new number of row to clear.
+ * @param col the new number of column to clear.
+ * @param cell pointer to return cell reference, if any exists.
+ *
+ * @return 1 on success, 0 on failure. It is considered success if did not
+ *     exist but index is inside matrix size, in this case @c *cell == NULL
+ *
+ * @see eina_matrixsparse_cell_data_get()
+ * @see eina_matrixsparse_data_idx_get()
+ */
+EAPI Eina_Bool
+eina_matrixsparse_cell_idx_get(const Eina_Matrixsparse *m,
+                               unsigned long row,
+                               unsigned long col,
+                               Eina_Matrixsparse_Cell **cell)
+{
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m, 0);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cell, 0);
+   *cell = NULL;
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(row < m->size.rows, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(col < m->size.cols, 0);
+   *cell = _eina_matrixsparse_cell_idx_get(m, row, col);
+   return 1;
+}
+
+/**
+ * Get data associated with given cell reference.
+ *
+ * @param cell given cell reference, must @b not be @c NULL.
+ *
+ * @return data associated with given cell.
+ *
+ * @see eina_matrixsparse_cell_idx_get()
+ * @see eina_matrixsparse_data_idx_get()
+ */
+EAPI void *
+eina_matrixsparse_cell_data_get(const Eina_Matrixsparse_Cell *cell)
+{
+   EINA_MAGIC_CHECK_MATRIXSPARSE_CELL(cell, NULL);
+   return cell->data;
+}
+
+/**
+ * Get data associated with given cell given its indexes.
+ *
+ * @param m the sparse matrix to operate on.
+ * @param row the new number of row to clear.
+ * @param col the new number of column to clear.
+ *
+ * @return data associated with given cell or NULL if nothing is associated.
+ *
+ * @see eina_matrixsparse_cell_idx_get()
+ * @see eina_matrixsparse_cell_data_get()
+ */
+EAPI void *
+eina_matrixsparse_data_idx_get(const Eina_Matrixsparse *m,
+                               unsigned long row,
+                               unsigned long col)
+{
+   Eina_Matrixsparse_Cell *c;
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m, NULL);
+   c = _eina_matrixsparse_cell_idx_get(m, row, col);
+   if (c)
+      return c->data;
+   else
+      return NULL;
+}
+
+/**
+ * Get position (indexes) of the given cell.
+ *
+ * @param cell the cell reference, must @b not be @c NULL.
+ * @param row where to store cell row number, may be @c NULL.
+ * @param col where to store cell column number, may be @c NULL.
+ *
+ * @return 1 on success, 0 otherwise (@c cell is @c NULL).
+ */
+EAPI Eina_Bool
+eina_matrixsparse_cell_position_get(const Eina_Matrixsparse_Cell *cell,
+                                    unsigned long *row,
+                                    unsigned long *col)
+{
+   if (row)
+      *row = 0;
+
+   if (col)
+      *col = 0;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE_CELL(cell, 0);
+   EINA_MAGIC_CHECK_MATRIXSPARSE_ROW(cell->parent, 0);
+   if (row)
+      *row = cell->parent->row;
+
+   if (col)
+      *col = cell->col;
+
+   return 1;
+}
+
+/**
+ * Change cell reference value without freeing the possibly existing old value.
+ *
+ * @param cell the cell reference, must @b not be @c NULL.
+ * @param data new data to set.
+ * @param p_old returns the old value intact (not freed).
+ *
+ * @return 1 on success, 0 otherwise (@a cell is @c NULL).
+ *
+ * @see eina_matrixsparse_cell_data_set()
+ * @see eina_matrixsparse_data_idx_replace()
+ */
+EAPI Eina_Bool
+eina_matrixsparse_cell_data_replace(Eina_Matrixsparse_Cell *cell,
+                                    const void *data,
+                                    void **p_old)
+{
+   if (p_old)
+      *p_old = NULL;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE_CELL(cell, 0);
+
+   if (p_old)
+      *p_old = cell->data;
+
+   cell->data = (void *)data;
+   return 1;
+}
+
+/**
+ * Change cell value freeing the possibly existing old value.
+ *
+ * In contrast to eina_matrixsparse_cell_data_replace(), this function will
+ * call @c free_func() on existing value.
+ *
+ * @param cell the cell reference, must @b not be @c NULL.
+ * @param data new data to set.
+ *
+ * @return 1 on success, 0 otherwise (@a cell is @c NULL).
+ *
+ * @see eina_matrixsparse_cell_data_replace()
+ * @see eina_matrixsparse_data_idx_set()
+ */
+EAPI Eina_Bool
+eina_matrixsparse_cell_data_set(Eina_Matrixsparse_Cell *cell, const void *data)
+{
+   Eina_Matrixsparse *m;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE_CELL(cell, 0);
+   EINA_MAGIC_CHECK_MATRIXSPARSE_ROW(cell->parent, 0);
+   EINA_MAGIC_CHECK_MATRIXSPARSE(cell->parent->parent, 0);
+
+   m = cell->parent->parent;
+
+   if (m->free.func)
+      m->free.func(m->free.user_data, cell->data);
+
+   cell->data = (void *)data;
+   return 1;
+}
+
+/**
+ * Change cell value without freeing the possibly existing old value, using
+ * indexes.
+ *
+ * @param m the sparse matrix, must @b not be @c NULL.
+ * @param row the row number to set the value.
+ * @param col the column number to set the value.
+ * @param data new data to set.
+ * @param p_old returns the old value intact (not freed).
+ *
+ * @return 1 on success, 0 otherwise (@a m is @c NULL, indexes are not valid).
+ *
+ * @see eina_matrixsparse_cell_data_replace()
+ * @see eina_matrixsparse_data_idx_set()
+ */
+EAPI Eina_Bool
+eina_matrixsparse_data_idx_replace(Eina_Matrixsparse *m,
+                                   unsigned long row,
+                                   unsigned long col,
+                                   const void *data,
+                                   void **p_old)
+{
+   Eina_Matrixsparse_Cell *cell;
+
+   if (p_old)
+      *p_old = NULL;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(row < m->size.rows, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(col < m->size.cols, 0);
+
+   cell = _eina_matrixsparse_cell_idx_get(m, row, col);
+   if (cell)
+     {
+        if (p_old)
+           *p_old = cell->data;
+
+        cell->data = (void *)data;
+        return 1;
+     }
+
+   return _eina_matrixsparse_cell_idx_add(m, row, col, data);
+}
+
+/**
+ * Change cell value freeing the possibly existing old value, using
+ * indexes.
+ *
+ * In contrast to eina_matrixsparse_data_idx_replace(), this function will
+ * call @c free_func() on existing value.
+ *
+ * @param m the sparse matrix, must @b not be @c NULL.
+ * @param row the row number to set the value.
+ * @param col the column number to set the value.
+ * @param data new data to set.
+ *
+ * @return 1 on success, 0 otherwise (@a m is @c NULL, indexes are not valid).
+ *
+ * @see eina_matrixsparse_cell_data_replace()
+ */
+EAPI Eina_Bool
+eina_matrixsparse_data_idx_set(Eina_Matrixsparse *m,
+                               unsigned long row,
+                               unsigned long col,
+                               const void *data)
+{
+   Eina_Matrixsparse_Cell *cell;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(row < m->size.rows, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(col < m->size.cols, 0);
+
+   cell = _eina_matrixsparse_cell_idx_get(m, row, col);
+   if (cell)
+     {
+        if (m->free.func)
+           m->free.func(m->free.user_data, cell->data);
+
+        cell->data = (void *)data;
+        return 1;
+     }
+
+   return _eina_matrixsparse_cell_idx_add(m, row, col, data);
+}
+
+/**
+ * Clear (erase all cells) of row given its index.
+ *
+ * Existing cells will be cleared with @c free_func() given to
+ * eina_matrixsparse_new().
+ *
+ * @param m the sparse matrix to operate on.
+ * @param row the new number of row to clear.
+ *
+ * @return 1 on success, 0 on failure. It is considered success if row
+ *     had no cells filled. Failure is asking for clear row outside
+ *     matrix size.
+ *
+ * @warning cells, rows or columns are not reference counted and thus
+ *     after this call any reference might be invalid if instance were
+ *     freed.
+ */
+EAPI Eina_Bool
+eina_matrixsparse_row_idx_clear(Eina_Matrixsparse *m, unsigned long row)
+{
+   Eina_Matrixsparse_Row *r;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(row < m->size.rows, 0);
+
+   r = _eina_matrixsparse_row_idx_get(m, row);
+   if (!r)
+      return 1;
+
+   _eina_matrixsparse_row_unlink(r);
+   _eina_matrixsparse_row_free(r, m->free.func, m->free.user_data);
+
+   return 1;
+}
+
+/**
+ * Clear (erase all cells) of column given its index.
+ *
+ * Existing cells will be cleared with @c free_func() given to
+ * eina_matrixsparse_new().
+ *
+ * @param m the sparse matrix to operate on.
+ * @param col the new number of column to clear.
+ *
+ * @return 1 on success, 0 on failure. It is considered success if column
+ *     had no cells filled. Failure is asking for clear column outside
+ *     matrix size.
+ *
+ * @warning cells, rows or columns are not reference counted and thus
+ *     after this call any reference might be invalid if instance were
+ *     freed.
+ */
+EAPI Eina_Bool
+eina_matrixsparse_column_idx_clear(Eina_Matrixsparse *m, unsigned long col)
+{
+   Eina_Matrixsparse_Row *r;
+   void (*free_func)(void *, void *);
+   void *user_data;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(col < m->size.cols, 0);
+
+   free_func = m->free.func;
+   user_data = m->free.user_data;
+
+   for (r = m->rows; r; )
+     {
+        Eina_Matrixsparse_Row *r_aux = r;
+        Eina_Matrixsparse_Cell *c;
+
+        c = _eina_matrixsparse_row_cell_idx_get(r, col);
+        r = r->next;
+
+        if (!c)
+           continue;
+
+        if ((r_aux->cols != c) || (r_aux->last_col != c))
+          {
+             _eina_matrixsparse_cell_unlink(c);
+             _eina_matrixsparse_cell_free(c, free_func, user_data);
+          }
+        else
+          {
+             _eina_matrixsparse_row_unlink(r_aux);
+             _eina_matrixsparse_row_free(r_aux, free_func, user_data);
+          }
+     }
+
+   return 1;
+}
+
+/**
+ * Clear (erase) cell given its indexes.
+ *
+ * Existing cell will be cleared with @c free_func() given to
+ * eina_matrixsparse_new().
+ *
+ * @param m the sparse matrix to operate on.
+ * @param row the new number of row to clear.
+ * @param col the new number of column to clear.
+ *
+ * @return 1 on success, 0 on failure. It is considered success if did not
+ *     exist but index is inside matrix size.
+ *
+ * @warning cells, rows or columns are not reference counted and thus
+ *     after this call any reference might be invalid if instance were
+ *     freed. Note that this call might delete container column and
+ *     row if this cell was the last remainder.
+ */
+EAPI Eina_Bool
+eina_matrixsparse_cell_idx_clear(Eina_Matrixsparse *m,
+                                 unsigned long row,
+                                 unsigned long col)
+{
+   Eina_Matrixsparse_Cell *c;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE(m, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(row < m->size.rows, 0);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(col < m->size.cols, 0);
+
+   c = _eina_matrixsparse_cell_idx_get(m, row, col);
+   if (!c)
+      return 1;
+
+   _eina_matrixsparse_cell_unlink(c);
+   _eina_matrixsparse_cell_free(c, m->free.func, m->free.user_data);
+
+   return 1;
+}
+
+/**
+ * Clear (erase) cell given its reference.
+ *
+ * @param cell the cell reference, must @b not be @c NULL.
+ *
+ * @return 1 on success, 0 on failure.
+ *
+ * @warning cells, rows or columns are not reference counted and thus
+ *     after this call any reference might be invalid if instance were
+ *     freed. Note that this call might delete container column and
+ *     row if this cell was the last remainder.
+ */
+EAPI Eina_Bool
+eina_matrixsparse_cell_clear(Eina_Matrixsparse_Cell *cell)
+{
+   Eina_Matrixsparse *m;
+
+   EINA_MAGIC_CHECK_MATRIXSPARSE_CELL(cell, 0);
+   EINA_MAGIC_CHECK_MATRIXSPARSE_ROW(cell->parent, 0);
+   EINA_MAGIC_CHECK_MATRIXSPARSE(cell->parent->parent, 0);
+
+   m = cell->parent->parent;
+
+   _eina_matrixsparse_cell_unlink(cell);
+   _eina_matrixsparse_cell_free(cell, m->free.func, m->free.user_data);
+   return 1;
+}
+
+/**
+ * Creates a new iterator over existing matrix cells.
+ *
+ * This is a cheap walk, it will just report existing cells and holes
+ * in the sparse matrix will be ignored. That means the reported
+ * indexes will not be sequential.
+ *
+ * The iterator data will be the cell reference, one may query current
+ * position with eina_matrixsparse_cell_position_get() and cell value
+ * with eina_matrixsparse_cell_data_get().
+ *
+ * @param m The Sparse Matrix reference, must @b not be @c NULL.
+ * @return A new iterator.
+ *
+ * @warning if the matrix structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove cells this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_matrixsparse_iterator_new(const Eina_Matrixsparse *m)
+{
+   Eina_Matrixsparse_Iterator *it;
+
+   it = calloc(1, sizeof(*it));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(it,            EINA_MAGIC_MATRIXSPARSE_ITERATOR);
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->m = m;
+   it->ref.row = m->rows;
+   it->ref.col = m->rows ? m->rows->cols : NULL;
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_matrixsparse_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _eina_matrixsparse_iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_matrixsparse_iterator_free);
+   return &it->iterator;
+}
+
+/**
+ * Creates a new iterator over all matrix cells.
+ *
+ * Unlike eina_matrixsparse_iterator_new() this one will report all
+ * matrix cells, even those that are still empty (holes). These will
+ * be reported as dummy cells that contains no data.
+ *
+ * Be aware that iterating a big matrix (1000x1000) will call your
+ * function that number of times (1000000 times in that case) even if
+ * your matrix have no elements at all!
+ *
+ * The iterator data will be the cell reference, one may query current
+ * position with eina_matrixsparse_cell_position_get() and cell value
+ * with eina_matrixsparse_cell_data_get(). If cell is empty then the
+ * reference will be a dummy/placeholder, thus setting value with
+ * eina_matrixsparse_cell_data_set() will leave pointer unreferenced.
+ *
+ * @param m The Sparse Matrix reference, must @b not be @c NULL.
+ * @return A new iterator.
+ *
+ * @warning if the matrix structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove cells this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_matrixsparse_iterator_complete_new(const Eina_Matrixsparse *m)
+{
+   Eina_Matrixsparse_Iterator_Complete *it;
+
+   it = calloc(1, sizeof(*it));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(it,            EINA_MAGIC_MATRIXSPARSE_ITERATOR);
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->m = m;
+   it->idx.row = 0;
+   it->idx.col = 0;
+   it->ref.row = m->rows;
+   it->ref.col = m->rows ? m->rows->cols : NULL;
+
+   it->dummy.row.next = it->dummy.row.prev = NULL;
+   it->dummy.row.cols = it->dummy.row.last_col = it->dummy.row.last_used = 
NULL;
+   it->dummy.row.parent = (Eina_Matrixsparse *)m;
+   EINA_MAGIC_SET(&it->dummy.row, EINA_MAGIC_MATRIXSPARSE_ROW);
+
+   it->dummy.col.next = it->dummy.col.prev = NULL;
+   it->dummy.col.data = NULL;
+   it->dummy.col.parent = &it->dummy.row;
+   EINA_MAGIC_SET(&it->dummy.col, EINA_MAGIC_MATRIXSPARSE_CELL);
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(
+         _eina_matrixsparse_iterator_complete_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _eina_matrixsparse_iterator_complete_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(
+         _eina_matrixsparse_iterator_complete_free);
+   return &it->iterator;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_mempool.c 
b/tests/suite/ecore/src/lib/eina_mempool.c
new file mode 100644
index 0000000..b9062be
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_mempool.c
@@ -0,0 +1,399 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_hash.h"
+#include "eina_module.h"
+#include "eina_log.h"
+#include "eina_main.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_mempool.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static Eina_Hash *_backends;
+static Eina_Array *_modules;
+static int _eina_mempool_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_mempool_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_mempool_log_dom, __VA_ARGS__)
+
+
+static Eina_Mempool *
+_new_va(const char *name,
+        const char *context,
+        const char *options,
+        va_list args)
+{
+   Eina_Mempool_Backend *be;
+   Eina_Mempool *mp;
+
+   Eina_Error err = EINA_ERROR_NOT_MEMPOOL_MODULE;
+
+   eina_error_set(0);
+   be = eina_hash_find(_backends, name);
+   if (!be)
+      goto on_error;
+
+   err = EINA_ERROR_OUT_OF_MEMORY;
+   mp = calloc(1, sizeof(Eina_Mempool));
+   if (!mp)
+      goto on_error;
+
+   /* FIXME why backend is not a pointer? */
+   mp->backend = *be;
+   mp->backend_data = mp->backend.init(context, options, args);
+
+   return mp;
+
+on_error:
+   eina_error_set(err);
+   return NULL;
+}
+
+/* Built-in backend's prototypes */
+#ifdef EINA_STATIC_BUILD_CHAINED_POOL
+Eina_Bool chained_init(void);
+void      chained_shutdown(void);
+#endif
+
+#ifdef EINA_STATIC_BUILD_PASS_THROUGH
+Eina_Bool pass_through_init(void);
+void      pass_through_shutdown(void);
+#endif
+
+#ifdef EINA_STATIC_BUILD_EMEMOA_UNKNOWN
+Eina_Bool ememoa_unknown_init(void);
+void      ememoa_unknown_shutdown(void);
+#endif
+
+#ifdef EINA_STATIC_BUILD_EMEMOA_FIXED
+Eina_Bool ememoa_fixed_init(void);
+void      ememoa_fixed_shutdown(void);
+#endif
+
+#ifdef EINA_STATIC_BUILD_FIXED_BITMAP
+Eina_Bool fixed_bitmap_init(void);
+void      fixed_bitmap_shutdown(void);
+#endif
+
+#ifdef EINA_STATIC_BUILD_BUDDY
+Eina_Bool buddy_init(void);
+void      buddy_shutdown(void);
+#endif
+
+#ifdef EINA_STATIC_BUILD_ONE_BIG
+Eina_Bool one_big_init(void);
+void      one_big_shutdown(void);
+#endif
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+EAPI Eina_Error EINA_ERROR_NOT_MEMPOOL_MODULE = 0;
+
+static const char EINA_ERROR_NOT_MEMPOOL_MODULE_STR[] =
+   "Not a memory pool module.";
+
+/**
+ * @endcond
+ */
+
+EAPI Eina_Bool
+eina_mempool_register(Eina_Mempool_Backend *be)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(be, 0);
+   DBG("be=%p, name=%p", be, be->name);
+   return eina_hash_add(_backends, be->name, be);
+}
+
+EAPI void
+eina_mempool_unregister(Eina_Mempool_Backend *be)
+{
+   EINA_SAFETY_ON_NULL_RETURN(be);
+   DBG("be=%p, name=%p", be, be->name);
+   eina_hash_del(_backends, be->name, be);
+}
+
+Eina_Bool
+eina_mempool_init(void)
+{
+   char *path;
+
+   _eina_mempool_log_dom = eina_log_domain_register("eina_mempool",
+                                                    EINA_LOG_COLOR_DEFAULT);
+   if (_eina_mempool_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_mempool");
+        return 0;
+     }
+
+   EINA_ERROR_NOT_MEMPOOL_MODULE = eina_error_msg_static_register(
+         EINA_ERROR_NOT_MEMPOOL_MODULE_STR);
+   _backends = eina_hash_string_superfast_new(NULL);
+
+   /* dynamic backends */
+   _modules = eina_module_arch_list_get(NULL,
+                                        PACKAGE_LIB_DIR "/eina/modules/mp",
+                                        MODULE_ARCH);
+
+   path = eina_module_environment_path_get("HOME", "/.eina/mp/modules/mp");
+   _modules = eina_module_arch_list_get(_modules, path, MODULE_ARCH);
+   if (path)
+      free(path);
+
+   path = eina_module_environment_path_get("EINA_MODULES_MEMPOOL_DIR",
+                                           "/eina/modules/mp");
+   _modules = eina_module_arch_list_get(_modules, path, MODULE_ARCH);
+   if (path)
+      free(path);
+
+   path = eina_module_symbol_path_get((const void *)eina_init,
+                                      "/eina/modules/mp");
+   _modules = eina_module_arch_list_get(_modules, path, MODULE_ARCH);
+   if (path)
+      free(path);
+
+   if (!_modules)
+     {
+        ERR("no mempool modules able to be loaded.");
+        eina_hash_free(_backends);
+        goto mempool_init_error;
+     }
+
+   eina_module_list_load(_modules);
+
+   /* builtin backends */
+#ifdef EINA_STATIC_BUILD_CHAINED_POOL
+   chained_init();
+#endif
+#ifdef EINA_STATIC_BUILD_PASS_THROUGH
+   pass_through_init();
+#endif
+#ifdef EINA_STATIC_BUILD_EMEMOA_UNKNOWN
+   ememoa_unknown_init();
+#endif
+#ifdef EINA_STATIC_BUILD_EMEMOA_FIXED
+   ememoa_fixed_init();
+#endif
+#ifdef EINA_STATIC_BUILD_FIXED_BITMAP
+   fixed_bitmap_init();
+#endif
+#ifdef EINA_STATIC_BUILD_BUDDY
+   buddy_init();
+#endif
+#ifdef EINA_STATIC_BUILD_ONE_BIG
+   one_big_init();
+#endif
+
+   return EINA_TRUE;
+
+mempool_init_error:
+   eina_log_domain_unregister(_eina_mempool_log_dom);
+   _eina_mempool_log_dom = -1;
+
+   return EINA_FALSE;
+}
+
+Eina_Bool
+eina_mempool_shutdown(void)
+{
+   /* builtin backends */
+#ifdef EINA_STATIC_BUILD_CHAINED_POOL
+   chained_shutdown();
+#endif
+#ifdef EINA_STATIC_BUILD_PASS_THROUGH
+   pass_through_shutdown();
+#endif
+#ifdef EINA_STATIC_BUILD_EMEMOA_UNKNOWN
+   ememoa_unknown_shutdown();
+#endif
+#ifdef EINA_STATIC_BUILD_EMEMOA_FIXED
+   ememoa_fixed_shutdown();
+#endif
+#ifdef EINA_STATIC_BUILD_FIXED_BITMAP
+   fixed_bitmap_shutdown();
+#endif
+#ifdef EINA_STATIC_BUILD_BUDDY
+   buddy_shutdown();
+#endif
+#ifdef EINA_STATIC_BUILD_ONE_BIG
+   one_big_shutdown();
+#endif
+   /* dynamic backends */
+   eina_module_list_free(_modules);
+   if (_modules)
+      eina_array_free(_modules);
+
+   if (_backends)
+      eina_hash_free(_backends);
+
+   eina_log_domain_unregister(_eina_mempool_log_dom);
+   _eina_mempool_log_dom = -1;
+
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Memory_Pool_Group Memory Pool
+ *
+ * @brief These functions provide memory pool management.
+ *
+ * Several mempool are available:
+ *
+ * @li @c buddy: It uses the
+ * <a href="http://en.wikipedia.org/wiki/Buddy_memory_allocation";>"buddy
+ * allocator" algorithm</a> but the Eina implementation differs in the
+ * sense that the chunk information is not stored on the chunk itself,
+ * but on another memory area. This is useful for cases where the
+ * memory to manage might be slower to access, or limited (like video
+ * memory).
+ * @li @c chained_pool: It is the default one. It allocates a big
+ * chunk of memory with malloc() and split the result in chunks of the
+ * requested size that are pushed inside a stack. When requested, it
+ * takes this pointer from the stack to give them to whoever wants
+ * them.
+ * @li @c ememoa_fixed and @c ememoa_unknown: experimental allocators
+ * which could be useful when a fixed amount of memory is needed.
+ * @li @c fixed_bitmap: It allocates with malloc) 32* the requested
+ * size and push the pool pointer in an rbtree. To find empty space in
+ * a pool, it will just search for the first bit set in an int (32
+ * bits). Then, when a pointer is freed, it will do a search inside
+ * the rbtree.
+ * @li @c pass_through: it just call malloc() and free(). It may be
+ * faster on some computers than using our own allocators (like having
+ * a huge L2 cache, over 4MB).
+ * @li @c one_big: It call just one time malloc for the requested number
+ * of items. Usefull when you know in advance how many object of some
+ * type will live during the life of the mempool.
+ *
+ * @{
+ */
+
+EAPI Eina_Mempool *
+eina_mempool_add(const char *name,
+                 const char *context,
+                 const char *options,
+                 ...)
+{
+   Eina_Mempool *mp;
+   va_list args;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL);
+   DBG("name=%s, context=%s, options=%s",
+       name, context ? context : "", options ? options : "");
+
+   va_start(args, options);
+   mp = _new_va(name, context, options, args);
+   va_end(args);
+
+   DBG("name=%s, context=%s, options=%s, mp=%p",
+       name, context ? context : "", options ? options : "", mp);
+
+   return mp;
+}
+
+EAPI void eina_mempool_del(Eina_Mempool *mp)
+{
+   EINA_SAFETY_ON_NULL_RETURN(mp);
+   EINA_SAFETY_ON_NULL_RETURN(mp->backend.shutdown);
+   DBG("mp=%p", mp);
+   mp->backend.shutdown(mp->backend_data);
+   free(mp);
+}
+
+EAPI void eina_mempool_gc(Eina_Mempool *mp)
+{
+   EINA_SAFETY_ON_NULL_RETURN(mp);
+   EINA_SAFETY_ON_NULL_RETURN(mp->backend.garbage_collect);
+   DBG("mp=%p", mp);
+   mp->backend.garbage_collect(mp->backend_data);
+}
+
+EAPI void eina_mempool_statistics(Eina_Mempool *mp)
+{
+   EINA_SAFETY_ON_NULL_RETURN(mp);
+   EINA_SAFETY_ON_NULL_RETURN(mp->backend.statistics);
+   DBG("mp=%p", mp);
+   mp->backend.statistics(mp->backend_data);
+}
+
+EAPI unsigned int
+eina_mempool_alignof(unsigned int size)
+{
+   int align;
+
+   if (size <= 2)
+      align = 2;
+   else if (size < 8)
+      align = 4;
+   else
+#if __WORDSIZE == 32
+      align = 8;
+
+#else
+   if (size < 16)
+      align = 8;
+   else
+      align = 16;
+#endif
+
+   return ((size / align) + 1) * align;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_module.c 
b/tests/suite/ecore/src/lib/eina_module.c
new file mode 100644
index 0000000..7ae4bdb
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_module.c
@@ -0,0 +1,762 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Cedric BAIL
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_DLADDR
+# define _GNU_SOURCE
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+
+#ifndef _MSC_VER
+# include <libgen.h>
+#else
+# include <Evil.h>
+#endif
+
+#include <dlfcn.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_error.h"
+#include "eina_file.h"
+#include "eina_log.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_module.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static int EINA_MODULE_LOG_DOM = -1;
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(EINA_MODULE_LOG_DOM, __VA_ARGS__)
+
+#ifdef WRN
+#undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(EINA_MODULE_LOG_DOM, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(EINA_MODULE_LOG_DOM, __VA_ARGS__)
+
+#define EINA_MODULE_SYMBOL_INIT "__eina_module_init"
+#define EINA_MODULE_SYMBOL_SHUTDOWN "__eina_module_shutdown"
+
+struct _Eina_Module
+{
+   void *handle;
+   int ref;
+   const char file[];
+};
+
+typedef struct _Dir_List_Get_Cb_Data
+{
+   Eina_Module_Cb cb;
+   void *data;
+   Eina_Array *array;
+} Dir_List_Get_Cb_Data;
+
+typedef struct _Dir_List_Cb_Data
+{
+   Eina_Module_Cb cb;
+   void *data;
+} Dir_List_Cb_Data;
+
+static Eina_Bool _dir_list_get_cb(Eina_Module *m, void *data)
+{
+   Dir_List_Get_Cb_Data *cb_data = data;
+   Eina_Bool ret = EINA_TRUE;
+
+   if (cb_data->cb)
+      ret = cb_data->cb(m, cb_data->data);
+
+   if (ret)
+      eina_array_push(cb_data->array, m);
+
+   return ret;
+}
+
+static void _dir_list_cb(const char *name, const char *path, void *data)
+{
+   Dir_List_Cb_Data *cb_data = data;
+   size_t length;
+
+   length = strlen(name);
+   if (length < sizeof(SHARED_LIB_SUFFIX)) /* x.so */
+      return;
+
+   if (!strcmp(name + length - sizeof(SHARED_LIB_SUFFIX) + 1,
+               SHARED_LIB_SUFFIX))
+     {
+        char *file;
+        Eina_Module *m;
+
+        length = strlen(path) + strlen(name) + 2;
+
+        file = alloca(sizeof (char) * length);
+        if (!file)
+           return;
+
+        snprintf(file, length, "%s/%s", path, name);
+        m = eina_module_new(file);
+        if (!m)
+          {
+             return; /* call the user provided cb on this module */
+
+          }
+
+        if (!cb_data->cb(m, cb_data->data))
+           eina_module_free(m);
+     }
+}
+
+static void _dir_arch_list_cb(const char *name, const char *path, void *data)
+{
+   Dir_List_Get_Cb_Data *cb_data = data;
+   Eina_Module *m;
+   char *file = NULL;
+   size_t length;
+
+   length = strlen(path) + 1 + strlen(name) + 1 +
+      strlen((char *)(cb_data->data)) + 1 + sizeof("module") +
+      sizeof(SHARED_LIB_SUFFIX) + 1;
+
+   file = alloca(length);
+   snprintf(file, length, "%s/%s/%s/module" SHARED_LIB_SUFFIX,
+            path, name, (char *)(cb_data->data));
+   m = eina_module_new(file);
+   if (!m)
+      return;
+
+   eina_array_push(cb_data->array, m);
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+static const char EINA_ERROR_WRONG_MODULE_STR[] =
+   "Wrong file format or no file module found";
+static const char EINA_ERROR_MODULE_INIT_FAILED_STR[] =
+   "Module initialisation function failed";
+
+EAPI Eina_Error EINA_ERROR_WRONG_MODULE = 0;
+EAPI Eina_Error EINA_ERROR_MODULE_INIT_FAILED = 0;
+
+/**
+ * @endcond
+ */
+
+/**
+ * @internal
+ * @brief Initialize the module loader module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the module loader module of Eina. It is
+ * called by eina_init().
+ *
+ * This function sets up the module module of Eina. It also registers
+ * the errors #EINA_ERROR_WRONG_MODULE and
+ * #EINA_ERROR_MODULE_INIT_FAILED.
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_module_init(void)
+{
+   EINA_MODULE_LOG_DOM = eina_log_domain_register
+         ("eina_module", EINA_LOG_COLOR_DEFAULT);
+   if (EINA_MODULE_LOG_DOM < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_module");
+        return EINA_FALSE;
+     }
+
+#define EEMR(n) n = eina_error_msg_static_register(n ## _STR)
+   EEMR(EINA_ERROR_WRONG_MODULE);
+   EEMR(EINA_ERROR_MODULE_INIT_FAILED);
+#undef EEMR
+
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the module loader module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the module loader module set up by
+ * eina_module_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_module_shutdown(void)
+{
+   /* TODO should we store every module when "new" is called and
+    * delete the list of modules here
+    */
+
+   eina_log_domain_unregister(EINA_MODULE_LOG_DOM);
+   EINA_MODULE_LOG_DOM = -1;
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Module_Group Module
+ *
+ * @brief These functions provide module management.
+ *
+ * @{
+ */
+
+/**
+ * @brief Return a new module.
+ *
+ * @param file The name of the file module to load.
+ *
+ * This function returns a new module. If @p file is @c NULL, the
+ * function returns @c NULL, otherwise, it allocates an Eina_Module,
+ * stores a duplicate string of @p file, sets its reference to @c 0
+ * and its handle to @c NULL.
+ *
+ * When the new module is not needed anymore, use eina_module_free()
+ * to free the allocated memory.
+ *
+ * @see eina_module_load
+ */
+EAPI Eina_Module *eina_module_new(const char *file)
+{
+   Eina_Module *m;
+   size_t len;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+   /* TODO check that the file exists. Update doc too */
+
+   len = strlen(file);
+   EINA_SAFETY_ON_FALSE_RETURN_VAL(len > 0, NULL);
+
+   m = malloc(sizeof(Eina_Module) + len + 1);
+   if (!m)
+     {
+        ERR("could not malloc(%lu)",
+            (unsigned long)(sizeof(Eina_Module) + len + 1));
+        return NULL;
+     }
+
+   memcpy((char *)m->file, file, len + 1);
+   m->ref = 0;
+   m->handle = NULL;
+   DBG("m=%p, file=%s", m, file);
+
+   return m;
+}
+
+/**
+ * @brief Delete a module.
+ *
+ * @param m The module to delete.
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ *
+ * This function calls eina_module_unload() if @p m has been previously
+ * loaded and frees the allocated memory. On success this function
+ * returns EINA_TRUE and EINA_FALSE otherwise. If @p m is @c NULL, the
+ * function returns immediately.
+ */
+EAPI Eina_Bool eina_module_free(Eina_Module *m)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
+
+   DBG("m=%p, handle=%p, file=%s, refs=%d", m, m->handle, m->file, m->ref);
+
+   if (m->handle)
+      if (eina_module_unload(m) == EINA_FALSE)
+         return EINA_FALSE;
+
+   free(m);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Load a module.
+ *
+ * @param m The module to load.
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ *
+ * This function load the shared file object passed in
+ * eina_module_new(). If it is a internal Eina module (like the
+ * mempools), it also initialize it. It the shared file object can not
+ * be loaded, the error #EINA_ERROR_WRONG_MODULE is set and
+ * #EINA_FALSE is returned. If it is a internal Eina module and the
+ * module can not be initialized, the error
+ * #EINA_ERROR_MODULE_INIT_FAILED is set and #EINA_FALSE is
+ * returned. If the module has already been loaded, it's refeence
+ * counter is increased by one and #EINA_TRUE is returned. If @p m is
+ * @c NULL, the function returns immediately #EINA_FALSE.
+ *
+ * When the symbols of the shared file objetcts are not needed
+ * anymore, call eina_module_unload() to unload the module.
+ */
+EAPI Eina_Bool eina_module_load(Eina_Module *m)
+{
+   void *dl_handle;
+   Eina_Module_Init *initcall;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
+
+   DBG("m=%p, handle=%p, file=%s, refs=%d", m, m->handle, m->file, m->ref);
+
+   if (m->handle)
+      goto loaded;
+
+   dl_handle = dlopen(m->file, RTLD_NOW);
+   if (!dl_handle)
+     {
+        WRN("could not dlopen(\"%s\", RTLD_NOW): %s", m->file, dlerror());
+        eina_error_set(EINA_ERROR_WRONG_MODULE);
+        return EINA_FALSE;
+     }
+
+   initcall = dlsym(dl_handle, EINA_MODULE_SYMBOL_INIT);
+   if ((!initcall) || (!(*initcall)))
+      goto ok;
+
+   if ((*initcall)() == EINA_TRUE)
+      goto ok;
+
+   WRN("could not find eina's entry symbol %s inside module %s",
+       EINA_MODULE_SYMBOL_INIT, m->file);
+   eina_error_set(EINA_ERROR_MODULE_INIT_FAILED);
+   dlclose(dl_handle);
+   return EINA_FALSE;
+ok:
+   DBG("successfully loaded %s", m->file);
+   m->handle = dl_handle;
+loaded:
+   m->ref++;
+   DBG("ref %d", m->ref);
+
+   eina_error_set(0);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Unload a module.
+ *
+ * @param m The module to load.
+ * @return EINA_TRUE on success, EINA_FALSE otherwise.
+ *
+ * This function unload the module @p m that has been previously
+ * loaded by eina_module_load(). If the reference counter of @p m is
+ * strictly greater than @c 1, #EINA_FALSE is returned. Otherwise, the
+ * shared object file is closed and if it is a internal Eina module, it
+ * is shutted down just before. In that case, #EINA_TRUE is
+ * returned. In all case, the reference counter is decreased. If @p m
+ * is @c NULL, the function returns immediately #EINA_FALSE.
+ */
+EAPI Eina_Bool eina_module_unload(Eina_Module *m)
+{
+   Eina_Module_Shutdown *shut;
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m, EINA_FALSE);
+
+   DBG("m=%p, handle=%p, file=%s, refs=%d", m, m->handle, m->file, m->ref);
+
+   m->ref--;
+   if (!m->ref)
+     {
+        shut = dlsym(m->handle, EINA_MODULE_SYMBOL_SHUTDOWN);
+        if ((shut) && (*shut))
+           (*shut)();
+
+        dlclose(m->handle);
+        m->handle = NULL;
+        DBG("unloaded module %s", m->file);
+        return EINA_TRUE;
+     }
+
+   return EINA_FALSE;
+}
+
+/**
+ * @brief Retrive the data associated to a symbol.
+ *
+ * @param m The module.
+ * @param symbol The symbol.
+ * @return The data associated to the symbol, or @c NULL on failure.
+ *
+ * This function returns the data associated to @p symbol of @p m. @p
+ * m must have been loaded before with eina_module_load(). If @p m
+ * is @c NULL, or if it has not been correctly loaded before, the
+ * function returns immediately @c NULL.
+ */
+EAPI void *eina_module_symbol_get(const Eina_Module *m, const char *symbol)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m,         NULL);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m->handle, NULL);
+   return dlsym(m->handle, symbol);
+}
+
+/**
+ * @brief Return the file name associated to the module.
+ *
+ * @param m The module.
+ * @return The file name.
+ *
+ * This function returns the file name passed in eina_module_new(). If
+ * @p m is @c NULL, the function returns immediately @c NULL. The
+ * returned value must no be freed.
+ */
+EAPI const char *eina_module_file_get(const Eina_Module *m)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(m, NULL);
+   return m->file;
+}
+
+/**
+ * @brief Return the path built from the location of a library and a
+ * given sub directory.
+ *
+ * @param symbol The symbol to search for.
+ * @param sub_dir The subdirectory to append.
+ * @return The built path on success, @c NULL otherwise.
+ *
+ * This function returns the path built by concatenating the path of
+ * the library containing the symbol @p symbol and @p sub_dir. @p sub_dir
+ * can be @c NULL. The returned path must be freed when not used
+ * anymore. If the symbol is not found, or dl_addr() is not supported,
+ * or allocation fails, this function returns @c NULL.
+ */
+EAPI char *eina_module_symbol_path_get(const void *symbol, const char *sub_dir)
+{
+#ifdef HAVE_DLADDR
+   Dl_info eina_dl;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(symbol, NULL);
+
+   if (dladdr(symbol, &eina_dl))
+     {
+        char *pos = strrchr(eina_dl.dli_fname, '/');
+        if (pos)
+          {
+             char *path;
+             int l0;
+             int l1;
+             int l2 = 0;
+
+             l0 = strlen(eina_dl.dli_fname);
+             l1 = strlen(pos);
+             if (sub_dir && (*sub_dir != '\0'))
+                l2 = strlen(sub_dir);
+
+             path = malloc(l0 - l1 + l2 + 1);
+             if (path)
+               {
+                  memcpy(path, eina_dl.dli_fname, l0 - l1);
+                  if (sub_dir && (*sub_dir != '\0'))
+                     memcpy(path + l0 - l1, sub_dir, l2);
+
+                  path[l0 - l1 + l2] = '\0';
+                  return path;
+               }
+          }
+     }
+
+#endif /* ! HAVE_DLADDR */
+
+   return NULL;
+}
+
+/**
+ * @brief Return the path built from the value of an environment varialbe and a
+ * given sub directory.
+ *
+ * @param env The environment variable to expand.
+ * @param sub_dir The subdirectory to append.
+ * @return The built path on success, @c NULL otherwise.
+ *
+ * This function returns the path built by concatenating the value of
+ * the environment variable named @p env and @p sub_dir. @p sub_dir
+ * can be @c NULL. The returned path must be freed when not used
+ * anymore. If the symbol is not found, or @p env does not exist, or
+ * allocation fails, this function returns @c NULL.
+ */
+EAPI char *eina_module_environment_path_get(const char *env,
+                                            const char *sub_dir)
+{
+   const char *env_dir;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(env, NULL);
+
+   env_dir = getenv(env);
+   if (env_dir)
+     {
+        char *path;
+        size_t l1;
+        size_t l2 = 0;
+
+        l1 = strlen(env_dir);
+        if (sub_dir && (*sub_dir != '\0'))
+           l2 = strlen(sub_dir);
+
+        path = (char *)malloc(l1 + l2 + 1);
+        if (path)
+          {
+                memcpy(path,      env_dir, l1);
+             if (sub_dir && (*sub_dir != '\0'))
+                memcpy(path + l1, sub_dir, l2);
+
+             path[l1 + l2] = '\0';
+
+             return path;
+          }
+     }
+
+   return NULL;
+}
+
+/**
+ * @brief Get an array of modules found on the directory path matching an arch 
type.
+ *
+ * @param array The array that stores the list of the modules.
+ * @param path The directory's path to search for modules.
+ * @param arch The architecture string.
+ *
+ * This function adds to @p array the module names found in @p path
+ * which match the cpu architecture @p arch. If @p path or @p arch is
+ * @c NULL, the function returns immediately @p array. @p array can be
+ * @c NULL. In that case, it is created with 4 elements.
+ */
+EAPI Eina_Array *eina_module_arch_list_get(Eina_Array *array,
+                                           const char *path,
+                                           const char *arch)
+{
+   Dir_List_Get_Cb_Data list_get_cb_data;
+
+   if ((!path) || (!arch))
+      return array;
+
+   list_get_cb_data.array = array ? array : eina_array_new(4);
+   list_get_cb_data.cb = NULL;
+   list_get_cb_data.data = (void *)arch;
+
+   eina_file_dir_list(path, 0, &_dir_arch_list_cb, &list_get_cb_data);
+
+   return list_get_cb_data.array;
+}
+
+/**
+ * @brief Get a list of modules found on the directory path.
+ *
+ * @param array The array that stores the list of the modules.
+ * @param path The directory's path to search for modules.
+ * @param recursive Iterate recursively on the path.
+ * @param cb Callback function to call on each module.
+ * @param data Data passed to the callback function.
+ *
+ * This function adds to @p array the list of modules found in
+ * @p path. If @p recursive is #EINA_TRUE, then recursive search is
+ * done. The callback @p cb is called on each module found, and @p data
+ * is passed to @p cb. If @p path is @c NULL, the function returns
+ * immediately @p array. If the returned value of @p cb is 0, the
+ * module will not be added to the list, otherwise it will be added.
+ * @p array can be @c NULL. In that case, it is created with 4
+ * elements. @p cb can be @c NULL.
+ */
+EAPI Eina_Array *eina_module_list_get(Eina_Array *array,
+                                      const char *path,
+                                      Eina_Bool recursive,
+                                      Eina_Module_Cb cb,
+                                      void *data)
+{
+   Dir_List_Get_Cb_Data list_get_cb_data;
+   Dir_List_Cb_Data list_cb_data;
+
+   if (!path)
+      return array;
+
+   list_get_cb_data.array = array ? array : eina_array_new(4);
+   list_get_cb_data.cb = cb;
+   list_get_cb_data.data = data;
+
+   list_cb_data.cb = &_dir_list_get_cb;
+   list_cb_data.data = &list_get_cb_data;
+
+   eina_file_dir_list(path, recursive, &_dir_list_cb, &list_cb_data);
+
+   return list_get_cb_data.array;
+}
+
+/**
+ * @brief Find an module in array.
+ *
+ * @param array The array to find the module.
+ * @param module The name of module to be searched.
+ *
+ * This function finds an @p module in @p array.
+ * If the element is found  the function returns the module, else
+ * @c NULL is returned.
+ */
+EAPI Eina_Module *
+eina_module_find(const Eina_Array *array, const char *module)
+{
+   unsigned int i;
+   Eina_Array_Iterator iterator;
+   Eina_Module *m;
+
+   EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
+     {
+        char *file_m;
+        char *tmp;
+        ssize_t len;
+
+        /* basename() can modify its argument, so we first get a copie */
+        /* do not use strdupa, as opensolaris does not have it */
+        len = strlen(eina_module_file_get(m));
+        tmp = alloca(len + 1);
+        memcpy(tmp, eina_module_file_get(m), len + 1);
+        file_m = basename(tmp);
+        len = strlen(file_m);
+        len -= sizeof(SHARED_LIB_SUFFIX) - 1;
+        if (len <= 0)
+           continue;
+
+        if (!strncmp(module, file_m, len))
+          return m;;
+     }
+
+   return NULL;
+}
+
+/**
+ * @brief Load every module on the list of modules.
+ *
+ * @param array The array of modules to load.
+ *
+ * This function calls eina_module_load() on each element found in
+ * @p array. If @p array is @c NULL, this function does nothing.
+ */
+EAPI void eina_module_list_load(Eina_Array *array)
+{
+   Eina_Array_Iterator iterator;
+   Eina_Module *m;
+   unsigned int i;
+
+   EINA_SAFETY_ON_NULL_RETURN(array);
+   DBG("array %p, count %u", array, array->count);
+   EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
+     eina_module_load(m);
+}
+
+/**
+ * @brief Unload every module on the list of modules.
+ *
+ * @param array The array of modules to unload.
+ *
+ * This function calls eina_module_unload() on each element found in
+ * @p array. If @p array is @c NULL, this function does nothing.
+ */
+EAPI void eina_module_list_unload(Eina_Array *array)
+{
+   Eina_Array_Iterator iterator;
+   Eina_Module *m;
+   unsigned int i;
+
+   EINA_SAFETY_ON_NULL_RETURN(array);
+   DBG("array %p, count %u", array, array->count);
+   EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
+     eina_module_unload(m);
+}
+
+/**
+ * @p Free every module on the list of modules.
+ *
+ * @param array The array of modules to free.
+ *
+ * This function calls eina_module_free() on each element found in
+ * @p array. If @p array is @c NULL, this function does nothing.
+ */
+EAPI void eina_module_list_free(Eina_Array *array)
+{
+   Eina_Array_Iterator iterator;
+   Eina_Module *m;
+   unsigned int i;
+
+   EINA_SAFETY_ON_NULL_RETURN(array);
+   DBG("array %p, count %u", array, array->count);
+   EINA_ARRAY_ITER_NEXT(array, i, m, iterator)
+     eina_module_free(m);
+
+   eina_array_flush(array);
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_private.h 
b/tests/suite/ecore/src/lib/eina_private.h
new file mode 100644
index 0000000..2f8ff81
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_private.h
@@ -0,0 +1,135 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Carsten Haitzler, Vincent Torri, Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef EINA_PRIVATE_H_
+#define EINA_PRIVATE_H_
+
+#include <stdarg.h>
+
+#if HAVE___ATTRIBUTE__
+# define __UNUSED__ __attribute__((unused))
+#else
+# define __UNUSED__
+#endif
+
+#include "eina_magic.h"
+#include "eina_iterator.h"
+#include "eina_accessor.h"
+
+#ifndef MIN
+# define MIN(x, y) (((x) > (y)) ? (y) : (x))
+#endif
+
+#ifndef MAX
+# define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+#ifndef ABS
+# define ABS(x) ((x) < 0 ? -(x) : (x))
+#endif
+
+#ifndef CLAMP
+# define CLAMP(x, min, \
+               max) (((x) > (max)) ? (max) : (((x) < (min)) ? (min) : (x)))
+#endif
+
+#define READBUFSIZ 65536
+
+#define EINA_LOG_COLOR_DEFAULT "\033[36m"
+
+/* eina magic types */
+#define EINA_MAGIC_SHARE 0x98761234
+#define EINA_MAGIC_SHARE_HEAD 0x98761235
+#define EINA_MAGIC_STRINGSHARE_NODE 0x98761254
+#define EINA_MAGIC_USTRINGSHARE_NODE 0x98761255
+#define EINA_MAGIC_BINSHARE_NODE 0x98761256
+
+#define EINA_MAGIC_LIST 0x98761237
+#define EINA_MAGIC_LIST_ITERATOR 0x98761238
+#define EINA_MAGIC_LIST_ACCESSOR 0x98761239
+#define EINA_MAGIC_LIST_ACCOUNTING 0x9876123a
+
+#define EINA_MAGIC_ARRAY 0x9876123b
+#define EINA_MAGIC_ARRAY_ITERATOR 0x9876123c
+#define EINA_MAGIC_ARRAY_ACCESSOR 0x9876123d
+
+#define EINA_MAGIC_HASH 0x9876123e
+#define EINA_MAGIC_HASH_ITERATOR 0x9876123f
+
+#define EINA_MAGIC_TILER 0x98761240
+#define EINA_MAGIC_TILER_ITERATOR 0x98761241
+
+#define EINA_MAGIC_MATRIXSPARSE 0x98761242
+#define EINA_MAGIC_MATRIXSPARSE_ROW 0x98761243
+#define EINA_MAGIC_MATRIXSPARSE_CELL 0x98761244
+#define EINA_MAGIC_MATRIXSPARSE_ITERATOR 0x98761245
+#define EINA_MAGIC_MATRIXSPARSE_ROW_ITERATOR 0x98761246
+#define EINA_MAGIC_MATRIXSPARSE_ROW_ACCESSOR 0x98761247
+#define EINA_MAGIC_MATRIXSPARSE_CELL_ITERATOR 0x98761248
+#define EINA_MAGIC_MATRIXSPARSE_CELL_ACCESSOR 0x98761249
+
+#define EINA_MAGIC_STRBUF 0x98761250
+#define EINA_MAGIC_USTRBUF 0x98761257
+
+#define EINA_MAGIC_QUADTREE 0x98761251
+#define EINA_MAGIC_QUADTREE_ROOT 0x98761252
+#define EINA_MAGIC_QUADTREE_ITEM 0x98761253
+
+/* undef the following, we want out version */
+#undef FREE
+#define FREE(ptr)                              \
+  do {                                         \
+     free(ptr);                                        \
+     ptr = NULL;                               \
+  } while(0);
+
+#undef IF_FREE
+#define IF_FREE(ptr)                           \
+  do {                                         \
+     if (ptr) {                                        \
+       free(ptr);                              \
+       ptr = NULL;                             \
+     }                                         \
+  } while(0);
+
+#undef IF_FN_DEL
+#define IF_FN_DEL(_fn, ptr)                    \
+  do {                                         \
+     if (ptr) {                                        \
+       _fn(ptr);                               \
+       ptr = NULL;                             \
+     }                                         \
+  } while(0);
+
+#define MAGIC_FREE(ptr)                                \
+  do {                                         \
+     if (ptr) {                                        \
+       EINA_MAGIC_SET(ptr, EINA_MAGIC_NONE);   \
+       FREE(ptr);                              \
+     }                                         \
+  } while(0);
+
+#ifdef EFL_HAVE_THREADS
+void eina_share_common_threads_init(void);
+void eina_share_common_threads_shutdown(void);
+void eina_log_threads_init(void);
+void eina_log_threads_shutdown(void);
+#endif
+
+#endif /* EINA_PRIVATE_H_ */
+
diff --git a/tests/suite/ecore/src/lib/eina_quadtree.c 
b/tests/suite/ecore/src/lib/eina_quadtree.c
new file mode 100644
index 0000000..251bb96
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_quadtree.c
@@ -0,0 +1,916 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2010 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @page tutorial_quadtree_page QuadTree Tutorial
+ *
+ * to be written...
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "eina_quadtree.h"
+#include "eina_magic.h"
+#include "eina_mempool.h"
+#include "eina_list.h"
+#include "eina_inlist.h"
+#include "eina_trash.h"
+#include "eina_log.h"
+#include "eina_rectangle.h"
+
+#include "eina_private.h"
+
+typedef struct _Eina_QuadTree_Root Eina_QuadTree_Root;
+
+static const char EINA_MAGIC_QUADTREE_STR[] = "Eina QuadTree";
+static const char EINA_MAGIC_QUADTREE_ROOT_STR[] = "Eina QuadTree Root";
+static const char EINA_MAGIC_QUADTREE_ITEM_STR[] = "Eina QuadTree Item";
+
+#define EINA_MAGIC_CHECK_QUADTREE(d, ...)               \
+   do {                                                  \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_QUADTREE))     \
+          {                                                \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_QUADTREE);      \
+             return __VA_ARGS__;                           \
+          }                                                \
+     } while(0);
+
+#define EINA_MAGIC_CHECK_QUADTREE_ROOT(d, ...)                  \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_QUADTREE_ROOT))        \
+          {                                                        \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_QUADTREE_ROOT);         \
+             return __VA_ARGS__;                                   \
+          }                                                        \
+     } while(0);
+
+#define EINA_MAGIC_CHECK_QUADTREE_ITEM(d, ...)                  \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_QUADTREE_ITEM))        \
+          {                                                        \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_QUADTREE_ITEM);         \
+             return __VA_ARGS__;                                   \
+          }                                                        \
+     } while(0);
+
+struct _Eina_QuadTree
+{
+   EINA_MAGIC;
+
+   Eina_QuadTree_Root *root;
+
+   Eina_List *hidden;
+
+   size_t root_count;
+   size_t items_count;
+
+   Eina_Trash *items_trash;
+   Eina_Trash *root_trash;
+
+   Eina_Inlist *change;
+   Eina_Inlist *cached;
+   Eina_Rectangle target;
+
+   size_t index;
+
+   struct
+   {
+      Eina_Quad_Callback v;
+      Eina_Quad_Callback h;
+   } func;
+
+   struct
+   {
+      size_t w;
+      size_t h;
+   } geom;
+
+   Eina_Bool resize : 1;
+   Eina_Bool lost : 1;
+};
+
+struct _Eina_QuadTree_Root
+{
+   EINA_MAGIC;
+
+   Eina_QuadTree_Root *parent;
+   Eina_QuadTree_Root *left;
+   Eina_QuadTree_Root *right;
+
+   Eina_List *both;
+
+   Eina_Bool sorted : 1;
+};
+
+struct _Eina_QuadTree_Item
+{
+   EINA_MAGIC;
+   EINA_INLIST;
+
+   Eina_QuadTree *quad;
+   Eina_QuadTree_Root *root;
+
+   const void *object;
+
+   size_t index;
+
+   Eina_Bool change : 1;
+   Eina_Bool delete_me : 1;
+   Eina_Bool visible : 1;
+   Eina_Bool hidden : 1;
+};
+
+static int _eina_log_qd_dom = -1;
+static Eina_Mempool *root_mp = NULL;
+static Eina_Mempool *items_mp = NULL;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_log_qd_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_log_qd_dom, __VA_ARGS__)
+
+
+static int
+_eina_quadtree_item_cmp(const void *a, const void *b)
+{
+   const Eina_QuadTree_Item *i = a;
+   const Eina_QuadTree_Item *j = b;
+
+   return i->index - j->index;
+}
+
+static Eina_QuadTree_Root *
+eina_quadtree_root_free(Eina_QuadTree *q, Eina_QuadTree_Root *root)
+{
+   Eina_QuadTree_Item *item;
+
+   if (!root)
+      return NULL;
+
+   EINA_MAGIC_CHECK_QUADTREE_ROOT(root, NULL);
+
+   EINA_LIST_FREE(root->both, item)
+   eina_mempool_free(items_mp, item);
+
+   root->left = eina_quadtree_root_free(q, root->left);
+   root->right = eina_quadtree_root_free(q, root->right);
+
+   EINA_MAGIC_SET(root, 0);
+   eina_mempool_free(root_mp, root);
+
+   return NULL;
+}
+
+static Eina_QuadTree_Root *
+eina_quadtree_root_rebuild_pre(Eina_QuadTree *q,
+                               Eina_Inlist **change,
+                               Eina_QuadTree_Root *root)
+{
+   Eina_QuadTree_Item *item;
+
+   if (!root)
+      return NULL;
+
+   EINA_LIST_FREE(root->both, item)
+   {
+      if (item->visible)
+         *change = eina_inlist_append(*change, EINA_INLIST_GET(item));
+      else if (!item->hidden)
+        {
+           q->hidden = eina_list_append(q->hidden, item);
+           item->hidden = EINA_TRUE;
+           item->root = NULL;
+        }
+   }
+
+   root->left = eina_quadtree_root_rebuild_pre(q, change, root->left);
+   root->right = eina_quadtree_root_rebuild_pre(q, change, root->right);
+
+   EINA_MAGIC_SET(root, 0);
+   if (q->root_count > 50)
+      eina_mempool_free(root_mp, root);
+   else
+     {
+        eina_trash_push(&q->root_trash, root);
+        q->root_count++;
+     }
+
+   return NULL;
+}
+
+static size_t
+_eina_quadtree_split(Eina_Inlist *objects,
+                     Eina_QuadTree_Root *root,
+                     Eina_Inlist **left,
+                     Eina_Inlist **right,
+                     Eina_Quad_Callback func,
+                     int border,
+                     int middle)
+{
+   Eina_QuadTree_Item *object;
+
+   middle /= 2;
+
+   if (middle <= 4)
+      while (objects)
+        {
+           object = EINA_INLIST_CONTAINER_GET(objects, Eina_QuadTree_Item);
+           objects = objects->next;
+
+           object->change = EINA_FALSE;
+           if (!object->visible)
+             {
+                if (!object->hidden)
+                  {
+                     object->hidden = EINA_TRUE;
+                     object->quad->hidden = eina_list_append(
+                           object->quad->hidden,
+                           object);
+                  }
+
+                continue;
+             }
+
+           if (object->hidden)
+             {
+                object->hidden = EINA_FALSE;
+                object->quad->hidden = eina_list_remove(object->quad->hidden,
+                                                        object);
+             }
+
+           if (!object->delete_me)
+             {
+                if (root->sorted)
+                   root->both = eina_list_sorted_insert(root->both,
+                                                        
_eina_quadtree_item_cmp,
+                                                        object);
+                else
+                   root->both = eina_list_append(root->both, object);
+
+                object->root = root;
+             }
+           else
+              eina_quadtree_del(object);
+        }
+   else
+      while (objects)
+        {
+           object = EINA_INLIST_CONTAINER_GET(objects, Eina_QuadTree_Item);
+           objects = objects->next;
+
+           object->change = EINA_FALSE;
+           if (!object->visible)
+             {
+                if (!object->hidden)
+                  {
+                     object->hidden = EINA_TRUE;
+                     object->quad->hidden = eina_list_append(
+                           object->quad->hidden,
+                           object);
+                  }
+
+                continue;
+             }
+
+           if (object->hidden)
+             {
+                object->hidden = EINA_FALSE;
+                object->quad->hidden = eina_list_remove(object->quad->hidden,
+                                                        object);
+             }
+
+           if (!object->delete_me)
+             {
+                switch (func(object->object, border + middle))
+                  {
+                   case EINA_QUAD_LEFT:
+                      *left = eina_inlist_append(*left, 
EINA_INLIST_GET(object));
+                      break;
+
+                   case EINA_QUAD_RIGHT:
+                      *right =
+                         eina_inlist_append(*right, EINA_INLIST_GET(object));
+                      break;
+
+                   case EINA_QUAD_BOTH:
+                      root->both = eina_list_append(root->both, object);
+                      object->root = root;
+                      break;
+
+                   default:
+                      abort();
+                  }
+             }
+           else
+              eina_quadtree_del(object);
+        }
+
+   return middle;
+}
+
+
+static Eina_QuadTree_Root *
+_eina_quadtree_update(Eina_QuadTree *q, Eina_QuadTree_Root *parent,
+                      Eina_QuadTree_Root *root, Eina_Inlist *objects,
+                      Eina_Bool direction, Eina_Rectangle *size)
+{
+   Eina_Inlist *right = NULL;
+   Eina_Inlist *left = NULL;
+   size_t w2;
+   size_t h2;
+
+   if (!objects)
+      return root;
+
+   if (!root)
+     {
+        root = eina_trash_pop(&q->root_trash);
+        if (!root)
+           root = eina_mempool_malloc(root_mp, sizeof (Eina_QuadTree_Root));
+        else
+           q->root_count--;
+
+        if (!root)
+           /* FIXME: NOT GOOD TIMING, WE ARE GOING TO LEAK MORE MEMORY */
+           return NULL;
+
+        root->parent = parent;
+        root->both = NULL;
+        root->left = NULL;
+        root->right = NULL;
+        root->sorted = EINA_TRUE;
+
+        EINA_MAGIC_SET(root, EINA_MAGIC_QUADTREE_ROOT);
+     }
+
+   w2 = 0;
+   h2 = 0;
+
+   if (direction)
+      w2 = _eina_quadtree_split(objects, root,
+                                &left, &right,
+                                q->func.h, size->x, size->w);
+   else
+      h2 = _eina_quadtree_split(objects, root,
+                                &left, &right,
+                                q->func.v, size->y, size->h);
+
+   size->w -= w2; size->h -= h2;
+   root->left = _eina_quadtree_update(q, root,
+                                      root->left, left,
+                                      !direction, size);
+   size->x += w2; size->y += h2;
+   root->right = _eina_quadtree_update(q, root,
+                                       root->right, right,
+                                       !direction, size);
+   size->x -= w2; size->y -= h2;
+   size->w += w2; size->h += h2;
+
+   return root;
+}
+
+static Eina_Inlist *
+_eina_quadtree_merge(Eina_Inlist *result,
+                     Eina_List *both)
+{
+   Eina_QuadTree_Item *item;
+   Eina_QuadTree_Item *b;
+   Eina_Inlist *moving;
+
+   if (!both)
+      return result;
+
+   if (!result)
+     {
+        Eina_List *l;
+
+        EINA_LIST_FOREACH(both, l, item)
+        if (item->visible)
+           result = eina_inlist_append(result, EINA_INLIST_GET(item));
+
+        return result;
+     }
+
+   moving = result;
+
+   item = EINA_INLIST_CONTAINER_GET(moving, Eina_QuadTree_Item);
+   b = eina_list_data_get(both);
+
+   while (both && moving)
+     {
+        if (!b->visible)
+          {
+             both = eina_list_next(both);
+             b = eina_list_data_get(both);
+             continue;
+          }
+
+        if (_eina_quadtree_item_cmp(item, b) < 0)
+          {
+             /* moving is still lower than item, so we can continue to the 
next one. */
+             moving = moving->next;
+             item = EINA_INLIST_CONTAINER_GET(moving, Eina_QuadTree_Item);
+          }
+        else
+          {
+             /* we just get above the limit of both, so insert it */
+             result = eina_inlist_prepend_relative(result,
+                                                   EINA_INLIST_GET(b),
+                                                   moving);
+             both = eina_list_next(both);
+             b = eina_list_data_get(both);
+          }
+     }
+
+   item = EINA_INLIST_CONTAINER_GET(result->last, Eina_QuadTree_Item);
+
+   while (both)
+     {
+        b = eina_list_data_get(both);
+        if (b->visible)
+          {
+             if (_eina_quadtree_item_cmp(item, b) < 0)
+                break;
+
+             result = eina_inlist_prepend_relative(result,
+                                                   EINA_INLIST_GET(b),
+                                                   result->last);
+          }
+
+        both = eina_list_next(both);
+     }
+
+   while (both)
+     {
+        b = eina_list_data_get(both);
+        if (b->visible)
+           result = eina_inlist_append(result, EINA_INLIST_GET(b));
+
+        both = eina_list_next(both);
+     }
+
+   return result;
+}
+
+static Eina_Inlist *
+_eina_quadtree_collide(Eina_Inlist *result,
+                       Eina_QuadTree_Root *root,
+                       Eina_Bool direction, Eina_Rectangle *size,
+                       Eina_Rectangle *target)
+{
+   if (!root)
+      return result;
+
+   if (!root->sorted)
+     {
+        root->both = eina_list_sort(root->both, -1, _eina_quadtree_item_cmp);
+        root->sorted = EINA_TRUE;
+     }
+
+   result = _eina_quadtree_merge(result, root->both);
+   DBG("%p: %i in both for (%i, %i - %i, %i)",
+       root, eina_list_count(root->both),
+       size->x, size->y, size->w, size->h);
+
+   if (direction)
+     {
+        int middle = size->w / 2;
+
+        size->w -= middle;
+        if (eina_spans_intersect(size->x, size->w, target->x, target->w))
+           result = _eina_quadtree_collide(result, root->left,
+                                           !direction, size,
+                                           target);
+
+        size->x += middle;
+        if (eina_spans_intersect(size->x, size->w, target->x, target->w))
+           result = _eina_quadtree_collide(result, root->right,
+                                           !direction, size,
+                                           target);
+
+        size->x -= middle;
+        size->w += middle;
+     }
+   else
+     {
+        int middle = size->h / 2;
+
+        size->h -= middle;
+        if (eina_spans_intersect(size->y, size->h, target->y, target->h))
+           result = _eina_quadtree_collide(result, root->left,
+                                           !direction, size,
+                                           target);
+
+        size->y += middle;
+        if (eina_spans_intersect(size->y, size->h, target->y, target->h))
+           result = _eina_quadtree_collide(result, root->right,
+                                           !direction, size,
+                                           target);
+
+        size->y -= middle;
+        size->h += middle;
+     }
+
+   return result;
+}
+
+static void
+_eina_quadtree_remove(Eina_QuadTree_Item *object)
+{
+   if (!object->root)
+      return;
+
+   object->root->both = eina_list_remove(object->root->both, object);
+   if (object->root->both)
+      goto end;
+
+   if (object->root->left)
+      goto end;
+
+   if (object->root->right)
+      goto end;
+
+   /* The root is not useful anymore... */
+   if (object->root->parent)
+     {
+        if (object->root->parent->left == object->root)
+           object->root->parent->left = NULL;
+        else
+           object->root->parent->right = NULL;
+
+        object->root->parent = NULL;
+     }
+   else
+      object->quad->root = NULL;
+
+   if (object->quad->root_count > 50)
+      eina_mempool_free(root_mp, object->root);
+   else
+     {
+        eina_trash_push(&object->quad->root_trash, object->root);
+        object->quad->root_count++;
+     }
+
+end:
+   object->root = NULL;
+}
+
+EAPI Eina_QuadTree *
+eina_quadtree_new(size_t w, size_t h,
+                  Eina_Quad_Callback vertical, Eina_Quad_Callback horizontal)
+{
+   Eina_QuadTree *result;
+
+   if (!vertical || !horizontal || h == 0 || w == 0)
+      return NULL;
+
+   result = calloc(1, sizeof (Eina_QuadTree));
+   if (!result)
+      return NULL;
+
+   result->func.v = vertical;
+   result->func.h = horizontal;
+
+   result->geom.w = w;
+   result->geom.h = h;
+
+   result->change = NULL;
+
+   result->lost = EINA_TRUE;
+
+   EINA_MAGIC_SET(result, EINA_MAGIC_QUADTREE);
+
+   return result;
+}
+
+EAPI void
+eina_quadtree_free(Eina_QuadTree *q)
+{
+   Eina_QuadTree_Item *item;
+
+   if (!q)
+      return;
+
+   EINA_MAGIC_CHECK_QUADTREE(q);
+
+   while (q->change)
+     {
+        item = EINA_INLIST_CONTAINER_GET(q->change, Eina_QuadTree_Item);
+        q->change = q->change->next;
+        if (!item->hidden)
+           eina_mempool_free(items_mp, item);
+     }
+
+   EINA_LIST_FREE(q->hidden, item)
+   eina_mempool_free(items_mp, item);
+
+   eina_quadtree_root_free(q, q->root);
+
+   while (q->items_trash)
+     {
+        item = eina_trash_pop(&q->items_trash);
+        eina_mempool_free(items_mp, item);
+     }
+
+   while (q->root_trash)
+     {
+        Eina_QuadTree_Root *root;
+
+        root = eina_trash_pop(&q->root_trash);
+        eina_mempool_free(root_mp, root);
+     }
+
+        EINA_MAGIC_SET(q, 0);
+   free(q);
+}
+
+EAPI Eina_QuadTree_Item *
+eina_quadtree_add(Eina_QuadTree *q, const void *object)
+{
+   Eina_QuadTree_Item *result;
+
+   EINA_MAGIC_CHECK_QUADTREE(q, NULL);
+
+   if (!object)
+      return NULL;
+
+   result = eina_trash_pop(&q->items_trash);
+   if (!result)
+      result = eina_mempool_malloc(items_mp, sizeof (Eina_QuadTree_Item));
+   else
+      q->items_count--;
+
+   if (!result)
+      return NULL;
+
+   result->quad = q;
+   result->root = NULL;
+   result->object = object;
+
+   result->index = q->index++;
+
+   result->change = EINA_TRUE;
+   result->delete_me = EINA_FALSE;
+   result->visible = EINA_TRUE;
+   result->hidden = EINA_FALSE;
+
+   EINA_MAGIC_SET(result, EINA_MAGIC_QUADTREE_ITEM);
+
+   /* Insertion is delayed until we really need to use it */
+   q->change = eina_inlist_append(q->change, EINA_INLIST_GET(result));
+
+   return result;
+}
+
+EAPI Eina_Bool
+eina_quadtree_del(Eina_QuadTree_Item *object)
+{
+   if (!object)
+      return EINA_FALSE;
+
+   EINA_MAGIC_CHECK_QUADTREE_ITEM(object, EINA_FALSE);
+
+   _eina_quadtree_remove(object);
+
+   if (object->change)
+     {
+        /* This object is still in the update array, delaying it's removal !*/
+        object->delete_me = EINA_TRUE;
+        object->visible = EINA_TRUE;
+        return EINA_TRUE;
+     }
+
+   if (object->hidden)
+     {
+        object->quad->hidden = eina_list_remove(object->quad->hidden, object);
+        object->hidden = EINA_TRUE;
+     }
+
+   /* This object is not anymore inside the tree, we can remove it now !*/
+   EINA_MAGIC_SET(object, 0);
+   if (object->quad->items_count > 256)
+      eina_mempool_free(items_mp, object);
+   else
+     {
+        object->quad->items_count++;
+        eina_trash_push(&object->quad->items_trash, object);
+     }
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+eina_quadtree_change(Eina_QuadTree_Item *object)
+{
+   EINA_MAGIC_CHECK_QUADTREE_ITEM(object, EINA_FALSE);
+
+   if (object->delete_me || !object->visible)
+      return EINA_FALSE;
+
+   if (object->quad->resize)
+      return EINA_TRUE;
+
+   /* Delaying change until needed */
+   if (!object->change)
+      object->quad->change = eina_inlist_append(object->quad->change,
+                                                EINA_INLIST_GET(object));
+
+   object->change = EINA_TRUE;
+
+   _eina_quadtree_remove(object);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+eina_quadtree_hide(Eina_QuadTree_Item *object)
+{
+   EINA_MAGIC_CHECK_QUADTREE_ITEM(object, EINA_FALSE);
+
+   object->visible = EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Bool
+eina_quadtree_show(Eina_QuadTree_Item *object)
+{
+   EINA_MAGIC_CHECK_QUADTREE_ITEM(object, EINA_FALSE);
+
+   object->quad->lost = EINA_TRUE;
+
+   if (object->visible)
+      return EINA_TRUE;
+
+   object->visible = EINA_TRUE;
+   if (!object->change)
+      return eina_quadtree_change(object);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Inlist *
+eina_quadtree_collide(Eina_QuadTree *q, int x, int y, int w, int h)
+{
+   Eina_Rectangle canvas;
+
+   EINA_MAGIC_CHECK_QUADTREE(q, NULL);
+
+   /* Now we need the tree to be up to date, so it's time */
+   if (q->resize) /* Full rebuild needed ! */
+     {
+        DBG("resizing quadtree");
+        q->root = eina_quadtree_root_rebuild_pre(q, &q->change, q->root);
+        q->resize = EINA_FALSE;
+     }
+
+   EINA_RECTANGLE_SET(&canvas, 0, 0, q->geom.w, q->geom.h);
+
+   if (q->change)
+     {
+        DBG("updating quadtree content");
+        q->root = _eina_quadtree_update(q, NULL, q->root, q->change,
+                                        EINA_FALSE, &canvas);
+        q->change = NULL;
+        q->lost = EINA_TRUE;
+     }
+
+   if (q->target.x != x
+       || q->target.y != y
+       || q->target.w != w
+       || q->target.h != h)
+     {
+        DBG("new target");
+        EINA_RECTANGLE_SET(&q->target, x, y, w, h);
+        q->lost = EINA_TRUE;
+     }
+
+   if (q->lost)
+     {
+        DBG("computing collide");
+        q->cached = _eina_quadtree_collide(NULL, q->root,
+                                           EINA_FALSE, &canvas,
+                                           &q->target);
+        q->lost = EINA_FALSE;
+     }
+
+   return q->cached;
+}
+
+EAPI void *
+eina_quadtree_object(Eina_Inlist *item)
+{
+   Eina_QuadTree_Item *qi;
+
+   if (!item)
+      return NULL;
+
+   qi = EINA_INLIST_CONTAINER_GET(item, Eina_QuadTree_Item);
+   if (!qi)
+      return NULL;
+
+   EINA_MAGIC_CHECK_QUADTREE_ITEM(qi, NULL);
+
+   if (!qi->visible)
+      return NULL;
+
+   return (void *)qi->object;
+}
+
+EAPI void
+eina_quadtree_resize(Eina_QuadTree *q, size_t w, size_t h)
+{
+   EINA_MAGIC_CHECK_QUADTREE(q);
+
+   if (q->geom.w == w
+       && q->geom.h == h)
+      return;
+
+   q->resize = EINA_TRUE;
+   q->geom.w = w;
+   q->geom.h = h;
+}
+
+EAPI void
+eina_quadtree_cycle(Eina_QuadTree *q)
+{
+   EINA_MAGIC_CHECK_QUADTREE(q);
+
+   q->index = 0;
+}
+
+EAPI void
+eina_quadtree_increase(Eina_QuadTree_Item *object)
+{
+   size_t tmp;
+
+   tmp = object->quad->index++;
+   if (object->index == tmp)
+      return;
+
+   object->index = tmp;
+   if (object->root)
+      object->root->sorted = EINA_FALSE;
+}
+
+Eina_Bool
+eina_quadtree_init(void)
+{
+   _eina_log_qd_dom = eina_log_domain_register("eina_quadtree",
+                                               EINA_LOG_COLOR_DEFAULT);
+   if (_eina_log_qd_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_quadtree");
+        return EINA_FALSE;
+     }
+
+#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
+   EMS(EINA_MAGIC_QUADTREE);
+   EMS(EINA_MAGIC_QUADTREE_ROOT);
+   EMS(EINA_MAGIC_QUADTREE_ITEM);
+#undef EMS
+
+   items_mp = eina_mempool_add("chained_mempool", "QuadTree Item", NULL,
+                               sizeof (Eina_QuadTree_Item), 320);
+   root_mp = eina_mempool_add("chained_mempool", "QuadTree Root", NULL,
+                              sizeof (Eina_QuadTree_Root), 32);
+
+   return EINA_TRUE;
+}
+
+Eina_Bool
+eina_quadtree_shutdown(void)
+{
+   eina_log_domain_unregister(_eina_log_qd_dom);
+   _eina_log_qd_dom = -1;
+   return EINA_TRUE;
+}
+
+
+
diff --git a/tests/suite/ecore/src/lib/eina_rbtree.c 
b/tests/suite/ecore/src/lib/eina_rbtree.c
new file mode 100644
index 0000000..1f03308
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_rbtree.c
@@ -0,0 +1,592 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Cedric Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_array.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_rbtree.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+#define EINA_RBTREE_ITERATOR_PREFIX_MASK  0x1
+#define EINA_RBTREE_ITERATOR_INFIX_MASK   0x2
+#define EINA_RBTREE_ITERATOR_POSTFIX_MASK 0x4
+
+typedef struct _Eina_Iterator_Rbtree Eina_Iterator_Rbtree;
+typedef struct _Eina_Iterator_Rbtree_List Eina_Iterator_Rbtree_List;
+
+struct _Eina_Iterator_Rbtree
+{
+   Eina_Iterator iterator;
+
+   Eina_Array *stack;
+
+   unsigned char mask;
+};
+
+struct _Eina_Iterator_Rbtree_List
+{
+   Eina_Rbtree *tree;
+
+   Eina_Rbtree_Direction dir : 1;
+   Eina_Bool up : 1;
+};
+
+static Eina_Iterator_Rbtree_List *
+_eina_rbtree_iterator_list_new(const Eina_Rbtree *tree)
+{
+   Eina_Iterator_Rbtree_List *new;
+
+        eina_error_set(0);
+   new = malloc(sizeof (Eina_Iterator_Rbtree_List));
+   if (!new)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   new->tree = (Eina_Rbtree *)tree;
+   new->dir = EINA_RBTREE_RIGHT;
+   new->up = EINA_FALSE;
+
+   return new;
+}
+
+static Eina_Rbtree *
+_eina_rbtree_iterator_get_content(Eina_Iterator_Rbtree *it)
+{
+   if (eina_array_count_get(it->stack) <= 0)
+      return NULL;
+
+   return eina_array_data_get(it->stack, 0);
+}
+
+static void
+_eina_rbtree_iterator_free(Eina_Iterator_Rbtree *it)
+{
+   Eina_Iterator_Rbtree_List *item;
+   Eina_Array_Iterator et;
+   unsigned int i;
+
+   EINA_ARRAY_ITER_NEXT(it->stack, i, item, et)
+     free(item);
+
+   eina_array_free(it->stack);
+                     free(it);
+}
+
+static Eina_Bool
+_eina_rbtree_iterator_next(Eina_Iterator_Rbtree *it, void **data)
+{
+   Eina_Iterator_Rbtree_List *last;
+   Eina_Iterator_Rbtree_List *new;
+   Eina_Rbtree *tree;
+
+   if (eina_array_count_get(it->stack) <= 0)
+      return EINA_FALSE;
+
+   last = eina_array_data_get(it->stack, eina_array_count_get(it->stack) - 1);
+   tree = last->tree;
+
+   if (!last->tree || last->up == EINA_TRUE)
+     {
+        last = eina_array_pop(it->stack);
+        while (last->dir == EINA_RBTREE_LEFT
+               || !last->tree)
+          {
+             if (tree)
+                if ((it->mask & EINA_RBTREE_ITERATOR_POSTFIX_MASK) ==
+                    EINA_RBTREE_ITERATOR_POSTFIX_MASK)
+                  {
+                     free(last);
+
+                     if (eina_array_count_get(it->stack) > 0)
+                       {
+                          last = eina_array_data_get(it->stack,
+                                                     eina_array_count_get(
+                                                        it->
+                                                        stack)
+                                                     - 1);
+                          last->up = EINA_TRUE;
+                       }
+
+                     goto onfix;
+                  }
+
+             free(last);
+
+             last = eina_array_pop(it->stack);
+             if (!last)
+                return EINA_FALSE;
+
+             tree = last->tree;
+          }
+
+        last->dir = EINA_RBTREE_LEFT;
+        last->up = EINA_FALSE;
+
+        eina_array_push(it->stack, last);
+
+        if ((it->mask & EINA_RBTREE_ITERATOR_INFIX_MASK) ==
+            EINA_RBTREE_ITERATOR_INFIX_MASK)
+           goto onfix;
+     }
+
+   new = _eina_rbtree_iterator_list_new(last->tree->son[last->dir]);
+   if (!new)
+      return EINA_FALSE;
+
+        eina_array_push(it->stack, new);
+
+   if (last->dir == EINA_RBTREE_RIGHT)
+      if ((it->mask & EINA_RBTREE_ITERATOR_PREFIX_MASK) ==
+          EINA_RBTREE_ITERATOR_PREFIX_MASK)
+         goto onfix;
+
+   return _eina_rbtree_iterator_next(it, data);
+
+onfix:
+   *data = tree;
+   return EINA_TRUE;
+}
+
+static Eina_Iterator *
+_eina_rbtree_iterator_build(const Eina_Rbtree *root, unsigned char mask)
+{
+   Eina_Iterator_Rbtree_List *first;
+   Eina_Iterator_Rbtree *it;
+
+   eina_error_set(0);
+   it = calloc(1, sizeof (Eina_Iterator_Rbtree));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   it->stack = eina_array_new(8);
+   if (!it->stack)
+      goto on_error2;
+
+   first = _eina_rbtree_iterator_list_new(root);
+   if (!first)
+      goto on_error;
+
+   eina_array_push(it->stack, first);
+
+   it->mask = mask;
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_rbtree_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _eina_rbtree_iterator_get_content);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_rbtree_iterator_free);
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   return &it->iterator;
+
+on_error:
+   eina_array_free(it->stack);
+on_error2:
+   free(it);
+
+   return NULL;
+}
+
+/*
+ * Thanks to Julienne Walker public domain tutorial.
+ * http://eternallyconfuzzled.com/tuts/datastructures/jsw_tut_rbtree.aspx
+ */
+
+static void
+_eina_rbtree_node_init(Eina_Rbtree *node)
+{
+   if (!node)
+      return;
+
+   node->son[0] = NULL;
+   node->son[1] = NULL;
+
+   node->color = EINA_RBTREE_RED;
+}
+
+static inline Eina_Bool
+_eina_rbtree_is_red(Eina_Rbtree *node)
+{
+   return !!node && node->color == EINA_RBTREE_RED;
+}
+
+static inline Eina_Rbtree *
+_eina_rbtree_inline_single_rotation(Eina_Rbtree *node,
+                                    Eina_Rbtree_Direction dir)
+{
+   Eina_Rbtree *save = node->son[!dir];
+
+   node->son[!dir] = save->son[dir];
+   save->son[dir] = node;
+
+   node->color = EINA_RBTREE_RED;
+   save->color = EINA_RBTREE_BLACK;
+
+   return save;
+}
+
+static inline Eina_Rbtree *
+_eina_rbtree_inline_double_rotation(Eina_Rbtree *node,
+                                    Eina_Rbtree_Direction dir)
+{
+   node->son[!dir] = _eina_rbtree_inline_single_rotation(node->son[!dir], 
!dir);
+   return _eina_rbtree_inline_single_rotation(node, dir);
+}
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Rbtree_Group Red-Black tree
+ *
+ * @brief These functions provide Red-Black trees management.
+ *
+ * @{
+ */
+
+EAPI Eina_Rbtree *
+eina_rbtree_inline_insert(Eina_Rbtree *root,
+                          Eina_Rbtree *node,
+                          Eina_Rbtree_Cmp_Node_Cb cmp,
+                          const void *data)
+{
+   Eina_Rbtree head;
+   Eina_Rbtree *g, *t; /* Grandparent & parent */
+   Eina_Rbtree *p, *q; /* Iterator & parent */
+   /* WARNING:
+      Compiler is not able to understand the underlying algorithm and don't 
know that
+      first top node is always black, so it will never use last before running 
the loop
+      one time.
+    */
+   Eina_Rbtree_Direction dir, last;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(node, root);
+   EINA_SAFETY_ON_NULL_RETURN_VAL( cmp, root);
+
+   if (!node)
+      return root;
+
+   _eina_rbtree_node_init(node);
+
+   if (!root)
+     {
+        root = node;
+        goto end_add;
+     }
+
+   memset(&head, 0, sizeof (Eina_Rbtree));
+   last = dir = EINA_RBTREE_LEFT;
+
+   /* Set up helpers */
+   t = &head;
+   g = p = NULL;
+   q = t->son[1] = root;
+
+   /* Search down the tree */
+   for (;; )
+     {
+        if (!q)
+           /* Insert new node at the bottom */
+           p->son[dir] = q = node;
+        else if (_eina_rbtree_is_red(q->son[0])
+                 && _eina_rbtree_is_red(q->son[1]))
+          {
+             /* Color flip */
+             q->color = EINA_RBTREE_RED;
+             q->son[0]->color = EINA_RBTREE_BLACK;
+             q->son[1]->color = EINA_RBTREE_BLACK;
+          }
+
+        /* Fix red violation */
+        if (_eina_rbtree_is_red(q) && _eina_rbtree_is_red(p))
+          {
+             Eina_Rbtree_Direction dir2;
+
+             dir2 = (t->son[1] == g) ? EINA_RBTREE_RIGHT : EINA_RBTREE_LEFT;
+
+             if (q == p->son[last])
+                t->son[dir2] = _eina_rbtree_inline_single_rotation(g, !last);
+             else
+                t->son[dir2] = _eina_rbtree_inline_double_rotation(g, !last);
+          }
+
+        /* Stop if found */
+        if (q == node)
+           break;
+
+        last = dir;
+        dir = cmp(q, node, (void *)data);
+
+        /* Update helpers */
+        if ( g )
+           t = g;
+
+        g = p, p = q;
+        q = q->son[dir];
+     }
+
+   root = head.son[1];
+
+end_add:
+   /* Make root black */
+   root->color = EINA_RBTREE_BLACK;
+
+   return root;
+}
+
+EAPI Eina_Rbtree *
+eina_rbtree_inline_remove(Eina_Rbtree *root,
+                          Eina_Rbtree *node,
+                          Eina_Rbtree_Cmp_Node_Cb cmp,
+                          const void *data)
+{
+   Eina_Rbtree head;
+   Eina_Rbtree *q, *p;
+   Eina_Rbtree *f = NULL;
+   Eina_Rbtree_Direction dir;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(node, root);
+   EINA_SAFETY_ON_NULL_RETURN_VAL( cmp, root);
+
+   if (!root || !node)
+      return root;
+
+   memset(&head, 0, sizeof(Eina_Rbtree));
+
+   dir = EINA_RBTREE_RIGHT;
+   q = &head;
+   p = NULL;
+   q->son[EINA_RBTREE_RIGHT] = root;
+
+   /* Search and push a red down */
+   while (q->son[dir])
+     {
+        Eina_Rbtree_Direction last = dir;
+        Eina_Rbtree *g;
+
+        /* Update helpers */
+        g = p; p = q;
+        q = q->son[dir];
+        dir = cmp(q, node, (void *)data);
+
+        /* Save parent node found */
+        if (q == node)
+           f = p;
+
+        /* Push the red node down */
+        if (!_eina_rbtree_is_red(q)
+            && !_eina_rbtree_is_red(q->son[dir]))
+          {
+             if (_eina_rbtree_is_red(q->son[!dir]))
+                q = p->son[last] = _eina_rbtree_inline_single_rotation(q, dir);
+             else if (!_eina_rbtree_is_red(q->son[!dir]))
+               {
+                  Eina_Rbtree *s = p->son[!last];
+
+                  if (s)
+                    {
+                       if (!_eina_rbtree_is_red(s->son[EINA_RBTREE_LEFT])
+                           && !_eina_rbtree_is_red(s->son[EINA_RBTREE_RIGHT]))
+                         {
+/* Color flip */
+                            p->color = EINA_RBTREE_BLACK;
+                            p->son[EINA_RBTREE_LEFT]->color = EINA_RBTREE_RED;
+                            p->son[EINA_RBTREE_RIGHT]->color = EINA_RBTREE_RED;
+                         }
+                       else
+                         {
+                            Eina_Rbtree_Direction dir2;
+
+                            dir2 = g->son[1] ==
+                               p ? EINA_RBTREE_RIGHT : EINA_RBTREE_LEFT;
+
+                            if (_eina_rbtree_is_red(s->son[last]))
+                              {
+                                 g->son[dir2] =
+                                    _eina_rbtree_inline_double_rotation(p, 
last);
+                                 if (f == g)
+                                   {
+                                      p = g->son[dir2]->son[last];
+                                      f = g->son[dir2];
+                                   }
+                              }
+                            else if (_eina_rbtree_is_red(s->son[!last]))
+                              {
+                                 g->son[dir2] =
+                                    _eina_rbtree_inline_single_rotation(p, 
last);
+                                 if (f == g)
+                                   {
+                                      p = g->son[dir2]->son[last];
+                                      f = g->son[dir2];
+                                   }
+                              }
+
+/* Ensure correct coloring */
+                            q->color = g->son[dir2]->color = EINA_RBTREE_RED;
+                            g->son[dir2]->son[EINA_RBTREE_LEFT]->color =
+                               EINA_RBTREE_BLACK;
+                            g->son[dir2]->son[EINA_RBTREE_RIGHT]->color =
+                               EINA_RBTREE_BLACK;
+                         }
+                    }
+               }
+          }
+     }
+
+   /* Replace and remove if found */
+   if (f)
+     {
+        /* 'q' should take the place of 'node' parent */
+        f->son[f->son[1] == node] = q;
+
+        /* Switch the link from the parent to q's son */
+        p->son[p->son[1] == q] = q->son[!q->son[0]];
+
+        /* Put q at the place of node */
+        q->son[0] = node->son[0];
+        q->son[1] = node->son[1];
+        q->color = node->color;
+
+        /* Reset node link */
+        node->son[0] = NULL;
+        node->son[1] = NULL;
+     }
+
+   root = head.son[1];
+   if (root)
+      root->color = EINA_RBTREE_BLACK;
+
+   return root;
+}
+
+/**
+ * @brief Returned a new prefix iterator associated to a rbtree.
+ *
+ * @param root The root of rbtree.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to @p
+ * root. It will iterate the tree using prefix walk. If @p root is @c
+ * NULL, this function still returns a valid iterator that will always
+ * return false on eina_iterator_next(), thus keeping API sane.
+ *
+ * If the memory can not be allocated, NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
+ * returned.
+ *
+ * @warning if the rbtree structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove nodes this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_rbtree_iterator_prefix(const Eina_Rbtree *root)
+{
+   return _eina_rbtree_iterator_build(root, EINA_RBTREE_ITERATOR_PREFIX_MASK);
+}
+
+/**
+ * @brief Returned a new prefix iterator associated to a rbtree.
+ *
+ * @param root The root of rbtree.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to @p
+ * root. It will iterate the tree using infix walk. If @p root is @c
+ * NULL, this function still returns a valid iterator that will always
+ * return false on eina_iterator_next(), thus keeping API sane.
+ *
+ * If the memory can not be allocated, NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
+ * returned.
+ *
+ * @warning if the rbtree structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove nodes this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_rbtree_iterator_infix(const Eina_Rbtree *root)
+{
+   return _eina_rbtree_iterator_build(root, EINA_RBTREE_ITERATOR_INFIX_MASK);
+}
+
+/**
+ * @brief Returned a new prefix iterator associated to a rbtree.
+ *
+ * @param root The root of rbtree.
+ * @return A new iterator.
+ *
+ * This function returns a newly allocated iterator associated to @p
+ * root. It will iterate the tree using postfix walk. If @p root is @c
+ * NULL, this function still returns a valid iterator that will always
+ * return false on eina_iterator_next(), thus keeping API sane.
+ *
+ * If the memory can not be allocated, NULL is returned and
+ * #EINA_ERROR_OUT_OF_MEMORY is set. Otherwise, a valid iterator is
+ * returned.
+ *
+ * @warning if the rbtree structure changes then the iterator becomes
+ *    invalid! That is, if you add or remove nodes this iterator
+ *    behavior is undefined and your program may crash!
+ */
+EAPI Eina_Iterator *
+eina_rbtree_iterator_postfix(const Eina_Rbtree *root)
+{
+   return _eina_rbtree_iterator_build(root, EINA_RBTREE_ITERATOR_POSTFIX_MASK);
+}
+
+EAPI void
+eina_rbtree_delete(Eina_Rbtree *root, Eina_Rbtree_Free_Cb func, void *data)
+{
+   if (!root)
+      return;
+
+   EINA_SAFETY_ON_NULL_RETURN(func);
+
+   eina_rbtree_delete(root->son[0], func, data);
+   eina_rbtree_delete(root->son[1], func, data);
+   func(root, data);
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_rectangle.c 
b/tests/suite/ecore/src/lib/eina_rectangle.c
new file mode 100644
index 0000000..237ca8b
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_rectangle.c
@@ -0,0 +1,693 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Cedric BAIL, Carsten Haitzler
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_magic.h"
+#include "eina_inlist.h"
+#include "eina_mempool.h"
+#include "eina_list.h"
+#include "eina_trash.h"
+#include "eina_log.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_rectangle.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#define EINA_RECTANGLE_POOL_MAGIC 0x1578FCB0
+#define EINA_RECTANGLE_ALLOC_MAGIC 0x1578FCB1
+
+#define BUCKET_THRESHOLD 110
+
+typedef struct _Eina_Rectangle_Alloc Eina_Rectangle_Alloc;
+
+struct _Eina_Rectangle_Pool
+{
+   Eina_Inlist *head;
+   Eina_List *empty;
+   void *data;
+
+   Eina_Trash *bucket;
+   unsigned int bucket_count;
+
+   unsigned int references;
+   int w;
+   int h;
+
+   Eina_Bool sorted;
+   EINA_MAGIC
+};
+
+struct _Eina_Rectangle_Alloc
+{
+   EINA_INLIST;
+   Eina_Rectangle_Pool *pool;
+   EINA_MAGIC
+};
+
+#define EINA_MAGIC_CHECK_RECTANGLE_POOL(d)                     \
+   do {                                                         \
+        if (!EINA_MAGIC_CHECK((d), EINA_RECTANGLE_POOL_MAGIC)) {    \
+             EINA_MAGIC_FAIL((d), EINA_RECTANGLE_POOL_MAGIC); }        \
+     } while (0)
+
+#define EINA_MAGIC_CHECK_RECTANGLE_ALLOC(d)                    \
+   do {                                                         \
+        if (!EINA_MAGIC_CHECK((d), EINA_RECTANGLE_ALLOC_MAGIC)) {   \
+             EINA_MAGIC_FAIL((d), EINA_RECTANGLE_ALLOC_MAGIC); }       \
+     } while (0)
+
+static Eina_Mempool *_eina_rectangle_alloc_mp = NULL;
+static Eina_Mempool *_eina_rectangle_mp = NULL;
+
+static Eina_Trash *_eina_rectangles = NULL;
+static unsigned int _eina_rectangles_count = 0;
+static int _eina_rectangle_log_dom = -1;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_rectangle_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_rectangle_log_dom, __VA_ARGS__)
+
+static int
+_eina_rectangle_cmp(const Eina_Rectangle *r1, const Eina_Rectangle *r2)
+{
+   return (r2->w * r2->h) - (r1->w * r1->h);
+}
+
+static Eina_List *
+_eina_rectangle_merge_list(Eina_List *empty, Eina_Rectangle *r)
+{
+   Eina_Rectangle *match;
+   Eina_List *l;
+   int xw;
+   int yh;
+
+   if (r->w == 0 || r->h == 0)
+     {
+        eina_rectangle_free(r);
+        return empty;
+     }
+
+start_again:
+   xw = r->x + r->w;
+   yh = r->y + r->h;
+
+   EINA_LIST_FOREACH(empty, l, match)
+   {
+      if (match->x == r->x && match->w == r->w
+          && (match->y == yh || r->y == match->y + match->h))
+        {
+           if (match->y > r->y)
+              match->y = r->y;
+
+           match->h += r->h;
+
+           eina_rectangle_free(r);
+
+           empty = eina_list_remove_list(empty, l);
+
+           r = match;
+
+           goto start_again;
+        }
+      else if (match->y == r->y && match->h == r->h
+               && (match->x == xw || r->x == match->x + match->w))
+        {
+           if (match->x > r->x)
+              match->x = r->x;
+
+           match->w += r->w;
+
+           eina_rectangle_free(r);
+
+           empty = eina_list_remove_list(empty, l);
+
+           r = match;
+
+           goto start_again;
+        }
+   }
+
+   return eina_list_append(empty, r);
+}
+
+static Eina_List *
+_eina_rectangle_empty_space_find(Eina_List *empty, int w, int h, int *x, int 
*y)
+{
+   Eina_Rectangle *r;
+   Eina_List *l;
+
+   EINA_LIST_FOREACH(empty, l, r)
+   {
+      if (r->w >= w && r->h >= h)
+        {
+           /* Remove l from empty */
+           empty = eina_list_remove_list(empty, l);
+           /* Remember x and y */
+           *x = r->x;
+           *y = r->y;
+           /* Split r in 2 rectangle if needed (only the empty one) and insert 
them */
+           if (r->w == w)
+             {
+                r->y += h;
+                r->h -= h;
+             }
+           else if (r->h == h)
+             {
+                r->x += w;
+                r->w -= w;
+             }
+           else
+             {
+                int rx1, ry1, rw1, rh1;
+                int x2, y2, w2, h2;
+
+                rx1 = r->x + w;
+                ry1 = r->y;
+                rw1 = r->w - w;
+                /* h1 could be h or r->h */
+                x2 = r->x;
+                y2 = r->y + h;
+                /* w2 could be w or r->w */
+                h2 = r->h - h;
+
+                if (rw1 * r->h > h2 * r->w)
+                  {
+                     rh1 = r->h;
+                     w2 = w;
+                  }
+                else
+                  {
+                     rh1 = h;
+                     w2 = r->w;
+                  }
+
+                EINA_RECTANGLE_SET(r, rx1, ry1, rw1, rh1);
+                empty = _eina_rectangle_merge_list(empty, r);
+
+                r = eina_rectangle_new(x2, y2, w2, h2);
+             }
+
+           if (r)
+             {
+                empty = _eina_rectangle_merge_list(empty, r); /* Return empty 
*/
+
+             }
+
+           return empty;
+        }
+   }
+
+   *x = -1;
+   *y = -1;
+   return empty;
+}
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+Eina_Bool
+eina_rectangle_init(void)
+{
+   const char *choice, *tmp;
+
+   _eina_rectangle_log_dom = eina_log_domain_register("eina_rectangle",
+                                                      EINA_LOG_COLOR_DEFAULT);
+   if (_eina_rectangle_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_rectangle");
+        return EINA_FALSE;
+     }
+
+#ifdef EINA_DEFAULT_MEMPOOL
+   choice = "pass_through";
+#else
+   choice = "chained_mempool";
+#endif
+   tmp = getenv("EINA_MEMPOOL");
+   if (tmp && tmp[0])
+      choice = tmp;
+
+   _eina_rectangle_alloc_mp = eina_mempool_add
+         (choice, "rectangle-alloc", NULL,
+         sizeof(Eina_Rectangle_Alloc) + sizeof(Eina_Rectangle), 1024);
+   if (!_eina_rectangle_alloc_mp)
+     {
+        ERR("Mempool for rectangle cannot be allocated in rectangle init.");
+        goto init_error;
+     }
+
+   _eina_rectangle_mp = eina_mempool_add
+         (choice, "rectangle", NULL, sizeof(Eina_Rectangle), 256);
+   if (!_eina_rectangle_mp)
+     {
+        ERR("Mempool for rectangle cannot be allocated in rectangle init.");
+        goto init_error;
+     }
+
+   return EINA_TRUE;
+
+init_error:
+   eina_log_domain_unregister(_eina_rectangle_log_dom);
+   _eina_rectangle_log_dom = -1;
+
+   return EINA_FALSE;
+}
+
+Eina_Bool
+eina_rectangle_shutdown(void)
+{
+   Eina_Rectangle *del;
+
+   while ((del = eina_trash_pop(&_eina_rectangles)))
+      eina_mempool_free(_eina_rectangle_mp, del);
+   _eina_rectangles_count = 0;
+
+   eina_mempool_del(_eina_rectangle_alloc_mp);
+   eina_mempool_del(_eina_rectangle_mp);
+
+   eina_log_domain_unregister(_eina_rectangle_log_dom);
+   _eina_rectangle_log_dom = -1;
+
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Rectangle_Group Rectangle
+ *
+ * @brief These functions provide rectangle management.
+ *
+ * @{
+ */
+
+/**
+ * @brief Create a new rectangle.
+ *
+ * @param x The X coordinate of the top left corner of the rectangle.
+ * @param y The Y coordinate of the top left corner of the rectangle.
+ * @param w The width of the rectangle.
+ * @param h The height of the rectangle.
+ * @return The new rectangle on success, @ NULL otherwise.
+ *
+ * This function creates a rectangle which top left corner has the
+ * coordinates (@p x, @p y), with height @p w and height @p h and adds
+ * it to the rectangles pool. No check is done on @p w and @p h. This
+ * function returns a new rectangle on success, @c NULL otherwhise.
+ */
+EAPI Eina_Rectangle *
+eina_rectangle_new(int x, int y, int w, int h)
+{
+   Eina_Rectangle *rect;
+
+   if (_eina_rectangles)
+     {
+        rect = eina_trash_pop(&_eina_rectangles);
+        _eina_rectangles_count--;
+     }
+   else
+      rect = eina_mempool_malloc(_eina_rectangle_mp, sizeof (Eina_Rectangle));
+
+   if (!rect)
+      return NULL;
+
+   EINA_RECTANGLE_SET(rect, x, y, w, h);
+
+   return rect;
+}
+
+/**
+ * @brief Free the given rectangle.
+ *
+ * @param rect The rectangle to free.
+ *
+ * This function removes @p rect from the rectangles pool.
+ */
+EAPI void
+eina_rectangle_free(Eina_Rectangle *rect)
+{
+   EINA_SAFETY_ON_NULL_RETURN(rect);
+
+   if (_eina_rectangles_count > BUCKET_THRESHOLD)
+      eina_mempool_free(_eina_rectangle_mp, rect);
+   else
+     {
+        eina_trash_push(&_eina_rectangles, rect);
+        _eina_rectangles_count++;
+     }
+}
+
+/**
+ * @brief Add a rectangle in a new pool.
+ *
+ * @param w The width of the rectangle.
+ * @param h The height of the rectangle.
+ * @return A newly allocated pool on success, @c NULL otherwise.
+ *
+ * This function adds the rectangle of size (@p width, @p height) to a
+ * new pool. If the pool can not be created, @c NULL is
+ * returned. Otherwise the newly allocated pool is returned.
+ */
+EAPI Eina_Rectangle_Pool *
+eina_rectangle_pool_new(int w, int h)
+{
+   Eina_Rectangle_Pool *new;
+
+   new = malloc(sizeof (Eina_Rectangle_Pool));
+   if (!new)
+      return NULL;
+
+   new->head = NULL;
+   new->empty = eina_list_append(NULL, eina_rectangle_new(0, 0, w, h));
+   new->references = 0;
+   new->sorted = EINA_FALSE;
+   new->w = w;
+   new->h = h;
+   new->bucket = NULL;
+   new->bucket_count = 0;
+
+   EINA_MAGIC_SET(new, EINA_RECTANGLE_POOL_MAGIC);
+   DBG("pool=%p, size=(%d, %d)", new, w, h);
+
+   return new;
+}
+
+/**
+ * @brief Free the given pool.
+ *
+ * @param pool The pool to free.
+ *
+ * This function frees the allocated data of @p pool. If @p pool is
+ * @c NULL, ths function returned immediately.
+ */
+EAPI void
+eina_rectangle_pool_free(Eina_Rectangle_Pool *pool)
+{
+   Eina_Rectangle_Alloc *del;
+
+   EINA_SAFETY_ON_NULL_RETURN(pool);
+   DBG("pool=%p, size=(%d, %d), references=%u",
+       pool, pool->w, pool->h, pool->references);
+   while (pool->head)
+     {
+        del = (Eina_Rectangle_Alloc *)pool->head;
+
+        pool->head = (EINA_INLIST_GET(del))->next;
+
+        EINA_MAGIC_SET(del, EINA_MAGIC_NONE);
+        eina_mempool_free(_eina_rectangle_alloc_mp, del);
+     }
+
+   while (pool->bucket)
+     {
+        del = eina_trash_pop(&pool->bucket);
+        eina_mempool_free(_eina_rectangle_alloc_mp, del);
+     }
+
+        MAGIC_FREE(pool);
+}
+
+/**
+ * @brief Return the number of rectangles in the given pool.
+ *
+ * @param pool The pool.
+ * @return The number of rectangles in the pool.
+ *
+ * This function returns the number of rectangles in @p pool.
+ */
+EAPI int
+eina_rectangle_pool_count(Eina_Rectangle_Pool *pool)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pool, 0);
+   return pool->references;
+}
+
+/**
+ * @brief Request a rectangle of given size in the given pool.
+ *
+ * @param pool The pool.
+ * @param w The width of the rectangle to request.
+ * @param h The height of the rectangle to request.
+ * @return The requested rectangle on success, @c NULL otherwise.
+ *
+ * This function retrieve from @p pool the rectangle of width @p w and
+ * height @p h. If @p pool is @c NULL, or @p w or @p h are non-positive,
+ * the function returns @c NULL. If @p w or @p h are greater than the
+ * pool size, the function returns @c NULL. On success, the function
+ * returns the rectangle which matches the size (@p w, @p h).
+ * Otherwise it returns @c NULL.
+ */
+EAPI Eina_Rectangle *
+eina_rectangle_pool_request(Eina_Rectangle_Pool *pool, int w, int h)
+{
+   Eina_Rectangle_Alloc *new;
+   Eina_Rectangle *rect;
+   int x;
+   int y;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL);
+
+   DBG("pool=%p, size=(%d, %d), references=%u",
+       pool, pool->w, pool->h, pool->references);
+
+   if (w <= 0 || h <= 0)
+      return NULL;
+
+   if (w > pool->w || h > pool->h)
+      return NULL;
+
+   /* Sort empty if dirty */
+   if (pool->sorted)
+     {
+        pool->empty =
+           eina_list_sort(pool->empty, 0, 
EINA_COMPARE_CB(_eina_rectangle_cmp));
+        pool->sorted = EINA_TRUE;
+     }
+
+   pool->empty = _eina_rectangle_empty_space_find(pool->empty, w, h, &x, &y);
+   if (x == -1)
+      return NULL;
+
+   pool->sorted = EINA_FALSE;
+
+   if (pool->bucket_count > 0)
+     {
+        new = eina_trash_pop(&pool->bucket);
+        pool->bucket_count--;
+     }
+   else
+      new = eina_mempool_malloc(_eina_rectangle_alloc_mp,
+                                sizeof (Eina_Rectangle_Alloc) +
+                                sizeof (Eina_Rectangle));
+
+   if (!new)
+      return NULL;
+
+   rect = (Eina_Rectangle *)(new + 1);
+   eina_rectangle_coords_from(rect, x, y, w, h);
+
+   pool->head = eina_inlist_prepend(pool->head, EINA_INLIST_GET(new));
+   pool->references++;
+
+   new->pool = pool;
+
+   EINA_MAGIC_SET(new, EINA_RECTANGLE_ALLOC_MAGIC);
+   DBG("rect=%p pool=%p, size=(%d, %d), references=%u",
+       rect, pool, pool->w, pool->h, pool->references);
+
+   return rect;
+}
+
+/**
+ * @brief Remove the given rectangle from the pool.
+ *
+ * @param rect The rectangle to remove from the pool.
+ *
+ * This function removes @p rect from the pool. If @p rect is
+ * @c NULL, the function returns immediately. Otherwise it remoes @p
+ * rect from the pool.
+ */
+EAPI void
+eina_rectangle_pool_release(Eina_Rectangle *rect)
+{
+   Eina_Rectangle_Alloc *era = ((Eina_Rectangle_Alloc *)rect) - 1;
+   Eina_Rectangle *r;
+
+   EINA_SAFETY_ON_NULL_RETURN(rect);
+
+   EINA_MAGIC_CHECK_RECTANGLE_ALLOC(era);
+   EINA_MAGIC_CHECK_RECTANGLE_POOL(era->pool);
+
+   DBG("rect=%p pool=%p, size=(%d, %d), references=%u",
+       rect, era->pool, era->pool->w, era->pool->h, era->pool->references);
+
+   era->pool->references--;
+   era->pool->head = eina_inlist_remove(era->pool->head, EINA_INLIST_GET(era));
+
+   r = eina_rectangle_new(rect->x, rect->y, rect->w, rect->h);
+   if (r)
+     {
+        era->pool->empty = _eina_rectangle_merge_list(era->pool->empty, r);
+        era->pool->sorted = EINA_FALSE;
+     }
+
+   if (era->pool->bucket_count < BUCKET_THRESHOLD)
+     {
+        Eina_Rectangle_Pool *pool;
+
+        pool = era->pool;
+
+        pool->bucket_count++;
+        eina_trash_push(&pool->bucket, era);
+     }
+   else
+     {
+        EINA_MAGIC_SET(era, EINA_MAGIC_NONE);
+        eina_mempool_free(_eina_rectangle_alloc_mp, era);
+     }
+}
+
+/**
+ * @brief Return the pool of the given rectangle.
+ *
+ * @param rect The rectangle.
+ * @return The pool of the given rectangle.
+ *
+ * This function returns the pool in which @p rect is. If  @p rect is
+ * @c NULL, @c NULL is returned.
+ */
+EAPI Eina_Rectangle_Pool *
+eina_rectangle_pool_get(Eina_Rectangle *rect)
+{
+   Eina_Rectangle_Alloc *era = ((Eina_Rectangle_Alloc *)rect) - 1;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(rect, NULL);
+
+   EINA_MAGIC_CHECK_RECTANGLE_ALLOC(era);
+   EINA_MAGIC_CHECK_RECTANGLE_POOL(era->pool);
+
+   return era->pool;
+}
+
+/**
+ * @brief Set the data to the given pool.
+ *
+ * @param pool The pool.
+ * @param data The data to set.
+ *
+ * This function sets @p data to @p pool. If @p pool is @c NULL, this
+ * function does nothing.
+ */
+EAPI void
+eina_rectangle_pool_data_set(Eina_Rectangle_Pool *pool, const void *data)
+{
+   EINA_MAGIC_CHECK_RECTANGLE_POOL(pool);
+   EINA_SAFETY_ON_NULL_RETURN(pool);
+
+   DBG("data=%p pool=%p, size=(%d, %d), references=%u",
+       data, pool, pool->w, pool->h, pool->references);
+
+   pool->data = (void *)data;
+}
+
+/**
+ * @brief Get the data from the given pool.
+ *
+ * @param pool The pool.
+ * @return The returned data.
+ *
+ * This function gets the data from @p pool set by
+ * eina_rectangle_pool_data_set(). If @p pool is @c NULL, this
+ * function returns @c NULL.
+ */
+EAPI void *
+eina_rectangle_pool_data_get(Eina_Rectangle_Pool *pool)
+{
+   EINA_MAGIC_CHECK_RECTANGLE_POOL(pool);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pool, NULL);
+
+   return pool->data;
+}
+
+/**
+ * @brief Return the width and height of the given pool.
+ *
+ * @param pool The pool.
+ * @param w The returned width.
+ * @param h The returned height.
+ * @return #EINA_TRUE on success, #EINA_FALSE otherwise.
+ *
+ * This function returns the width and height of @p pool and store
+ * them in respectively @p w and @p h if they are not @c NULL. If
+ * @p pool is @c NULL, #EINA_FALSE is returned. Otherwise #EINA_TRUE is
+ * returned.
+ */
+EAPI Eina_Bool
+eina_rectangle_pool_geometry_get(Eina_Rectangle_Pool *pool, int *w, int *h)
+{
+   if (!pool)
+      return EINA_FALSE;
+
+   EINA_MAGIC_CHECK_RECTANGLE_POOL(pool);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(pool, EINA_FALSE);
+
+   if (w)
+      *w = pool->w;
+
+   if (h)
+      *h = pool->h;
+
+   return EINA_TRUE;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_safety_checks.c 
b/tests/suite/ecore/src/lib/eina_safety_checks.c
new file mode 100644
index 0000000..09aa298
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_safety_checks.c
@@ -0,0 +1,114 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2008 Gustavo Sverzut Barbieri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "eina_private.h"
+#include "eina_error.h"
+#include "eina_log.h"
+#include "eina_safety_checks.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Shut down the safety checks module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the error module set up by
+ * eina_safety_checks_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_safety_checks_shutdown(void)
+{
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Safety_Checks_Group Safety Checks
+ *
+ * Safety checks are a set of macros to check for parameters or values
+ * that should never happen, it is similar in concept to assert(), but
+ * will log and return instead of abort() your program.
+ *
+ * Since these cases should never happen, one may wantto keep safety
+ * checks enabled during tests but disable then during deploy, not
+ * doing any checks at all. This is a common requirement for embedded
+ * systems. Whenever to check or not should be set during compile time
+ * by using @c --disable-safety-checks or @c --enable-safety-checks
+ * options to @c configure script.
+ *
+ * Whenever these macros capture an error, EINA_LOG_ERR() will be
+ * called and @c eina_error set to @c EINA_ERROR_SAFETY_FAILED and can
+ * be checked with eina_error_get() after call.
+ *
+ * @see EINA_SAFETY_ON_NULL_RETURN(), EINA_SAFETY_ON_NULL_RETURN_VAL()
+ *      and other macros.
+ *
+ * @{
+ */
+
+/**
+ * @cond LOCAL
+ */
+
+EAPI Eina_Error EINA_ERROR_SAFETY_FAILED = 0;
+
+static const char EINA_ERROR_SAFETY_FAILED_STR[] = "Safety check failed.";
+
+/**
+ * @endcond
+ */
+
+/**
+ * @internal
+ * @brief Initialize the safety checks module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the safety checks module of Eina. It is
+ * called by eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_safety_checks_init(void)
+{
+   EINA_ERROR_SAFETY_FAILED = eina_error_msg_static_register(
+         EINA_ERROR_SAFETY_FAILED_STR);
+   return EINA_TRUE;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_sched.c 
b/tests/suite/ecore/src/lib/eina_sched.c
new file mode 100644
index 0000000..dbb3da6
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_sched.c
@@ -0,0 +1,95 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2010 ProFUSION embedded systems
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef EFL_HAVE_POSIX_THREADS
+# include <pthread.h>
+# ifdef __linux__
+#  include <sched.h>
+#  include <sys/time.h>
+#  include <sys/resource.h>
+#  include <errno.h>
+# endif
+#endif
+
+#include "eina_sched.h"
+#include "eina_log.h"
+
+#define RTNICENESS 5
+#define NICENESS 5
+
+/**
+ * @brief Lower priority of current thread.
+ *
+ * It's used by worker threads so they use up background cpu and do not stall
+ * the main thread If current thread is running with real-time priority, we
+ * decrease our priority by @c RTNICENESS. This is done in a portable way.
+ *
+ * Otherwise (we are running with SCHED_OTHER policy) there's no portable way 
to
+ * set the nice level on current thread. In Linux, it does work and it's the
+ * only one that is implemented as of now. In this case the nice level is
+ * incremented on this thread by @c NICENESS.
+ */
+EAPI void
+eina_sched_prio_drop(void)
+{
+#ifdef EFL_HAVE_POSIX_THREADS
+   struct sched_param param;
+   int pol, prio, ret;
+   pthread_t pthread_id;
+
+   pthread_id = pthread_self();
+   ret = pthread_getschedparam(pthread_id, &pol, &param);
+   if (ret)
+     {
+        EINA_LOG_ERR("Unable to query sched parameters");
+        return;
+     }
+
+   if (EINA_UNLIKELY(pol == SCHED_RR || pol == SCHED_FIFO))
+     {
+        prio = sched_get_priority_max(pol);
+        param.sched_priority += RTNICENESS;
+        if (prio > 0 && param.sched_priority > prio)
+           param.sched_priority = prio;
+
+        pthread_setschedparam(pthread_id, pol, &param);
+     }
+#ifdef __linux__
+   else
+     {
+        errno = 0;
+        prio = getpriority(PRIO_PROCESS, 0);
+        if (errno == 0)
+          {
+             prio += NICENESS;
+             if (prio > 19)
+                prio = 19;
+
+             setpriority(PRIO_PROCESS, 0, prio);
+          }
+     }
+#endif
+#else
+   EINA_LOG_ERR("Eina does not have support for threads enabled"
+                "or it doesn't support setting scheduler priorities");
+#endif
+}
diff --git a/tests/suite/ecore/src/lib/eina_share_common.c 
b/tests/suite/ecore/src/lib/eina_share_common.c
new file mode 100644
index 0000000..2302843
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_share_common.c
@@ -0,0 +1,974 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2010
+ *                         Carsten Haitzler,
+ *                         Jorge Luis Zapata Muga,
+ *                         Cedric Bail,
+ *                         Gustavo Sverzut Barbieri
+ *                         Tom Hacohen
+ *                         Brett Nash
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (C) 2008 Peter Wehrfritz
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a 
copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies of the Software and its Copyright notices. In addition publicly
+ *  documented acknowledgment must be given that this software has been used 
if no
+ *  source code of this software is made available publicly. This includes
+ *  acknowledgments in either Copyright notices, Manuals, Publicity and 
Marketing
+ *  documents or any documentation provided with any product containing this
+ *  software. This License does not apply to any software that links to the
+ *  libraries provided by this software (statically or dynamically), but only 
to
+ *  the software provided.
+ *
+ *  Please see the OLD-COPYING.PLAIN for a plain-english explanation of this 
notice
+ *  and it's intent.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stddef.h>
+
+#ifdef EFL_HAVE_POSIX_THREADS
+# include <pthread.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_hash.h"
+#include "eina_rbtree.h"
+#include "eina_error.h"
+#include "eina_log.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_share_common.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#define EINA_SHARE_COMMON_BUCKETS 256
+#define EINA_SHARE_COMMON_MASK 0xFF
+
+static const char EINA_MAGIC_SHARE_STR[] = "Eina Share";
+static const char EINA_MAGIC_SHARE_HEAD_STR[] = "Eina Share Head";
+
+
+#define EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(d, unlock, ...)      \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK((d), EINA_MAGIC_SHARE_HEAD))  \
+          {                                                           \
+             EINA_MAGIC_FAIL((d), EINA_MAGIC_SHARE_HEAD);    \
+             unlock;                                                 \
+             return __VA_ARGS__;                                     \
+          }                                                           \
+     } while (0)
+
+#define EINA_MAGIC_CHECK_SHARE_COMMON_NODE(d, _node_magic, unlock)             
 \
+   do {                                                          \
+        if (!EINA_MAGIC_CHECK((d), _node_magic))    \
+          {                                                           \
+             unlock;                                                   \
+             EINA_MAGIC_FAIL((d), _node_magic);        \
+          }                                                           \
+     } while (0)
+
+#ifdef EINA_SHARE_USAGE
+typedef struct _Eina_Share_Common_Population Eina_Share_Common_Population;
+#endif
+
+typedef struct _Eina_Share_Common Eina_Share_Common;
+typedef struct _Eina_Share_Common_Node Eina_Share_Common_Node;
+typedef struct _Eina_Share_Common_Head Eina_Share_Common_Head;
+
+int _eina_share_common_log_dom = -1;
+
+struct _Eina_Share
+{
+   Eina_Share_Common *share;
+   Eina_Magic node_magic;
+#ifdef EINA_SHARE_COMMON_USAGE
+   Eina_Share_Common_Population population;
+   int max_node_population;
+#endif
+};
+
+struct _Eina_Share_Common
+{
+   Eina_Share_Common_Head *buckets[EINA_SHARE_COMMON_BUCKETS];
+
+   EINA_MAGIC
+};
+
+struct _Eina_Share_Common_Node
+{
+   Eina_Share_Common_Node *next;
+
+   EINA_MAGIC
+
+   unsigned int length;
+   unsigned int references;
+   char str[];
+};
+
+struct _Eina_Share_Common_Head
+{
+   EINA_RBTREE;
+   EINA_MAGIC
+
+   int hash;
+
+#ifdef EINA_SHARE_COMMON_USAGE
+   int population;
+#endif
+
+   Eina_Share_Common_Node *head;
+   Eina_Share_Common_Node builtin_node;
+};
+
+#ifdef EFL_HAVE_THREADS
+Eina_Bool _share_common_threads_activated = EINA_FALSE;
+
+# ifdef EFL_HAVE_POSIX_THREADS
+static pthread_mutex_t _mutex_big = PTHREAD_MUTEX_INITIALIZER;
+#  define SHARE_COMMON_LOCK_BIG() if(_share_common_threads_activated) \
+      pthread_mutex_lock(&_mutex_big)
+#  define SHARE_COMMON_UNLOCK_BIG() if(_share_common_threads_activated) \
+      pthread_mutex_unlock(&_mutex_big)
+# else /* EFL_HAVE_WIN32_THREADS */
+static HANDLE _mutex_big = NULL;
+#  define SHARE_COMMON_LOCK_BIG() if(_share_common_threads_activated) \
+      WaitForSingleObject(_mutex_big, INFINITE)
+#  define SHARE_COMMON_UNLOCK_BIG() if(_share_common_threads_activated) \
+      ReleaseMutex(_mutex_big)
+
+# endif /* EFL_HAVE_WIN32_THREADS */
+#else /* EFL_HAVE_THREADS */
+# define SHARE_COMMON_LOCK_BIG() do {} while (0)
+# define SHARE_COMMON_UNLOCK_BIG() do {} while (0)
+#endif
+
+#ifdef EINA_SHARE_COMMON_USAGE
+struct _Eina_Share_Common_Population
+{
+   int count;
+   int max;
+};
+
+static Eina_Share_Common_Population population = { 0, 0 };
+
+static Eina_Share_Common_Population population_group[4] =
+{
+   { 0, 0 },
+   { 0, 0 },
+   { 0, 0 },
+   { 0, 0 }
+};
+
+static void
+_eina_share_common_population_init(Eina_Share *share)
+{
+   unsigned int i;
+
+   for (i = 0;
+        i < sizeof (share->population_group) /
+        sizeof (share->population_group[0]);
+        ++i)
+     {
+        share->population_group[i].count = 0;
+        share->population_group[i].max = 0;
+     }
+}
+
+static void
+_eina_share_common_population_shutdown(Eina_Share *share)
+{
+   unsigned int i;
+
+   share->max_node_population = 0;
+   share->population.count = 0;
+   share->population.max = 0;
+
+   for (i = 0;
+        i < sizeof (share->population_group) /
+        sizeof (share->population_group[0]);
+        ++i)
+     {
+        share->population_group[i].count = 0;
+        share->population_group[i].max = 0;
+     }
+}
+
+static void
+_eina_share_common_population_stats(Eina_Share *share)
+{
+   unsigned int i;
+
+      fprintf(stderr, "eina share_common statistic:\n");
+      fprintf(stderr,
+           " * maximum shared strings : %i\n",
+           share->population.max);
+      fprintf(stderr,
+           " * maximum shared strings per node : %i\n",
+           share->max_node_population);
+
+   for (i = 0;
+        i < sizeof (share->population_group) /
+        sizeof (share->population_group[0]);
+        ++i)
+      fprintf(stderr,
+              "DDD: %i strings of length %i, max strings: %i\n",
+              share->population_group[i].count,
+              i,
+              share->population_group[i].max);
+}
+
+void
+eina_share_common_population_add(Eina_Share *share, int slen)
+{
+   SHARE_COMMON_LOCK_BIG();
+
+   share->population.count++;
+   if (share->population.count > share->population.max)
+      share->population.max = share->population.count;
+
+   if (slen < 4)
+     {
+        share->population_group[slen].count++;
+        if (share->population_group[slen].count >
+            share->population_group[slen].max)
+           share->population_group[slen].max =
+              share->population_group[slen].count;
+     }
+
+   SHARE_COMMON_UNLOCK_BIG();
+}
+
+void
+eina_share_common_population_del(Eina_Share *share, int slen)
+{
+   SHARE_COMMON_LOCK_BIG();
+
+   share->population.count--;
+   if (slen < 4)
+      share->population_group[slen].count--;
+
+   SHARE_COMMON_UNLOCK_BIG();
+}
+
+static void
+_eina_share_common_population_head_init(Eina_Share *share,
+                                        Eina_Share_Common_Head *head)
+{
+   head->population = 1;
+}
+
+static void
+_eina_share_common_population_head_add(Eina_Share *share,
+                                       Eina_Share_Common_Head *head)
+{
+   head->population++;
+   if (head->population > share->max_node_population)
+      share->max_node_population = head->population;
+}
+
+static void
+_eina_share_common_population_head_del(Eina_Share *share,
+                                       Eina_Share_Common_Head *head)
+{
+   head->population--;
+}
+
+#else /* EINA_SHARE_COMMON_USAGE undefined */
+
+static void _eina_share_common_population_init(__UNUSED__ Eina_Share *share) {
+}
+static void _eina_share_common_population_shutdown(__UNUSED__ Eina_Share 
*share)
+{
+}
+static void _eina_share_common_population_stats(__UNUSED__ Eina_Share *share) {
+}
+void eina_share_common_population_add(__UNUSED__ Eina_Share *share,
+                                      __UNUSED__ int slen) {
+}
+void eina_share_common_population_del(__UNUSED__ Eina_Share *share,
+                                      __UNUSED__ int slen) {
+}
+static void _eina_share_common_population_head_init(
+   __UNUSED__ Eina_Share *share,
+   __UNUSED__ Eina_Share_Common_Head *head) {
+}
+static void _eina_share_common_population_head_add(
+   __UNUSED__ Eina_Share *share,
+   __UNUSED__
+   Eina_Share_Common_Head *head) {
+}
+static void _eina_share_common_population_head_del(
+   __UNUSED__ Eina_Share *share,
+   __UNUSED__
+   Eina_Share_Common_Head *head) {
+}
+#endif
+
+static int
+_eina_share_common_cmp(const Eina_Share_Common_Head *ed,
+                       const int *hash,
+                       __UNUSED__ int length,
+                       __UNUSED__ void *data)
+{
+   EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, , 0);
+
+   return ed->hash - *hash;
+}
+
+static Eina_Rbtree_Direction
+_eina_share_common_node(const Eina_Share_Common_Head *left,
+                        const Eina_Share_Common_Head *right,
+                        __UNUSED__ void *data)
+{
+   EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(left,  , 0);
+   EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(right, , 0);
+
+   if (left->hash - right->hash < 0)
+      return EINA_RBTREE_LEFT;
+
+   return EINA_RBTREE_RIGHT;
+}
+
+static void
+_eina_share_common_head_free(Eina_Share_Common_Head *ed, __UNUSED__ void *data)
+{
+   EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, );
+
+   while (ed->head)
+     {
+        Eina_Share_Common_Node *el = ed->head;
+
+        ed->head = ed->head->next;
+        if (el != &ed->builtin_node)
+           MAGIC_FREE(el);
+     }
+           MAGIC_FREE(ed);
+}
+
+static void
+_eina_share_common_node_init(Eina_Share_Common_Node *node,
+                             const char *str,
+                             int slen,
+                             unsigned int null_size,
+                             Eina_Magic node_magic)
+{
+   EINA_MAGIC_SET(node, node_magic);
+   node->references = 1;
+   node->length = slen;
+   memcpy(node->str, str, slen);
+   memset(node->str + slen, 0, null_size); /* Nullify the null */
+
+   (void) node_magic; /* When magic are disable, node_magic is unused, this 
remove a warning. */
+}
+
+static Eina_Share_Common_Head *
+_eina_share_common_head_alloc(int slen)
+{
+   Eina_Share_Common_Head *head;
+   const size_t head_size = offsetof(Eina_Share_Common_Head, builtin_node.str);
+
+   head = malloc(head_size + slen);
+   if (!head)
+      eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+
+   return head;
+}
+
+static const char *
+_eina_share_common_add_head(Eina_Share *share,
+                            Eina_Share_Common_Head **p_bucket,
+                            int hash,
+                            const char *str,
+                            unsigned int slen,
+                            unsigned int null_size)
+{
+   Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
+   Eina_Share_Common_Head *head;
+
+   head = _eina_share_common_head_alloc(slen + null_size);
+   if (!head)
+      return NULL;
+
+   EINA_MAGIC_SET(head, EINA_MAGIC_SHARE_HEAD);
+   head->hash = hash;
+   head->head = &head->builtin_node;
+   _eina_share_common_node_init(head->head,
+                                str,
+                                slen,
+                                null_size,
+                                share->node_magic);
+   head->head->next = NULL;
+
+   _eina_share_common_population_head_init(share, head);
+
+   *p_tree = eina_rbtree_inline_insert
+         (*p_tree, EINA_RBTREE_GET(head),
+         EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
+
+   return head->head->str;
+}
+
+static void
+_eina_share_common_del_head(Eina_Share_Common_Head **p_bucket,
+                            Eina_Share_Common_Head *head)
+{
+   Eina_Rbtree **p_tree = (Eina_Rbtree **)p_bucket;
+
+   *p_tree = eina_rbtree_inline_remove
+         (*p_tree, EINA_RBTREE_GET(head),
+         EINA_RBTREE_CMP_NODE_CB(_eina_share_common_node), NULL);
+
+         MAGIC_FREE(head);
+}
+
+
+static inline Eina_Bool
+_eina_share_common_node_eq(const Eina_Share_Common_Node *node,
+                           const char *str,
+                           unsigned int slen)
+{
+   return ((node->length == slen) &&
+           (memcmp(node->str, str, slen) == 0));
+}
+
+static Eina_Share_Common_Node *
+_eina_share_common_head_find(Eina_Share_Common_Head *head,
+                             const char *str,
+                             unsigned int slen)
+{
+   Eina_Share_Common_Node *node, *prev;
+
+   node = head->head;
+   if (_eina_share_common_node_eq(node, str, slen))
+      return node;
+
+   prev = node;
+   node = node->next;
+   for (; node; prev = node, node = node->next)
+      if (_eina_share_common_node_eq(node, str, slen))
+        {
+           /* promote node, make hot items be at the beginning */
+           prev->next = node->next;
+           node->next = head->head;
+           head->head = node;
+           return node;
+        }
+
+   return NULL;
+}
+
+static Eina_Bool
+_eina_share_common_head_remove_node(Eina_Share_Common_Head *head,
+                                    const Eina_Share_Common_Node *node)
+{
+   Eina_Share_Common_Node *cur, *prev;
+
+   if (head->head == node)
+     {
+        head->head = node->next;
+        return 1;
+     }
+
+   prev = head->head;
+   cur = head->head->next;
+   for (; cur; prev = cur, cur = cur->next)
+      if (cur == node)
+        {
+           prev->next = cur->next;
+           return 1;
+        }
+
+   return 0;
+}
+
+static Eina_Share_Common_Head *
+_eina_share_common_find_hash(Eina_Share_Common_Head *bucket, int hash)
+{
+   return (Eina_Share_Common_Head *)eina_rbtree_inline_lookup
+             (EINA_RBTREE_GET(bucket), &hash, 0,
+             EINA_RBTREE_CMP_KEY_CB(_eina_share_common_cmp), NULL);
+}
+
+static Eina_Share_Common_Node *
+_eina_share_common_node_alloc(unsigned int slen, unsigned int null_size)
+{
+   Eina_Share_Common_Node *node;
+   const size_t node_size = offsetof(Eina_Share_Common_Node, str);
+
+   node = malloc(node_size + slen + null_size);
+   if (!node)
+      eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+
+   return node;
+}
+
+static Eina_Share_Common_Node *
+_eina_share_common_node_from_str(const char *str, Eina_Magic node_magic)
+{
+   Eina_Share_Common_Node *node;
+   const size_t offset = offsetof(Eina_Share_Common_Node, str);
+
+   node = (Eina_Share_Common_Node *)(str - offset);
+   EINA_MAGIC_CHECK_SHARE_COMMON_NODE(node, node_magic, );
+   return node;
+
+   (void) node_magic; /* When magic are disable, node_magic is unused, this 
remove a warning. */
+}
+
+static Eina_Bool
+eina_iterator_array_check(const Eina_Rbtree *rbtree __UNUSED__,
+                          Eina_Share_Common_Head *head,
+                          struct dumpinfo *fdata)
+{
+   Eina_Share_Common_Node *node;
+
+   SHARE_COMMON_LOCK_BIG();
+
+   fdata->used += sizeof(Eina_Share_Common_Head);
+   for (node = head->head; node; node = node->next)
+     {
+        printf("DDD: %5i %5i ", node->length, node->references);
+        printf("'%.*s'\n", node->length, ((char *)node) + 
sizeof(Eina_Share_Common_Node));
+        fdata->used += sizeof(Eina_Share_Common_Node);
+        fdata->used += node->length;
+        fdata->saved += (node->references - 1) * node->length;
+        fdata->dups += node->references - 1;
+        fdata->unique++;
+     }
+
+   SHARE_COMMON_UNLOCK_BIG();
+
+   return EINA_TRUE;
+}
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the share_common module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_share_common_init(Eina_Share **_share,
+                       Eina_Magic node_magic,
+                       const char *node_magic_STR)
+{
+   Eina_Share *share;
+   share = *_share = calloc(sizeof(Eina_Share), 1);
+   if (!share)
+      return EINA_FALSE;
+
+   if (_eina_share_common_log_dom < 0) /*Only register if not already */
+      _eina_share_common_log_dom = eina_log_domain_register(
+            "eina_share",
+            EINA_LOG_COLOR_DEFAULT);
+
+   if (_eina_share_common_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_share_common");
+        return EINA_FALSE;
+     }
+
+   share->share = calloc(1, sizeof(Eina_Share_Common));
+   if (!share->share)
+     {
+        if (_eina_share_common_log_dom > 0)
+          {
+             eina_log_domain_unregister(_eina_share_common_log_dom);
+             _eina_share_common_log_dom = -1;
+          }
+
+        return EINA_FALSE;
+     }
+
+   share->node_magic = node_magic;
+#define EMS(n) eina_magic_string_static_set(n, n ## _STR)
+   EMS(EINA_MAGIC_SHARE);
+   EMS(EINA_MAGIC_SHARE_HEAD);
+   EMS(node_magic);
+#undef EMS
+   EINA_MAGIC_SET(share->share, EINA_MAGIC_SHARE);
+
+   _eina_share_common_population_init(share);
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the share_common module set up by
+ * eina_share_common_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_share_common_shutdown(Eina_Share **_share)
+{
+   unsigned int i;
+   Eina_Share *share = *_share;
+
+   SHARE_COMMON_LOCK_BIG();
+
+   _eina_share_common_population_stats(share);
+
+   /* remove any string still in the table */
+   for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
+     {
+        eina_rbtree_delete(EINA_RBTREE_GET(
+                              share->share->buckets[i]),
+                           EINA_RBTREE_FREE_CB(
+                              _eina_share_common_head_free), NULL);
+        share->share->buckets[i] = NULL;
+     }
+   MAGIC_FREE(share->share);
+
+   _eina_share_common_population_shutdown(share);
+   if (_eina_share_common_log_dom > 0) /* Only free if necessary */
+     {
+        eina_log_domain_unregister(_eina_share_common_log_dom);
+        _eina_share_common_log_dom = -1;
+     }
+
+   SHARE_COMMON_UNLOCK_BIG();
+
+   free(*_share);
+   *_share = NULL;
+   return EINA_TRUE;
+}
+
+#ifdef EFL_HAVE_THREADS
+
+/**
+ * @internal
+ * @brief Activate the share_common mutexes.
+ *
+ * This function activate the mutexes in the eina share_common module. It is 
called by
+ * eina_threads_init().
+ *
+ * @see eina_threads_init()
+ */
+void
+eina_share_common_threads_init(void)
+{
+   _share_common_threads_activated = EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the share_common mutexes.
+ *
+ * This function shuts down the mutexes in the share_common module.
+ * It is called by eina_threads_shutdown().
+ *
+ * @see eina_threads_shutdown()
+ */
+void
+eina_share_common_threads_shutdown(void)
+{
+   _share_common_threads_activated = EINA_FALSE;
+}
+
+#endif
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+const char *
+eina_share_common_add_length(Eina_Share *share,
+                             const char *str,
+                             unsigned int slen,
+                             unsigned int null_size)
+{
+   Eina_Share_Common_Head **p_bucket, *ed;
+   Eina_Share_Common_Node *el;
+   int hash_num, hash;
+
+   if (!str)
+      return NULL;
+
+   eina_share_common_population_add(share, slen);
+
+   if (slen <= 0)
+      return NULL;
+
+   hash = eina_hash_superfast(str, slen);
+   hash_num = hash & 0xFF;
+   hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
+
+   SHARE_COMMON_LOCK_BIG();
+   p_bucket = share->share->buckets + hash_num;
+
+   ed = _eina_share_common_find_hash(*p_bucket, hash);
+   if (!ed)
+     {
+        const char *s = _eina_share_common_add_head(share,
+                                                    p_bucket,
+                                                    hash,
+                                                    str,
+                                                    slen,
+                                                    null_size);
+        SHARE_COMMON_UNLOCK_BIG();
+        return s;
+     }
+
+   EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, SHARE_COMMON_UNLOCK_BIG(), NULL);
+
+   el = _eina_share_common_head_find(ed, str, slen);
+   if (el)
+     {
+        EINA_MAGIC_CHECK_SHARE_COMMON_NODE(el,
+                                           share->node_magic,
+                                           SHARE_COMMON_UNLOCK_BIG());
+        el->references++;
+                                           SHARE_COMMON_UNLOCK_BIG();
+        return el->str;
+     }
+
+   el = _eina_share_common_node_alloc(slen, null_size);
+   if (!el)
+     {
+                                           SHARE_COMMON_UNLOCK_BIG();
+        return NULL;
+     }
+
+   _eina_share_common_node_init(el, str, slen, null_size, share->node_magic);
+   el->next = ed->head;
+   ed->head = el;
+   _eina_share_common_population_head_add(share, ed);
+
+   SHARE_COMMON_UNLOCK_BIG();
+
+   return el->str;
+}
+
+const char *
+eina_share_common_ref(Eina_Share *share, const char *str)
+{
+   Eina_Share_Common_Node *node;
+
+   if (!str)
+      return NULL;
+
+   SHARE_COMMON_LOCK_BIG();
+   node = _eina_share_common_node_from_str(str, share->node_magic);
+   node->references++;
+   DBG("str=%p refs=%u", str, node->references);
+
+   SHARE_COMMON_UNLOCK_BIG();
+
+   eina_share_common_population_add(share, node->length);
+
+   return str;
+}
+
+
+void
+eina_share_common_del(Eina_Share *share, const char *str)
+{
+   unsigned int slen;
+   Eina_Share_Common_Head *ed;
+   Eina_Share_Common_Head **p_bucket;
+   Eina_Share_Common_Node *node;
+   int hash_num, hash;
+
+   if (!str)
+      return;
+
+   SHARE_COMMON_LOCK_BIG();
+
+   node = _eina_share_common_node_from_str(str, share->node_magic);
+   slen = node->length;
+   eina_share_common_population_del(share, slen);
+   if (node->references > 1)
+     {
+        node->references--;
+        DBG("str=%p refs=%u", str, node->references);
+        SHARE_COMMON_UNLOCK_BIG();
+        return;
+     }
+
+   DBG("str=%p refs=0, delete.", str);
+   node->references = 0;
+
+   hash = eina_hash_superfast(str, slen);
+   hash_num = hash & 0xFF;
+   hash = (hash >> 8) & EINA_SHARE_COMMON_MASK;
+
+   p_bucket = share->share->buckets + hash_num;
+   ed = _eina_share_common_find_hash(*p_bucket, hash);
+   if (!ed)
+      goto on_error;
+
+   EINA_MAGIC_CHECK_SHARE_COMMON_HEAD(ed, SHARE_COMMON_UNLOCK_BIG());
+
+   if (!_eina_share_common_head_remove_node(ed, node))
+      goto on_error;
+
+   if (node != &ed->builtin_node)
+      MAGIC_FREE(node);
+
+   if (!ed->head)
+      _eina_share_common_del_head(p_bucket, ed);
+   else
+      _eina_share_common_population_head_del(share, ed);
+
+   SHARE_COMMON_UNLOCK_BIG();
+
+   return;
+
+on_error:
+   SHARE_COMMON_UNLOCK_BIG();
+   /* possible segfault happened before here, but... */
+   CRITICAL("EEEK trying to del non-shared share_common \"%s\"", str);
+}
+
+int
+eina_share_common_length(__UNUSED__ Eina_Share *share, const char *str)
+{
+   const Eina_Share_Common_Node *node;
+
+   if (!str)
+      return -1;
+
+   node = _eina_share_common_node_from_str(str, share->node_magic);
+   return node->length;
+}
+
+void
+eina_share_common_dump(Eina_Share *share, void (*additional_dump)(
+                          struct dumpinfo *), int used)
+{
+   Eina_Iterator *it;
+   unsigned int i;
+   struct dumpinfo di;
+
+   if (!share)
+      return;
+
+   di.used = used;
+   di.saved = 0;
+   di.dups = 0;
+   di.unique = 0;
+   printf("DDD:   len   ref string\n");
+   printf("DDD:-------------------\n");
+
+   SHARE_COMMON_LOCK_BIG();
+   for (i = 0; i < EINA_SHARE_COMMON_BUCKETS; i++)
+     {
+        if (!share->share->buckets[i])
+          {
+             continue; //      printf("DDD: BUCKET # %i (HEAD=%i, NODE=%i)\n", 
i,
+
+          }
+
+//            sizeof(Eina_Share_Common_Head), sizeof(Eina_Share_Common_Node));
+        it = eina_rbtree_iterator_prefix(
+              (Eina_Rbtree *)share->share->buckets[i]);
+        eina_iterator_foreach(it, EINA_EACH_CB(eina_iterator_array_check), 
&di);
+        eina_iterator_free(it);
+     }
+   if (additional_dump)
+      additional_dump(&di);
+
+#ifdef EINA_SHARE_COMMON_USAGE
+   /* One character strings are not counted in the hash. */
+   di.saved += share->population_group[0].count * sizeof(char);
+   di.saved += share->population_group[1].count * sizeof(char) * 2;
+#endif
+   printf("DDD:-------------------\n");
+   printf("DDD: usage (bytes) = %i, saved = %i (%3.0f%%)\n",
+          di.used, di.saved, di.used ? (di.saved * 100.0 / di.used) : 0.0);
+   printf("DDD: unique: %d, duplicates: %d (%3.0f%%)\n",
+          di.unique, di.dups, di.unique ? (di.dups * 100.0 / di.unique) : 0.0);
+
+#ifdef EINA_SHARE_COMMON_USAGE
+   printf("DDD: Allocated strings: %i\n",     share->population.count);
+   printf("DDD: Max allocated strings: %i\n", share->population.max);
+
+   for (i = 0;
+        i < sizeof (share->population_group) /
+        sizeof (share->population_group[0]);
+        ++i)
+      fprintf(stderr,
+              "DDD: %i strings of length %i, max strings: %i\n",
+              share->population_group[i].count,
+              i,
+              share->population_group[i].max);
+#endif
+
+   SHARE_COMMON_UNLOCK_BIG();
+}
+
+/**
+ * @endcond
+ */
diff --git a/tests/suite/ecore/src/lib/eina_share_common.h 
b/tests/suite/ecore/src/lib/eina_share_common.h
new file mode 100644
index 0000000..002c652
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_share_common.h
@@ -0,0 +1,103 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler, Jorge Luis Zapata Muga, Cedric 
Bail
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright (C) 2008 Peter Wehrfritz
+ *
+ *  Permission is hereby granted, free of charge, to any person obtaining a 
copy
+ *  of this software and associated documentation files (the "Software"), to
+ *  deal in the Software without restriction, including without limitation the
+ *  rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ *  sell copies of the Software, and to permit persons to whom the Software is
+ *  furnished to do so, subject to the following conditions:
+ *
+ *  The above copyright notice and this permission notice shall be included in
+ *  all copies of the Software and its Copyright notices. In addition publicly
+ *  documented acknowledgment must be given that this software has been used 
if no
+ *  source code of this software is made available publicly. This includes
+ *  acknowledgments in either Copyright notices, Manuals, Publicity and 
Marketing
+ *  documents or any documentation provided with any product containing this
+ *  software. This License does not apply to any software that links to the
+ *  libraries provided by this software (statically or dynamically), but only 
to
+ *  the software provided.
+ *
+ *  Please see the OLD-COPYING.PLAIN for a plain-english explanation of this 
notice
+ *  and it's intent.
+ *
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ *  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ *  THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+ *  IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ *  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef EINA_SHARE_COMMON_H_
+#define EINA_SHARE_COMMON_H_
+
+#include "eina_types.h"
+#include "eina_magic.h"
+
+typedef struct _Eina_Share Eina_Share;
+
+struct dumpinfo
+{
+   int used, saved, dups, unique;
+};
+
+Eina_Bool   eina_share_common_init(Eina_Share **share,
+                                   Eina_Magic node_magic,
+                                   const char *node_magic_STR);
+Eina_Bool   eina_share_common_shutdown(Eina_Share **share);
+const char *eina_share_common_add_length(Eina_Share *share,
+                                         const char *str,
+                                         unsigned int slen,
+                                         unsigned int null_size)
+EINA_WARN_UNUSED_RESULT;
+const char *eina_share_common_ref(Eina_Share *share, const char *str);
+void        eina_share_common_del(Eina_Share *share, const char *str);
+int         eina_share_common_length(Eina_Share *share,
+                                     const char *str) EINA_CONST
+EINA_WARN_UNUSED_RESULT;
+void        eina_share_common_dump(Eina_Share *share, void (*additional_dump)(
+                                      struct dumpinfo *), int used);
+
+
+/* Population functions */
+void        eina_share_common_population_add(Eina_Share *share, int slen);
+void        eina_share_common_population_del(Eina_Share *share, int slen);
+
+/* Share logging */
+#ifdef CRITICAL
+#undef CRITICAL
+#endif
+#define CRITICAL(...) EINA_LOG_DOM_CRIT(_eina_share_common_log_dom, 
__VA_ARGS__)
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_share_common_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_share_common_log_dom, __VA_ARGS__)
+extern int _eina_share_common_log_dom;
+
+#endif /* EINA_STRINGSHARE_H_ */
diff --git a/tests/suite/ecore/src/lib/eina_str.c 
b/tests/suite/ecore/src/lib/eina_str.c
new file mode 100644
index 0000000..bd9badb
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_str.c
@@ -0,0 +1,639 @@
+/* Leave the OpenBSD version below so we can track upstream fixes */
+/*      $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $        */
+
+/*
+ * Copyright (c) 1998 Todd C. Miller <address@hidden>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <ctype.h>
+
+#ifdef HAVE_ICONV
+# include <errno.h>
+# include <iconv.h>
+#endif
+
+#include "eina_private.h"
+#include "eina_str.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+/*
+ * Internal helper function used by eina_str_has_suffix() and
+ * eina_str_has_extension()
+ */
+static inline Eina_Bool
+eina_str_has_suffix_helper(const char *str,
+                           const char *suffix,
+                           int (*cmp)(const char *, const char *))
+{
+   size_t str_len;
+   size_t suffix_len;
+
+   str_len = strlen(str);
+   suffix_len = eina_strlen_bounded(suffix, str_len);
+   if (suffix_len == (size_t)-1)
+      return EINA_FALSE;
+
+   return cmp(str + str_len - suffix_len, suffix) == 0;
+}
+
+static inline char **
+eina_str_split_full_helper(const char *str,
+                           const char *delim,
+                           int max_tokens,
+                           unsigned int *elements)
+{
+   char *s, **str_array;
+   const char *src;
+   size_t len, dlen;
+   unsigned int tokens;
+
+   dlen = strlen(delim);
+   if (dlen == 0)
+     {
+        if (elements)
+           *elements = 0;
+
+        return NULL;
+     }
+
+   tokens = 0;
+   src = str;
+   /* count tokens and check strlen(str) */
+   while (*src != '\0')
+     {
+        const char *d = delim, *d_end = d + dlen;
+        const char *tmp = src;
+        for (; (d < d_end) && (*tmp != '\0'); d++, tmp++)
+          {
+             if (EINA_LIKELY(*d != *tmp))
+                break;
+          }
+        if (EINA_UNLIKELY(d == d_end))
+          {
+             src = tmp;
+             tokens++;
+          }
+        else
+           src++;
+     }
+   len = src - str;
+
+   if ((max_tokens > 0) && (tokens > (unsigned int)max_tokens))
+      tokens = max_tokens;
+
+   str_array = malloc(sizeof(char *) * (tokens + 2));
+   if (!str_array)
+     {
+        if (elements)
+           *elements = 0;
+
+        return NULL;
+     }
+
+   s = malloc(len + 1);
+   if (!s)
+     {
+        free(str_array);
+        if (elements)
+           *elements = 0;
+
+        return NULL;
+     }
+
+   /* copy tokens and string */
+   tokens = 0;
+   str_array[0] = s;
+   src = str;
+   while (*src != '\0')
+     {
+        const char *d = delim, *d_end = d + dlen;
+        const char *tmp = src;
+        for (; (d < d_end) && (*tmp != '\0'); d++, tmp++)
+          {
+             if (EINA_LIKELY(*d != *tmp))
+                break;
+          }
+        if (EINA_UNLIKELY(d == d_end))
+          {
+             src = tmp;
+             *s = '\0';
+             s += dlen;
+             tokens++;
+             str_array[tokens] = s;
+          }
+        else
+          {
+             *s = *src;
+             s++;
+             src++;
+          }
+     }
+   *s = '\0';
+   str_array[tokens + 1] = NULL;
+   if (elements)
+      *elements = (tokens + 1);
+
+   return str_array;
+}
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_String_Group String
+ *
+ * @brief These functions provide useful C string management.
+ *
+ * @{
+ */
+
+
+/**
+ * @brief Copy a c-string to another.
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @param siz The size of the destination string.
+ * @return The length of the source string.
+ *
+ * This function copies up to @p siz - 1 characters from the
+ * NUL-terminated string @p src to @p dst, NUL-terminating the result
+ * (unless @p siz is equal to 0). The returned value is the length of
+ * @p src. If the returned value is greater than @p siz, truncation
+ * occurred.
+ */
+EAPI size_t
+eina_strlcpy(char *dst, const char *src, size_t siz)
+{
+#ifdef HAVE_STRLCPY
+   return strlcpy(dst, src, siz);
+#else
+   char *d = dst;
+   const char *s = src;
+   size_t n = siz;
+
+   /* Copy as many bytes as will fit */
+   if (n != 0)
+      while (--n != 0)
+        {
+           if ((*d++ = *s++) == '\0')
+              break;
+        }
+
+   /* Not enough room in dst, add NUL and traverse rest of src */
+   if (n == 0)
+     {
+        if (siz != 0)
+           *d = '\0';  /* NUL-terminate dst */
+
+        while (*s++)
+           ;
+     }
+
+   return(s - src - 1); /* count does not include NUL */
+#endif
+}
+
+/**
+ * @brief Append a c-string.
+ *
+ * @param dst The destination string.
+ * @param src The source string.
+ * @param siz The size of the destination string.
+ * @return The length of the source string plus MIN(siz, strlen(initial dst))
+ *
+ * This function appends @p src to @p dst of size @p siz (unlike
+ * strncat, @p siz is the full size of @p dst, not space left).  At
+ * most @p siz - 1 characters will be copied.  Always NUL terminates
+ * (unless @p siz <= strlen(dst)). This function returns strlen(src) +
+ * MIN(siz, strlen(initial dst)). If the returned value is greater or
+ * equal than @p siz, truncation occurred.
+ */
+EAPI size_t
+eina_strlcat(char *dst, const char *src, size_t siz)
+{
+   char *d = dst;
+   const char *s = src;
+   size_t n = siz;
+   size_t dlen;
+
+   /* Find the end of dst and adjust bytes left but don't go past end */
+   while (n-- != 0 && *d != '\0')
+      d++;
+   dlen = d - dst;
+   n = siz - dlen;
+
+   if (n == 0)
+      return(dlen + strlen(s));
+
+   while (*s != '\0') {
+        if (n != 1)
+          {
+             *d++ = *s;
+             n--;
+          }
+
+        s++;
+     }
+   *d = '\0';
+
+   return(dlen + (s - src)); /* count does not include NUL */
+}
+
+/**
+ * @brief Check if the given string has the given prefix.
+ *
+ * @param str The string to work with.
+ * @param prefix The prefix to check for.
+ * @return #EINA_TRUE if the string has the given prefix, #EINA_FALSE 
otherwise.
+ *
+ * This function returns #EINA_TRUE if @p str has the prefix
+ * @p prefix, #EINA_FALSE otherwise. If the length of @p prefix is
+ * greater than @p str, #EINA_FALSE is returned.
+ */
+EAPI Eina_Bool
+eina_str_has_prefix(const char *str, const char *prefix)
+{
+   size_t str_len;
+   size_t prefix_len;
+
+   str_len = strlen(str);
+   prefix_len = eina_strlen_bounded(prefix, str_len);
+   if (prefix_len == (size_t)-1)
+      return EINA_FALSE;
+
+   return (strncmp(str, prefix, prefix_len) == 0);
+}
+
+/**
+ * @brief Check if the given string has the given suffix.
+ *
+ * @param str The string to work with.
+ * @param suffix The suffix to check for.
+ * @return #EINA_TRUE if the string has the given suffix, #EINA_FALSE 
otherwise.
+ *
+ * This function returns #EINA_TRUE if @p str has the suffix
+ * @p suffix, #EINA_FALSE otherwise. If the length of @p suffix is
+ * greater than @p str, #EINA_FALSE is returned.
+ */
+/**
+ * @param str the string to work with
+ * @param suffix the suffix to check for
+ * @return true if str has the given suffix
+ * @brief checks if the string has the given suffix
+ */
+EAPI Eina_Bool
+eina_str_has_suffix(const char *str, const char *suffix)
+{
+   return eina_str_has_suffix_helper(str, suffix, strcmp);
+}
+
+/**
+ * @brief Check if the given string has the given suffix.
+ *
+ * @param str The string to work with.
+ * @param ext The  extension to check for.
+ * @return #EINA_TRUE if the string has the given extension, #EINA_FALSE 
otherwise.
+ *
+ * This function does the same like eina_str_has_suffix(), but with a
+ * case insensitive compare.
+ */
+EAPI Eina_Bool
+eina_str_has_extension(const char *str, const char *ext)
+{
+   return eina_str_has_suffix_helper(str, ext, strcasecmp);
+}
+
+/**
+ * @brief Split a string using a delimiter and returns number of elements.
+ *
+ * @param str The string to split.
+ * @param delim The string which specifies the places at which to split the 
string.
+ * @param max_tokens The maximum number of strings to split string into.
+ * @param elements Where to return the number of elements in returned
+ *        array (not counting the terminating @c NULL). May be @c NULL.
+ * @return A newly-allocated NULL-terminated array of strings or NULL if it
+ * fails to allocate the array.
+ *
+ * This functin splits @p str into a maximum of @p max_tokens pieces,
+ * using the given delimiter @p delim. @p delim is not included in any
+ * of the resulting strings, unless @p max_tokens is reached. If
+ * @p max_tokens is less than @c 1, the string is splitted completely. If
+ * @p max_tokens is reached, the last string in the returned string
+ * array contains the remainder of string. The returned value is a
+ * newly allocated NULL-terminated array of strings or NULL if it fails to
+ * allocate the array. To free it, free the first element of the array and the
+ * array itself.
+ *
+ * @see eina_str_split()
+ */
+EAPI char **
+eina_str_split_full(const char *str,
+                    const char *delim,
+                    int max_tokens,
+                    unsigned int *elements)
+{
+   return eina_str_split_full_helper(str, delim, max_tokens, elements);
+}
+
+
+/**
+ * @brief Split a string using a delimiter.
+ *
+ * @param str The string to split.
+ * @param delim The string which specifies the places at which to split the 
string.
+ * @param max_tokens The maximum number of strings to split string into.
+ * @return A newly-allocated NULL-terminated array of strings or NULL if it
+ * fails to allocate the array.
+ *
+ * This functin splits @p str into a maximum of @p max_tokens pieces,
+ * using the given delimiter @p delim. @p delim is not included in any
+ * of the resulting strings, unless @p max_tokens is reached. If
+ * @p max_tokens is less than @c 1, the string is splitted completely. If
+ * @p max_tokens is reached, the last string in the returned string
+ * array contains the remainder of string. The returned value is a
+ * newly allocated NULL-terminated array of strings or NULL if it fails to
+ * allocate the array. To free it, free the first element of the array and the
+ * array itself.
+ */
+EAPI char **
+eina_str_split(const char *str, const char *delim, int max_tokens)
+{
+   return eina_str_split_full_helper(str, delim, max_tokens, NULL);
+}
+
+/**
+ * @brief Join two strings of known length.
+ *
+ * @param dst The buffer to store the result.
+ * @param size Size (in byte) of the buffer.
+ * @param sep The separator character to use.
+ * @param a First string to use, before @p sep.
+ * @param a_len length of @p a.
+ * @param b Second string to use, after @p sep.
+ * @param b_len length of @p b.
+ * @return The number of characters printed.
+ *
+ * This function joins the strings @p a and @p b (in that order) and
+ * separate them with @p sep. The result is stored in the buffer
+ * @p dst and at most @p size - 1 characters will be written and the
+ * string is NULL-terminated. @p a_len is the length of @p a (not
+ * including '\\0') and @p b_len is the length of @p b (not including
+ * '\\0'). This function returns the number of characters printed (not
+ * including the trailing '\\0' used to end output to strings). Just
+ * like snprintf(), it will not write more than @p size bytes, thus a
+ * returned value of @p size or more means that the output was
+ * truncated.
+ *
+ * @see eina_str_join()
+ * @see eina_str_join_static()
+ */
+EAPI size_t
+eina_str_join_len(char *dst,
+                  size_t size,
+                  char sep,
+                  const char *a,
+                  size_t a_len,
+                  const char *b,
+                  size_t b_len)
+{
+   size_t ret = a_len + b_len + 1;
+   size_t off;
+
+   if (size < 1)
+      return ret;
+
+   if (size <= a_len)
+     {
+        memcpy(dst, a, size - 1);
+        dst[size - 1] = '\0';
+        return ret;
+     }
+
+        memcpy(dst, a, a_len);
+   off = a_len;
+
+   if (size <= off + 1)
+     {
+        dst[size - 1] = '\0';
+        return ret;
+     }
+
+   dst[off] = sep;
+   off++;
+
+   if (size <= off + b_len + 1)
+     {
+        memcpy(dst + off, b, size - off - 1);
+        dst[size - 1] = '\0';
+        return ret;
+     }
+
+        memcpy(dst + off, b, b_len);
+   dst[off + b_len] = '\0';
+   return ret;
+}
+
+/**
+ * @brief Use iconv to convert a text string from one encoding to another
+ *
+ * @param enc_from encoding to convert from
+ * @param enc_to   encoding to convert to
+ * @param text     text to convert
+ *
+ */
+#ifdef HAVE_ICONV
+EAPI char *
+eina_str_convert(const char *enc_from, const char *enc_to, const char *text)
+{
+   iconv_t ic;
+   char *new_txt, *inp, *outp;
+   size_t inb, outb, outlen, tob, outalloc;
+
+   if (!text)
+      return NULL;
+
+   ic = iconv_open(enc_to, enc_from);
+   if (ic == (iconv_t)(-1))
+      return NULL;
+
+   new_txt = malloc(64);
+   inb = strlen(text);
+   outb = 64;
+   inp = (char *)text;
+   outp = new_txt;
+   outalloc = 64;
+   outlen = 0;
+
+   for (;; )
+     {
+        size_t count;
+
+        tob = outb;
+        count = iconv(ic, &inp, &inb, &outp, &outb);
+        outlen += tob - outb;
+        if (count == (size_t)(-1))
+          {
+             if (errno == E2BIG)
+               {
+                  new_txt = realloc(new_txt, outalloc + 64);
+                  outp = new_txt + outlen;
+                  outalloc += 64;
+                  outb += 64;
+               }
+             else if (errno == EILSEQ)
+               {
+                  if (new_txt)
+                     free(new_txt);
+
+                  new_txt = NULL;
+                  break;
+               }
+             else if (errno == EINVAL)
+               {
+                  if (new_txt)
+                     free(new_txt);
+
+                  new_txt = NULL;
+                  break;
+               }
+             else
+               {
+                  if (new_txt)
+                     free(new_txt);
+
+                  new_txt = NULL;
+                  break;
+               }
+          }
+
+        if (inb == 0)
+          {
+             if (outalloc == outlen)
+                new_txt = realloc(new_txt, outalloc + 1);
+
+             new_txt[outlen] = 0;
+             break;
+          }
+     }
+   iconv_close(ic);
+   return new_txt;
+}
+#else
+EAPI char *
+eina_str_convert(const char *enc_from __UNUSED__,
+                 const char *enc_to __UNUSED__,
+                 const char *text __UNUSED__)
+{
+   return NULL;
+}
+#endif
+
+/**
+ * @brief Put a \ before and Space( ), \ or ' in a string.
+ *
+ * @param str the string to escape
+ *
+ * A newly allocated string is returned.
+ */
+EAPI char *
+eina_str_escape(const char *str)
+{
+   char *s2, *d;
+   const char *s;
+
+   s2 = malloc((strlen(str) * 2) + 1);
+   if (!s2)
+      return NULL;
+
+   for (s = str, d = s2; *s != 0; s++, d++)
+     {
+        if ((*s == ' ') || (*s == '\\') || (*s == '\''))
+          {
+             *d = '\\';
+             d++;
+          }
+
+        *d = *s;
+     }
+   *d = 0;
+   return s2;
+}
+
+/**
+ * @brief Lowercase all the characters in range [A-Z] in the given string.
+ *
+ * @param str the string to lowercase
+ *
+ * This modifies the original string, changing all characters in [A-Z] to 
lowercase.
+ */
+EAPI void
+eina_str_tolower(char **str)
+{
+   char *p;
+   if ((!str) || (!(*str)))
+      return;
+
+   for (p = *str; (*p); p++)
+      *p = tolower((unsigned char )(*p));
+}
+
+/**
+ * @brief Uppercase all the characters in range [a-z] in the given string.
+ *
+ * @param str the string to uppercase
+ *
+ * This modifies the original string, changing all characters in [a-z] to 
uppercase.
+ */
+EAPI void
+eina_str_toupper(char **str)
+{
+   char *p;
+   if ((!str) || (!(*str)))
+      return;
+
+   for (p = *str; (*p); p++)
+      *p = toupper((unsigned char)(*p));
+}
+
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_strbuf.c 
b/tests/suite/ecore/src/lib/eina_strbuf.c
new file mode 100644
index 0000000..3968af5
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_strbuf.c
@@ -0,0 +1,180 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_private.h"
+#include "eina_str.h"
+#include "eina_strbuf_common.h"
+#include "eina_unicode.h"
+
+/*============================================================================*
+ *                                  Local                                     *
+ 
*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#ifdef _STRBUF_DATA_TYPE
+# undef _STRBUF_DATA_TYPE
+#endif
+
+#ifdef _STRBUF_CSIZE
+# undef _STRBUF_CSIZE
+#endif
+
+#ifdef _STRBUF_STRUCT_NAME
+# undef _STRBUF_STRUCT_NAME
+#endif
+
+#ifdef _STRBUF_STRLEN_FUNC
+# undef _STRBUF_STRLEN_FUNC
+#endif
+
+#ifdef _STRBUF_STRESCAPE_FUNC
+# undef _STRBUF_STRESCAPE_FUNC
+#endif
+
+#ifdef _STRBUF_MAGIC
+# undef _STRBUF_MAGIC
+#endif
+
+#ifdef _STRBUF_MAGIC_STR
+# undef _STRBUF_MAGIC_STR
+#endif
+
+#ifdef _FUNC_EXPAND
+# undef _FUNC_EXPAND
+#endif
+
+
+#define _STRBUF_DATA_TYPE         char
+#define _STRBUF_CSIZE             sizeof(_STRBUF_DATA_TYPE)
+#define _STRBUF_STRUCT_NAME       Eina_Strbuf
+#define _STRBUF_STRLEN_FUNC(x)    strlen(x)
+#define _STRBUF_STRESCAPE_FUNC(x) eina_str_escape(x)
+#define _STRBUF_MAGIC             EINA_MAGIC_STRBUF
+#define _STRBUF_MAGIC_STR         __STRBUF_MAGIC_STR
+static const char __STRBUF_MAGIC_STR[] = "Eina Strbuf";
+
+#define _FUNC_EXPAND(y) eina_strbuf_ ## y
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ *                                 Global                                     *
+ 
*============================================================================*/
+
+
+/*============================================================================*
+ *                                   API                                      *
+ 
*============================================================================*/
+
+
+/**
+ * @addtogroup Eina_String_Buffer_Group String Buffer
+ *
+ * @brief These functions provide string buffers management.
+ *
+ * The String Buffer data type is designed to be a mutable string,
+ * allowing to append, prepend or insert a string to a buffer.
+ *
+ * @{
+ */
+
+EAPI Eina_Bool
+eina_strbuf_append_printf(Eina_Strbuf *buf, const char *fmt, ...)
+{
+   va_list args;
+   char *str;
+   size_t len;
+   Eina_Bool ret;
+
+   va_start(args, fmt);
+   len = vasprintf(&str, fmt, args);
+   va_end(args);
+
+   if (len <= 0 || !str)
+      return EINA_FALSE;
+
+   ret = eina_strbuf_append_length(buf, str, len);
+   free(str);
+   return ret;
+}
+
+EAPI Eina_Bool
+eina_strbuf_append_vprintf(Eina_Strbuf *buf, const char *fmt, va_list args)
+{
+   char *str;
+   size_t len;
+   Eina_Bool ret;
+
+   len = vasprintf(&str, fmt, args);
+
+   if (len <= 0 || !str)
+      return EINA_FALSE;
+
+   ret = eina_strbuf_append_length(buf, str, len);
+   free(str);
+   return ret;
+}
+
+EAPI Eina_Bool
+eina_strbuf_insert_printf(Eina_Strbuf *buf, const char *fmt, size_t pos, ...)
+{
+   va_list args;
+   char *str;
+   size_t len;
+   Eina_Bool ret;
+
+   va_start(args, pos);
+   len = vasprintf(&str, fmt, args);
+   va_end(args);
+
+   if (len <= 0 || !str)
+      return EINA_FALSE;
+
+   ret = eina_strbuf_insert(buf, str, pos);
+   free(str);
+   return ret;
+}
+
+EAPI Eina_Bool
+eina_strbuf_insert_vprintf(Eina_Strbuf *buf,
+                           const char *fmt,
+                           size_t pos,
+                           va_list args)
+{
+   char *str;
+   size_t len;
+   Eina_Bool ret;
+
+   len = vasprintf(&str, fmt, args);
+
+   if (len <= 0 || !str)
+      return EINA_FALSE;
+
+   ret = eina_strbuf_insert(buf, str, pos);
+   free(str);
+   return ret;
+}
+
+/* Unicode */
+
+#include "eina_strbuf_template_c.x"
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_strbuf_common.c 
b/tests/suite/ecore/src/lib/eina_strbuf_common.c
new file mode 100644
index 0000000..c96e701
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_strbuf_common.c
@@ -0,0 +1,862 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef _WIN32
+# include <Evil.h>
+#endif
+
+#include "eina_private.h"
+#include "eina_str.h"
+#include "eina_magic.h"
+#include "eina_error.h"
+#include "eina_safety_checks.h"
+#include "eina_strbuf.h"
+#include "eina_strbuf_common.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#define EINA_STRBUF_INIT_SIZE 32
+#define EINA_STRBUF_INIT_STEP 32
+#define EINA_STRBUF_MAX_STEP 4096
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the strbuf module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the strbuf module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_strbuf_common_init(void)
+{
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ * @brief Shut down the strbuf module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the strbuf module set up by
+ * eina_strbuf_common_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_strbuf_common_shutdown(void)
+{
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ *
+ * init the buffer
+ * @param buf the buffer to init
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ */
+static Eina_Bool
+_eina_strbuf_common_init(size_t csize, Eina_Strbuf *buf)
+{
+   buf->len = 0;
+   buf->size = EINA_STRBUF_INIT_SIZE;
+   buf->step = EINA_STRBUF_INIT_STEP;
+
+        eina_error_set(0);
+   buf->buf = calloc(csize, buf->size);
+   if (EINA_UNLIKELY(!buf->buf))
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return EINA_FALSE;
+     }
+
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ *
+ * resize the buffer
+ * @param buf the buffer to resize
+ * @param size the minimum size of the buffer
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ */
+static inline Eina_Bool
+_eina_strbuf_common_resize(size_t csize, Eina_Strbuf *buf, size_t size)
+{
+   size_t new_size, new_step, delta;
+   void *buffer;
+
+   size += 1; // Add extra space for '\0'
+
+   if (size == buf->size)
+      /* nothing to do */
+      return EINA_TRUE;
+   else if (size > buf->size)
+      delta = size - buf->size;
+   else
+      delta = buf->size - size;
+
+   /* check if should keep the same step (just used while growing) */
+   if ((delta <= buf->step) && (size > buf->size))
+      new_step = buf->step;
+   else
+     {
+        new_step = (((delta / EINA_STRBUF_INIT_STEP) + 1)
+                    * EINA_STRBUF_INIT_STEP);
+
+        if (new_step > EINA_STRBUF_MAX_STEP)
+           new_step = EINA_STRBUF_MAX_STEP;
+     }
+
+   new_size = (((size / new_step) + 1) * new_step);
+
+   /* reallocate the buffer to the new size */
+   buffer = realloc(buf->buf, new_size * csize);
+   if (EINA_UNLIKELY(!buffer))
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return EINA_FALSE;
+     }
+
+   buf->buf = buffer;
+   buf->size = new_size;
+   buf->step = new_step;
+        eina_error_set(0);
+   return EINA_TRUE;
+}
+
+/**
+ * @internal
+ *
+ * If required, enlarge the buffer to fit the new size.
+ *
+ * @param buf the buffer to resize
+ * @param size the minimum size of the buffer
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ */
+Eina_Bool
+_eina_strbuf_common_grow(size_t csize, Eina_Strbuf *buf, size_t size)
+{
+   if ((size + 1) < buf->size)
+      return EINA_TRUE;
+
+   return _eina_strbuf_common_resize(csize, buf, size);
+}
+
+/**
+ * @internal
+ *
+ * insert string of known length at random within existing strbuf limits.
+ *
+ * @param buf the buffer to resize, must be valid.
+ * @param str the string to copy, must be valid (!NULL and smaller than @a len)
+ * @param len the amount of bytes in @a str to copy, must be valid.
+ * @param pos the position inside buffer to insert, must be valid (smaller
+ *        than eina_strbuf_common_length_get())
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ */
+static inline Eina_Bool
+_eina_strbuf_common_insert_length(size_t csize,
+                                  Eina_Strbuf *buf,
+                                  const void *str,
+                                  size_t len,
+                                  size_t pos)
+{
+   if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + len)))
+      return EINA_FALSE;
+
+   /* move the existing text */
+   memmove(buf->buf + ((len + pos) * csize), buf->buf + (pos * csize),
+           (buf->len - pos) * csize);
+
+   /* and now insert the given string */
+   memcpy(buf->buf + (pos * csize), str, len * csize);
+
+   buf->len += len;
+   memset(buf->buf + (buf->len * csize), 0, csize);
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @brief Create a new string buffer.
+ *
+ * @return Newly allocated string buffer instance.
+ *
+ * This function creates a new string buffer. On error, @c NULL is
+ * returned and Eina error is set to #EINA_ERROR_OUT_OF_MEMORY. To
+ * free the resources, use eina_strbuf_common_free().
+ *
+ * @see eina_strbuf_common_free()
+ * @see eina_strbuf_common_append()
+ * @see eina_strbuf_common_string_get()
+ */
+Eina_Strbuf *
+eina_strbuf_common_new(size_t csize)
+{
+   Eina_Strbuf *buf;
+
+        eina_error_set(0);
+   buf = malloc(sizeof(Eina_Strbuf));
+   if (EINA_UNLIKELY(!buf))
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   if (EINA_UNLIKELY(!_eina_strbuf_common_init(csize, buf)))
+     {
+        eina_strbuf_common_free(buf);
+        return NULL;
+     }
+
+   return buf;
+}
+
+/**
+ * @brief Free a string buffer.
+ *
+ * @param buf The string buffer to free.
+ *
+ * This function frees the memory of @p buf. @p buf must have been
+ * created by eina_strbuf_common_new().
+ */
+void
+eina_strbuf_common_free(Eina_Strbuf *buf)
+{
+   free(buf->buf);
+   free(buf);
+}
+
+/**
+ * @brief Reset a string buffer.
+ *
+ * @param buf The string buffer to reset.
+ *
+ * This function reset @p buf: the buffer len is set to 0, and the
+ * string is set to '\\0'. No memory is free'd.
+ */
+void
+eina_strbuf_common_reset(size_t csize, Eina_Strbuf *buf)
+{
+   buf->len = 0;
+   buf->step = EINA_STRBUF_INIT_STEP;
+
+   memset(buf->buf, 0, csize);
+}
+
+/**
+ * @brief Append a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends @p str to @p buf. It computes the length of
+ * @p str, so is slightly slower than eina_strbuf_common_append_length(). If
+ * the length is known beforehand, consider using that variant. If
+ * @p buf can't append it, #EINA_FALSE is returned, otherwise
+ * #EINA_TRUE is returned.
+ *
+ * @see eina_strbuf_common_append()
+ * @see eina_strbuf_common_append_length()
+ */
+Eina_Bool
+eina_strbuf_common_append(size_t csize,
+                          Eina_Strbuf *buf,
+                          const void *str,
+                          size_t len)
+{
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
+
+   if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + len)))
+      return EINA_FALSE;
+
+   memcpy(buf->buf + (buf->len * csize), str, (len + 1) * csize);
+   buf->len += len;
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Append a string to a buffer, reallocating as necessary,
+ * limited by the given length.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @param maxlen The maximum number of characters to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends at most @p maxlen characters of @p str to
+ * @p buf. It can't appends more than the length of @p str. It
+ * computes the length of @p str, so is slightly slower than
+ * eina_strbuf_common_append_length(). If the length is known beforehand,
+ * consider using that variant (@p maxlen should then be checked so
+ * that it is greater than the size of @p str). If @p str can not be
+ * appended, #EINA_FALSE is returned, otherwise, #EINA_TRUE is
+ * returned.
+ *
+ * @see eina_strbuf_common_append()
+ * @see eina_strbuf_common_append_length()
+ */
+Eina_Bool
+eina_strbuf_common_append_n(size_t csize,
+                            Eina_Strbuf *buf,
+                            const void *str,
+                            size_t len,
+                            size_t maxlen)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
+
+   if (len > maxlen)
+      len = maxlen;
+
+   if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + len)))
+      return EINA_FALSE;
+
+   memcpy(buf->buf + (buf->len * csize), str, len * csize);
+   buf->len += len;
+   memset(buf->buf + (buf->len * csize), 0, csize);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Append a string of exact length to a buffer, reallocating as 
necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param str The string to append.
+ * @param length The exact length to use.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function appends @p str to @p buf. @p str must be of size at
+ * most @p length. It is slightly faster than eina_strbuf_common_append() as
+ * it does not compute the size of @p str. It is useful when dealing
+ * with strings of known size, such as eina_strngshare. If @p buf
+ * can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ *
+ * @see eina_stringshare_length()
+ * @see eina_strbuf_common_append()
+ * @see eina_strbuf_common_append_n()
+ */
+Eina_Bool
+eina_strbuf_common_append_length(size_t csize,
+                                 Eina_Strbuf *buf,
+                                 const void *str,
+                                 size_t length)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
+
+   if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + length)))
+      return EINA_FALSE;
+
+   memcpy(buf->buf + (buf->len * csize), str, length * csize);
+   buf->len += length;
+   memset(buf->buf + (buf->len * csize), 0, csize);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Insert a string to a buffer, reallocating as necessary.
+ *
+ * @param buf The string buffer to insert.
+ * @param str The string to insert.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p str to @p buf at position @p pos. It
+ * computes the length of @p str, so is slightly slower than
+ * eina_strbuf_common_insert_length(). If  the length is known beforehand,
+ * consider using that variant. If @p buf can't insert it, #EINA_FALSE
+ * is returned, otherwise #EINA_TRUE is returned.
+ */
+Eina_Bool
+eina_strbuf_common_insert(size_t csize,
+                          Eina_Strbuf *buf,
+                          const void *str,
+                          size_t len,
+                          size_t pos)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
+
+   if (pos >= buf->len)
+      return eina_strbuf_common_append(csize, buf, str, len);
+
+   return _eina_strbuf_common_insert_length(csize, buf, str, len, pos);
+}
+
+/**
+ * @brief Insert a string to a buffer, reallocating as necessary. Limited by 
maxlen.
+ *
+ * @param buf The string buffer to insert to.
+ * @param str The string to insert.
+ * @param maxlen The maximum number of chars to insert.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p str ot @p buf at position @p pos, with at
+ * most @p maxlen bytes. The number of inserted characters can not be
+ * greater than the length of @p str. It computes the length of
+ * @p str, so is slightly slower than eina_strbuf_common_insert_length(). If 
the
+ * length is known beforehand, consider using that variant (@p maxlen
+ * should then be checked so that it is greater than the size of
+ * @p str). If @p str can not be inserted, #EINA_FALSE is returned,
+ * otherwise, #EINA_TRUE is returned.
+ */
+Eina_Bool
+eina_strbuf_common_insert_n(size_t csize,
+                            Eina_Strbuf *buf,
+                            const void *str,
+                            size_t len,
+                            size_t maxlen,
+                            size_t pos)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
+
+   if (pos >= buf->len)
+      return eina_strbuf_common_append_n(csize, buf, str, len, maxlen);
+
+   if (len > maxlen)
+      len = maxlen;
+
+   return _eina_strbuf_common_insert_length(csize, buf, str, len, pos);
+}
+
+/**
+ * @brief Insert a string of exact length to a buffer, reallocating as 
necessary.
+ *
+ * @param buf The string buffer to insert to.
+ * @param str The string to insert.
+ * @param length The exact length to use.
+ * @param pos The position to insert the string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p str to @p buf. @p str must be of size at
+ * most @p length. It is slightly faster than eina_strbuf_common_insert() as
+ * it does not compute the size of @p str. It is useful when dealing
+ * with strings of known size, such as eina_strngshare. If @p buf
+ * can't insert it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ *
+ * @see eina_stringshare_length()
+ * @see eina_strbuf_common_insert()
+ * @see eina_strbuf_common_insert_n()
+ */
+Eina_Bool
+eina_strbuf_common_insert_length(size_t csize,
+                                 Eina_Strbuf *buf,
+                                 const void *str,
+                                 size_t length,
+                                 size_t pos)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(str, EINA_FALSE);
+
+   if (pos >= buf->len)
+      return eina_strbuf_common_append_length(csize, buf, str, length);
+
+   return _eina_strbuf_common_insert_length(csize, buf, str, length, pos);
+}
+
+/**
+ * @brief Append a character to a string buffer, reallocating as
+ * necessary.
+ *
+ * @param buf The string buffer to append to.
+ * @param c The char to append.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p c to @p buf. If it can not insert it,
+ * #EINA_FALSE is returned, otherwise #EINA_TRUE is returned.
+ */
+Eina_Bool
+eina_strbuf_common_append_char(size_t csize, Eina_Strbuf *buf, const void *c)
+{
+
+   if (EINA_UNLIKELY(!_eina_strbuf_common_grow(csize, buf, buf->len + 1)))
+      return EINA_FALSE;
+
+   memcpy(buf->buf + ((buf->len)++ *csize), c, csize);
+   memset(buf->buf + (buf->len * csize), 0, csize);
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Insert a character to a string buffer, reallocating as
+ * necessary.
+ *
+ * @param buf The string buffer to insert to.
+ * @param c The char to insert.
+ * @param pos The position to insert the char.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function inserts @p c to @p buf at position @p pos. If @p buf
+ * can't append it, #EINA_FALSE is returned, otherwise #EINA_TRUE is
+ * returned.
+ */
+Eina_Bool
+eina_strbuf_common_insert_char(size_t csize,
+                               Eina_Strbuf *buf,
+                               const void *c,
+                               size_t pos)
+{
+
+   if (pos >= buf->len)
+      return eina_strbuf_common_append_char(csize, buf, c);
+
+   return _eina_strbuf_common_insert_length(csize, buf, c, 1, pos);
+}
+
+/**
+ * @brief Remove a slice of the given string buffer.
+ *
+ * @param buf The string buffer to remove a slice.
+ * @param start The initial (inclusive) slice position to start
+ *        removing, in bytes.
+ * @param end The final (non-inclusive) slice position to finish
+ *        removing, in bytes.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function removes a slice of @p buf, starting at @p start
+ * (inclusive) and ending at @p end (non-inclusive). Both values are
+ * in bytes. It returns #EINA_FALSE on failure, #EINA_TRUE otherwise.
+ */
+Eina_Bool
+eina_strbuf_common_remove(size_t csize,
+                          Eina_Strbuf *buf,
+                          size_t start,
+                          size_t end)
+{
+   size_t remove_len, tail_len;
+
+   if (end >= buf->len)
+      end = buf->len;
+
+   if (end <= start)
+      return EINA_TRUE;
+
+   remove_len = end - start;
+   if (remove_len == buf->len)
+     {
+        free(buf->buf);
+        return _eina_strbuf_common_init(csize, buf);
+     }
+
+   tail_len = buf->len - end + 1; /* includes '\0' */
+   memmove(buf->buf + (start * csize),
+           buf->buf + (end * csize),
+           tail_len * csize);
+   buf->len -= remove_len;
+   return _eina_strbuf_common_resize(csize, buf, buf->len);
+}
+
+/**
+ * @brief Retrieve a pointer to the contents of a string buffer
+ *
+ * @param buf The string buffer.
+ * @return The current string in the string buffer.
+ *
+ * This function returns the string contained in @p buf. The returned
+ * value must not be modified and will no longer be valid if @p buf is
+ * modified. In other words, any eina_strbuf_common_append() or similar will
+ * make that pointer invalid.
+ *
+ * @see eina_strbuf_common_string_steal()
+ */
+const void *
+eina_strbuf_common_string_get(const Eina_Strbuf *buf)
+{
+   return buf->buf;
+}
+
+/**
+ * @brief Steal the contents of a string buffer.
+ *
+ * @param buf The string buffer to steal.
+ * @return The current string in the string buffer.
+ *
+ * This function returns the string contained in @p buf. @p buf is
+ * then initialized and does not own the returned string anymore. The
+ * caller must release the memory of the returned string by calling
+ * free().
+ *
+ * @see eina_strbuf_common_string_get()
+ */
+void *
+eina_strbuf_common_string_steal(size_t csize, Eina_Strbuf *buf)
+{
+   void *ret;
+
+   ret = buf->buf;
+   // TODO: Check return value and do something clever
+   _eina_strbuf_common_init(csize, buf);
+   return ret;
+}
+
+/**
+ * @brief Free the contents of a string buffer but not the buffer.
+ *
+ * @param buf The string buffer to free the string of.
+ *
+ * This function frees the string contained in @p buf without freeing
+ * @p buf.
+ */
+void
+eina_strbuf_common_string_free(size_t csize, Eina_Strbuf *buf)
+{
+   free(buf->buf);
+   _eina_strbuf_common_init(csize, buf);
+}
+
+/**
+ * @brief Retrieve the length of the string buffer content.
+ *
+ * @param buf The string buffer.
+ * @return The current length of the string, in bytes.
+ *
+ * This function returns the length of @p buf.
+ */
+size_t
+eina_strbuf_common_length_get(const Eina_Strbuf *buf)
+{
+   return buf->len;
+}
+
+/**
+ * @addtogroup Eina_String_Buffer_Group String Buffer
+ *
+ * @brief These functions provide string buffers management.
+ *
+ * The String Buffer data type is designed to be a mutable string,
+ * allowing to append, prepend or insert a string to a buffer.
+ *
+ * @{
+ */
+
+
+/**
+ * @cond LOCAL
+ */
+
+/*FIXME: Implementing them here is a hack! */
+
+#ifdef _STRBUF_CSIZE
+# undef _STRBUF_CSIZE
+#endif
+
+#ifdef _STRBUF_MAGIC
+# undef _STRBUF_MAGIC
+#endif
+
+#ifdef _STRBUF_MAGIC_STR
+# undef _STRBUF_MAGIC_STR
+#endif
+
+#define _STRBUF_CSIZE 1
+#define _STRBUF_MAGIC             EINA_MAGIC_STRBUF
+#define _STRBUF_MAGIC_STR         __STRBUF_STR_MAGIC_STR
+static const char __STRBUF_STR_MAGIC_STR[] = "Eina Strbuf";
+
+
+/**
+ * @endcond
+ */
+
+
+/**
+ * @brief Replace the n-th string with an other string.
+ *
+ * @param buf The string buffer to work with.
+ * @param str The string to replace.
+ * @param with The replaceing string.
+ * @param n The number of the fitting string.
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function replaces the n-th occurrence of @p str in @p buf with
+ * @p with. It returns #EINA_FALSE on failure, #EINA_TRUE otherwise.
+ */
+EAPI Eina_Bool
+eina_strbuf_replace(Eina_Strbuf *buf,
+                    const char *str,
+                    const char *with,
+                    unsigned int n)
+{
+   size_t len1, len2;
+   char *spos;
+   size_t pos;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL( str, EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(with, EINA_FALSE);
+   EINA_MAGIC_CHECK_STRBUF(buf, 0);
+
+   if (n == 0)
+      return EINA_FALSE;
+
+   spos = buf->buf;
+   while (n--)
+     {
+        spos = strstr(spos, str);
+        if (!spos || *spos == '\0')
+           return EINA_FALSE;
+
+        if (n)
+           spos++;
+     }
+
+   pos = spos - (const char *)buf->buf;
+   len1 = strlen(str);
+   len2 = strlen(with);
+   if (len1 != len2)
+     {
+        /* resize the buffer if necessary */
+        if (EINA_UNLIKELY(!_eina_strbuf_common_grow(_STRBUF_CSIZE, buf,
+                                                    buf->len - len1 + len2)))
+          {
+             return EINA_FALSE; /* move the existing text */
+
+          }
+
+        memmove(buf->buf + pos + len2, buf->buf + pos + len1,
+                buf->len - pos - len1);
+     }
+
+   /* and now insert the given string */
+   memcpy(buf->buf + pos, with, len2);
+   buf->len += len2 - len1;
+   memset((char *)buf->buf + buf->len, 0, 1);
+
+   return EINA_TRUE;
+}
+
+/**
+ * @brief Replace all strings with an other string.
+
+ * @param buf the string buffer to work with.
+ * @param str The string to replace.
+ * @param with The replaceing string.
+ * @return How often the string was replaced.
+ *
+ * This function replaces all the occurrences of @p str in @ buf with
+ * the string @p with. This function returns the number of times @p str
+ * has been replaced. On failure, it returns 0.
+ */
+EAPI int
+eina_strbuf_replace_all(Eina_Strbuf *buf, const char *str, const char *with)
+{
+   size_t len1, len2, len;
+   char *tmp_buf = NULL;
+   char *spos;
+   size_t pos, start;
+   size_t pos_tmp, start_tmp;
+   int n = 0;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL( str, 0);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(with, 0);
+   EINA_MAGIC_CHECK_STRBUF(buf, 0);
+
+   spos = strstr(buf->buf, str);
+   if (!spos || *spos == '\0')
+      return 0;
+
+   len1 = strlen(str);
+   len2 = strlen(with);
+
+   /* if the size of the two string is equal, it is fairly easy to replace them
+    * we don't need to resize the buffer or doing other calculations */
+   if (len1 == len2)
+     {
+        while (spos)
+          {
+             memcpy(spos, with, len2);
+             spos = strstr(spos + len2, str);
+             n++;
+          }
+        return n;
+     }
+
+   pos = pos_tmp = spos - (const char *)buf->buf;
+   tmp_buf = buf->buf;
+   buf->buf = malloc(buf->size);
+   if (EINA_UNLIKELY(!buf->buf))
+     {
+        buf->buf = tmp_buf;
+        return 0;
+     }
+
+   start = start_tmp = 0;
+   len = buf->len;
+
+   while (spos)
+     {
+        n++;
+        len = (len + len2) - len1;
+        /* resize the buffer if necessary */
+        if (EINA_UNLIKELY(!_eina_strbuf_common_grow(_STRBUF_CSIZE, buf, len)))
+          {
+             /* we have to stop replacing here, because we haven't enough
+              * memory to go on */
+             len = (len + len1) - len2;
+             break;
+          }
+
+        /* copy the untouched text */
+             memcpy(buf->buf + start, tmp_buf + start_tmp, pos - start);
+        /* copy the new string */
+             memcpy(buf->buf + pos,   with,                len2);
+
+        /* calculate the next positions */
+        start_tmp = pos_tmp + len1;
+        start = pos + len2;
+        spos = strstr(tmp_buf + start_tmp, str);
+        /* this calculations don't make sense if spos == NULL, but the
+         * calculated values won't be used, because the loop will stop
+         * then */
+        pos_tmp = spos - tmp_buf;
+        pos = start + pos_tmp - start_tmp;
+     }
+   /* and now copy the rest of the text */
+             memcpy(buf->buf + start, tmp_buf + start_tmp, len - start);
+   buf->len = len;
+             memset((char *)buf->buf + buf->len, 0, 1);
+
+   free(tmp_buf);
+
+   return n;
+}
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_strbuf_common.h 
b/tests/suite/ecore/src/lib/eina_strbuf_common.h
new file mode 100644
index 0000000..3713f2c
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_strbuf_common.h
@@ -0,0 +1,112 @@
+#ifndef EINA_STRBUF_COMMON_H
+#define EINA_STRBUF_COMMON_H
+
+#include <stdlib.h>
+
+#include "eina_private.h"
+#include "eina_magic.h"
+#include "eina_strbuf.h"
+
+struct _Eina_Strbuf
+{
+   void *buf;
+   size_t len;
+   size_t size;
+   size_t step;
+
+   EINA_MAGIC
+};
+
+#define EINA_MAGIC_CHECK_STRBUF(d, ...)                         \
+   do {                                                         \
+        if (!EINA_MAGIC_CHECK((d), _STRBUF_MAGIC))              \
+          {                                                     \
+             EINA_MAGIC_FAIL((d), _STRBUF_MAGIC);               \
+             return __VA_ARGS__;                                \
+          }                                                     \
+     } while (0)
+
+Eina_Bool
+eina_strbuf_common_init(void);
+
+Eina_Bool
+eina_strbuf_common_shutdown(void);
+Eina_Strbuf *
+eina_strbuf_common_new(size_t csize);
+void
+eina_strbuf_common_free(Eina_Strbuf *buf);
+void
+eina_strbuf_common_reset(size_t csize, Eina_Strbuf *buf);
+Eina_Bool
+eina_strbuf_common_append(size_t csize,
+                          Eina_Strbuf *buf,
+                          const void *str,
+                          size_t len);
+Eina_Bool
+eina_strbuf_common_append_escaped(size_t csize,
+                                  Eina_Strbuf *buf,
+                                  const void *str);
+Eina_Bool
+eina_strbuf_common_append_n(size_t csize,
+                            Eina_Strbuf *buf,
+                            const void *str,
+                            size_t len,
+                            size_t maxlen);
+Eina_Bool
+eina_strbuf_common_append_length(size_t csize,
+                                 Eina_Strbuf *buf,
+                                 const void *str,
+                                 size_t length);
+Eina_Bool
+eina_strbuf_common_insert(size_t csize,
+                          Eina_Strbuf *buf,
+                          const void *str,
+                          size_t len,
+                          size_t pos);
+Eina_Bool
+eina_strbuf_common_insert_escaped(size_t csize,
+                                  Eina_Strbuf *buf,
+                                  const void *str,
+                                  size_t len,
+                                  size_t pos);
+Eina_Bool
+eina_strbuf_common_insert_n(size_t csize,
+                            Eina_Strbuf *buf,
+                            const void *str,
+                            size_t len,
+                            size_t maxlen,
+                            size_t pos);
+Eina_Bool
+eina_strbuf_common_insert_length(size_t csize,
+                                 Eina_Strbuf *buf,
+                                 const void *str,
+                                 size_t length,
+                                 size_t pos);
+Eina_Bool
+eina_strbuf_common_append_char(size_t csize, Eina_Strbuf *buf, const void *c);
+Eina_Bool
+eina_strbuf_common_insert_char(size_t csize,
+                               Eina_Strbuf *buf,
+                               const void *c,
+                               size_t pos);
+Eina_Bool
+eina_strbuf_common_remove(size_t csize,
+                          Eina_Strbuf *buf,
+                          size_t start,
+                          size_t end);
+const void *
+eina_strbuf_common_string_get(const Eina_Strbuf *buf);
+void *
+eina_strbuf_common_string_steal(size_t csize, Eina_Strbuf *buf);
+void
+eina_strbuf_common_string_free(size_t csize, Eina_Strbuf *buf);
+size_t
+eina_strbuf_common_length_get(const Eina_Strbuf *buf);
+
+Eina_Bool
+_eina_strbuf_common_grow(size_t csize, Eina_Strbuf *buf, size_t size);
+/**
+ * @}
+ */
+
+#endif
diff --git a/tests/suite/ecore/src/lib/eina_strbuf_template_c.x 
b/tests/suite/ecore/src/lib/eina_strbuf_template_c.x
new file mode 100644
index 0000000..2f3aeae
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_strbuf_template_c.x
@@ -0,0 +1,216 @@
+/*
+ * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
+ */
+
+/* This file should be included from files implementing strbuf. The including 
file
+ * should define the following macros:
+ * _STRBUF_DATA_TYPE
+ * _STRBUF_CSIZE
+ * _STRBUF_STRUCT_NAME
+ * _STRBUF_STRLEN_FUNC(x)
+ * _STRBUF_STRESCAPE_FUNC(x)
+ * _STRBUF_STRSTR_FUNC(x, y)
+ * _STRBUF_MAGIC
+ * _STRBUF_MAGIC_STR
+ * See how it's done in eina_ustrbuf.c and eina_strbuf.c. This just makes 
things
+ * a lot easier since those are essentially the same just with different sizes.
+ */
+
+/*============================================================================*
+ *                                  Local                                     *
+ 
*============================================================================*/
+
+
+/*============================================================================*
+ *                                 Global                                     *
+ 
*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the strbuf module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the strbuf module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+_FUNC_EXPAND(init)(void)
+{
+   eina_magic_string_static_set(_STRBUF_MAGIC, _STRBUF_MAGIC_STR);
+   return eina_strbuf_common_init();
+}
+
+/**
+ * @internal
+ * @brief Shut down the strbuf module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the strbuf module set up by
+ * eina_ustrbuf_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+_FUNC_EXPAND(shutdown)(void)
+{
+   return eina_strbuf_common_shutdown();
+}
+
+/*============================================================================*
+ *                                   API                                      *
+ 
*============================================================================*/
+
+EAPI _STRBUF_STRUCT_NAME *
+_FUNC_EXPAND(new)(void)
+{
+   _STRBUF_STRUCT_NAME *buf = eina_strbuf_common_new(_STRBUF_CSIZE);
+   EINA_MAGIC_SET(buf, _STRBUF_MAGIC);
+   return buf;
+}
+
+EAPI void
+_FUNC_EXPAND(free)(_STRBUF_STRUCT_NAME *buf)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf);
+   EINA_MAGIC_SET(buf, EINA_MAGIC_NONE);
+   eina_strbuf_common_free(buf);
+}
+
+EAPI void
+_FUNC_EXPAND(reset)(_STRBUF_STRUCT_NAME *buf)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf);
+   eina_strbuf_common_reset(_STRBUF_CSIZE, buf);
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(append)(_STRBUF_STRUCT_NAME *buf, const _STRBUF_DATA_TYPE *str)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   return eina_strbuf_common_append(_STRBUF_CSIZE, buf, (const void *) str, 
_STRBUF_STRLEN_FUNC(str));
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(append_escaped)(_STRBUF_STRUCT_NAME *buf, const _STRBUF_DATA_TYPE 
*str)
+{
+   _STRBUF_DATA_TYPE *esc;
+   Eina_Bool ret;
+
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   esc = _STRBUF_STRESCAPE_FUNC(str);
+   if (!esc) {
+      return _FUNC_EXPAND(append)(buf, str);
+   }
+   ret = _FUNC_EXPAND(append)(buf, esc);
+   if (esc)
+      free(esc);
+
+   return ret;
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(append_n)(_STRBUF_STRUCT_NAME *buf, const _STRBUF_DATA_TYPE *str, 
size_t maxlen)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   return eina_strbuf_common_append_n(_STRBUF_CSIZE, buf, (const void *) str, 
_STRBUF_STRLEN_FUNC(str), maxlen);
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(append_length)(_STRBUF_STRUCT_NAME *buf, const _STRBUF_DATA_TYPE 
*str, size_t length)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   return eina_strbuf_common_append_length(_STRBUF_CSIZE, buf, (const void *) 
str, length);
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(insert)(_STRBUF_STRUCT_NAME *buf, const _STRBUF_DATA_TYPE *str, 
size_t pos)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   return eina_strbuf_common_insert(_STRBUF_CSIZE, buf, (const void *) str, 
_STRBUF_STRLEN_FUNC(str), pos);
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(insert_escaped)(_STRBUF_STRUCT_NAME *buf, const _STRBUF_DATA_TYPE 
*str, size_t pos)
+{
+   _STRBUF_DATA_TYPE *esc;
+   Eina_Bool ret;
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+
+   esc = _STRBUF_STRESCAPE_FUNC(str);
+   if (!esc) {
+      return _FUNC_EXPAND(insert)(buf, str, pos);
+   }
+   ret = _FUNC_EXPAND(insert)(buf, esc, pos);
+   if (esc)
+      free(esc);
+
+   return ret;
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(insert_n)(_STRBUF_STRUCT_NAME *buf, const _STRBUF_DATA_TYPE *str, 
size_t maxlen, size_t pos)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   return eina_strbuf_common_insert_n(_STRBUF_CSIZE, buf, (const void *) str, 
_STRBUF_STRLEN_FUNC(str), maxlen, pos);
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(insert_length)(_STRBUF_STRUCT_NAME *buf, const _STRBUF_DATA_TYPE 
*str, size_t length, size_t pos)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   return eina_strbuf_common_insert_length(_STRBUF_CSIZE, buf, (const void *) 
str, length, pos);
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(append_char)(_STRBUF_STRUCT_NAME *buf, _STRBUF_DATA_TYPE c)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   return eina_strbuf_common_append_char(_STRBUF_CSIZE, buf, (const void *) 
&c);
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(insert_char)(_STRBUF_STRUCT_NAME *buf, _STRBUF_DATA_TYPE c, 
size_t pos)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   return eina_strbuf_common_insert_char(_STRBUF_CSIZE, buf, (const void *) 
&c, pos);
+}
+
+EAPI Eina_Bool
+_FUNC_EXPAND(remove)(_STRBUF_STRUCT_NAME *buf, size_t start, size_t end)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, EINA_FALSE);
+   return eina_strbuf_common_remove(_STRBUF_CSIZE, buf, start, end);
+}
+
+EAPI const _STRBUF_DATA_TYPE *
+_FUNC_EXPAND(string_get)(const _STRBUF_STRUCT_NAME *buf)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, NULL);
+   return (const _STRBUF_DATA_TYPE *) eina_strbuf_common_string_get(buf);
+}
+
+EAPI _STRBUF_DATA_TYPE *
+_FUNC_EXPAND(string_steal)(_STRBUF_STRUCT_NAME *buf)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, NULL);
+   return (_STRBUF_DATA_TYPE *) eina_strbuf_common_string_steal(_STRBUF_CSIZE, 
buf);
+}
+
+
+EAPI void
+_FUNC_EXPAND(string_free)(_STRBUF_STRUCT_NAME *buf)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf);
+   eina_strbuf_common_string_free(_STRBUF_CSIZE, buf);
+}
+
+EAPI size_t
+_FUNC_EXPAND(length_get)(const _STRBUF_STRUCT_NAME *buf)
+{
+   EINA_MAGIC_CHECK_STRBUF(buf, 0);
+   return eina_strbuf_common_length_get(buf);
+}
diff --git a/tests/suite/ecore/src/lib/eina_stringshare.c 
b/tests/suite/ecore/src/lib/eina_stringshare.c
new file mode 100644
index 0000000..86b4617
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_stringshare.c
@@ -0,0 +1,956 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002,2003,2004,2005,2006,2007,2008,2010
+ *                        Carsten Haitzler,
+ *                         Jorge Luis Zapata Muga,
+ *                         Cedric Bail,
+ *                         Gustavo Sverzut Barbieri
+ *                         Tom Hacohen
+ *                         Brett Nash
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @page tutorial_stringshare_page Stringshare Tutorial
+ *
+ * to be written...
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#define _GNU_SOURCE
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef EFL_HAVE_POSIX_THREADS
+# include <pthread.h>
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_hash.h"
+#include "eina_rbtree.h"
+#include "eina_error.h"
+#include "eina_log.h"
+#include "eina_stringshare.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_share_common.h"
+
+/* The actual share */
+static Eina_Share *stringshare_share;
+static const char EINA_MAGIC_STRINGSHARE_NODE_STR[] = "Eina Stringshare Node";
+
+#ifdef EFL_HAVE_THREADS
+extern Eina_Bool _share_common_threads_activated;
+
+# ifdef EFL_HAVE_POSIX_THREADS
+static pthread_mutex_t _mutex_small = PTHREAD_MUTEX_INITIALIZER;
+#  define STRINGSHARE_LOCK_SMALL() if(_share_common_threads_activated) \
+      pthread_mutex_lock(&_mutex_small)
+#  define STRINGSHARE_UNLOCK_SMALL() if(_share_common_threads_activated) \
+      pthread_mutex_unlock(&_mutex_small)
+# else /* EFL_HAVE_WIN32_THREADS */
+static HANDLE _mutex_small = NULL;
+#  define STRINGSHARE_LOCK_SMALL() if(_share_common_threads_activated) \
+      WaitForSingleObject(_mutex_small, INFINITE)
+#  define STRINGSHARE_UNLOCK_SMALL() if(_share_common_threads_activated) \
+      ReleaseMutex(_mutex_small)
+
+# endif /* EFL_HAVE_WIN32_THREADS */
+#else /* EFL_HAVE_THREADS */
+# define STRINGSHARE_LOCK_SMALL() do {} while (0)
+# define STRINGSHARE_UNLOCK_SMALL() do {} while (0)
+#endif
+
+/* Stringshare optimizations */
+static const unsigned char _eina_stringshare_single[512] = {
+   0,0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8,0,9,0,10,0,11,0,12,0,13,0,14,0,15,0,
+   16,0,17,0,18,0,19,0,20,0,21,0,22,0,23,0,24,0,25,0,26,0,27,0,28,0,29,0,30,0,
+   31,0,32,0,33,0,34,0,35,0,36,0,37,0,38,0,39,0,40,0,41,0,42,0,43,0,44,0,45,0,
+   46,0,47,0,48,0,49,0,50,0,51,0,52,0,53,0,54,0,55,0,56,0,57,0,58,0,59,0,60,0,
+   61,0,62,0,63,0,64,0,65,0,66,0,67,0,68,0,69,0,70,0,71,0,72,0,73,0,74,0,75,0,
+   76,0,77,0,78,0,79,0,80,0,81,0,82,0,83,0,84,0,85,0,86,0,87,0,88,0,89,0,90,0,
+   91,0,92,0,93,0,94,0,95,0,96,0,97,0,98,0,99,0,100,0,101,0,102,0,103,0,104,0,
+   105,0,
+   106,0,107,0,108,0,109,0,110,0,111,0,112,0,113,0,114,0,115,0,116,0,117,0,118,
+   0,119,0,120,0,
+   121,0,122,0,123,0,124,0,125,0,126,0,127,0,128,0,129,0,130,0,131,0,132,0,133,
+   0,134,0,135,0,
+   136,0,137,0,138,0,139,0,140,0,141,0,142,0,143,0,144,0,145,0,146,0,147,0,148,
+   0,149,0,150,0,
+   151,0,152,0,153,0,154,0,155,0,156,0,157,0,158,0,159,0,160,0,161,0,162,0,163,
+   0,164,0,165,0,
+   166,0,167,0,168,0,169,0,170,0,171,0,172,0,173,0,174,0,175,0,176,0,177,0,178,
+   0,179,0,180,0,
+   181,0,182,0,183,0,184,0,185,0,186,0,187,0,188,0,189,0,190,0,191,0,192,0,193,
+   0,194,0,195,0,
+   196,0,197,0,198,0,199,0,200,0,201,0,202,0,203,0,204,0,205,0,206,0,207,0,208,
+   0,209,0,210,0,
+   211,0,212,0,213,0,214,0,215,0,216,0,217,0,218,0,219,0,220,0,221,0,222,0,223,
+   0,224,0,225,0,
+   226,0,227,0,228,0,229,0,230,0,231,0,232,0,233,0,234,0,235,0,236,0,237,0,238,
+   0,239,0,240,0,
+   241,0,242,0,243,0,244,0,245,0,246,0,247,0,248,0,249,0,250,0,251,0,252,0,253,
+   0,254,0,255,0
+};
+
+typedef struct _Eina_Stringshare_Small Eina_Stringshare_Small;
+typedef struct _Eina_Stringshare_Small_Bucket Eina_Stringshare_Small_Bucket;
+
+struct _Eina_Stringshare_Small_Bucket
+{
+   /* separate arrays for faster lookups */
+   const char **strings;
+   unsigned char *lengths;
+   unsigned short *references;
+   int count;
+   int size;
+};
+
+struct _Eina_Stringshare_Small
+{
+   Eina_Stringshare_Small_Bucket *buckets[256];
+};
+
+#define EINA_STRINGSHARE_SMALL_BUCKET_STEP 8
+static Eina_Stringshare_Small _eina_small_share;
+
+static inline int
+_eina_stringshare_small_cmp(const Eina_Stringshare_Small_Bucket *bucket,
+                            int i,
+                            const char *pstr,
+                            unsigned char plength)
+{
+   /* pstr and plength are from second char and on, since the first is
+    * always the same.
+    *
+    * First string being always the same, size being between 2 and 3
+    * characters (there is a check for special case length==1 and then
+    * small stringshare is applied to strings < 4), we just need to
+    * compare 2 characters of both strings.
+    */
+   const unsigned char cur_plength = bucket->lengths[i] - 1;
+   const char *cur_pstr;
+
+   if (cur_plength > plength)
+      return 1;
+   else if (cur_plength < plength)
+      return -1;
+
+   cur_pstr = bucket->strings[i] + 1;
+
+   if (cur_pstr[0] > pstr[0])
+      return 1;
+   else if (cur_pstr[0] < pstr[0])
+      return -1;
+
+   if (plength == 1)
+      return 0;
+
+   if (cur_pstr[1] > pstr[1])
+      return 1;
+   else if (cur_pstr[1] < pstr[1])
+      return -1;
+
+   return 0;
+}
+
+static const char *
+_eina_stringshare_small_bucket_find(const Eina_Stringshare_Small_Bucket 
*bucket,
+                                    const char *str,
+                                    unsigned char length,
+                                    int *idx)
+{
+   const char *pstr = str + 1; /* skip first letter, it's always the same */
+   unsigned char plength = length - 1;
+   int i, low, high;
+
+   if (bucket->count == 0)
+     {
+        *idx = 0;
+        return NULL;
+     }
+
+   low = 0;
+   high = bucket->count;
+
+   while (low < high)
+     {
+        int r;
+
+        i = (low + high - 1) / 2;
+
+        r = _eina_stringshare_small_cmp(bucket, i, pstr, plength);
+        if (r > 0)
+           high = i;
+        else if (r < 0)
+           low = i + 1;
+        else
+          {
+             *idx = i;
+             return bucket->strings[i];
+          }
+     }
+
+   *idx = low;
+   return NULL;
+}
+
+static Eina_Bool
+_eina_stringshare_small_bucket_resize(Eina_Stringshare_Small_Bucket *bucket,
+                                      int size)
+{
+   void *tmp;
+
+   tmp = realloc((void *)bucket->strings, size * sizeof(bucket->strings[0]));
+   if (!tmp)
+     {
+             eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return 0;
+     }
+
+   bucket->strings = tmp;
+
+   tmp = realloc(bucket->lengths, size * sizeof(bucket->lengths[0]));
+   if (!tmp)
+     {
+             eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return 0;
+     }
+
+   bucket->lengths = tmp;
+
+   tmp = realloc(bucket->references, size * sizeof(bucket->references[0]));
+   if (!tmp)
+     {
+             eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return 0;
+     }
+
+   bucket->references = tmp;
+
+   bucket->size = size;
+   return 1;
+}
+
+static const char *
+_eina_stringshare_small_bucket_insert_at(
+   Eina_Stringshare_Small_Bucket **p_bucket,
+   const char *str,
+   unsigned char length,
+   int idx)
+{
+   Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
+   int todo, off;
+   char *snew;
+
+   if (!bucket)
+     {
+        *p_bucket = bucket = calloc(1, sizeof(*bucket));
+        if (!bucket)
+          {
+             eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+             return NULL;
+          }
+     }
+
+   if (bucket->count + 1 >= bucket->size)
+     {
+        int size = bucket->size + EINA_STRINGSHARE_SMALL_BUCKET_STEP;
+        if (!_eina_stringshare_small_bucket_resize(bucket, size))
+           return NULL;
+     }
+
+   snew = malloc(length + 1);
+   if (!snew)
+     {
+             eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   memcpy(snew, str, length);
+   snew[length] = '\0';
+
+   off = idx + 1;
+   todo = bucket->count - idx;
+   if (todo > 0)
+     {
+        memmove((void *)(bucket->strings + off), bucket->strings + idx,
+                todo * sizeof(bucket->strings[0]));
+        memmove(bucket->lengths + off,           bucket->lengths + idx,
+                todo * sizeof(bucket->lengths[0]));
+        memmove(bucket->references + off,        bucket->references + idx,
+                todo * sizeof(bucket->references[0]));
+     }
+
+   bucket->strings[idx] = snew;
+   bucket->lengths[idx] = length;
+   bucket->references[idx] = 1;
+   bucket->count++;
+
+   return snew;
+}
+
+static void
+_eina_stringshare_small_bucket_remove_at(
+   Eina_Stringshare_Small_Bucket **p_bucket,
+   int idx)
+{
+   Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
+   int todo, off;
+
+   if (bucket->references[idx] > 1)
+     {
+        bucket->references[idx]--;
+        return;
+     }
+
+        free((char *)bucket->strings[idx]);
+
+   if (bucket->count == 1)
+     {
+        free((void *)bucket->strings);
+        free(bucket->lengths);
+        free(bucket->references);
+        free(bucket);
+        *p_bucket = NULL;
+        return;
+     }
+
+   bucket->count--;
+   if (idx == bucket->count)
+      goto end;
+
+   off = idx + 1;
+   todo = bucket->count - idx;
+
+   memmove((void *)(bucket->strings + idx), bucket->strings + off,
+           todo * sizeof(bucket->strings[0]));
+   memmove(bucket->lengths + idx,           bucket->lengths + off,
+           todo * sizeof(bucket->lengths[0]));
+   memmove(bucket->references + idx,        bucket->references + off,
+           todo * sizeof(bucket->references[0]));
+
+end:
+   if (bucket->count + EINA_STRINGSHARE_SMALL_BUCKET_STEP < bucket->size)
+     {
+        int size = bucket->size - EINA_STRINGSHARE_SMALL_BUCKET_STEP;
+        _eina_stringshare_small_bucket_resize(bucket, size);
+     }
+}
+
+static const char *
+_eina_stringshare_small_add(const char *str, unsigned char length)
+{
+   Eina_Stringshare_Small_Bucket **bucket;
+   int i;
+
+   bucket = _eina_small_share.buckets + (unsigned char)str[0];
+   if (!*bucket)
+      i = 0;
+   else
+     {
+        const char *ret;
+        ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i);
+        if (ret)
+          {
+             (*bucket)->references[i]++;
+             return ret;
+          }
+     }
+
+   return _eina_stringshare_small_bucket_insert_at(bucket, str, length, i);
+}
+
+static void
+_eina_stringshare_small_del(const char *str, unsigned char length)
+{
+   Eina_Stringshare_Small_Bucket **bucket;
+   const char *ret;
+   int i;
+
+   bucket = _eina_small_share.buckets + (unsigned char)str[0];
+   if (!*bucket)
+      goto error;
+
+   ret = _eina_stringshare_small_bucket_find(*bucket, str, length, &i);
+   if (!ret)
+      goto error;
+
+   _eina_stringshare_small_bucket_remove_at(bucket, i);
+   return;
+
+error:
+   CRITICAL("EEEK trying to del non-shared stringshare \"%s\"", str);
+}
+
+static void
+_eina_stringshare_small_init(void)
+{
+   memset(&_eina_small_share, 0, sizeof(_eina_small_share));
+}
+
+static void
+_eina_stringshare_small_shutdown(void)
+{
+   Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end;
+
+   p_bucket = _eina_small_share.buckets;
+   p_bucket_end = p_bucket + 256;
+
+   for (; p_bucket < p_bucket_end; p_bucket++)
+     {
+        Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
+        char **s, **s_end;
+
+        if (!bucket)
+           continue;
+
+        s = (char **)bucket->strings;
+        s_end = s + bucket->count;
+        for (; s < s_end; s++)
+           free(*s);
+
+           free((void *)bucket->strings);
+           free(bucket->lengths);
+           free(bucket->references);
+           free(bucket);
+        *p_bucket = NULL;
+     }
+}
+
+static void
+_eina_stringshare_small_bucket_dump(Eina_Stringshare_Small_Bucket *bucket,
+                                    struct dumpinfo *di)
+{
+   const char **s = bucket->strings;
+   unsigned char *l = bucket->lengths;
+   unsigned short *r = bucket->references;
+   int i;
+
+   di->used += sizeof(*bucket);
+   di->used += bucket->count * sizeof(*s);
+   di->used += bucket->count * sizeof(*l);
+   di->used += bucket->count * sizeof(*r);
+   di->unique += bucket->count;
+
+   for (i = 0; i < bucket->count; i++, s++, l++, r++)
+     {
+        int dups;
+#ifdef _WIN32
+        printf("DDD: %5hu %5hu '%s'\n",  *l, *r, *s);
+#else
+        printf("DDD: %5hhu %5hu '%s'\n", *l, *r, *s);
+#endif
+
+        dups = (*r - 1);
+
+        di->used += *l;
+        di->saved += *l * dups;
+        di->dups += dups;
+     }
+}
+
+static void
+_eina_stringshare_small_dump(struct dumpinfo *di)
+{
+   Eina_Stringshare_Small_Bucket **p_bucket, **p_bucket_end;
+
+   p_bucket = _eina_small_share.buckets;
+   p_bucket_end = p_bucket + 256;
+
+   for (; p_bucket < p_bucket_end; p_bucket++)
+     {
+        Eina_Stringshare_Small_Bucket *bucket = *p_bucket;
+
+        if (!bucket)
+           continue;
+
+        _eina_stringshare_small_bucket_dump(bucket, di);
+     }
+}
+
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the share_common module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_stringshare_init(void)
+{
+   Eina_Bool ret;
+   ret = eina_share_common_init(&stringshare_share,
+                                EINA_MAGIC_STRINGSHARE_NODE,
+                                EINA_MAGIC_STRINGSHARE_NODE_STR);
+   if (ret)
+      _eina_stringshare_small_init();
+
+   return ret;
+}
+
+/**
+ * @internal
+ * @brief Shut down the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the share_common module set up by
+ * eina_share_common_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_stringshare_shutdown(void)
+{
+   Eina_Bool ret;
+   _eina_stringshare_small_shutdown();
+   ret = eina_share_common_shutdown(&stringshare_share);
+   return ret;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+/**
+ * @addtogroup Eina_Stringshare_Group Stringshare
+ *
+ * These functions allow you to store one copy of a string, and use it
+ * throughout your program.
+ *
+ * This is a method to reduce the number of duplicated strings kept in
+ * memory. It's pretty common for the same strings to be dynamically
+ * allocated repeatedly between applications and libraries, especially in
+ * circumstances where you could have multiple copies of a structure that
+ * allocates the string. So rather than duplicating and freeing these
+ * strings, you request a read-only pointer to an existing string and
+ * only incur the overhead of a hash lookup.
+ *
+ * It sounds like micro-optimizing, but profiling has shown this can have
+ * a significant impact as you scale the number of copies up. It improves
+ * string creation/destruction speed, reduces memory use and decreases
+ * memory fragmentation, so a win all-around.
+ *
+ * For more information, you can look at the @ref tutorial_stringshare_page.
+ *
+ * @{
+ */
+
+/**
+ * @brief Note that the given string has lost an instance.
+ *
+ * @param str string The given string.
+ *
+ * This function decreases the reference counter associated to @p str
+ * if it exists. If that counter reaches 0, the memory associated to
+ * @p str is freed. If @p str is NULL, the function returns
+ * immediately.
+ *
+ * Note that if the given pointer is not shared or NULL, bad things
+ * will happen, likely a segmentation fault.
+ */
+EAPI void
+eina_stringshare_del(const char *str)
+{
+   int slen;
+   DBG("str=%p (%s)", str, str ? str : "");
+   if (!str)
+      return;
+
+   /* special cases */
+   if      (str[0] == '\0')
+      slen = 0;
+   else if (str[1] == '\0')
+      slen = 1;
+   else if (str[2] == '\0')
+      slen = 2;
+   else if (str[3] == '\0')
+      slen = 3;
+   else
+      slen = 4;  /* handled later */
+
+   if (slen < 2)
+      return;
+   else if (slen < 4)
+     {
+        eina_share_common_population_del(stringshare_share, slen);
+        STRINGSHARE_LOCK_SMALL();
+        _eina_stringshare_small_del(str, slen);
+        STRINGSHARE_UNLOCK_SMALL();
+        return;
+     }
+
+   eina_share_common_del(stringshare_share, str);
+}
+
+/**
+ * @brief Retrieve an instance of a string for use in a program.
+ *
+ * @param   str The string to retrieve an instance of.
+ * @param   slen The string size (<= strlen(str)).
+ * @return  A pointer to an instance of the string on success.
+ *          @c NULL on failure.
+ *
+ * This function retrieves an instance of @p str. If @p str is
+ * @c NULL, then @c NULL is returned. If @p str is already stored, it
+ * is just returned and its reference counter is increased. Otherwise
+ * it is added to the strings to be searched and a duplicated string
+ * of @p str is returned.
+ *
+ * This function does not check string size, but uses the
+ * exact given size. This can be used to share_common part of a larger
+ * buffer or substring.
+ *
+ * @see eina_share_common_add()
+ */
+EAPI const char *
+eina_stringshare_add_length(const char *str, unsigned int slen)
+{
+   DBG("str=%p (%.*s), slen=%u", str, slen, str ? str : "", slen);
+
+   if (slen <= 0)
+      return "";
+   else if (slen == 1)
+      return (const char *)_eina_stringshare_single + ((*str) << 1);
+   else if (slen < 4)
+     {
+        const char *s;
+
+        STRINGSHARE_LOCK_SMALL();
+        s = _eina_stringshare_small_add(str, slen);
+        STRINGSHARE_UNLOCK_SMALL();
+        return s;
+     }
+
+   return eina_share_common_add_length(stringshare_share, str, slen *
+                                       sizeof(char), sizeof(char));
+}
+
+/**
+ * @brief Retrieve an instance of a string for use in a program.
+ *
+ * @param   str The NULL terminated string to retrieve an instance of.
+ * @return  A pointer to an instance of the string on success.
+ *          @c NULL on failure.
+ *
+ * This function retrieves an instance of @p str. If @p str is
+ * @c NULL, then @c NULL is returned. If @p str is already stored, it
+ * is just returned and its reference counter is increased. Otherwise
+ * it is added to the strings to be searched and a duplicated string
+ * of @p str is returned.
+ *
+ * The string @p str must be NULL terminated ('@\0') and its full
+ * length will be used. To use part of the string or non-null
+ * terminated, use eina_stringshare_add_length() instead.
+ *
+ * @see eina_stringshare_add_length()
+ */
+EAPI const char *
+eina_stringshare_add(const char *str)
+{
+   int slen;
+   if (!str)
+      return NULL;
+
+   if      (str[0] == '\0')
+      slen = 0;
+   else if (str[1] == '\0')
+      slen = 1;
+   else if (str[2] == '\0')
+      slen = 2;
+   else if (str[3] == '\0')
+      slen = 3;
+   else
+      slen = 3 + (int)strlen(str + 3);
+
+   return eina_stringshare_add_length(str, slen);
+}
+
+/**
+ * @brief Retrieve an instance of a string for use in a program
+ * from a format string.
+ *
+ * @param   fmt The NULL terminated format string to retrieve an instance of.
+ * @return  A pointer to an instance of the string on success.
+ *          @c NULL on failure.
+ *
+ * This function retrieves an instance of @p fmt. If @p fmt is
+ * @c NULL, then @c NULL is returned. If @p fmt is already stored, it
+ * is just returned and its reference counter is increased. Otherwise
+ * it is added to the strings to be searched and a duplicated string
+ * is returned.
+ *
+ * The format string @p fmt must be NULL terminated ('@\0') and its full
+ * length will be used. To use part of the format string or non-null
+ * terminated, use eina_stringshare_nprintf() instead.
+ *
+ * @see eina_stringshare_nprintf()
+ */
+EAPI const char *
+eina_stringshare_printf(const char *fmt, ...)
+{
+   va_list args;
+   char *tmp;
+   const char *ret;
+   int len;
+
+   if (!fmt)
+      return NULL;
+
+   va_start(args, fmt);
+   len = vasprintf(&tmp, fmt, args);
+   va_end(args);
+
+   if (len < 1)
+      return NULL;
+
+   ret = eina_stringshare_add_length(tmp, len);
+   free(tmp);
+
+   return ret;
+}
+
+/**
+ * @brief Retrieve an instance of a string for use in a program
+ * from a format string.
+ *
+ * @param   fmt The NULL terminated format string to retrieve an instance of.
+ * @param   args The va_args for @p fmt
+ * @return  A pointer to an instance of the string on success.
+ *          @c NULL on failure.
+ *
+ * This function retrieves an instance of @p fmt with @p args. If @p fmt is
+ * @c NULL, then @c NULL is returned. If @p fmt with @p args is already 
stored, it
+ * is just returned and its reference counter is increased. Otherwise
+ * it is added to the strings to be searched and a duplicated string
+ * is returned.
+ *
+ * The format string @p fmt must be NULL terminated ('@\0') and its full
+ * length will be used. To use part of the format string or non-null
+ * terminated, use eina_stringshare_nprintf() instead.
+ *
+ * @see eina_stringshare_nprintf()
+ */
+EAPI const char *
+eina_stringshare_vprintf(const char *fmt, va_list args)
+{
+   char *tmp;
+   const char *ret;
+   int len;
+
+   if (!fmt)
+      return NULL;
+
+   len = vasprintf(&tmp, fmt, args);
+
+   if (len < 1)
+      return NULL;
+
+   ret = eina_stringshare_add_length(tmp, len);
+   free(tmp);
+
+   return ret;
+}
+
+/**
+ * @brief Retrieve an instance of a string for use in a program
+ * from a format string with size limitation.
+ * @param   len The length of the format string to use
+ * @param   fmt The format string to retrieve an instance of.
+ * @return  A pointer to an instance of the string on success.
+ *          @c NULL on failure.
+ *
+ * This function retrieves an instance of @p fmt limited by @p len. If @p fmt 
is
+ * @c NULL or @p len is < 1, then @c NULL is returned. If the resulting string
+ * is already stored, it is returned and its reference counter is increased. 
Otherwise
+ * it is added to the strings to be searched and a duplicated string
+ * is returned.
+ *
+ * @p len length of the format string will be used. To use the
+ * entire format string, use eina_stringshare_printf() instead.
+ *
+ * @see eina_stringshare_printf()
+ */
+EAPI const char *
+eina_stringshare_nprintf(unsigned int len, const char *fmt, ...)
+{
+   va_list args;
+   char *tmp;
+   int size;
+
+   if (!fmt)
+      return NULL;
+
+   if (len < 1)
+      return NULL;
+
+   tmp = alloca(sizeof(char) * len + 1);
+
+   va_start(args, fmt);
+   size = vsnprintf(tmp, len, fmt, args);
+   va_end(args);
+
+   if (size < 1)
+      return NULL;
+
+   return eina_stringshare_add_length(tmp, len);
+}
+
+/**
+ * Increment references of the given shared string.
+ *
+ * @param str The shared string.
+ * @return    A pointer to an instance of the string on success.
+ *            @c NULL on failure.
+ *
+ * This is similar to eina_share_common_add(), but it's faster since it will
+ * avoid lookups if possible, but on the down side it requires the parameter
+ * to be shared before, in other words, it must be the return of a previous
+ * eina_share_common_add().
+ *
+ * There is no unref since this is the work of eina_share_common_del().
+ */
+EAPI const char *
+eina_stringshare_ref(const char *str)
+{
+   int slen;
+   DBG("str=%p (%s)", str, str ? str : "");
+
+   if (!str)
+      return eina_share_common_ref(stringshare_share, str);
+
+   /* special cases */
+   if      (str[0] == '\0')
+      slen = 0;
+   else if (str[1] == '\0')
+      slen = 1;
+   else if (str[2] == '\0')
+      slen = 2;
+   else if (str[3] == '\0')
+      slen = 3;
+   else
+      slen = 3 + (int)strlen(str + 3);
+
+   if (slen < 2)
+     {
+        eina_share_common_population_add(stringshare_share, slen);
+
+        return str;
+     }
+   else if (slen < 4)
+     {
+        const char *s;
+        eina_share_common_population_add(stringshare_share, slen);
+
+        STRINGSHARE_LOCK_SMALL();
+        s = _eina_stringshare_small_add(str, slen);
+        STRINGSHARE_UNLOCK_SMALL();
+
+        return s;
+     }
+
+   return eina_share_common_ref(stringshare_share, str);
+}
+
+/**
+ * @brief Note that the given string @b must be shared.
+ *
+ * @param str the shared string to know the length. It is safe to
+ *        give NULL, in that case -1 is returned.
+ *
+ * This function is a cheap way to known the length of a shared
+ * string. Note that if the given pointer is not shared, bad
+ * things will happen, likely a segmentation fault. If in doubt, try
+ * strlen().
+ */
+EAPI int
+eina_stringshare_strlen(const char *str)
+{
+   int len;
+   /* special cases */
+   if (str[0] == '\0')
+      return 0;
+
+   if (str[1] == '\0')
+      return 1;
+
+   if (str[2] == '\0')
+      return 2;
+
+   if (str[3] == '\0')
+      return 3;
+
+   len = eina_share_common_length(stringshare_share, (const char *)str);
+   len = (len > 0) ? len / (int)sizeof(char) : -1;
+   return len;
+}
+
+/**
+ * @brief Dump the contents of the share_common.
+ *
+ * This function dumps all strings in the share_common to stdout with a
+ * DDD: prefix per line and a memory usage summary.
+ */
+EAPI void
+eina_stringshare_dump(void)
+{
+   eina_share_common_dump(stringshare_share,
+                          _eina_stringshare_small_dump,
+                          sizeof(_eina_stringshare_single));
+}
+
+/**
+ * @}
+ */
+
diff --git a/tests/suite/ecore/src/lib/eina_tiler.c 
b/tests/suite/ecore/src/lib/eina_tiler.c
new file mode 100644
index 0000000..2d263b7
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_tiler.c
@@ -0,0 +1,1295 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2007-2008 Gustavo Sverzut Barbieri, Jorge Luis Zapata Muga
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* TODO
+ * it is possible to have more than one tiler algorithm, but for now the
+ * version Gustavo did is hardcoded here
+ * 
http://blog.gustavobarbieri.com.br/2007/06/03/evas-now-using-rectangle-split-and-merge/
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+#include "eina_tiler.h"
+#include "eina_error.h"
+
+/*============================================================================*
+*                                  Local                                     *
+*============================================================================*/
+
+/* The splitter data types */
+typedef struct list_node list_node_t;
+typedef struct list list_t;
+typedef struct rect rect_t;
+typedef struct rect_node rect_node_t;
+
+struct list_node
+{
+   struct list_node *next;
+};
+
+struct list
+{
+   struct list_node *head;
+   struct list_node *tail;
+};
+
+struct rect
+{
+   short right;
+   short bottom;
+   short left;
+   short top;
+   short width;
+   short height;
+   int area;
+};
+
+struct rect_node
+{
+   struct list_node _lst;
+   struct rect rect;
+};
+
+typedef struct splitter
+{
+   Eina_Bool need_merge;
+   list_t rects;
+} splitter_t;
+
+typedef struct list_node_pool
+{
+   list_node_t *node;
+   int len;
+   int max;
+} list_node_pool_t;
+
+
+static const list_node_t list_node_zeroed = { NULL };
+static const list_t list_zeroed = { NULL, NULL };
+static list_node_pool_t list_node_pool = { NULL, 0, 1024 };
+
+
+typedef struct _Eina_Iterator_Tiler
+{
+   Eina_Iterator iterator;
+   const Eina_Tiler *tiler;
+   list_node_t *curr;
+   EINA_MAGIC
+} Eina_Iterator_Tiler;
+
+struct _Eina_Tiler
+{
+   struct
+   {
+      int w, h;
+   } tile;
+   Eina_Rectangle area;
+   EINA_MAGIC
+   splitter_t splitter;
+};
+
+#define EINA_MAGIC_CHECK_TILER(d, ...)                                  \
+   do {                                                            \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_TILER))             \
+          {                                                       \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_TILER);           \
+             return __VA_ARGS__;                             \
+          }                                                       \
+     } while(0)
+
+
+#define EINA_MAGIC_CHECK_TILER_ITERATOR(d, ...)                         \
+   do {                                                            \
+        if (!EINA_MAGIC_CHECK(d, EINA_MAGIC_TILER_ITERATOR))    \
+          {                                                       \
+             EINA_MAGIC_FAIL(d, EINA_MAGIC_TILER_ITERATOR);  \
+             return __VA_ARGS__;                             \
+          }                                                       \
+     } while(0)
+
+/* The Splitter algorithm */
+static inline void rect_init(rect_t *r, int x, int y, int w, int h)
+{
+   r->area = w * h;
+
+   r->left = x;
+   r->top = y;
+
+   r->right = x + w;
+   r->bottom = y + h;
+
+   r->width = w;
+   r->height = h;
+}
+
+static inline list_node_t *
+rect_list_node_pool_get(void)
+{
+   if (list_node_pool.node)
+     {
+        list_node_t *node;
+
+        node = list_node_pool.node;
+        list_node_pool.node = node->next;
+        list_node_pool.len--;
+
+        return node;
+     }
+   else
+      return malloc(sizeof(rect_node_t));
+}
+
+
+static inline void rect_list_concat(list_t *rects, list_t *other)
+{
+   if (!other->head)
+      return;
+
+   if (rects->tail)
+     {
+        rects->tail->next = other->head;
+        rects->tail = other->tail;
+     }
+   else
+     {
+        rects->head = other->head;
+        rects->tail = other->tail;
+     }
+
+   *other = list_zeroed;
+}
+
+static inline void rect_list_append_node(list_t *rects, list_node_t *node)
+{
+   if (rects->tail)
+     {
+        rects->tail->next = node;
+        rects->tail = node;
+     }
+   else
+     {
+        rects->head = node;
+        rects->tail = node;
+     }
+}
+
+static inline void rect_list_append(list_t *rects, const rect_t r)
+{
+   rect_node_t *rect_node;
+
+   rect_node = (rect_node_t *)rect_list_node_pool_get();
+   rect_node->rect = r;
+   rect_node->_lst = list_node_zeroed;
+
+   rect_list_append_node(rects, (list_node_t *)rect_node);
+}
+
+static inline void rect_list_append_xywh(list_t *rects,
+                                         int x,
+                                         int y,
+                                         int w,
+                                         int h)
+{
+   rect_t r;
+
+   rect_init(&r, x, y, w, h);
+   rect_list_append(rects, r);
+}
+
+static inline void _calc_intra_rect_area(const rect_t a, const rect_t b,
+                                         int *width, int *height)
+{
+   int max_left, min_right, max_top, min_bottom;
+
+   if (a.left < b.left)
+      max_left = b.left;
+   else
+      max_left = a.left;
+
+   if (a.right < b.right)
+      min_right = a.right;
+   else
+      min_right = b.right;
+
+   *width = min_right - max_left;
+
+   if (a.top < b.top)
+      max_top = b.top;
+   else
+      max_top = a.top;
+
+   if (a.bottom < b.bottom)
+      min_bottom = a.bottom;
+   else
+      min_bottom = b.bottom;
+
+   *height = min_bottom - max_top;
+}
+
+static inline void _split_strict(list_t *dirty, const rect_t current, rect_t r)
+{
+   int h_1, h_2, w_1, w_2;
+
+   h_1 = current.top - r.top;
+   h_2 = r.bottom - current.bottom;
+   w_1 = current.left - r.left;
+   w_2 = r.right - current.right;
+
+   if (h_1 > 0)
+     {
+        /*    .--.r (b)                .---.r2
+         *    |  |                     |   |
+         *  .-------.cur (a) .---.r    '---'
+         *  | |  |  |     -> |   |   +
+         *  | `--'  |        `---'
+         *  `-------'
+         */
+        rect_list_append_xywh(dirty, r.left, r.top, r.width, h_1);
+        r.height -= h_1;
+        r.top = current.top;
+     }
+
+   if (h_2 > 0)
+     {
+        /*  .-------.cur (a)
+         *  | .---. |        .---.r
+         *  | |   | |    ->  |   |
+         *  `-------'        `---'   +  .---.r2
+         *    |   |                     |   |
+         *    `---'r (b)                `---'
+         */
+        rect_list_append_xywh(dirty, r.left, current.bottom, r.width,
+                              h_2);
+        r.height -= h_2;
+     }
+
+   if (w_1 > 0)
+      /* (b) r  .----.cur (a)
+       *     .--|-.  |      .--.r2   .-.r
+       *     |  | |  |  ->  |  |   + | |
+       *     `--|-'  |      `--'     `-'
+       *        `----'
+       */
+        rect_list_append_xywh(dirty, r.left, r.top, w_1, r.height);  /* not 
necessary to keep these, r (b) will be destroyed */
+
+   /* r.width -= w_1; */
+   /* r.left = current.left; */
+
+   if (w_2 > 0)
+      /*  .----.cur (a)
+       *  |    |
+       *  |  .-|--.r (b)  .-.r   .--.r2
+       *  |  | |  |    -> | |  + |  |
+       *  |  `-|--'       `-'    `--'
+       *  `----'
+       */
+        rect_list_append_xywh(dirty, current.right, r.top, w_2,
+                            r.height);  /* not necessary to keep this, r (b) 
will be destroyed */
+
+   /* r.width -= w_2; */
+}
+
+static inline void _calc_intra_outer_rect_area(const rect_t a, const rect_t b,
+                                               rect_t *intra, rect_t *outer)
+{
+   int min_left, max_left, min_right, max_right;
+   int min_top, max_top, min_bottom, max_bottom;
+
+   if (a.left < b.left)
+     {
+        max_left = b.left;
+        min_left = a.left;
+     }
+   else
+     {
+        max_left = a.left;
+        min_left = b.left;
+     }
+
+   if (a.right < b.right)
+     {
+        min_right = a.right;
+        max_right = b.right;
+     }
+   else
+     {
+        min_right = b.right;
+        max_right = a.right;
+     }
+
+   intra->left = max_left;
+   intra->right = min_right;
+   intra->width = min_right - max_left;
+
+   outer->left = min_left;
+   outer->right = max_right;
+   outer->width = max_right - min_left;
+
+   if (a.top < b.top)
+     {
+        max_top = b.top;
+        min_top = a.top;
+     }
+   else
+     {
+        max_top = a.top;
+        min_top = b.top;
+     }
+
+   if (a.bottom < b.bottom)
+     {
+        min_bottom = a.bottom;
+        max_bottom = b.bottom;
+     }
+   else
+     {
+        min_bottom = b.bottom;
+        max_bottom = a.bottom;
+     }
+
+   intra->top = max_top;
+   intra->bottom = min_bottom;
+   intra->height = min_bottom - max_top;
+   if ((intra->width > 0) && (intra->height > 0))
+      intra->area = intra->width * intra->height;
+   else
+      intra->area = 0;
+
+   outer->top = min_top;
+   outer->bottom = max_bottom;
+   outer->height = max_bottom - min_top;
+   outer->area = outer->width * outer->height;
+}
+
+enum
+{
+   SPLIT_FUZZY_ACTION_NONE,
+   SPLIT_FUZZY_ACTION_SPLIT,
+   SPLIT_FUZZY_ACTION_MERGE
+};
+
+static inline int _split_fuzzy(list_t *dirty, const rect_t a, rect_t *b)
+{
+   int h_1, h_2, w_1, w_2, action;
+
+   h_1 = a.top - b->top;
+   h_2 = b->bottom - a.bottom;
+   w_1 = a.left - b->left;
+   w_2 = b->right - a.right;
+
+   action = SPLIT_FUZZY_ACTION_NONE;
+
+   if (h_1 > 0)
+     {
+        /*    .--.r (b)                .---.r2
+         *    |  |                     |   |
+         *  .-------.cur (a) .---.r    '---'
+         *  | |  |  |     -> |   |   +
+         *  | `--'  |        `---'
+         *  `-------'
+         */
+        rect_list_append_xywh(dirty, b->left, b->top, b->width, h_1);
+        b->height -= h_1;
+        b->top = a.top;
+        action = SPLIT_FUZZY_ACTION_SPLIT;
+     }
+
+   if (h_2 > 0)
+     {
+        /*  .-------.cur (a)
+         *  | .---. |        .---.r
+         *  | |   | |    ->  |   |
+         *  `-------'        `---'   +  .---.r2
+         *    |   |                     |   |
+         *    `---'r (b)                `---'
+         */
+        rect_list_append_xywh(dirty, b->left, a.bottom, b->width, h_2);
+        b->height -= h_2;
+        action = SPLIT_FUZZY_ACTION_SPLIT;
+     }
+
+   if (((w_1 > 0) || (w_2 > 0)) && (a.height == b->height))
+      return SPLIT_FUZZY_ACTION_MERGE;
+
+   if (w_1 > 0)
+     {
+        /* (b)  r  .----.cur (a)
+         *      .--|-.  |      .--.r2   .-.r
+         *      |  | |  |  ->  |  |   + | |
+         *      `--|-'  |      `--'     `-'
+         *         `----'
+         */
+        rect_list_append_xywh(dirty, b->left, b->top, w_1, b->height);
+        /* not necessary to keep these, r (b) will be destroyed */
+        /* b->width -= w_1; */
+        /* b->left = a.left; */
+        action = SPLIT_FUZZY_ACTION_SPLIT;
+     }
+
+   if (w_2 > 0)
+     {
+        /* .----.cur (a)
+         * |    |
+         * |  .-|--.r (b)  .-.r   .--.r2
+         * |  | |  |    -> | |  + |  |
+         * |  `-|--'       `-'    `--'
+         * `----'
+         */
+        rect_list_append_xywh(dirty, a.right, b->top, w_2, b->height);
+        /* not necessary to keep these, r (b) will be destroyed */
+        /* b->width -= w_2; */
+        action = SPLIT_FUZZY_ACTION_SPLIT;
+     }
+
+   return action;
+}
+
+#if 0
+static void rect_list_node_pool_set_max(int max)
+{
+   int diff;
+
+   diff = list_node_pool.len - max;
+   for (; diff > 0 && list_node_pool.node != NULL; diff--)
+     {
+        list_node_t *node;
+
+        node = list_node_pool.node;
+        list_node_pool.node = node->next;
+        list_node_pool.len--;
+
+        free(node);
+     }
+
+   list_node_pool.max = max;
+}
+#endif
+
+static void rect_list_node_pool_flush(void)
+{
+   while (list_node_pool.node)
+     {
+        list_node_t *node;
+
+        node = list_node_pool.node;
+        list_node_pool.node = node->next;
+        list_node_pool.len--;
+
+        free(node);
+     }
+}
+
+
+
+static inline void rect_list_node_pool_put(list_node_t *node)
+{
+   if (list_node_pool.len < list_node_pool.max)
+     {
+        node->next = list_node_pool.node;
+        list_node_pool.node = node;
+        list_node_pool.len++;
+     }
+   else
+        free(node);
+}
+
+#if 0
+static void rect_print(const rect_t r)
+{
+        printf("<rect(%d, %d, %d, %d)>", r.left, r.top, r.width, r.height);
+}
+
+static void rect_list_print(const list_t rects)
+{
+   list_node_t *node;
+   int len;
+
+   len = 0;
+   for (node = rects.head; node != NULL; node = node->next)
+      len++;
+
+        printf("[");
+   for (node = rects.head; node != NULL; node = node->next)
+     {
+        rect_print(((rect_node_t *)node)->rect);
+        if (node->next)
+          {
+                  putchar(',');
+             if (len < 4)
+                  putchar(' ');
+             else
+               {
+                  putchar('\n');
+                  putchar(' ');
+               }
+          }
+     }
+   printf("]\n");
+}
+#endif
+
+static inline list_node_t *
+rect_list_unlink_next(list_t *rects, list_node_t *parent_node)
+{
+   list_node_t *node;
+
+   if (parent_node)
+     {
+        node = parent_node->next;
+        parent_node->next = node->next;
+     }
+   else
+     {
+        node = rects->head;
+        rects->head = node->next;
+     }
+
+   if (rects->tail == node)
+      rects->tail = parent_node;
+
+   *node = list_node_zeroed;
+   return node;
+}
+
+static inline void rect_list_del_next(list_t *rects, list_node_t *parent_node)
+{
+   list_node_t *node;
+
+   node = rect_list_unlink_next(rects, parent_node);
+        rect_list_node_pool_put(node);
+}
+
+static void rect_list_clear(list_t *rects)
+{
+   list_node_t *node;
+
+   node = rects->head;
+   while (node)
+     {
+        list_node_t *aux;
+
+        aux = node->next;
+        rect_list_node_pool_put(node);
+        node = aux;
+     }
+   *rects = list_zeroed;
+}
+
+static void rect_list_del_split_strict(list_t *rects, const rect_t del_r)
+{
+   list_t modified = list_zeroed;
+   list_node_t *cur_node, *prev_node;
+
+   prev_node = NULL;
+   cur_node = rects->head;
+   while (cur_node)
+     {
+        int intra_width, intra_height;
+        rect_t current;
+
+        current = ((rect_node_t *)cur_node)->rect;
+
+        _calc_intra_rect_area(del_r, current, &intra_width,
+                              &intra_height);
+        if ((intra_width <= 0) || (intra_height <= 0))
+          {
+             /*  .---.current      .---.del_r
+              *  |   |             |   |
+              *  `---+---.del_r    `---+---.current
+              *      |   |             |   |
+              *      `---'             `---'
+              * no intersection, nothing to do
+              */
+             prev_node = cur_node;
+             cur_node = cur_node->next;
+          }
+        else if ((intra_width == current.width) && (intra_height
+                                                    == current.height))
+          {
+             /*  .-------.del_r
+              *  | .---. |
+              *  | |   | |
+              *  | `---'current
+              *  `-------'
+              * current is contained, remove from rects
+              */
+             cur_node = cur_node->next;
+             rect_list_del_next(rects, prev_node);
+          }
+        else
+          {
+             _split_strict(&modified, del_r, current);
+             cur_node = cur_node->next;
+             rect_list_del_next(rects, prev_node);
+          }
+     }
+
+   rect_list_concat(rects, &modified);
+}
+
+#if 0
+static void rect_list_add_split_strict(list_t *rects, list_node_t *node)
+{
+   list_t dirty = list_zeroed;
+   list_t new_dirty = list_zeroed;
+   list_node_t *cur_node;
+
+   if (!rects->head)
+     {
+        rect_list_append_node(rects, node);
+        return;
+     }
+
+        rect_list_append_node(&dirty, node);
+
+   cur_node = rects->head;
+   while (dirty.head)
+     {
+        rect_t current;
+
+        if (!cur_node)
+          {
+             rect_list_concat(rects, &dirty);
+             break;
+          }
+
+        current = ((rect_node_t *)cur_node)->rect;
+
+        while (dirty.head)
+          {
+             int intra_width, intra_height;
+             rect_t r;
+
+             r = ((rect_node_t *)dirty.head)->rect;
+             _calc_intra_rect_area(r, current, &intra_width,
+                                   &intra_height);
+             if ((intra_width == r.width) && (intra_height
+                                              == r.height))
+                /*  .-------.cur
+                 *  | .---.r|
+                 *  | |   | |
+                 *  | `---' |
+                 *  `-------'
+                 */
+                rect_list_del_next(&dirty, NULL);
+             else if ((intra_width <= 0) || (intra_height <= 0))
+               {
+                  /*  .---.cur     .---.r
+                   *  |   |        |   |
+                   *  `---+---.r   `---+---.cur
+                   *      |   |        |   |
+                   *      `---'        `---'
+                   */
+                  list_node_t *tmp;
+                  tmp = rect_list_unlink_next(&dirty, NULL);
+                  rect_list_append_node(&new_dirty, tmp);
+               }
+             else
+               {
+                  _split_strict(&new_dirty, current, r);
+                  rect_list_del_next(&dirty, NULL);
+               }
+          }
+        dirty = new_dirty;
+        new_dirty = list_zeroed;
+
+        cur_node = cur_node->next;
+     }
+}
+#endif
+
+static list_node_t *
+rect_list_add_split_fuzzy(list_t *rects, list_node_t *node, int accepted_error)
+{
+   list_t dirty = list_zeroed;
+   list_node_t *old_last;
+
+   old_last = rects->tail;
+
+   if (!rects->head)
+     {
+        rect_list_append_node(rects, node);
+        return old_last;
+     }
+
+        rect_list_append_node(&dirty, node);
+   while (dirty.head)
+     {
+        list_node_t *d_node, *cur_node, *prev_cur_node;
+        int keep_dirty;
+        rect_t r;
+
+        d_node = rect_list_unlink_next(&dirty, NULL);
+        r = ((rect_node_t *)d_node)->rect;
+
+        prev_cur_node = NULL;
+        cur_node = rects->head;
+        keep_dirty = 1;
+        while (cur_node)
+          {
+             int area, action;
+             rect_t current, intra, outer;
+
+             current = ((rect_node_t *)cur_node)->rect;
+
+             _calc_intra_outer_rect_area(r, current, &intra, &outer);
+             area = current.area + r.area - intra.area;
+
+             if ((intra.width == r.width) && (intra.height
+                                              == r.height))
+               {
+                  /*  .-------.cur
+                   *  | .---.r|
+                   *  | |   | |
+                   *  | `---' |
+                   *  `-------'
+                   */
+                  keep_dirty = 0;
+                  break;
+               }
+             else if ((intra.width == current.width)
+                      && (intra.height == current.height))
+               {
+                  /* .-------.r
+                   * | .---.cur
+                   * | |   | |
+                   * | `---' |
+                   * `-------'
+                   */
+                  if (old_last == cur_node)
+                     old_last = prev_cur_node;
+
+                  cur_node = cur_node->next;
+                  rect_list_del_next(rects, prev_cur_node);
+               }
+             else if ((outer.area - area) <= accepted_error)
+               {
+                  /* .-----------. bounding box (outer)
+                   * |.---. .---.|
+                   * ||cur| |r  ||
+                   * ||   | |   ||
+                   * |`---' `---'|
+                   * `-----------'
+                   * merge them, remove both and add merged
+                   */
+                  rect_node_t *n;
+
+                  if (old_last == cur_node)
+                     old_last = prev_cur_node;
+
+                  n = (rect_node_t *)rect_list_unlink_next(
+                        rects, prev_cur_node);
+                  n->rect = outer;
+                       rect_list_append_node(&dirty, (list_node_t *)n);
+
+                  keep_dirty = 0;
+                  break;
+               }
+             else if (intra.area <= accepted_error)
+               {
+                  /*  .---.cur     .---.r
+                   *  |   |        |   |
+                   *  `---+---.r   `---+---.cur
+                   *      |   |        |   |
+                   *      `---'        `---'
+                   *  no split, no merge
+                   */
+                  prev_cur_node = cur_node;
+                  cur_node = cur_node->next;
+               }
+             else
+               {
+                  /* split is required */
+                  action = _split_fuzzy(&dirty, current, &r);
+                  if (action == SPLIT_FUZZY_ACTION_MERGE)
+                    {
+/* horizontal merge is possible: remove both, add merged */
+                       rect_node_t *n;
+
+                       if (old_last == cur_node)
+                          old_last = prev_cur_node;
+
+                       n
+                          = (rect_node_t *)rect_list_unlink_next(
+                                rects,
+                                prev_cur_node);
+
+                       n->rect.left = outer.left;
+                       n->rect.width = outer.width;
+                       n->rect.right = outer.right;
+                       n->rect.area = outer.width * r.height;
+                       rect_list_append_node(&dirty,
+                                             (list_node_t *)n);
+                    }
+                  else if (action == SPLIT_FUZZY_ACTION_NONE)
+                    {
+/*
+ * this rect check was totally useless,
+ * should never happen
+ */
+/* prev_cur_node = cur_node; */
+/* cur_node = cur_node->next; */
+                       printf("Should not get here!\n");
+                       abort();
+                    }
+
+                  keep_dirty = 0;
+                  break;
+               }
+          }
+        if (EINA_UNLIKELY(keep_dirty))
+           rect_list_append_node(rects, d_node);
+        else
+           rect_list_node_pool_put(d_node);
+     }
+
+   return old_last;
+}
+
+static inline void _calc_outer_rect_area(const rect_t a, const rect_t b,
+                                         rect_t *outer)
+{
+   int min_left, max_right;
+   int min_top, max_bottom;
+
+   if (a.left < b.left)
+      min_left = a.left;
+   else
+      min_left = b.left;
+
+   if (a.right < b.right)
+      max_right = b.right;
+   else
+      max_right = a.right;
+
+   outer->left = min_left;
+   outer->right = max_right;
+   outer->width = max_right - min_left;
+
+   if (a.top < b.top)
+      min_top = a.top;
+   else
+      min_top = b.top;
+
+   if (a.bottom < b.bottom)
+      max_bottom = b.bottom;
+   else
+      max_bottom = a.bottom;
+
+   outer->top = min_top;
+   outer->bottom = max_bottom;
+   outer->height = max_bottom - min_top;
+
+   outer->area = outer->width * outer->height;
+}
+
+static void rect_list_merge_rects(list_t *rects,
+                                  list_t *to_merge,
+                                  int accepted_error)
+{
+   while (to_merge->head)
+     {
+        list_node_t *node, *parent_node;
+        rect_t r1;
+        int merged;
+
+        r1 = ((rect_node_t *)to_merge->head)->rect;
+
+        merged = 0;
+        parent_node = NULL;
+        node = rects->head;
+        while (node)
+          {
+             rect_t r2, outer;
+             int area;
+
+             r2 = ((rect_node_t *)node)->rect;
+
+             _calc_outer_rect_area(r1, r2, &outer);
+             area = r1.area + r2.area; /* intra area is taken as 0 */
+             if (outer.area - area <= accepted_error)
+               {
+                  /*
+                   * remove both r1 and r2, create r3
+                   * actually r3 uses r2 instance, saves memory
+                   */
+                  rect_node_t *n;
+
+                  n = (rect_node_t *)rect_list_unlink_next(
+                        rects, parent_node);
+                  n->rect = outer;
+                  rect_list_append_node(to_merge,
+                                        (list_node_t *)n);
+                  merged = 1;
+                  break;
+               }
+
+             parent_node = node;
+             node = node->next;
+          }
+
+        if (!merged)
+          {
+             list_node_t *n;
+             n = rect_list_unlink_next(to_merge, NULL);
+                  rect_list_append_node(rects, n);
+          }
+        else
+                  rect_list_del_next(to_merge, NULL);
+     }
+}
+
+static void rect_list_add_split_fuzzy_and_merge(list_t *rects,
+                                                list_node_t *node,
+                                                int split_accepted_error,
+                                                int merge_accepted_error)
+{
+   list_node_t *n;
+
+   n = rect_list_add_split_fuzzy(rects, node, split_accepted_error);
+   if (n && n->next)
+     {
+        list_t to_merge;
+
+        /* split list into 2 segments, already merged and to merge */
+        to_merge.head = n->next;
+        to_merge.tail = rects->tail;
+        rects->tail = n;
+        n->next = NULL;
+
+        rect_list_merge_rects(rects, &to_merge, merge_accepted_error);
+     }
+}
+
+static inline void _splitter_new(Eina_Tiler *t)
+{
+   t->splitter.rects = list_zeroed;
+   t->splitter.need_merge = EINA_FALSE;
+}
+
+static inline void _splitter_del(Eina_Tiler *t)
+{
+   rect_list_clear(&t->splitter.rects);
+   rect_list_node_pool_flush();
+}
+
+static inline void _splitter_tile_size_set(Eina_Tiler *t,
+                                           int w __UNUSED__,
+                                           int h __UNUSED__)
+{
+   /* TODO are w and h used for something? */
+   t->splitter.rects = list_zeroed;
+}
+
+static inline Eina_Bool _splitter_rect_add(Eina_Tiler *t, Eina_Rectangle *rect)
+{
+   rect_node_t *rn;
+
+   //printf("ACCOUNTING[1]: add_redraw: %4d,%4d %3dx%3d\n", x, y, w, h);
+   rect->x >>= 1;
+   rect->y >>= 1;
+   rect->w += 2;
+   rect->w >>= 1;
+   rect->h += 2;
+   rect->h >>= 1;
+
+   rn = (rect_node_t *)rect_list_node_pool_get();
+   rn->_lst = list_node_zeroed;
+   rect_init(&rn->rect, rect->x, rect->y, rect->w, rect->h);
+   //printf("ACCOUNTING[2]: add_redraw: %4d,%4d %3dx%3d\n", x, y, w, h);
+   //testing on my core2 duo desktop - fuzz of 32 or 48 is best.
+#define FUZZ 32
+   rect_list_add_split_fuzzy_and_merge(&t->splitter.rects,
+                                       (list_node_t *)rn,
+                                       FUZZ * FUZZ,
+                                       FUZZ * FUZZ);
+   return EINA_TRUE;
+}
+
+static inline void _splitter_rect_del(Eina_Tiler *t, Eina_Rectangle *rect)
+{
+   rect_t r;
+
+   if (!t->splitter.rects.head)
+      return;
+
+   rect->x += 1;
+   rect->y += 1;
+   rect->x >>= 1;
+   rect->y >>= 1;
+   rect->w -= 1;
+   rect->w >>= 1;
+   rect->h -= 1;
+   rect->h >>= 1;
+
+   if ((rect->w <= 0) || (rect->h <= 0))
+      return;
+
+   rect_init(&r, rect->x, rect->y, rect->w, rect->h);
+   //fprintf(stderr, "ACCOUNTING: del_redraw: %4d,%4d %3dx%3d\n", x, y, w, h);
+
+   rect_list_del_split_strict(&t->splitter.rects, r);
+   t->splitter.need_merge = EINA_TRUE;
+   return;
+}
+
+static inline void _splitter_clear(Eina_Tiler *t)
+{
+   rect_list_clear(&t->splitter.rects);
+   t->splitter.need_merge = EINA_FALSE;
+}
+/* end of splitter algorithm */
+
+static Eina_Bool _iterator_next(Eina_Iterator_Tiler *it, void **data)
+{
+   Eina_Rectangle *rect = (Eina_Rectangle *)data;
+   list_node_t *n;
+
+   for (n = it->curr; n; n = n->next)
+     {
+        rect_t cur;
+
+        cur = ((rect_node_t *)n)->rect;
+
+        rect->x = cur.left << 1;
+        rect->y = cur.top << 1;
+        rect->w = cur.width << 1;
+        rect->h = cur.height << 1;
+
+        if (eina_rectangle_intersection(rect, &it->tiler->area) == EINA_FALSE)
+           continue;
+
+        if ((rect->w <= 0) || (rect->h <= 0))
+           continue;
+
+        it->curr = n->next;
+        return EINA_TRUE;
+     }
+   return EINA_FALSE;
+}
+
+static void *_iterator_get_container(Eina_Iterator_Tiler *it)
+{
+   EINA_MAGIC_CHECK_TILER_ITERATOR(it, NULL);
+   return (void *)it->tiler;
+}
+
+static void _iterator_free(Eina_Iterator_Tiler *it)
+{
+   EINA_MAGIC_CHECK_TILER_ITERATOR(it);
+   free(it);
+}
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+EAPI Eina_Tiler *eina_tiler_new(int w, int h)
+{
+   Eina_Tiler *t;
+
+   t = calloc(1, sizeof(Eina_Tiler));
+   t->area.w = w;
+   t->area.h = h;
+   t->tile.w = w;
+   t->tile.h = h;
+   EINA_MAGIC_SET(t, EINA_MAGIC_TILER);
+   _splitter_new(t);
+   return t;
+}
+
+EAPI void eina_tiler_free(Eina_Tiler *t)
+{
+   EINA_MAGIC_CHECK_TILER(t);
+   _splitter_del(t);
+   free(t);
+}
+
+EAPI void eina_tiler_tile_size_set(Eina_Tiler *t, int w, int h)
+{
+   EINA_MAGIC_CHECK_TILER(t);
+   if ((w <= 0) || (h <= 0))
+      return;
+
+   t->tile.w = w;
+   t->tile.h = h;
+   _splitter_tile_size_set(t, w, h);
+}
+
+EAPI Eina_Bool eina_tiler_rect_add(Eina_Tiler *t, const Eina_Rectangle *r)
+{
+   Eina_Rectangle tmp;
+
+   EINA_MAGIC_CHECK_TILER(t, EINA_FALSE);
+   if ((r->w <= 0) || (r->h <= 0))
+      return EINA_FALSE;
+
+   tmp = *r;
+   if (eina_rectangle_intersection(&tmp, &t->area) == EINA_FALSE)
+      return EINA_FALSE;
+
+   if ((tmp.w <= 0) || (tmp.h <= 0))
+      return EINA_FALSE;
+
+   return _splitter_rect_add(t, &tmp);
+}
+
+EAPI void eina_tiler_rect_del(Eina_Tiler *t, const Eina_Rectangle *r)
+{
+   Eina_Rectangle tmp;
+
+   EINA_MAGIC_CHECK_TILER(t);
+   if ((r->w <= 0) || (r->h <= 0))
+      return;
+
+   tmp = *r;
+   if (eina_rectangle_intersection(&tmp, &t->area) == EINA_FALSE)
+      return;
+
+   if ((tmp.w <= 0) || (tmp.h <= 0))
+      return;
+
+   _splitter_rect_del(t, &tmp);
+}
+
+EAPI void eina_tiler_clear(Eina_Tiler *t)
+{
+   EINA_MAGIC_CHECK_TILER(t);
+   _splitter_clear(t);
+}
+
+
+EAPI Eina_Iterator *eina_tiler_iterator_new(const Eina_Tiler *t)
+{
+   Eina_Iterator_Tiler *it;
+
+   EINA_MAGIC_CHECK_TILER(t, NULL);
+
+   it = calloc(1, sizeof (Eina_Iterator_Tiler));
+   if (!it)
+      return NULL;
+
+   it->tiler = t;
+
+   if (t->splitter.need_merge == EINA_TRUE)
+     {
+        list_t to_merge;
+        splitter_t *sp;
+
+        sp = (splitter_t *)&(t->splitter);
+        to_merge = t->splitter.rects;
+        sp->rects = list_zeroed;
+        rect_list_merge_rects(&sp->rects, &to_merge, FUZZ * FUZZ);
+        sp->need_merge = 0;
+     }
+
+   it->curr = it->tiler->splitter.rects.head;
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
+         _iterator_get_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_iterator_free);
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+   EINA_MAGIC_SET(it,            EINA_MAGIC_TILER_ITERATOR);
+
+   return &it->iterator;
+}
+
+struct _Eina_Tile_Grid_Slicer_Iterator
+{
+   Eina_Iterator iterator;
+   Eina_Tile_Grid_Slicer priv;
+};
+
+typedef struct _Eina_Tile_Grid_Slicer_Iterator Eina_Tile_Grid_Slicer_Iterator;
+
+static void
+eina_tile_grid_slicer_iterator_free(Eina_Tile_Grid_Slicer_Iterator *it)
+{
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_NONE);
+   free(it);
+}
+
+static Eina_Bool
+eina_tile_grid_slicer_iterator_next(Eina_Tile_Grid_Slicer_Iterator *it,
+                                    void **data)
+{
+   return eina_tile_grid_slicer_next
+             (&it->priv, (const Eina_Tile_Grid_Info **)data);
+}
+
+/**
+ * @brief Creates a new Eina_Iterator that slices over a list of tiles.
+ *
+ * @param   x X axis coordinate.
+ * @param   y Y axis coordinate.
+ * @param   w width.
+ * @param   h height.
+ * @param   tile_w tile width.
+ * @param   tile_h tile height.
+ * @return  A pointer to the Eina_Iterator.
+ *          @c NULL on failure.
+ *
+ * The tile grid is defined by @a tile_w and @a tile_h while the region is
+ * defined by @a x, @a y, @a w, @a h. The output is given as
+ * @c Eina_Tile_Grid_Info where tile index is given in @c col col and
+ * @c row row with tile-relative
+ *    coordinates in @c x, @c y, @c w, @c h. If tile was fully filled by
+ *    region, then @c full flag
+ *     is set.
+ */
+EAPI Eina_Iterator *
+eina_tile_grid_slicer_iterator_new(int x,
+                                   int y,
+                                   int w,
+                                   int h,
+                                   int tile_w,
+                                   int tile_h)
+{
+   Eina_Tile_Grid_Slicer_Iterator *it;
+
+   it = calloc(1, sizeof(*it));
+   if (!it)
+     {
+        eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
+        return NULL;
+     }
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(eina_tile_grid_slicer_iterator_next);
+   it->iterator.free = FUNC_ITERATOR_FREE(eina_tile_grid_slicer_iterator_free);
+
+   eina_tile_grid_slicer_setup(&it->priv, x, y, w, h, tile_w, tile_h);
+
+   return &it->iterator;
+}
diff --git a/tests/suite/ecore/src/lib/eina_unicode.c 
b/tests/suite/ecore/src/lib/eina_unicode.c
new file mode 100644
index 0000000..cef07fb
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_unicode.c
@@ -0,0 +1,176 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2010 Tom Hacohen,
+ *             Brett Nash
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+
+ */
+
+#include <Eina.h>
+#include "eina_unicode.h"
+
+/* FIXME: check if sizeof(wchar_t) == sizeof(Eina_Unicode) if so,
+ * probably better to use the standard functions */
+
+/* Maybe I'm too tired, but this is the only thing that actually worked. */
+const Eina_Unicode _EINA_UNICODE_EMPTY_STRING[1] = {0};
+EAPI const Eina_Unicode *EINA_UNICODE_EMPTY_STRING = 
_EINA_UNICODE_EMPTY_STRING;
+/**
+ * @brief Same as the standard strcmp just with Eina_Unicode instead of char.
+ */
+EAPI int
+eina_unicode_strcmp(const Eina_Unicode *a, const Eina_Unicode *b)
+{
+   for (; *a && *a == *b; a++, b++)
+      ;
+   if (*a == *b)
+      return 0;
+   else if (*a < *b)
+      return -1;
+   else
+      return 1;
+}
+
+/**
+ * @brief Same as the standard strcpy just with Eina_Unicode instead of char.
+ */
+EAPI Eina_Unicode *
+eina_unicode_strcpy(Eina_Unicode *dest, const Eina_Unicode *source)
+{
+   Eina_Unicode *ret = dest;
+
+   while (*source)
+      *dest++ = *source++;
+   *dest = 0;
+   return ret;
+}
+
+/**
+ * @brief Same as the standard strncpy just with Eina_Unicode instead of char.
+ */
+EAPI Eina_Unicode *
+eina_unicode_strncpy(Eina_Unicode *dest, const Eina_Unicode *source, size_t n)
+{
+   Eina_Unicode *ret = dest;
+
+   for ( ; n && *source ; n--)
+      *dest++ = *source++;
+   for (; n; n--)
+      *dest++ = 0;
+   return ret;
+}
+
+/**
+ * @brief Same as the standard strlen just with Eina_Unicode instead of char.
+ */
+EAPI size_t
+eina_unicode_strlen(const Eina_Unicode *ustr)
+{
+   const Eina_Unicode *end;
+   for (end = ustr; *end; end++)
+      ;
+   return end - ustr;
+}
+
+/**
+ * @brief Returns the length of a Eina_Unicode string, up to a limit.
+ *
+ * This function returns the number of characters in string, up to a maximum
+ * of n.  If the terminating character is not found in the string, it returns
+ * n.
+ *
+ * @param ustr String to search
+ * @param n Max length to search
+ * @return Number of characters or n.
+ */
+EAPI size_t
+eina_unicode_strnlen(const Eina_Unicode *ustr, int n)
+{
+   const Eina_Unicode *end;
+   const Eina_Unicode *last = ustr + n; /* technically not portable ;-) */
+   for (end = ustr; end < last && *end; end++)
+      ;
+   return end - ustr;
+}
+
+
+
+
+/**
+ * @brief Same as the standard strdup just with Eina_Unicode instead of char.
+ */
+EAPI Eina_Unicode *
+eina_unicode_strdup(const Eina_Unicode *text)
+{
+   Eina_Unicode *ustr;
+   int len;
+
+   len = eina_unicode_strlen(text);
+   ustr = (Eina_Unicode *)calloc(len + 1, sizeof(Eina_Unicode));
+   memcpy(ustr, text, len * sizeof(Eina_Unicode));
+
+   return ustr;
+}
+
+/**
+ * @brief Same as the standard strdup just with Eina_Unicode instead of char.
+ */
+EAPI Eina_Unicode *
+eina_unicode_strstr(const Eina_Unicode *haystack, const Eina_Unicode *needle)
+{
+   const Eina_Unicode *i, *j;
+
+   for (i = haystack; *i; i++)
+     {
+        haystack = i; /* set this location as the base position */
+        for (j = needle; *j && *i && *j == *i; j++, i++)
+           ;
+
+        if (!*j) /*if we got to the end of j this means we got a full match */
+          {
+             return (Eina_Unicode *)haystack; /* return the new base position 
*/
+          }
+     }
+
+   return NULL;
+}
+
+/**
+ * @see eina_str_escape()
+ */
+EAPI Eina_Unicode *
+eina_unicode_escape(const Eina_Unicode *str)
+{
+   Eina_Unicode *s2, *d;
+   const Eina_Unicode *s;
+
+   s2 = malloc((eina_unicode_strlen(str) * 2) + 1);
+   if (!s2)
+      return NULL;
+
+   for (s = str, d = s2; *s != 0; s++, d++)
+     {
+        if ((*s == ' ') || (*s == '\\') || (*s == '\''))
+          {
+             *d = '\\';
+             d++;
+          }
+
+        *d = *s;
+     }
+   *d = 0;
+   return s2;
+}
+
diff --git a/tests/suite/ecore/src/lib/eina_ustrbuf.c 
b/tests/suite/ecore/src/lib/eina_ustrbuf.c
new file mode 100644
index 0000000..7df5b16
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_ustrbuf.c
@@ -0,0 +1,89 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "eina_strbuf_common.h"
+#include "eina_unicode.h"
+#include "eina_ustrbuf.h"
+
+/*============================================================================*
+ *                                  Local                                     *
+ 
*============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#ifdef _STRBUF_DATA_TYPE
+# undef _STRBUF_DATA_TYPE
+#endif
+
+#ifdef _STRBUF_CSIZE
+# undef _STRBUF_CSIZE
+#endif
+
+#ifdef _STRBUF_STRUCT_NAME
+# undef _STRBUF_STRUCT_NAME
+#endif
+
+#ifdef _STRBUF_STRLEN_FUNC
+# undef _STRBUF_STRLEN_FUNC
+#endif
+
+#ifdef _STRBUF_STRESCAPE_FUNC
+# undef _STRBUF_STRESCAPE_FUNC
+#endif
+
+#ifdef _STRBUF_MAGIC
+# undef _STRBUF_MAGIC
+#endif
+
+#ifdef _STRBUF_MAGIC_STR
+# undef _STRBUF_MAGIC_STR
+#endif
+
+#ifdef _FUNC_EXPAND
+# undef _FUNC_EXPAND
+#endif
+
+#define _STRBUF_DATA_TYPE         Eina_Unicode
+#define _STRBUF_CSIZE             sizeof(_STRBUF_DATA_TYPE)
+#define _STRBUF_STRUCT_NAME       Eina_UStrbuf
+#define _STRBUF_STRLEN_FUNC(x)    eina_unicode_strlen(x)
+#define _STRBUF_STRESCAPE_FUNC(x) eina_unicode_escape(x)
+#define _STRBUF_MAGIC             EINA_MAGIC_USTRBUF
+#define _STRBUF_MAGIC_STR         __USTRBUF_MAGIC_STR
+static const char __USTRBUF_MAGIC_STR[] = "Eina UStrbuf";
+
+#define _FUNC_EXPAND(y) eina_ustrbuf_ ## y
+
+/**
+ * @endcond
+ */
+
+
+/*============================================================================*
+ *                                 Global                                     *
+ 
*============================================================================*/
+
+
+/*============================================================================*
+ *                                   API                                      *
+ 
*============================================================================*/
+
+/**
+ * @addtogroup Eina_Unicode_String_Buffer_Group Unicode String Buffer
+ *
+ * @brief These functions provide unicode string buffers management.
+ *
+ * The Unicode String Buffer data type is designed to be a mutable string,
+ * allowing to append, prepend or insert a string to a buffer.
+ *
+ * @{
+ */
+
+#include "eina_strbuf_template_c.x"
+
+/**
+ * @}
+ */
diff --git a/tests/suite/ecore/src/lib/eina_ustringshare.c 
b/tests/suite/ecore/src/lib/eina_ustringshare.c
new file mode 100644
index 0000000..8fe18c8
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_ustringshare.c
@@ -0,0 +1,243 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2002-2008 Carsten Haitzler,
+ *                         Jorge Luis Zapata Muga,
+ *                         Cedric Bail,
+ *                         Gustavo Sverzut Barbieri
+ *                         Tom Hacohen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+
+ */
+/**
+ * @page tutorial_ustringshare_page UStringshare Tutorial
+ *
+ * to be written...
+ *
+ */
+
+#include "eina_share_common.h"
+#include "eina_unicode.h"
+#include "eina_private.h"
+#include "eina_ustringshare.h"
+
+/* The actual share */
+static Eina_Share *ustringshare_share;
+static const char EINA_MAGIC_USTRINGSHARE_NODE_STR[] = "Eina UStringshare 
Node";
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/**
+ * @internal
+ * @brief Initialize the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function sets up the share_common module of Eina. It is called by
+ * eina_init().
+ *
+ * @see eina_init()
+ */
+Eina_Bool
+eina_ustringshare_init(void)
+{
+   return eina_share_common_init(&ustringshare_share,
+                                 EINA_MAGIC_USTRINGSHARE_NODE,
+                                 EINA_MAGIC_USTRINGSHARE_NODE_STR);
+}
+
+/**
+ * @internal
+ * @brief Shut down the share_common module.
+ *
+ * @return #EINA_TRUE on success, #EINA_FALSE on failure.
+ *
+ * This function shuts down the share_common module set up by
+ * eina_share_common_init(). It is called by eina_shutdown().
+ *
+ * @see eina_shutdown()
+ */
+Eina_Bool
+eina_ustringshare_shutdown(void)
+{
+   Eina_Bool ret;
+   ret = eina_share_common_shutdown(&ustringshare_share);
+   return ret;
+}
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+/**
+ * @addtogroup Eina_UStringshare_Group Unicode Stringshare
+ *
+ * These functions allow you to store one copy of a string, and use it
+ * throughout your program.
+ *
+ * This is a method to reduce the number of duplicated strings kept in
+ * memory. It's pretty common for the same strings to be dynamically
+ * allocated repeatedly between applications and libraries, especially in
+ * circumstances where you could have multiple copies of a structure that
+ * allocates the string. So rather than duplicating and freeing these
+ * strings, you request a read-only pointer to an existing string and
+ * only incur the overhead of a hash lookup.
+ *
+ * It sounds like micro-optimizing, but profiling has shown this can have
+ * a significant impact as you scale the number of copies up. It improves
+ * string creation/destruction speed, reduces memory use and decreases
+ * memory fragmentation, so a win all-around.
+ *
+ * For more information, you can look at the @ref tutorial_ustringshare_page.
+ *
+ * @{
+ */
+
+/**
+ * @brief Note that the given string has lost an instance.
+ *
+ * @param str string The given string.
+ *
+ * This function decreases the reference counter associated to @p str
+ * if it exists. If that counter reaches 0, the memory associated to
+ * @p str is freed. If @p str is NULL, the function returns
+ * immediately.
+ *
+ * Note that if the given pointer is not shared or NULL, bad things
+ * will happen, likely a segmentation fault.
+ */
+EAPI void
+eina_ustringshare_del(const Eina_Unicode *str)
+{
+   if (!str)
+      return;
+
+   eina_share_common_del(ustringshare_share,(const char *)str);
+}
+
+/**
+ * @brief Retrieve an instance of a string for use in a program.
+ *
+ * @param   str The string to retrieve an instance of.
+ * @param   slen The string size (<= strlen(str)).
+ * @return  A pointer to an instance of the string on success.
+ *          @c NULL on failure.
+ *
+ * This function retrieves an instance of @p str. If @p str is
+ * @c NULL, then @c NULL is returned. If @p str is already stored, it
+ * is just returned and its reference counter is increased. Otherwise
+ * it is added to the strings to be searched and a duplicated string
+ * of @p str is returned.
+ *
+ * This function does not check string size, but uses the
+ * exact given size. This can be used to share_common part of a larger
+ * buffer or substring.
+ *
+ * @see eina_ustringshare_add()
+ */
+EAPI const Eina_Unicode *
+eina_ustringshare_add_length(const Eina_Unicode *str, unsigned int slen)
+{
+   return (const Eina_Unicode 
*)eina_share_common_add_length(ustringshare_share,
+                                                             (const char *)str,
+                                                             slen *
+                                                             sizeof(
+                                                                Eina_Unicode),
+                                                             sizeof(
+                                                                Eina_Unicode));
+}
+
+/**
+ * @brief Retrieve an instance of a string for use in a program.
+ *
+ * @param   str The NULL terminated string to retrieve an instance of.
+ * @return  A pointer to an instance of the string on success.
+ *          @c NULL on failure.
+ *
+ * This function retrieves an instance of @p str. If @p str is
+ * @c NULL, then @c NULL is returned. If @p str is already stored, it
+ * is just returned and its reference counter is increased. Otherwise
+ * it is added to the strings to be searched and a duplicated string
+ * of @p str is returned.
+ *
+ * The string @p str must be NULL terminated ('@\0') and its full
+ * length will be used. To use part of the string or non-null
+ * terminated, use eina_stringshare_add_length() instead.
+ *
+ * @see eina_ustringshare_add_length()
+ */
+EAPI const Eina_Unicode *
+eina_ustringshare_add(const Eina_Unicode *str)
+{
+   int slen = (str) ? (int)eina_unicode_strlen(str) : -1;
+   return eina_ustringshare_add_length(str, slen);
+}
+
+/**
+ * Increment references of the given shared string.
+ *
+ * @param str The shared string.
+ * @return    A pointer to an instance of the string on success.
+ *            @c NULL on failure.
+ *
+ * This is similar to eina_share_common_add(), but it's faster since it will
+ * avoid lookups if possible, but on the down side it requires the parameter
+ * to be shared before, in other words, it must be the return of a previous
+ * eina_ustringshare_add().
+ *
+ * There is no unref since this is the work of eina_ustringshare_del().
+ */
+EAPI const Eina_Unicode *
+eina_ustringshare_ref(const Eina_Unicode *str)
+{
+   return (const Eina_Unicode *)eina_share_common_ref(ustringshare_share,
+                                                      (const char *)str);
+}
+
+/**
+ * @brief Note that the given string @b must be shared.
+ *
+ * @param str the shared string to know the length. It is safe to
+ *        give NULL, in that case -1 is returned.
+ *
+ * This function is a cheap way to known the length of a shared
+ * string. Note that if the given pointer is not shared, bad
+ * things will happen, likely a segmentation fault. If in doubt, try
+ * strlen().
+ */
+EAPI int
+eina_ustringshare_strlen(const Eina_Unicode *str)
+{
+   int len = eina_share_common_length(ustringshare_share, (const char *)str);
+   len = (len > 0) ? len / (int)sizeof(Eina_Unicode) : -1;
+   return len;
+}
+
+/**
+ * @brief Dump the contents of the share_common.
+ *
+ * This function dumps all strings in the share_common to stdout with a
+ * DDD: prefix per line and a memory usage summary.
+ */
+EAPI void
+eina_ustringshare_dump(void)
+{
+   eina_share_common_dump(ustringshare_share, NULL, 0);
+}
+
+/**
+ * @}
+ */
+
diff --git a/tests/suite/ecore/src/lib/eina_value.c 
b/tests/suite/ecore/src/lib/eina_value.c
new file mode 100644
index 0000000..554f907
--- /dev/null
+++ b/tests/suite/ecore/src/lib/eina_value.c
@@ -0,0 +1,47 @@
+/* eina_value.c
+
+   Copyright (C) 2001 Christopher Rosendahl    <address@hidden>
+                   Nathan Ingersoll         <address@hidden>
+
+   Permission is hereby granted, free of charge, to any person obtaining a copy
+   of this software and associated documentation files (the "Software"), to
+   deal in the Software without restriction, including without limitation the
+   rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+   sell copies of the Software, and to permit persons to whom the Software is
+   furnished to do so, subject to the following conditions:
+
+   The above copyright notice and this permission notice shall be included in
+   all copies of the Software and its documentation and acknowledgment shall be
+   given in the documentation and software packages that this Software was
+   used.
+
+   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+   THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+   IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+   CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "eina_config.h"
+#include "eina_private.h"
+
+/*============================================================================*
+*                                 Global                                     *
+*============================================================================*/
+
+/*============================================================================*
+*                                   API                                      *
+*============================================================================*/
+
+EAPI const unsigned int eina_prime_table[] =
+{
+   17, 31, 61, 127, 257, 509, 1021,
+   2053, 4093, 8191, 16381, 32771, 65537, 131071, 262147, 524287, 1048573,
+   2097143, 4194301, 8388617, 16777213
+};
diff --git a/tests/suite/mini-eagain2.c b/tests/suite/mini-eagain2.c
new file mode 100644
index 0000000..284fdc9
--- /dev/null
+++ b/tests/suite/mini-eagain2.c
@@ -0,0 +1,205 @@
+#include <Ecore.h>
+#include <fcntl.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <gnutls/gnutls.h>
+
+/* Ecore_Fd_Handler example
+ * 2010 Mike Blumenkrantz
+ * compile with gcc $(pkgconfig --cflags --libs gnutls ecore)
+ */
+
+
+#define print(...) fprintf(stderr, "line %i: ", __LINE__); fprintf(stderr, 
__VA_ARGS__); fprintf(stderr, "\n")
+
+static int done = 0;
+
+static void
+tls_log_func (int level, const char *str)
+{
+  fprintf(stderr, "|<%d>| %s", level, str);
+}
+
+static const char*
+SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_description_t status)
+{
+   switch (status)
+     {
+      case GNUTLS_HANDSHAKE_HELLO_REQUEST:
+        return "Hello request";
+      case GNUTLS_HANDSHAKE_CLIENT_HELLO:
+        return "Client hello";
+      case GNUTLS_HANDSHAKE_SERVER_HELLO:
+        return "Server hello";
+      case GNUTLS_HANDSHAKE_CERTIFICATE_PKT:
+        return "Certificate packet";
+      case GNUTLS_HANDSHAKE_SERVER_KEY_EXCHANGE:
+        return "Server key exchange";
+      case GNUTLS_HANDSHAKE_CERTIFICATE_REQUEST:
+        return "Certificate request";
+      case GNUTLS_HANDSHAKE_SERVER_HELLO_DONE:
+        return "Server hello done";
+      case GNUTLS_HANDSHAKE_CERTIFICATE_VERIFY:
+        return "Certificate verify";
+      case GNUTLS_HANDSHAKE_CLIENT_KEY_EXCHANGE:
+        return "Client key exchange";
+      case GNUTLS_HANDSHAKE_FINISHED:
+        return "Finished";
+      case GNUTLS_HANDSHAKE_SUPPLEMENTAL:
+        return "Supplemental";
+      default:
+        return NULL;
+     }
+   return NULL;
+}
+
+/* Connects to the peer and returns a socket
+ * descriptor.
+ */
+static int
+tcp_connect (void)
+{
+  const char *PORT = "4445";
+  const char *SERVER = "127.0.0.1"; //verisign.com
+  int err, sd;
+  int flag = 1, curstate = 0;
+  struct sockaddr_in sa;
+
+  /* sets some fd options such as nonblock */
+  sd = socket (AF_INET, SOCK_STREAM, 0);
+  fcntl(sd, F_SETFL, O_NONBLOCK);
+  fcntl(sd, F_SETFD, FD_CLOEXEC);
+  setsockopt(sd, SOL_SOCKET, SO_REUSEADDR, (const void *)&curstate, 
sizeof(curstate));
+
+  setsockopt(sd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int));
+
+  memset (&sa, '\0', sizeof (sa));
+  sa.sin_family = AF_INET;
+  sa.sin_port = htons (atoi (PORT));
+  inet_pton (AF_INET, SERVER, &sa.sin_addr);
+
+  /* connects to server
+   */
+  err = connect (sd, (struct sockaddr *) &sa, sizeof (sa));
+  if ((err < 0) && (errno != EINPROGRESS))
+    {
+      print("Connect error\n");
+      exit (1);
+    }
+
+  return sd;
+}
+
+/* closes the given socket descriptor.
+ */
+static void
+tcp_close (int sd)
+{
+  shutdown (sd, SHUT_RDWR);    /* no more receptions */
+  close (sd);
+}
+
+static Eina_Bool
+_process_data(gnutls_session_t client, Ecore_Fd_Handler *fd_handler)
+{
+   static int ret, lastret;
+   static unsigned int count = 0;
+   
+   if (!done)
+     {
+        lastret = ret;
+        ret = gnutls_handshake (client);
+        count++;
+        if (gnutls_record_get_direction(client))
+          ecore_main_fd_handler_active_set(fd_handler, ECORE_FD_WRITE);
+        else
+          ecore_main_fd_handler_active_set(fd_handler, ECORE_FD_READ);
+        /* avoid printing messages infinity times */
+        if (lastret != ret && ret != 0 && ret != GNUTLS_E_AGAIN)
+          {
+             print("gnutls returned with: %s - %s", gnutls_strerror_name(ret), 
gnutls_strerror(ret));
+             if ((ret == GNUTLS_E_WARNING_ALERT_RECEIVED) || (ret == 
GNUTLS_E_FATAL_ALERT_RECEIVED))
+               print("Also received alert: %s", 
gnutls_alert_get_name(gnutls_alert_get(client)));
+             print("last out: %s", 
SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_out(client)));
+             print("last in: %s", 
SSL_GNUTLS_PRINT_HANDSHAKE_STATUS(gnutls_handshake_get_last_in(client)));
+          }
+
+        if (gnutls_error_is_fatal(ret))
+          {
+             print("yarrr this be an error!");
+             exit(1);
+          }
+        
+     }
+  if (ret == GNUTLS_E_SUCCESS)
+    {
+       done = 1;
+       //print("Handshake successful in %u handshake calls!", count);
+       ecore_main_loop_quit();
+    }
+
+   return ECORE_CALLBACK_RENEW;
+}
+
+int
+main (void)
+{
+  /* credentials */
+  gnutls_anon_client_credentials_t c_anoncred;
+  gnutls_certificate_credentials_t c_certcred;
+  
+  gnutls_session_t client;
+  int sd, i;
+
+  /* General init. */
+  gnutls_global_init ();
+  ecore_init();
+//  gnutls_global_set_log_function (tls_log_func);
+//  gnutls_global_set_log_level (2);
+
+  /* Init client */
+  gnutls_anon_allocate_client_credentials (&c_anoncred);
+  gnutls_certificate_allocate_credentials (&c_certcred);
+
+
+  for (i=0;i<5;i++) 
+    {
+
+      gnutls_init (&client, GNUTLS_CLIENT);
+      /* set very specific priorities */
+      gnutls_priority_set_direct(client, "NORMAL:+ANON-DH", NULL);
+      gnutls_credentials_set (client, GNUTLS_CRD_ANON, c_anoncred);
+      gnutls_credentials_set (client, GNUTLS_CRD_CERTIFICATE, c_certcred);
+      gnutls_server_name_set(client, GNUTLS_NAME_DNS, "localhost", 
strlen("localhost"));
+
+      /* connect to the peer
+       */
+      sd = tcp_connect ();
+
+      /* associate gnutls with socket */
+      gnutls_transport_set_ptr (client, (gnutls_transport_ptr_t) sd);
+      /* add a callback for data being available for send/receive on socket */
+      if (!ecore_main_fd_handler_add(sd, ECORE_FD_READ | ECORE_FD_WRITE, 
(Ecore_Fd_Cb)_process_data, client, NULL, NULL))
+        {
+           print("could not create fd handler!");
+           exit(1);
+        }
+      /* begin main loop */
+      ecore_main_loop_begin();
+
+      gnutls_bye (client, GNUTLS_SHUT_RDWR);
+
+      gnutls_deinit (client);
+
+      tcp_close (sd);
+    }
+  
+  return 0;
+}
diff --git a/tests/safe-renegotiation/params.dh b/tests/suite/params.dh
similarity index 100%
rename from tests/safe-renegotiation/params.dh
rename to tests/suite/params.dh
diff --git a/tests/safe-renegotiation/testsrn b/tests/suite/testsrn
similarity index 100%
rename from tests/safe-renegotiation/testsrn
rename to tests/suite/testsrn


hooks/post-receive
-- 
GNU gnutls



reply via email to

[Prev in Thread] Current Thread [Next in Thread]