summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorVincent Torri <vincent.torri@gmail.com>2012-09-11 16:13:11 +0000
committerVincent Torri <vincent.torri@gmail.com>2012-09-11 16:13:11 +0000
commitcd69ef4c8a66e7155967a8b661a014856979cf31 (patch)
tree4a351ae4a4ca91abf29c85254b85ea8da71f74b0 /src
parent59a9dfd11860888a35e96dfe51af63cea5cecfe1 (diff)
downloadefl-cd69ef4c8a66e7155967a8b661a014856979cf31.tar.gz
merge: add evil files
SVN revision: 76464
Diffstat (limited to 'src')
-rw-r--r--src/bin/evil/Makefile.am53
-rw-r--r--src/bin/evil/evil_suite.c221
-rw-r--r--src/bin/evil/evil_suite.h14
-rw-r--r--src/bin/evil/evil_test_dlfcn.c80
-rw-r--r--src/bin/evil/evil_test_dlfcn.h8
-rw-r--r--src/bin/evil/evil_test_environment.c178
-rw-r--r--src/bin/evil/evil_test_environment.h8
-rw-r--r--src/bin/evil/evil_test_gettimeofday.c51
-rw-r--r--src/bin/evil/evil_test_gettimeofday.h8
-rw-r--r--src/bin/evil/evil_test_link.c158
-rw-r--r--src/bin/evil/evil_test_link.h8
-rw-r--r--src/bin/evil/evil_test_memcpy.c145
-rw-r--r--src/bin/evil/evil_test_memcpy.h8
-rw-r--r--src/bin/evil/evil_test_mkstemp.c53
-rw-r--r--src/bin/evil/evil_test_mkstemp.h8
-rw-r--r--src/bin/evil/evil_test_pipe.c126
-rw-r--r--src/bin/evil/evil_test_pipe.h8
-rw-r--r--src/bin/evil/evil_test_print.c46
-rw-r--r--src/bin/evil/evil_test_print.h8
-rw-r--r--src/bin/evil/evil_test_realpath.c44
-rw-r--r--src/bin/evil/evil_test_realpath.h8
-rw-r--r--src/bin/evil/evil_test_util.c110
-rw-r--r--src/bin/evil/evil_test_util.h8
-rw-r--r--src/bin/evil/memcpy_glibc_arm.S231
-rwxr-xr-xsrc/bin/evil/memcpy_glibc_i686.S81
-rw-r--r--src/bin/evil/test_evil.c27
-rw-r--r--src/lib/evil/Evil.h186
-rw-r--r--src/lib/evil/Makefile.am132
-rw-r--r--src/lib/evil/dirent.h141
-rw-r--r--src/lib/evil/dlfcn.c272
-rw-r--r--src/lib/evil/dlfcn.h258
-rw-r--r--src/lib/evil/evil_dirent.c197
-rw-r--r--src/lib/evil/evil_errno.c9
-rw-r--r--src/lib/evil/evil_fcntl.c124
-rw-r--r--src/lib/evil/evil_fcntl.h110
-rw-r--r--src/lib/evil/evil_fnmatch.c231
-rw-r--r--src/lib/evil/evil_fnmatch_list_of_states.c77
-rw-r--r--src/lib/evil/evil_fnmatch_private.h24
-rw-r--r--src/lib/evil/evil_inet.c648
-rw-r--r--src/lib/evil/evil_inet.h149
-rw-r--r--src/lib/evil/evil_langinfo.c53
-rw-r--r--src/lib/evil/evil_langinfo.h41
-rw-r--r--src/lib/evil/evil_libgen.c103
-rw-r--r--src/lib/evil/evil_libgen.h88
-rw-r--r--src/lib/evil/evil_link_ce.c90
-rw-r--r--src/lib/evil/evil_link_xp.cpp151
-rw-r--r--src/lib/evil/evil_macro.h193
-rw-r--r--src/lib/evil/evil_macro_pop.h93
-rw-r--r--src/lib/evil/evil_main.c74
-rw-r--r--src/lib/evil/evil_main.h52
-rw-r--r--src/lib/evil/evil_mman.c234
-rw-r--r--src/lib/evil/evil_pformat.h61
-rw-r--r--src/lib/evil/evil_pformata.c2493
-rw-r--r--src/lib/evil/evil_pformatw.c9
-rw-r--r--src/lib/evil/evil_print.h37
-rw-r--r--src/lib/evil/evil_printa.c1786
-rw-r--r--src/lib/evil/evil_printw.c4
-rw-r--r--src/lib/evil/evil_private.h20
-rw-r--r--src/lib/evil/evil_pwd.c65
-rw-r--r--src/lib/evil/evil_stdio.c215
-rw-r--r--src/lib/evil/evil_stdio.h196
-rw-r--r--src/lib/evil/evil_stdlib.c453
-rw-r--r--src/lib/evil/evil_stdlib.h199
-rw-r--r--src/lib/evil/evil_string.c128
-rw-r--r--src/lib/evil/evil_string.h152
-rw-r--r--src/lib/evil/evil_time.c45
-rw-r--r--src/lib/evil/evil_time.h61
-rw-r--r--src/lib/evil/evil_unistd.c431
-rw-r--r--src/lib/evil/evil_unistd.h326
-rw-r--r--src/lib/evil/evil_util.c247
-rw-r--r--src/lib/evil/evil_util.h134
-rw-r--r--src/lib/evil/evil_uuid.c12
-rw-r--r--src/lib/evil/fnmatch.h54
-rw-r--r--src/lib/evil/gdtoa/README357
-rw-r--r--src/lib/evil/gdtoa/README.mingw20
-rw-r--r--src/lib/evil/gdtoa/arithchk.c192
-rw-r--r--src/lib/evil/gdtoa/dmisc.c196
-rw-r--r--src/lib/evil/gdtoa/dtoa.c750
-rw-r--r--src/lib/evil/gdtoa/g__fmt.c142
-rw-r--r--src/lib/evil/gdtoa/g_dfmt.c90
-rw-r--r--src/lib/evil/gdtoa/g_ffmt.c88
-rw-r--r--src/lib/evil/gdtoa/g_xfmt.c143
-rw-r--r--src/lib/evil/gdtoa/gd_arith.h6
-rw-r--r--src/lib/evil/gdtoa/gd_qnan.h12
-rw-r--r--src/lib/evil/gdtoa/gdtoa.c733
-rw-r--r--src/lib/evil/gdtoa/gdtoa.h121
-rw-r--r--src/lib/evil/gdtoa/gdtoa_fltrnds.h18
-rw-r--r--src/lib/evil/gdtoa/gdtoaimp.h645
-rw-r--r--src/lib/evil/gdtoa/gethex.c340
-rw-r--r--src/lib/evil/gdtoa/gmisc.c76
-rw-r--r--src/lib/evil/gdtoa/hd_init.c49
-rw-r--r--src/lib/evil/gdtoa/hexnan.c139
-rw-r--r--src/lib/evil/gdtoa/misc.c860
-rw-r--r--src/lib/evil/gdtoa/qnan.c116
-rw-r--r--src/lib/evil/gdtoa/smisc.c149
-rw-r--r--src/lib/evil/gdtoa/strtodg.c979
-rw-r--r--src/lib/evil/gdtoa/strtof.c77
-rw-r--r--src/lib/evil/gdtoa/strtopx.c119
-rw-r--r--src/lib/evil/gdtoa/sum.c91
-rw-r--r--src/lib/evil/gdtoa/ulp.c61
-rw-r--r--src/lib/evil/mingw32ce/errno.h111
-rw-r--r--src/lib/evil/pwd.h71
-rw-r--r--src/lib/evil/sys/mman.h149
103 files changed, 19456 insertions, 0 deletions
diff --git a/src/bin/evil/Makefile.am b/src/bin/evil/Makefile.am
new file mode 100644
index 0000000000..538bbdcc69
--- /dev/null
+++ b/src/bin/evil/Makefile.am
@@ -0,0 +1,53 @@
+
+MAINTAINERCLEANFILES = Makefile.in
+
+AM_CPPFLAGS = \
+-I$(top_srcdir) \
+-I$(top_srcdir)/bin \
+-I$(top_srcdir)/src/lib \
+@EVIL_CPPFLAGS@
+
+AM_CFLAGS = @EVIL_CFLAGS@
+
+bin_PROGRAMS = evil_suite test_evil
+
+evil_suite_SOURCES = \
+evil_suite.c \
+evil_test_dlfcn.c \
+evil_test_environment.c \
+evil_test_gettimeofday.c \
+evil_test_link.c \
+evil_test_memcpy.c \
+evil_test_mkstemp.c \
+evil_test_pipe.c \
+evil_test_print.c \
+evil_test_realpath.c \
+evil_test_util.c \
+evil_suite.h \
+evil_test_dlfcn.h \
+evil_test_environment.h \
+evil_test_gettimeofday.h \
+evil_test_link.h \
+evil_test_memcpy.h \
+evil_test_mkstemp.h \
+evil_test_pipe.h \
+evil_test_print.h \
+evil_test_realpath.h \
+evil_test_util.h
+
+if EVIL_HAVE_WINCE
+
+evil_suite_SOURCES += memcpy_glibc_arm.S
+
+#else
+
+#suite_SOURCES += memcpy_glibc_i686.S
+
+endif
+
+evil_suite_LDADD = $(top_builddir)/src/lib/libdl.la $(top_builddir)/src/lib/libevil.la -lm
+evil_suite_LDFLAGS = -Wl,--enable-auto-import
+
+test_evil_SOURCES = test_evil.c
+test_evil_LDADD = $(top_builddir)/src/lib/libevil.la
+test_evil_LDFLAGS = -Wl,--enable-auto-import
diff --git a/src/bin/evil/evil_suite.c b/src/bin/evil/evil_suite.c
new file mode 100644
index 0000000000..ba928f0682
--- /dev/null
+++ b/src/bin/evil/evil_suite.c
@@ -0,0 +1,221 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include "Evil.h"
+#include "evil_suite.h"
+#include "evil_test_dlfcn.h"
+#include "evil_test_environment.h"
+#include "evil_test_gettimeofday.h"
+#include "evil_test_link.h"
+#include "evil_test_memcpy.h"
+#include "evil_test_mkstemp.h"
+#include "evil_test_pipe.h"
+#include "evil_test_print.h"
+#include "evil_test_realpath.h"
+#include "evil_test_util.h"
+
+
+typedef int(*function)(suite *s);
+
+struct test
+{
+ const char *name;
+ function fct;
+};
+
+struct list
+{
+ void *data;
+ int succeed;
+ list *next;
+};
+
+struct suite
+{
+ LARGE_INTEGER freq;
+ LARGE_INTEGER start;
+ LARGE_INTEGER end;
+
+ list *first;
+ list *l;
+
+ int tests_count;
+ int tests_success;
+};
+
+
+static suite *
+suite_new(void)
+{
+ suite *s;
+
+ s = (suite *)malloc(sizeof(suite));
+ if (!s) return NULL;
+
+ if (!QueryPerformanceFrequency(&s->freq))
+ {
+ free(s);
+ return NULL;
+ }
+
+ s->first = NULL;
+ s->l = NULL;
+
+ s->tests_count = 0;
+ s->tests_success = 0;
+
+ return s;
+}
+
+static void
+suite_del(suite *s)
+{
+ list *l;
+ list *tmp;
+
+ if (!s) return;
+
+ l = s->first;
+ while (l)
+ {
+ tmp = l->next;
+ free(l->data);
+ free(l);
+ l = tmp;
+ }
+
+ free(s);
+}
+
+void
+suite_time_start(suite *s)
+{
+ QueryPerformanceCounter(&s->start);
+}
+
+void
+suite_time_stop(suite *s)
+{
+ QueryPerformanceCounter(&s->end);
+}
+
+double
+suite_time_get(suite *s)
+{
+ return (double)(s->end.QuadPart - s->start.QuadPart) / (double)s->freq.QuadPart;
+}
+
+static void
+suite_test_add(suite *s, const char *name, function fct)
+{
+ test *t;
+ list *l;
+
+ t = (test *)malloc(sizeof(test));
+ if (!t) return;
+
+ l = (list *)malloc(sizeof(list));
+ if (!l)
+ {
+ free(t);
+ return;
+ }
+
+ t->name = name;
+ t->fct = fct;
+
+ l->data = t;
+ l->succeed = 0;
+ l->next = NULL;
+
+ if (!s->first) s->first = l;
+
+ if (!s->l)
+ s->l = l;
+ else
+ {
+ s->l->next = l;
+ s->l =l;
+ }
+}
+
+static void
+suite_run(suite *s)
+{
+ list *l;
+
+ l = s->first;
+ while (l)
+ {
+ test *t;
+
+ t = (test *)l->data;
+ l->succeed = t->fct(s);
+ printf("%s test: %s\n", t->name, l->succeed ? "success" : "failure");
+ s->tests_count++;
+ if (l->succeed)
+ s->tests_success++;
+ l = l->next;
+ }
+}
+
+static void
+suite_show(suite *s)
+{
+ printf ("\n%d/%d tests passed (%d%%)\n",
+ s->tests_success,
+ s->tests_count,
+ (100 * s->tests_success) / s->tests_count);
+}
+
+int
+main(void)
+{
+ test tests[] = {
+ { "dlfcn ", test_dlfcn },
+ { "environment ", test_environment },
+ { "gettimeofday", test_gettimeofday },
+ { "link ", test_link },
+ { "mkstemp ", test_mkstemp },
+ { "pipe ", test_pipe },
+ { "print ", test_print },
+ { "realpath ", test_realpath },
+ { "util ", test_util },
+/* { "memcpy ", test_memcpy }, */
+ { NULL, NULL },
+ };
+ suite *s;
+ int i;
+
+ if (!evil_init())
+ return EXIT_FAILURE;
+
+ s = suite_new();
+ if (!s)
+ {
+ evil_shutdown();
+ return EXIT_FAILURE;
+ }
+
+ for (i = 0; tests[i].name; ++i)
+ {
+ suite_test_add(s, tests[i].name, tests[i].fct);
+ }
+
+ suite_run(s);
+
+ suite_show(s);
+
+ suite_del(s);
+ evil_shutdown();
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/bin/evil/evil_suite.h b/src/bin/evil/evil_suite.h
new file mode 100644
index 0000000000..d3284b4fbb
--- /dev/null
+++ b/src/bin/evil/evil_suite.h
@@ -0,0 +1,14 @@
+#ifndef __EVIL_SUITE_H__
+#define __EVIL_SUITE_H__
+
+
+typedef struct test test;
+typedef struct list list;
+typedef struct suite suite;
+
+void suite_time_start(suite *s);
+void suite_time_stop(suite *s);
+double suite_time_get(suite *s);
+
+
+#endif /* __EVIL_SUITE_H__ */
diff --git a/src/bin/evil/evil_test_dlfcn.c b/src/bin/evil/evil_test_dlfcn.c
new file mode 100644
index 0000000000..fb32dd1540
--- /dev/null
+++ b/src/bin/evil/evil_test_dlfcn.c
@@ -0,0 +1,80 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <dlfcn.h>
+
+#include <Evil.h>
+
+#include "evil_suite.h"
+#include "evil_test_dlfcn.h"
+
+
+typedef int (*_evil_init)(void);
+typedef int (*_evil_shutdwon)(void);
+
+
+static int
+test_dlfcn_test_dlopen(void)
+{
+ void *handle;
+
+ handle = dlopen("libevil-1.dll", 0);
+ if (!handle)
+ return 0;
+
+ if (dlclose(handle))
+ return 0;
+
+ return 1;
+}
+
+static int
+test_dlfcn_test_dlsym(void)
+{
+ void *handle;
+ _evil_init sym_init;
+ _evil_shutdwon sym_shutdown;
+
+ handle = dlopen("libevil-1.dll", 0);
+ if (!handle)
+ return 0;
+
+ sym_init = dlsym(handle, "evil_init");
+ if (!sym_init)
+ {
+ dlclose(handle);
+ return 0;
+ }
+
+ sym_shutdown = dlsym(handle, "evil_shutdown");
+ if (!sym_shutdown)
+ {
+ dlclose(handle);
+ return 0;
+ }
+
+ if (dlclose(handle))
+ return 0;
+
+ return 1;
+}
+
+static int
+test_dlfcn_tests_run(suite *s __UNUSED__)
+{
+ int res;
+
+ res = test_dlfcn_test_dlopen();
+ res &= test_dlfcn_test_dlsym();
+
+ return res;
+}
+
+int
+test_dlfcn(suite *s)
+{
+
+ return test_dlfcn_tests_run(s);
+}
diff --git a/src/bin/evil/evil_test_dlfcn.h b/src/bin/evil/evil_test_dlfcn.h
new file mode 100644
index 0000000000..0c9bce689e
--- /dev/null
+++ b/src/bin/evil/evil_test_dlfcn.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_DLFCN_H__
+#define __EVIL_TEST_DLFCN_H__
+
+
+int test_dlfcn(suite *s);
+
+
+#endif /* __EVIL_TEST_DLFCN_H__ */
diff --git a/src/bin/evil/evil_test_environment.c b/src/bin/evil/evil_test_environment.c
new file mode 100644
index 0000000000..3048a40124
--- /dev/null
+++ b/src/bin/evil/evil_test_environment.c
@@ -0,0 +1,178 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+
+#include <Evil.h>
+
+#include "evil_suite.h"
+#include "evil_test_environment.h"
+
+
+static int
+test_env_test_setenv_NULL(void)
+{
+ char *val;
+ int res;
+
+ res = setenv("EVIL_TEST_ENV", NULL, 1);
+ if (res < 0)
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV");
+
+ return val ? 0 : 1;
+}
+
+static int
+test_env_test_setenv_NULL_after_set(void)
+{
+ char *val;
+ int res;
+
+ res = setenv("EVIL_TEST_ENV", "val", 1);
+ if (res < 0)
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV");
+ if (!val)
+ return 0;
+
+ if (strcmp(val, "val"))
+ return 0;
+
+ res = setenv("EVIL_TEST_ENV", NULL, 1);
+ if (res < 0)
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV");
+
+ return val ? 0 : 1;
+}
+
+static int
+test_env_test_getenv_one(void)
+{
+ char *val;
+ int res;
+
+ res = setenv("EVIL_TEST_ENV", "val", 1);
+ if (res < 0)
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV");
+ if (!val)
+ return 0;
+
+ if (strcmp(val, "val"))
+ return 0;
+
+ return 1;
+}
+
+static int
+test_env_test_getenv_two(void)
+{
+ char *val;
+ int res;
+
+ res = setenv("EVIL_TEST_ENV1", "val1", 1);
+ if (res < 0)
+ return 0;
+
+ res = setenv("EVIL_TEST_ENV2", "val2", 1);
+ if (res < 0)
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV1");
+ if (!val)
+ return 0;
+ if (strcmp(val, "val1"))
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV2");
+ if (!val)
+ return 0;
+
+ if (strcmp(val, "val2"))
+ return 0;
+
+ return 1;
+}
+
+static int
+test_env_test_getenv_two_swapped(void)
+{
+ char *val;
+ int res;
+
+ res = setenv("EVIL_TEST_ENV1", "val1", 1);
+ if (res < 0)
+ return 0;
+
+ res = setenv("EVIL_TEST_ENV2", "val2", 1);
+ if (res < 0)
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV2");
+ if (!val)
+ return 0;
+ if (strcmp(val, "val2"))
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV1");
+ if (!val)
+ return 0;
+
+ if (strcmp(val, "val1"))
+ return 0;
+
+ return 1;
+}
+
+static int
+test_env_test_unsetenv(void)
+{
+ char *val;
+ int res;
+
+ res = setenv("EVIL_TEST_ENV", "val", 1);
+ if (res < 0)
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV");
+ if (!val)
+ return 0;
+
+ if (unsetenv("EVIL_TEST_ENV") != 0)
+ return 0;
+
+ val = getenv("EVIL_TEST_ENV");
+ if (val)
+ return 0;
+
+ return 1;
+}
+
+static int
+test_env_tests_run(suite *s __UNUSED__)
+{
+ int res;
+
+ res = test_env_test_setenv_NULL();
+ res &= test_env_test_setenv_NULL_after_set();
+ res &= test_env_test_getenv_one();
+ res &= test_env_test_getenv_two();
+ res &= test_env_test_getenv_two_swapped();
+ res &= test_env_test_unsetenv();
+
+ return res;
+}
+
+int
+test_environment(suite *s)
+{
+
+ return test_env_tests_run(s);
+}
diff --git a/src/bin/evil/evil_test_environment.h b/src/bin/evil/evil_test_environment.h
new file mode 100644
index 0000000000..763ee401b1
--- /dev/null
+++ b/src/bin/evil/evil_test_environment.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_ENVIRONMENT_H__
+#define __EVIL_TEST_ENVIRONMENT_H__
+
+
+int test_environment(suite *s);
+
+
+#endif /* __EVIL_TEST_ENVIRONMENT_H__ */
diff --git a/src/bin/evil/evil_test_gettimeofday.c b/src/bin/evil/evil_test_gettimeofday.c
new file mode 100644
index 0000000000..49742eb5d3
--- /dev/null
+++ b/src/bin/evil/evil_test_gettimeofday.c
@@ -0,0 +1,51 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <math.h>
+#include <sys/time.h>
+
+#include <Evil.h>
+
+#include "evil_suite.h"
+#include "evil_test_gettimeofday.h"
+
+static int
+test_time_test_gettimeofday(void)
+{
+ struct timeval tp1;
+ struct timeval tp2;
+ double delta;
+
+ gettimeofday (&tp1, NULL);
+
+ Sleep(1000);
+
+ gettimeofday (&tp2, NULL);
+
+ delta = (double)(tp2.tv_sec - tp1.tv_sec) + (double)(tp2.tv_usec - tp1.tv_usec) / 1000000.0;
+ if (fabs(delta - 1) > 0.005)
+ {
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+test_time_tests_run(suite *s __UNUSED__)
+{
+ int res;
+
+ res = test_time_test_gettimeofday();
+
+ return res;
+}
+
+int
+test_gettimeofday(suite *s)
+{
+
+ return test_time_tests_run(s);
+}
diff --git a/src/bin/evil/evil_test_gettimeofday.h b/src/bin/evil/evil_test_gettimeofday.h
new file mode 100644
index 0000000000..ad3155b146
--- /dev/null
+++ b/src/bin/evil/evil_test_gettimeofday.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_GETTIMEOFDAY_H__
+#define __EVIL_TEST_GETTIMEOFDAY_H__
+
+
+int test_gettimeofday(suite *s);
+
+
+#endif /* __EVIL_TEST_GETTIMEOFDAY_H__ */
diff --git a/src/bin/evil/evil_test_link.c b/src/bin/evil/evil_test_link.c
new file mode 100644
index 0000000000..cf4cd931ae
--- /dev/null
+++ b/src/bin/evil/evil_test_link.c
@@ -0,0 +1,158 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+
+#include <Evil.h>
+
+#include "evil_suite.h"
+#include "evil_test_link.h"
+
+static int
+test_link_test_file_create(const char *name, const char *data)
+{
+ FILE *f;
+ size_t length;
+ size_t res;
+
+ f = fopen(name, "wb");
+ if (!f)
+ return 0;
+
+ length = strlen(data) + 1;
+ res = fwrite(data, 1, length, f);
+ if (res < length)
+ {
+ fclose(f);
+ return 0;
+ }
+
+ fclose(f);
+
+ return 1;
+}
+
+static int
+test_link_test_symlink(void)
+{
+#ifdef _WIN32_WCE
+ const char *old_name = "\\efl\\evil_test_link.dat";
+ const char *new_name = "\\efl\\evil_test_link.lnk";
+#else
+ const char *old_name = "evil_test_link.dat";
+ const char *new_name = "evil_test_link.lnk";
+#endif
+
+ if (!test_link_test_file_create(old_name,
+ "evil_test_link symlink data\n"))
+ return 0;
+
+ if (symlink(old_name, new_name) < 0)
+ {
+ unlink(old_name);
+ return 0;
+ }
+
+ if (unlink(new_name) < 0)
+ {
+ unlink(old_name);
+ return 0;
+ }
+
+ if (unlink(old_name) < 0)
+ return 0;
+
+ return 1;
+}
+
+static int
+test_link_test_readlink(void)
+{
+ char buf[1024];
+#ifdef _WIN32_WCE
+ const char *old_name = "\\efl\\evil_test_link.dat";
+ const char *new_name = "\\efl\\evil_test_link.lnk";
+#else
+ const char *old_name = "evil_test_link.dat";
+ const char *new_name = "evil_test_link.lnk";
+#endif
+ const char *data = "evil_test_link symlink data\n";
+ FILE *f;
+ ssize_t s1;
+ size_t s2;
+ int l;
+
+ if (!test_link_test_file_create(old_name, data))
+ return 0;
+
+ if (symlink(old_name, new_name) < 0)
+ return 0;
+
+ if ((s1 = readlink(new_name, buf, 1023)) < 0)
+ {
+ unlink(old_name);
+ unlink(new_name);
+ return 0;
+ }
+
+ buf[s1] = '\0';
+
+ f = fopen(buf, "rb");
+ if (!f)
+ {
+ unlink(old_name);
+ unlink(new_name);
+ return 0;
+ }
+
+ l = strlen(data);
+ s2 = fread(buf, 1, l + 1, f);
+
+ if ((int)s2 != (l + 1))
+ {
+ fclose(f);
+ unlink(old_name);
+ unlink(new_name);
+ return 0;
+ }
+
+ if (strcmp(buf, data))
+ {
+ fclose(f);
+ unlink(old_name);
+ unlink(new_name);
+ return 0;
+ }
+
+ fclose(f);
+
+ if (unlink(new_name) < 0)
+ {
+ unlink(old_name);
+ return 0;
+ }
+
+ if (unlink(old_name) < 0)
+ return 0;
+
+ return 1;
+}
+
+static int
+test_link_tests_run(suite *s __UNUSED__)
+{
+ int res;
+
+ res = test_link_test_symlink();
+ res &= test_link_test_readlink();
+
+ return res;
+}
+
+int
+test_link(suite *s)
+{
+
+ return test_link_tests_run(s);
+}
diff --git a/src/bin/evil/evil_test_link.h b/src/bin/evil/evil_test_link.h
new file mode 100644
index 0000000000..6f8bfa2328
--- /dev/null
+++ b/src/bin/evil/evil_test_link.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_LINK_H__
+#define __EVIL_TEST_LINK_H__
+
+
+int test_link(suite *s);
+
+
+#endif /* __EVIL_TEST_LINK_H__ */
diff --git a/src/bin/evil/evil_test_memcpy.c b/src/bin/evil/evil_test_memcpy.c
new file mode 100644
index 0000000000..0adfe373f0
--- /dev/null
+++ b/src/bin/evil/evil_test_memcpy.c
@@ -0,0 +1,145 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include "evil_suite.h"
+#include "evil_test_memcpy.h"
+
+
+typedef void *(*memcpy_decl)(void *dest, const void *src, size_t n);
+
+void *memcpy_glibc(void *dest, const void *src, size_t n);
+
+
+static unsigned char *buf1 = NULL;
+static unsigned char *buf2 = NULL;
+static size_t page_size = 0;
+
+
+#if defined (__MINGW32CE__) || defined (_MSC_VER)
+static int
+getpagesize()
+{
+ return 1024;
+}
+#endif /* __MINGW32CE__ || _MSC_VER */
+
+
+static void
+test_memcpy_test_run(suite *s, memcpy_decl fct, char *dst, const char *src, size_t len)
+{
+ double best;
+ int i;
+
+ best = 1000000000.0;
+
+ for (i = 0; i < 128; ++i)
+ {
+ double time;
+
+ suite_time_start(s);
+ fct(dst, src, len);
+ suite_time_stop(s);
+ time = suite_time_get(s);
+ if (time < best) best = time;
+ }
+
+ printf (" %e", best);
+}
+
+static void
+test_memcpy_tests_run(suite *s, size_t align1, size_t align2, size_t len)
+{
+ size_t i, j;
+ char *s1, *s2;
+
+ printf ("running test..\n");
+
+/* align1 &= 63; */
+/* if (align1 + len >= page_size) */
+/* return; */
+
+/* align2 &= 63; */
+/* if (align2 + len >= page_size) */
+/* return; */
+
+ s1 = (char *) (buf1 + align1);
+ s2 = (char *) (buf2 + align2);
+
+ for (i = 0, j = 1; i < len; i++, j += 23)
+ s1[i] = j;
+
+ printf ("length: %6d, align %2d/%2d:", (int)len, align1, align2);
+
+ test_memcpy_test_run(s, memcpy, s2, s1, len);
+#ifdef _WIN32_WCE
+ test_memcpy_test_run(s, memcpy_glibc, s2, s1, len);
+#endif /* _WIN32_WCE */
+
+ printf ("\n");
+}
+
+int
+test_memcpy(suite *s)
+{
+ size_t i;
+
+ page_size = 2 * 1024;
+
+ buf1 = (unsigned char *)malloc(16 * getpagesize());
+ if (!buf1) return 0;
+
+ buf2 = (unsigned char *)malloc(16 * getpagesize());
+ if (!buf2)
+ {
+ free(buf1);
+ return 0;
+ }
+
+ memset (buf1, 0xa5, page_size);
+ memset (buf2, 0x5a, page_size);
+
+ for (i = 0; i < 5; ++i)
+ {
+ test_memcpy_tests_run(s, 0, 0, 1 << i);
+ test_memcpy_tests_run(s, i, 0, 1 << i);
+ test_memcpy_tests_run(s, 0, i, 1 << i);
+ test_memcpy_tests_run(s, i, i, 1 << i);
+ }
+
+ for (i = 0; i < 32; ++i)
+ {
+ test_memcpy_tests_run(s, 0, 0, i);
+ test_memcpy_tests_run(s, i, 0, i);
+ test_memcpy_tests_run(s, 0, i, i);
+ test_memcpy_tests_run(s, i, i, i);
+ }
+
+ for (i = 3; i < 32; ++i)
+ {
+ if ((i & (i - 1)) == 0)
+ continue;
+ test_memcpy_tests_run(s, 0, 0, 16 * i);
+ test_memcpy_tests_run(s, i, 0, 16 * i);
+ test_memcpy_tests_run(s, 0, i, 16 * i);
+ test_memcpy_tests_run(s, i, i, 16 * i);
+ }
+
+ test_memcpy_tests_run(s, 0, 0, getpagesize ());
+ test_memcpy_tests_run(s, 0, 0, 2 * getpagesize ());
+ test_memcpy_tests_run(s, 0, 0, 4 * getpagesize ());
+ test_memcpy_tests_run(s, 0, 0, 8 * getpagesize ());
+ test_memcpy_tests_run(s, 0, 0, 16 * getpagesize ());
+
+ free(buf2);
+ free(buf1);
+
+ return 1;
+}
diff --git a/src/bin/evil/evil_test_memcpy.h b/src/bin/evil/evil_test_memcpy.h
new file mode 100644
index 0000000000..808dd09f37
--- /dev/null
+++ b/src/bin/evil/evil_test_memcpy.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_MEMCPY__
+#define __EVIL_TEST_MEMCPY__
+
+
+int test_memcpy(suite *s);
+
+
+#endif /* __EVIL_TEST_MEMCPY__ */
diff --git a/src/bin/evil/evil_test_mkstemp.c b/src/bin/evil/evil_test_mkstemp.c
new file mode 100644
index 0000000000..dc8c4e64f5
--- /dev/null
+++ b/src/bin/evil/evil_test_mkstemp.c
@@ -0,0 +1,53 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+
+#include <Evil.h>
+
+#include "evil_suite.h"
+#include "evil_test_mkstemp.h"
+
+
+static int
+test_mkstemp_test(void)
+{
+ char _template[PATH_MAX];
+#ifdef _WIN32_WCE
+ char cwd[PATH_MAX];
+#endif
+ int fd;
+
+#ifdef _WIN32_WCE
+ if (!getcwd(cwd, PATH_MAX))
+ return 0;
+ _snprintf(_template, PATH_MAX, "%s\\%s", cwd, "file_XXXXXX");
+#else
+ _snprintf(_template, PATH_MAX, "%s", "file_XXXXXX");
+#endif
+
+ fd = mkstemp(_template);
+
+ if (fd < 0)
+ return 0;
+
+ return 1;
+}
+
+static int
+test_mkstemp_run(suite *s __UNUSED__)
+{
+ int res;
+
+ res = test_mkstemp_test();
+
+ return res;
+}
+
+int
+test_mkstemp(suite *s)
+{
+
+ return test_mkstemp_run(s);
+}
diff --git a/src/bin/evil/evil_test_mkstemp.h b/src/bin/evil/evil_test_mkstemp.h
new file mode 100644
index 0000000000..f5bb0c4270
--- /dev/null
+++ b/src/bin/evil/evil_test_mkstemp.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_MKSTEMP_H__
+#define __EVIL_TEST_MKSTEMP_H__
+
+
+int test_mkstemp(suite *s);
+
+
+#endif /* __EVIL_TEST_MKSTEMP_H__ */
diff --git a/src/bin/evil/evil_test_pipe.c b/src/bin/evil/evil_test_pipe.c
new file mode 100644
index 0000000000..2fc530d545
--- /dev/null
+++ b/src/bin/evil/evil_test_pipe.c
@@ -0,0 +1,126 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+# define WIN32_LEAN_AND_MEAN
+# include <winsock2.h>
+# undef WIN32_LEAN_AND_MEAN
+
+#include <Evil.h>
+
+#include "evil_suite.h"
+#include "evil_test_pipe.h"
+
+
+#define FDREAD 0
+#define FDWRITE 1
+
+typedef struct
+{
+ int val;
+ int fd_write;
+} data;
+
+
+static DWORD WINAPI
+thread (void *param)
+{
+ data *d;
+ void *buf[1];
+
+ Sleep (2 * 1000);
+ d = (data *)param;
+ buf[0] = d;
+ send(d->fd_write, (char *)buf, sizeof(buf), 0);
+
+ return 0;
+}
+
+static int
+test_pipe_test(void)
+{
+ int sockets[2];
+ struct timeval t;
+ fd_set rfds;
+ int ret;
+ data *d;
+ DWORD thread_id;
+ HANDLE h;
+
+ FD_ZERO(&rfds);
+
+ t.tv_sec = 5;
+ t.tv_usec = 0;
+
+ if (pipe(sockets) < 0)
+ return 0;
+
+ FD_SET(sockets[FDREAD], &rfds);
+ fcntl(sockets[FDREAD], F_SETFL, O_NONBLOCK);
+
+ d = (data *)malloc(sizeof (data));
+ if (!d)
+ return 0;
+
+ d->val = 14;
+ d->fd_write = sockets[FDWRITE];
+
+ h = CreateThread(NULL, 0, thread, d, 0, &thread_id);
+ if (!h)
+
+ ret = select(sockets[FDREAD] + 1, &rfds, NULL, NULL, &t);
+
+ if (ret < 0)
+ goto free_d;
+ else if (ret == 0)
+ goto close_h;
+ else /* ret > 0 */
+ {
+ void *buf[1];
+ data *d2 = NULL;
+ int len;
+
+ while ((len = recv(sockets[FDREAD], (char *)buf, sizeof(buf), 0)) > 0)
+ {
+ if (len == sizeof(buf))
+ {
+ d2 = (data *)buf[0];
+ break;
+ }
+ }
+ if (d2 && (d2->val == d->val))
+ ret = 1;
+ else
+ ret = 0;
+ }
+
+ CloseHandle(h);
+ free(d);
+
+ return ret;
+
+ close_h:
+ CloseHandle(h);
+ free_d:
+ free(d);
+ return 0;
+}
+
+static int
+test_pipe_run(suite *s __UNUSED__)
+{
+ int res;
+
+ res = test_pipe_test();
+
+ return res;
+}
+
+int
+test_pipe(suite *s)
+{
+ return test_pipe_run(s);
+}
diff --git a/src/bin/evil/evil_test_pipe.h b/src/bin/evil/evil_test_pipe.h
new file mode 100644
index 0000000000..ff8041f716
--- /dev/null
+++ b/src/bin/evil/evil_test_pipe.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_PIPE_H__
+#define __EVIL_TEST_PIPE_H__
+
+
+int test_pipe(suite *s);
+
+
+#endif /* __EVIL_TEST_PIPE_H__ */
diff --git a/src/bin/evil/evil_test_print.c b/src/bin/evil/evil_test_print.c
new file mode 100644
index 0000000000..b930a538f4
--- /dev/null
+++ b/src/bin/evil/evil_test_print.c
@@ -0,0 +1,46 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include <Evil.h>
+
+#include "evil_suite.h"
+#include "evil_test_print.h"
+
+static int
+test_print_test(void)
+{
+ char buf[16];
+ int i1 = 1;
+ size_t i2 = 123456;
+ int res;
+
+ res = printf("%02hhd\n", i1);
+ if (res != 3)
+ return 0;
+
+ res = snprintf(buf, sizeof(buf), "%zu", i2);
+ if (res != 6)
+ return 0;
+
+ return 1;
+}
+
+static int
+test_print_run(suite *s __UNUSED__)
+{
+ int res;
+
+ res = test_print_test();
+
+ return res;
+}
+
+int
+test_print(suite *s)
+{
+ return test_print_run(s);
+}
diff --git a/src/bin/evil/evil_test_print.h b/src/bin/evil/evil_test_print.h
new file mode 100644
index 0000000000..2bbf43904f
--- /dev/null
+++ b/src/bin/evil/evil_test_print.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_PRINT_H__
+#define __EVIL_TEST_PRINT_H__
+
+
+int test_print(suite *s);
+
+
+#endif /* __EVIL_TEST_PRINT_H__ */
diff --git a/src/bin/evil/evil_test_realpath.c b/src/bin/evil/evil_test_realpath.c
new file mode 100644
index 0000000000..f9a48cb977
--- /dev/null
+++ b/src/bin/evil/evil_test_realpath.c
@@ -0,0 +1,44 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+
+#include <Evil.h>
+
+#include "evil_suite.h"
+#include "evil_test_realpath.h"
+
+
+static int
+test_realpath_test(void)
+{
+ char buf[PATH_MAX];
+ char *filename;
+ char *result;
+
+ filename = "evil_suite.exe";
+
+ if (!(result = realpath(filename, buf)))
+ return 0;
+
+ printf ("res : %s\n", buf);
+
+ return 1;
+}
+
+static int
+test_realpath_run(suite *s __UNUSED__)
+{
+ int res;
+
+ res = test_realpath_test();
+
+ return res;
+}
+
+int
+test_realpath(suite *s)
+{
+ return test_realpath_run(s);
+}
diff --git a/src/bin/evil/evil_test_realpath.h b/src/bin/evil/evil_test_realpath.h
new file mode 100644
index 0000000000..0205aad149
--- /dev/null
+++ b/src/bin/evil/evil_test_realpath.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_REALPATH_H__
+#define __EVIL_TEST_REALPATH_H__
+
+
+int test_realpath(suite *s);
+
+
+#endif /* __EVIL_TEST_REALPATH_H__ */
diff --git a/src/bin/evil/evil_test_util.c b/src/bin/evil/evil_test_util.c
new file mode 100644
index 0000000000..6226ceb040
--- /dev/null
+++ b/src/bin/evil/evil_test_util.c
@@ -0,0 +1,110 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+
+#include <Evil.h>
+
+#include "evil_suite.h"
+#include "evil_test_util.h"
+
+
+static int test_path_absolute_test_1(void)
+{
+ char *path;
+ int result;
+
+ path = NULL;
+ result = evil_path_is_absolute(path);
+ if (result != 0)
+ return 0;
+
+ return 1;
+}
+
+static int test_path_absolute_test_2(void)
+{
+ char *path;
+ int result;
+
+ path = "1";
+ result = evil_path_is_absolute(path);
+ if (result != 0)
+ return 0;
+
+ return 1;
+}
+
+static int test_path_absolute_test_3(void)
+{
+ char *path;
+ int result;
+
+ path = "1:\\";
+ result = evil_path_is_absolute(path);
+ if (result != 0)
+ return 0;
+
+ return 1;
+}
+
+static int test_path_absolute_test_4(void)
+{
+ char *path;
+ int result;
+
+ path = "1/\\";
+ result = evil_path_is_absolute(path);
+ if (result != 0)
+ return 0;
+
+ return 1;
+}
+
+static int test_path_absolute_test_5(void)
+{
+ char *path;
+ int result;
+
+ path = "F:/foo";
+ result = evil_path_is_absolute(path);
+ if (result == 0)
+ return 0;
+
+ return 1;
+}
+
+static int test_path_absolute_test_6(void)
+{
+ char *path;
+ int result;
+
+ path = "C:\\foo";
+ result = evil_path_is_absolute(path);
+ if (result == 0)
+ return 0;
+
+ return 1;
+}
+
+static int
+test_path_absolute_run(suite *s __UNUSED__)
+{
+ int res;
+
+ res = test_path_absolute_test_1();
+ res &= test_path_absolute_test_2();
+ res &= test_path_absolute_test_3();
+ res &= test_path_absolute_test_4();
+ res &= test_path_absolute_test_5();
+ res &= test_path_absolute_test_6();
+
+ return res;
+}
+
+int
+test_util(suite *s)
+{
+ return test_path_absolute_run(s);
+}
diff --git a/src/bin/evil/evil_test_util.h b/src/bin/evil/evil_test_util.h
new file mode 100644
index 0000000000..bee5c7a164
--- /dev/null
+++ b/src/bin/evil/evil_test_util.h
@@ -0,0 +1,8 @@
+#ifndef __EVIL_TEST_UTIL_H__
+#define __EVIL_TEST_UTIL_H__
+
+
+int test_util(suite *s);
+
+
+#endif /* __EVIL_TEST_UTIL_H__ */
diff --git a/src/bin/evil/memcpy_glibc_arm.S b/src/bin/evil/memcpy_glibc_arm.S
new file mode 100644
index 0000000000..7c42898647
--- /dev/null
+++ b/src/bin/evil/memcpy_glibc_arm.S
@@ -0,0 +1,231 @@
+/* Copyright (C) 2006 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ Contributed by MontaVista Software, Inc. (written by Nicolas Pitre)
+
+ The GNU C 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.
+
+ The GNU C 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 the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+/* Copyright (C) 2008 Vincent Torri
+ modification of the name and of the entry / end declaration
+ */
+
+/*
+ * Data preload for architectures that support it (ARM V5TE and above)
+ */
+#if (!defined (__ARM_ARCH_2__) && !defined (__ARM_ARCH_3__) \
+ && !defined (__ARM_ARCH_3M__) && !defined (__ARM_ARCH_4__) \
+ && !defined (__ARM_ARCH_4T__) && !defined (__ARM_ARCH_5__) \
+ && !defined (__ARM_ARCH_5T__))
+#define PLD(code...) code
+#else
+#define PLD(code...)
+#endif
+
+/*
+ * This can be used to enable code to cacheline align the source pointer.
+ * Experiments on tested architectures (StrongARM and XScale) didn't show
+ * this a worthwhile thing to do. That might be different in the future.
+ */
+//#define CALGN(code...) code
+#define CALGN(code...)
+
+/*
+ * Endian independent macros for shifting bytes within registers.
+ */
+#ifndef __ARMEB__
+#define pull lsr
+#define push lsl
+#else
+#define pull lsl
+#define push lsr
+#endif
+
+ .text
+
+/* Prototype: void *memcpy_glibc(void *dest, const void *src, size_t n); */
+
+ .align
+ .global memcpy_glibc
+ .func memcpy_glibc
+memcpy_glibc:
+
+ stmfd sp!, {r0, r4, lr}
+
+ subs r2, r2, #4
+ blt 8f
+ ands ip, r0, #3
+ PLD( pld [r1, #0] )
+ bne 9f
+ ands ip, r1, #3
+ bne 10f
+
+1: subs r2, r2, #(28)
+ stmfd sp!, {r5 - r8}
+ blt 5f
+
+ CALGN( ands ip, r1, #31 )
+ CALGN( rsb r3, ip, #32 )
+ CALGN( sbcnes r4, r3, r2 ) @ C is always set here
+ CALGN( bcs 2f )
+ CALGN( adr r4, 6f )
+ CALGN( subs r2, r2, r3 ) @ C gets set
+ CALGN( add pc, r4, ip )
+
+ PLD( pld [r1, #0] )
+2: PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #28] )
+ PLD( blt 4f )
+ PLD( pld [r1, #60] )
+ PLD( pld [r1, #92] )
+
+3: PLD( pld [r1, #124] )
+4: ldmia r1!, {r3, r4, r5, r6, r7, r8, ip, lr}
+ subs r2, r2, #32
+ stmia r0!, {r3, r4, r5, r6, r7, r8, ip, lr}
+ bge 3b
+ PLD( cmn r2, #96 )
+ PLD( bge 4b )
+
+5: ands ip, r2, #28
+ rsb ip, ip, #32
+ addne pc, pc, ip @ C is always clear here
+ b 7f
+6: nop
+ ldr r3, [r1], #4
+ ldr r4, [r1], #4
+ ldr r5, [r1], #4
+ ldr r6, [r1], #4
+ ldr r7, [r1], #4
+ ldr r8, [r1], #4
+ ldr lr, [r1], #4
+
+ add pc, pc, ip
+ nop
+ nop
+ str r3, [r0], #4
+ str r4, [r0], #4
+ str r5, [r0], #4
+ str r6, [r0], #4
+ str r7, [r0], #4
+ str r8, [r0], #4
+ str lr, [r0], #4
+
+ CALGN( bcs 2b )
+
+7: ldmfd sp!, {r5 - r8}
+
+8: movs r2, r2, lsl #31
+ ldrneb r3, [r1], #1
+ ldrcsb r4, [r1], #1
+ ldrcsb ip, [r1]
+ strneb r3, [r0], #1
+ strcsb r4, [r0], #1
+ strcsb ip, [r0]
+
+ ldmfd sp!, {r0, r4, pc}
+
+9: rsb ip, ip, #4
+ cmp ip, #2
+ ldrgtb r3, [r1], #1
+ ldrgeb r4, [r1], #1
+ ldrb lr, [r1], #1
+ strgtb r3, [r0], #1
+ strgeb r4, [r0], #1
+ subs r2, r2, ip
+ strb lr, [r0], #1
+ blt 8b
+ ands ip, r1, #3
+ beq 1b
+
+10: bic r1, r1, #3
+ cmp ip, #2
+ ldr lr, [r1], #4
+ beq 17f
+ bgt 18f
+
+
+ .macro forward_copy_shift pull push
+
+ subs r2, r2, #28
+ blt 14f
+
+ CALGN( ands ip, r1, #31 )
+ CALGN( rsb ip, ip, #32 )
+ CALGN( sbcnes r4, ip, r2 ) @ C is always set here
+ CALGN( subcc r2, r2, ip )
+ CALGN( bcc 15f )
+
+11: stmfd sp!, {r5 - r9}
+
+ PLD( pld [r1, #0] )
+ PLD( subs r2, r2, #96 )
+ PLD( pld [r1, #28] )
+ PLD( blt 13f )
+ PLD( pld [r1, #60] )
+ PLD( pld [r1, #92] )
+
+12: PLD( pld [r1, #124] )
+13: ldmia r1!, {r4, r5, r6, r7}
+ mov r3, lr, pull #\pull
+ subs r2, r2, #32
+ ldmia r1!, {r8, r9, ip, lr}
+ orr r3, r3, r4, push #\push
+ mov r4, r4, pull #\pull
+ orr r4, r4, r5, push #\push
+ mov r5, r5, pull #\pull
+ orr r5, r5, r6, push #\push
+ mov r6, r6, pull #\pull
+ orr r6, r6, r7, push #\push
+ mov r7, r7, pull #\pull
+ orr r7, r7, r8, push #\push
+ mov r8, r8, pull #\pull
+ orr r8, r8, r9, push #\push
+ mov r9, r9, pull #\pull
+ orr r9, r9, ip, push #\push
+ mov ip, ip, pull #\pull
+ orr ip, ip, lr, push #\push
+ stmia r0!, {r3, r4, r5, r6, r7, r8, r9, ip}
+ bge 12b
+ PLD( cmn r2, #96 )
+ PLD( bge 13b )
+
+ ldmfd sp!, {r5 - r9}
+
+14: ands ip, r2, #28
+ beq 16f
+
+15: mov r3, lr, pull #\pull
+ ldr lr, [r1], #4
+ subs ip, ip, #4
+ orr r3, r3, lr, push #\push
+ str r3, [r0], #4
+ bgt 15b
+ CALGN( cmp r2, #0 )
+ CALGN( bge 11b )
+
+16: sub r1, r1, #(\push / 8)
+ b 8b
+
+ .endm
+
+
+ forward_copy_shift pull=8 push=24
+
+17: forward_copy_shift pull=16 push=16
+
+18: forward_copy_shift pull=24 push=8
+
+.endfunc
diff --git a/src/bin/evil/memcpy_glibc_i686.S b/src/bin/evil/memcpy_glibc_i686.S
new file mode 100755
index 0000000000..72da118cf0
--- /dev/null
+++ b/src/bin/evil/memcpy_glibc_i686.S
@@ -0,0 +1,81 @@
+/* Copy memory block and return pointer to beginning of destination block
+ For Intel 80x86, x>=6.
+ This file is part of the GNU C Library.
+ Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
+ Contributed by Ulrich Drepper <drepper@cygnus.com>, 1999.
+
+ The GNU C 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.
+
+ The GNU C 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 the GNU C Library; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+# define CHECK_BOUNDS_BOTH_WIDE(VAL_REG, BP_MEM, LENGTH) \
+ CHECK_BOUNDS_LOW(VAL_REG, BP_MEM); \
+ addl LENGTH, VAL_REG; \
+ cmpl 8+BP_MEM, VAL_REG; \
+ jbe 0f; /* continue if value <= high */ \
+ BOUNDS_VIOLATED; \
+ 0: subl LENGTH, VAL_REG /* restore value */
+
+# define RETURN_BOUNDED_POINTER(BP_MEM) \
+ movl RTN(%esp), %edx; \
+ movl %eax, 0(%edx); \
+ movl 4+BP_MEM, %eax; \
+ movl %eax, 4(%edx); \
+ movl 8+BP_MEM, %eax; \
+ movl %eax, 8(%edx)
+
+#define PTR_SIZE 12
+#define RTN_SIZE 4
+#define LINKAGE 8
+
+#define PARMS LINKAGE /* no space for saved regs */
+#define RTN PARMS
+#define DEST RTN+RTN_SIZE
+#define SRC DEST+PTR_SIZE
+#define LEN SRC+PTR_SIZE
+
+ .text
+
+ .align
+ .global memcpy_glibc
+ .func memcpy_glibc
+memcpy_glibc:
+
+ pushl %ebp
+ movl %esp, %ebp
+
+ movl LEN(%esp), %ecx
+ movl %edi, %eax
+ movl DEST(%esp), %edi
+ movl %esi, %edx
+ movl SRC(%esp), %esi
+
+ cld
+ shrl $1, %ecx
+ jnc 1f
+ movsb
+1: shrl $1, %ecx
+ jnc 2f
+ movsw
+2: rep
+ movsl
+ movl %eax, %edi
+ movl %edx, %esi
+ movl DEST(%esp), %eax
+ RETURN_BOUNDED_POINTER (DEST(%esp))
+
+ movl %ebp, %esp
+ popl %ebp
+
+.endfunc
diff --git a/src/bin/evil/test_evil.c b/src/bin/evil/test_evil.c
new file mode 100644
index 0000000000..5b91172cb3
--- /dev/null
+++ b/src/bin/evil/test_evil.c
@@ -0,0 +1,27 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+
+#include <windows.h>
+
+
+
+int
+main()
+{
+ struct timeval tv;
+ double t1 = 0.0;
+ double t2 = 0.0;
+
+ if (gettimeofday(&tv, NULL) == 0)
+ t1 = tv.tv_sec + tv.tv_usec / 1000000.0;
+
+ Sleep(3000);
+
+ if (gettimeofday(&tv, NULL) == 0)
+ t2 = tv.tv_sec + tv.tv_usec / 1000000.0;
+
+ printf ("3 seconds ? %f\n", t2 - t1);
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/lib/evil/Evil.h b/src/lib/evil/Evil.h
new file mode 100644
index 0000000000..e807dffb61
--- /dev/null
+++ b/src/lib/evil/Evil.h
@@ -0,0 +1,186 @@
+#ifndef __EVIL_H__
+#define __EVIL_H__
+
+/**
+ * @mainpage Evil
+ * @image html e_big.png
+ * @author Vincent Torri
+ * @version 1.7.0
+ * @date 2008-2012
+ *
+ * @section intro_sec Introduction
+ *
+ * The Evil library is an evil library that ports some evil Unix
+ * functions to the Windows (XP or above, or Mobile) platform. The
+ * evilness is so huge that the most of the functions are not POSIX or
+ * BSD compliant.
+ *
+ * These functions are intended to be used in the Enlightenment
+ * Foundation Libraries only and can be compiled only on Windows,
+ * using MSYS/MinGW on Windows, and cross-compilation on Unix. This
+ * library is minimal in the sense that only the functions needed to
+ * compile the EFL are available. The purpose of this library is NOT
+ * to have a full POSIX emulation et it is NOT a replacement of
+ * cygwin. To compare the size of the DLL themselves, Evil is around
+ * 33 KB and cygwin DLL is around 800 KB.
+ *
+ * @section acknowledgments_sec Acknowledgments
+ *
+ * This library has receive some from people interested in the EFL or
+ * not. Among them, evil thanks to Lars Munch, Raoul Hecky, Nicolas
+ * Aguirre, Tor Lillqvist, Lance Fetters, Vincent Richomme, Paul
+ * Vixie, Daniel Stenberg, who helped the author of the library in
+ * different fields (code and tests).
+ *
+ * @section license_sec license
+ *
+ * The Evil library is distributes under a modified BSD license. See
+ * the files COPYING and COPYING-PLAIN in the top level directory for
+ * the full license text.
+ *
+ * @section reference_sec Reference API
+ *
+ * Use the horizontal menu above to navigate into the reference API
+ */
+
+/**
+ * @file Evil.h
+ * @brief The file that provides miscellaneous functions ported from Unix.
+ * @defgroup Evil Miscellaneous functions ported from Unix.
+ *
+ * This header provides miscellaneous functions that exist on Unix
+ * but not on Windows platform. They try to follow the conformance of
+ * the Unix versions.
+ */
+
+/**
+ * @cond LOCAL
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <limits.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <math.h>
+#include <direct.h>
+
+
+#ifdef _MSC_VER
+
+# include <io.h>
+
+# define F_OK 0 /* Check for file existence */
+# define X_OK 1 /* MS access() doesn't check for execute permission. */
+# define W_OK 2 /* Check for write permission */
+# define R_OK 4 /* Check for read permission */
+
+typedef DWORD pid_t;
+typedef unsigned short mode_t;
+
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+typedef signed int int32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+typedef SSIZE_T ssize_t;
+
+# define strdup(s) _strdup(s)
+# define unlink(filename) _unlink(filename)
+# define fileno(f) _fileno(f)
+# define fdopen(fd,m) _fdopen((fd),(m))
+# define access(p,m) _access((p),(m))
+# define hypot(x,y) _hypot((x),(y))
+# define tzset _tzset
+
+#endif /* _MSC_VER */
+
+#ifdef _WIN32_WCE
+# ifndef offsetof
+# define offsetof(type, ident) ((size_t)&(((type*)0)->ident))
+# endif
+#endif
+
+typedef unsigned long uid_t;
+typedef unsigned long gid_t;
+
+
+#include "evil_macro.h"
+#include "evil_fcntl.h"
+#include "evil_inet.h"
+#include "evil_langinfo.h"
+#include "evil_libgen.h"
+#include "evil_main.h"
+#include "evil_print.h"
+#include "evil_stdlib.h"
+#include "evil_stdio.h"
+#include "evil_string.h"
+#include "evil_time.h"
+#include "evil_unistd.h"
+#include "evil_util.h"
+#include "evil_macro_pop.h"
+
+
+#if (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__))
+# if defined(_MSC_VER) || defined(__MINGW32__)
+
+# ifdef S_ISDIR
+# undef S_ISDIR
+# endif
+# ifdef S_ISREG
+# undef S_ISREG
+# endif
+# define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
+# define S_ISREG(m) (((m) & _S_IFMT) == _S_IFREG)
+
+# define S_ISLNK(m) 0
+
+# define S_IRUSR _S_IRUSR
+# define S_IWUSR _S_IWUSR
+# define S_IXUSR _S_IXUSR
+# define S_IRGRP S_IRUSR
+# define S_IROTH S_IRUSR
+# define S_IWGRP S_IWUSR
+# define S_IWOTH S_IWUSR
+# define S_IXGRP S_IXUSR
+# define S_IXOTH S_IXUSR
+
+# define _S_IRWXU (_S_IREAD | _S_IWRITE | _S_IEXEC)
+# define _S_IXUSR _S_IEXEC
+# define _S_IWUSR _S_IWRITE
+# define _S_IRUSR _S_IREAD
+
+# define mkdir(p,m) _mkdir(p)
+ /*
+# define close(fd) _close(fd)
+# define read(fd,buffer,count) _read((fd),(buffer),(count))
+# define write(fd,buffer,count) _write((fd),(buffer),(count))
+# define unlink(filename) _unlink((filename))
+# define lstat(f,s) _stat((f),(s))
+ */
+
+# endif
+#endif
+
+
+#ifdef __cplusplus
+}
+#endif
+
+/**
+ * @endcond
+ */
+
+#endif /* __EVIL_H__ */
diff --git a/src/lib/evil/Makefile.am b/src/lib/evil/Makefile.am
new file mode 100644
index 0000000000..62d0d56bf3
--- /dev/null
+++ b/src/lib/evil/Makefile.am
@@ -0,0 +1,132 @@
+
+MAINTAINERCLEANFILES = Makefile.in
+
+lib_LTLIBRARIES = libevil.la libdl.la
+
+install_evilheadersdir = $(includedir)/evil-@VMAJ@
+dist_install_evilheaders_DATA = \
+Evil.h \
+evil_fcntl.h \
+evil_inet.h \
+evil_langinfo.h \
+evil_libgen.h \
+evil_macro.h \
+evil_macro_pop.h \
+evil_main.h \
+evil_print.h \
+evil_stdlib.h \
+evil_stdio.h \
+evil_string.h \
+evil_time.h \
+evil_unistd.h \
+evil_util.h
+
+stdheadersdir = $(includedir)/evil-@VMAJ@
+nobase_dist_stdheaders_DATA = pwd.h sys/mman.h fnmatch.h dirent.h dlfcn.h
+
+if EVIL_HAVE_WINCE
+
+nobase_dist_stdheaders_DATA += mingw32ce/errno.h
+
+endif
+
+# gdtoa
+libevil_la_SOURCES = \
+gdtoa/arithchk.c \
+gdtoa/dmisc.c \
+gdtoa/dtoa.c \
+gdtoa/gd_arith.h \
+gdtoa/g_dfmt.c \
+gdtoa/gd_qnan.h \
+gdtoa/gdtoa.c \
+gdtoa/gdtoa_fltrnds.h \
+gdtoa/gdtoa.h \
+gdtoa/gdtoaimp.h \
+gdtoa/gethex.c \
+gdtoa/g_ffmt.c \
+gdtoa/g__fmt.c \
+gdtoa/gmisc.c \
+gdtoa/g_xfmt.c \
+gdtoa/hd_init.c \
+gdtoa/hexnan.c \
+gdtoa/misc.c \
+gdtoa/qnan.c \
+gdtoa/smisc.c \
+gdtoa/strtodg.c \
+gdtoa/strtof.c \
+gdtoa/strtopx.c \
+gdtoa/sum.c \
+gdtoa/ulp.c
+
+#evil
+libevil_la_SOURCES += \
+evil_dirent.c \
+evil_fcntl.c \
+evil_fnmatch.c \
+evil_fnmatch_list_of_states.c \
+evil_inet.c \
+evil_langinfo.c \
+evil_libgen.c \
+evil_main.c \
+evil_mman.c \
+evil_pformata.c \
+evil_pformatw.c \
+evil_printa.c \
+evil_printw.c \
+evil_pwd.c \
+evil_stdlib.c \
+evil_stdio.c \
+evil_string.c \
+evil_time.c \
+evil_unistd.c \
+evil_util.c \
+evil_uuid.c \
+evil_pformat.h \
+evil_private.h \
+evil_fnmatch_private.h
+
+if EVIL_HAVE_WINCE
+
+libevil_la_SOURCES += evil_errno.c evil_link_ce.c
+
+else
+
+libevil_la_SOURCES += evil_link_xp.cpp
+
+endif
+
+libevil_la_CPPFLAGS = @EVIL_CPPFLAGS@
+libevil_la_CFLAGS = @EVIL_CFLAGS@
+libevil_la_CXXFLAGS = @EVIL_CXXFLAGS@
+libevil_la_LIBADD = @EVIL_LIBS@
+libevil_la_LDFLAGS = -no-undefined -Wl,--enable-auto-import -version-info @version_info@
+
+if EVIL_HAVE_WINCE
+
+libevil_la_LINK = $(LINK) $(libevil_la_LDFLAGS)
+
+else
+
+libevil_la_LINK = $(CXXLINK) $(libevil_la_LDFLAGS)
+
+endif
+
+libdl_la_SOURCES = dlfcn.c
+
+libdl_la_CPPFLAGS = @EVIL_DLFCN_CPPFLAGS@
+libdl_la_CFLAGS = @EVIL_CFLAGS@
+libdl_la_LIBADD = $(top_builddir)/src/lib/libevil.la @EVIL_DLFCN_LIBS@
+libdl_la_LDFLAGS = -no-undefined -Wl,--enable-auto-import -version-info @version_info@
+
+EXTRA_DIST = gdtoa/README gdtoa/README.mingw
+
+install-data-hook:
+ rm -f $(libdir)/libevil.la $(libdir)/libdl.la
+
+uninstall-local:
+ rm -f $(DESTDIR)$(bindir)/libevil-@VMAJ@.dll
+ rm -f $(DESTDIR)$(bindir)/libdl-@VMAJ@.dll
+ rm -f $(DESTDIR)$(libdir)/libevil.dll.a
+ rm -f $(DESTDIR)$(libdir)/libevil.a
+ rm -f $(DESTDIR)$(libdir)/libdl.dll.a
+ rm -f $(DESTDIR)$(libdir)/libdl.a
diff --git a/src/lib/evil/dirent.h b/src/lib/evil/dirent.h
new file mode 100644
index 0000000000..3fe9d12866
--- /dev/null
+++ b/src/lib/evil/dirent.h
@@ -0,0 +1,141 @@
+#ifndef __EVIL_DIRENT_H__
+#define __EVIL_DIRENT_H__
+
+#ifdef EAPI
+# undef EAPI
+#endif /* EAPI */
+
+#ifdef _WIN32
+# ifdef EFL_EVIL_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_EVIL_BUILD */
+#endif /* _WIN32 */
+
+
+/**
+ * @file dirent.h
+ * @brief The file that provides functions ported from Unix in dirent.h.
+ * @defgroup Evil_Dirent_Group Dirent.h functions
+ *
+ * This header provides functions ported from Unix in dirent.h.
+ *
+ * @{
+ */
+
+
+#ifdef UNICODE
+# include <wchar.h>
+#endif
+
+/**
+ * @def DT_UNKNOWN
+ * Specifies that the file type is unknown.
+ */
+#define DT_UNKNOWN 0
+
+/**
+ * @def DT_DIR
+ * Specifies that the file type is a directory.
+ */
+#define DT_DIR 4
+
+/**
+ * @typedef DIR
+ * @brief A structure that describes a directory stream.
+ */
+typedef struct DIR DIR;
+
+/**
+ * @struct dirent
+ * @brief A structure that describes a directory stream.
+ */
+struct dirent
+{
+ char d_name[260 + 1]; /**< The filename. */
+ int d_mode; /**< The mode */
+ unsigned char d_type; /**< The type */
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+/**
+ * @brief Open the given directory.
+ *
+ * @param name The directory to open.
+ * @return A pointer to the directory stream.
+ *
+ * This function opens the directory @p name and return the directory
+ * stream. On error or if @p dir is NULL, -1 is returned, and errno is
+ * set appropriately (on Windows XP only). On success, 0 is returned.
+ *
+ * @see closedir()
+ * @see readdir()
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows XP, CE.
+ */
+EAPI DIR *opendir(char const *name);
+
+/**
+ * @brief Close the given directory.
+ *
+ * @param dir The directory stream to close.
+ * @return A pointer to the directory stream.
+ *
+ * This function closes the stream directory @p dir. On error or is
+ * @p path is NULL or an empty string, NULL is returned, and errno is set
+ * appropriately (on Windows XP only).
+ *
+ * @see opendir()
+ * @see readdir()
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows XP, CE.
+ */
+EAPI int closedir(DIR *dir);
+
+/**
+ * @brief Read the given directory.
+ *
+ * @param dir The directory stream to read.
+ * @return A pointer to a dirent structure, @c NULL oterhwise.
+ *
+ * This function returns a pointer to a dirent structure representing
+ * the next directory entry in the directory stream pointed to by
+ * @p dir. It returns NULL on reaching the end of the directory stream
+ * or if an error occurred and errno is set appropriately (on Windows XP only).
+ *
+ * @see opendir()
+ * @see readdir()
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows XP, CE.
+ */
+EAPI struct dirent *readdir(DIR *dir);
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_DIRENT_H__ */
diff --git a/src/lib/evil/dlfcn.c b/src/lib/evil/dlfcn.c
new file mode 100644
index 0000000000..818cabf014
--- /dev/null
+++ b/src/lib/evil/dlfcn.c
@@ -0,0 +1,272 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#if defined(__MINGW32CE__) || defined(_MSC_VER)
+# include <limits.h>
+#endif /* __MINGW32CE__ || _MSC_VER */
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#ifdef _WIN32_WCE
+# include <tlhelp32.h> /* CreateToolhelp32Snapshot */
+#else
+# include <psapi.h> /* EnumProcessModules(Ex) */
+#endif
+
+#include "Evil.h"
+
+#include "dlfcn.h"
+
+
+static char *dl_err = NULL;
+static int dl_err_viewed = 0;
+
+static void
+get_last_error(char *desc)
+{
+ char *str;
+ size_t l1;
+ size_t l2;
+
+ str = evil_last_error_get();
+
+ l1 = strlen(desc);
+ l2 = strlen(str);
+
+ if (dl_err)
+ free(dl_err);
+
+ dl_err = (char *)malloc(sizeof(char) * (l1 + l2 + 1));
+ if (!dl_err)
+ dl_err = strdup("not enough resource");
+ else
+ {
+ memcpy(dl_err, desc, l1);
+ memcpy(dl_err + l1, str, l2);
+ dl_err[l1 + l2] = '\0';
+ }
+ free(str);
+ dl_err_viewed = 0;
+}
+
+void *
+dlopen(const char* path, int mode __UNUSED__)
+{
+ HMODULE module = NULL;
+
+ if (!path)
+ {
+ module = GetModuleHandle(NULL);
+ if (!module)
+ get_last_error("GetModuleHandle returned: ");
+ }
+ else
+ {
+ char *new_path;
+ size_t l;
+ unsigned int i;
+
+ /* according to MSDN, we must change the slash to backslash */
+ l = strlen(path);
+ new_path = (char *)malloc(sizeof(char) * (l + 1));
+ if (!new_path)
+ {
+ if (dl_err)
+ free(dl_err);
+ dl_err = strdup("not enough resource");
+ dl_err_viewed = 0;
+ return NULL;
+ }
+ for (i = 0; i <= l; i++)
+ {
+ if (path[i] == '/')
+ new_path[i] = '\\';
+ else
+ new_path[i] = path[i];
+ }
+#ifdef UNICODE
+ {
+ wchar_t *wpath;
+
+ wpath = evil_char_to_wchar(new_path);
+ module = LoadLibrary(wpath);
+ free(wpath);
+ }
+#else
+ module = LoadLibraryEx(new_path, NULL,
+ LOAD_WITH_ALTERED_SEARCH_PATH);
+#endif /* ! UNICODE */
+ if (!module)
+ get_last_error("LoadLibraryEx returned: ");
+
+ free(new_path);
+ }
+
+ return module;
+}
+
+int
+dlclose(void* handle)
+{
+ if (FreeLibrary(handle))
+ return 0;
+ else
+ {
+ get_last_error("FreeLibrary returned: ");
+ return -1;
+ }
+}
+
+void *
+dlsym(void *handle, const char *symbol)
+{
+ FARPROC fp = NULL;
+ LPCTSTR new_symbol;
+
+ if (!symbol || !*symbol) return NULL;
+
+#ifdef UNICODE
+ new_symbol = evil_char_to_wchar(symbol);
+#else
+ new_symbol = symbol;
+#endif /* UNICODE */
+
+ if (handle == RTLD_DEFAULT)
+ {
+#ifdef _WIN32_WCE
+ HANDLE snapshot;
+ MODULEENTRY32 module;
+
+ snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS |
+ TH32CS_SNAPMODULE |
+ TH32CS_GETALLMODS,
+ 0);
+ if (!snapshot)
+ return NULL;
+
+ module.dwSize = sizeof(module);
+ if (Module32First(snapshot, &module))
+ do {
+ fp = GetProcAddress(module.hModule, new_symbol);
+ if (fp) break;
+ } while (Module32Next(snapshot, &module));
+
+ CloseToolhelp32Snapshot(snapshot);
+#else
+ HMODULE modules[1024];
+ DWORD needed;
+ DWORD i;
+
+ /* TODO: use EnumProcessModulesEx() on Windows >= Vista */
+ if (!EnumProcessModules(GetCurrentProcess(),
+ modules, sizeof(modules), &needed))
+ return NULL;
+
+ for (i = 0; i < (needed / sizeof(HMODULE)); i++)
+ {
+ fp = GetProcAddress(modules[i], new_symbol);
+ if (fp) break;
+ }
+#endif
+ }
+ else
+ fp = GetProcAddress(handle, new_symbol);
+
+#ifdef UNICODE
+ free((void *)new_symbol);
+#endif /* UNICODE */
+
+ if (!fp)
+ get_last_error("GetProcAddress returned: ");
+
+ return fp;
+}
+
+int
+dladdr (const void *addr __UNUSED__, Dl_info *info)
+{
+ TCHAR tpath[PATH_MAX];
+ MEMORY_BASIC_INFORMATION mbi;
+ char *path;
+ char *tmp;
+ size_t length;
+ int ret = 0;
+
+ if (!info)
+ return 0;
+
+#ifdef _WIN32_WINNT
+ length = VirtualQuery(addr, &mbi, sizeof(mbi));
+ if (!length)
+ return 0;
+
+ if (mbi.State != MEM_COMMIT)
+ return 0;
+
+ if (!mbi.AllocationBase)
+ return 0;
+
+ ret = GetModuleFileName((HMODULE)mbi.AllocationBase, (LPTSTR)&tpath, PATH_MAX);
+ if (!ret)
+ return 0;
+#else
+ ret = GetModuleFileName(NULL, (LPTSTR)&tpath, PATH_MAX);
+ if (!ret)
+ return 0;
+#endif
+
+#ifdef UNICODE
+ path = evil_wchar_to_char(tpath);
+#else
+ path = tpath;
+#endif /* ! UNICODE */
+
+ length = strlen (path);
+ if (length >= PATH_MAX)
+ {
+ length = PATH_MAX - 1;
+ path[PATH_MAX - 1] = '\0';
+ }
+
+ /* replace '/' by '\' */
+ tmp = path;
+ while (*tmp)
+ {
+ if (*tmp == '/') *tmp = '\\';
+ tmp++;
+ }
+
+ memcpy (info->dli_fname, path, length + 1);
+ info->dli_fbase = NULL;
+ info->dli_sname = NULL;
+ info->dli_saddr = NULL;
+
+#ifdef UNICODE
+ free (path);
+#endif /* ! UNICODE */
+
+ return 1;
+}
+
+char *
+dlerror (void)
+{
+ if (!dl_err_viewed)
+ {
+ dl_err_viewed = 1;
+ return dl_err;
+ }
+ else
+ {
+ if (dl_err)
+ free(dl_err);
+ return NULL;
+ }
+}
diff --git a/src/lib/evil/dlfcn.h b/src/lib/evil/dlfcn.h
new file mode 100644
index 0000000000..610331b702
--- /dev/null
+++ b/src/lib/evil/dlfcn.h
@@ -0,0 +1,258 @@
+#ifndef __EVIL_DLFCN_H__
+#define __EVIL_DLFCN_H__
+
+
+#include <limits.h>
+
+
+#ifdef EAPI
+# undef EAPI
+#endif /* EAPI */
+
+#ifdef _WIN32
+# ifdef EFL_EVIL_DLFCN_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_EVIL_DLFCN_BUILD */
+#endif /* _WIN32 */
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef _WIN32_WCE
+# ifndef PATH_MAX
+# define PATH_MAX 260
+# endif
+#endif
+
+
+/**
+ * @file dlfcn.h
+ * @brief The file that provides functions to manage dynamic-link libraries
+ * @defgroup Dlfcn Functions that manage dynamic-link libraries.
+ *
+ * This header provides functions to load and unload dynamic-link
+ * libaries, to get the address of a symbol, and to get diagnostic
+ * information.
+ */
+
+
+/**
+ * @def RTLD_LAZY
+ * Lazy function call binding.
+ */
+# define RTLD_LAZY 0x00001 /* lazy function call binding */
+
+/**
+ * @def RTLD_NOW
+ * Immediate function call binding.
+ */
+# define RTLD_NOW 0x00002 /* immediate function call binding */
+
+/**
+ * @def RTLD_GLOBAL
+ * Symbols in this dlopen'ed obj are visible to other dlopen'ed objs.
+ */
+# define RTLD_GLOBAL 0x00100 /* symbols in this dlopen'ed obj are visible
+ to other dlopen'ed objs */
+
+/**
+ * @def RTLD_NODELETE
+ * Symbols are not deleted when closed.
+ */
+#define RTLD_NODELETE 0x01000 /* do not delete object when closed. */
+
+/**
+ * @def RTLD_DEFAULT
+ * Symbols are searched in all the DLL opened by the current process.
+ */
+#define RTLD_DEFAULT ((void*)1) /* search the symbol on all the DLL of the current process */
+
+/**
+ * @typedef Dl_info
+ * @brief A structure that stores infomation of a calling process.
+ */
+typedef struct Dl_info Dl_info;
+
+/**
+ * @struct Dl_info
+ * @brief A structure that stores infomation of a calling process.
+ */
+struct Dl_info
+{
+ char dli_fname[PATH_MAX]; /**< Filename of defining object */
+ void *dli_fbase; /**< Load address of that object */
+ const char *dli_sname; /**< Name of nearest lower symbol */
+ void *dli_saddr; /**< Exact value of nearest symbol */
+};
+
+/**
+ * @brief Map a specified executable module (either a .dll or .exe file)
+ * into the address space of the user process.
+ *
+ * @param path Name of the module.
+ * @param mode Unused.
+ * @return A pointer that represent the module, or @c NULL on failure.
+ *
+ * Map a specified executable module (either a .dll or .exe file)
+ * into the address space of the user process. If @p path is @c NULL,
+ * then the module corresponding to the current process is returned.
+ * Otherwise the module specified by @p path is loaded if it exists.
+ * If not, @c NULL is returned. The directory separators can be forward
+ * slash, or backward ones. Mapping a module can map other modules.
+ * @p mode is unused.
+ *
+ * If an error occurred, an error string can be retrived with dlerror().
+ *
+ * According to the OS, the search order of the module can change,
+ * according to the value of SafeDllSearchMode.
+ *
+ * - For Windows Vista, Windows Server 2003, and Windows XP SP2:
+ * SafeDLLSearchMode is enabled by default.
+ * - For Windows XP and Windows 2000 SP4: SafeDLLSearchMode is disabled
+ * by default.
+ *
+ * If SafeDllSearchMode is enabled
+ * - The directory from which the application loaded.
+ * - The system directory. Use the GetSystemDirectory() function
+ * to get the path of this directory.
+ * - The 16-bit system directory. There is no function that obtains
+ * the path of this directory, but it is searched.
+ * - The Windows directory. Use the GetWindowsDirectory() function
+ * to get the path of this directory.
+ * - The current directory.
+ * - The directories that are listed in the PATH environment variable.
+ * Note that this does not include the per-application path specified
+ * by the App Paths registry key.
+ *
+ * If SafeDllSearchMode is disabled
+ * - The directory from which the application loaded.
+ * - The current directory.
+ * - The system directory. Use the GetSystemDirectory() function
+ * to get the path of this directory.
+ * - The 16-bit system directory. There is no function that obtains
+ * the path of this directory, but it is searched.
+ * - The Windows directory. Use the GetWindowsDirectory() function
+ * to get the path of this directory.
+ * - The directories that are listed in the PATH environment variable.
+ * Note that this does not include the per-application path specified
+ * by the App Paths registry key.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows Vista, Windows XP or Windows 2000
+ * Professional.
+ *
+ * @ingroup Dlfcn
+ */
+EAPI void *dlopen(const char* path, int mode);
+
+/**
+ * @brief Close a dynamic-link library.
+ *
+ * @param handle Handle that references a dynamic-link library.
+ * @return O on sucess, -1 otherwise.
+ *
+ * Release a reference to the dynamic-link library referenced
+ * by @p handle. If the reference count drops to 0, the handle is
+ * removed from the address space and is rendered invalid. @p handle
+ * is the value returned by a previous call to dlopen().
+ *
+ * If no error occurred, the returned value is 0, otherwise the
+ * returned value is -1 and an error string can be retrived with
+ * dlerror().
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows Vista, Windows XP or Windows 2000
+ * Professional.
+ *
+ * @ingroup Dlfcn
+ */
+EAPI int dlclose(void* handle);
+
+/**
+ * @brief Get the address of a symbol.
+ *
+ * @param handle Handle that references a dynamic-link library.
+ * @param symbol @c NULL-terminated string.
+ * @return O on sucess, NULL otherwise.
+ *
+ * Return the address of the code or data location specified by the
+ * string @p symbol. @p handle references a library that contains
+ * the function or variable @p symbol.
+ *
+ * If no error occurred, the returned value is the code or data
+ * location, otherwise the returned value is NULL and an error
+ * string can be retrived with dlerror().
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows Vista, Windows XP or Windows 2000
+ * Professional.
+ *
+ * @ingroup Dlfcn
+ */
+EAPI void *dlsym(void* handle, const char* symbol);
+
+/**
+ * @brief Get the location of the current process (.exe)
+ *
+ * @param addr Unused.
+ * @param info Pointer to the Dl_info to fill.
+ * @return 1 on success, 0 otherwise.
+ *
+ * Fill the dli_fname member of @p info with the absolute name
+ * of the current calling process (.exe file that is executed).
+ * All other members are set to @c NULL.
+ *
+ * Contrary to the unix function, the full name of the shared
+ * library is not returned, but insted the full name of the current
+ * calling process (.exe file).
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows Vista, Windows XP or Windows 2000
+ * Professional.
+ *
+ * @ingroup Dlfcn
+ */
+EAPI int dladdr (const void *addr, Dl_info *info);
+
+/**
+ * @brief Get diagnostic information
+ *
+ * @return A @c NULL-terminated string if an error occured, @c NULL
+ * otherwise.
+ *
+ * Return a @c NULL-terminated character string describing the last
+ * error that occurred on this thread during a call to dlopen(),
+ * dlsym(), or dlclose(). If no such error has occurred, dlerror()
+ * returns a null pointer. At each call to dlerror(), the error
+ * indication is reset. Thus in the case of two calls to dlerror(),
+ * where the second call follows the first immediately, the second
+ * call will always return a null pointer.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows Vista, Windows XP or Windows 2000
+ * Professional.
+ *
+ * @ingroup Dlfcn
+ */
+EAPI char *dlerror (void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __EVIL_DLFCN_H__ */
diff --git a/src/lib/evil/evil_dirent.c b/src/lib/evil/evil_dirent.c
new file mode 100644
index 0000000000..e02b95fe27
--- /dev/null
+++ b/src/lib/evil/evil_dirent.c
@@ -0,0 +1,197 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <dirent.h>
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+
+#include "Evil.h"
+
+
+struct DIR
+{
+ struct dirent dirent;
+ WIN32_FIND_DATA data;
+ HANDLE handle;
+};
+
+
+DIR *opendir(char const *name)
+{
+ DIR *dir;
+ char *tmp1;
+ char *tmp2;
+ DWORD attr;
+ size_t l;
+#ifdef UNICODE
+ wchar_t *wname;
+ char *d_name;
+#endif
+
+ /* valid name */
+ if (!name || !*name)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = ENOENT;
+#endif
+ return NULL;
+ }
+
+#ifdef UNICODE
+ wname = evil_char_to_wchar(name);
+ if (!wname)
+ {
+# ifdef HAVE_ERRNO_H
+ errno = ENOMEM;
+# endif
+ return NULL;
+ }
+
+ if((attr = GetFileAttributes(wname)) == 0xFFFFFFFF)
+#else
+ if((attr = GetFileAttributes(name)) == 0xFFFFFFFF)
+#endif
+ {
+#ifdef HAVE_ERRNO_H
+ errno = ENOENT;
+#endif
+ return NULL;
+ }
+
+#ifdef UNICODE
+ free(wname);
+#endif
+
+ /* directory */
+ if (!(attr & FILE_ATTRIBUTE_DIRECTORY))
+ {
+#ifdef HAVE_ERRNO_H
+ errno = ENOTDIR;
+#endif
+ return NULL;
+ }
+
+ dir = (DIR *)malloc(sizeof(DIR));
+ if (!dir)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = ENOMEM;
+#endif
+ return NULL;
+ }
+
+ l = strlen(name);
+ tmp1 = (char *)malloc(sizeof(char) * l + 5);
+ if (!tmp1)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = ENOMEM;
+#endif
+ return NULL;
+ }
+
+ memcpy(tmp1, name, l);
+ memcpy(tmp1 + l, "\\*.*", 5);
+
+ tmp2 = tmp1;
+ while (*tmp2)
+ {
+ if (*tmp2 == '/') *tmp2 = '\\';
+ tmp2++;
+ }
+
+#ifdef UNICODE
+ wname = evil_char_to_wchar(tmp1);
+ if (!wname)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = ENOMEM;
+#endif
+ free(tmp1);
+
+ return NULL;
+ }
+ dir->handle = FindFirstFile(wname, &dir->data);
+ free(wname);
+#else
+ dir->handle = FindFirstFile(tmp1, &dir->data);
+#endif
+
+ free(tmp1);
+
+ if (dir->handle == INVALID_HANDLE_VALUE)
+ {
+ free(dir);
+ return NULL;
+ }
+
+#ifdef UNICODE
+ d_name = evil_wchar_to_char(dir->data.cFileName);
+ strcpy(dir->dirent.d_name, d_name);
+ free(d_name);
+#else
+ strcpy(dir->dirent.d_name, dir->data.cFileName);
+#endif
+ dir->dirent.d_mode = (int)dir->data.dwFileAttributes;
+
+ if (dir->data.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
+ dir->dirent.d_type = DT_DIR;
+ else
+ dir->dirent.d_type = DT_UNKNOWN;
+
+ return dir;
+}
+
+int closedir(DIR *dir)
+{
+ if (!dir)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EBADF;
+#endif
+ return -1;
+ }
+
+ if (dir->handle != INVALID_HANDLE_VALUE)
+ FindClose(dir->handle);
+ free(dir);
+
+ return 0;
+}
+
+struct dirent *readdir(DIR *dir)
+{
+#ifdef UNICODE
+ char *d_name;
+#endif
+
+ if (!dir)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EBADF;
+#endif
+ return NULL;
+ }
+
+ if (dir->handle == INVALID_HANDLE_VALUE)
+ return NULL;
+
+#ifdef UNICODE
+ d_name = evil_wchar_to_char(dir->data.cFileName);
+ strcpy(dir->dirent.d_name, d_name);
+ free(d_name);
+#else
+ strcpy(dir->dirent.d_name, dir->data.cFileName);
+#endif
+
+ if (!FindNextFile(dir->handle, &dir->data))
+ {
+ FindClose(dir->handle);
+ dir->handle = INVALID_HANDLE_VALUE;
+ }
+
+ return &dir->dirent;
+}
diff --git a/src/lib/evil/evil_errno.c b/src/lib/evil/evil_errno.c
new file mode 100644
index 0000000000..37cac611f0
--- /dev/null
+++ b/src/lib/evil/evil_errno.c
@@ -0,0 +1,9 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "Evil.h"
+#include "mingw32ce/errno.h"
+
+
+int errno = 0;
diff --git a/src/lib/evil/evil_fcntl.c b/src/lib/evil/evil_fcntl.c
new file mode 100644
index 0000000000..7c62c2a310
--- /dev/null
+++ b/src/lib/evil/evil_fcntl.c
@@ -0,0 +1,124 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+
+#ifdef _MSC_VER
+# include <io.h> /* for _get_osfhandle _lseek and _locking */
+#endif
+
+#include <sys/locking.h>
+
+#include <winsock2.h> /* for ioctlsocket */
+
+#include "Evil.h"
+
+
+#ifdef __MINGW32CE__
+# define _get_osfhandle(FILEDES) ((HANDLE)FILEDES)
+#endif /* __MINGW32CE__ */
+
+
+/*
+ * port of fcntl function
+ *
+ */
+
+int fcntl(int fd, int cmd, ...)
+{
+ va_list va;
+ HANDLE h;
+ int res = -1;
+
+ va_start (va, cmd);
+
+ h = (HANDLE)_get_osfhandle(fd);
+ if (h == INVALID_HANDLE_VALUE)
+ return -1;
+
+ if (cmd == F_GETFD)
+ {
+#ifndef __MINGW32CE__
+ DWORD flag;
+
+ if (!GetHandleInformation(h, &flag))
+ return -1;
+
+ res = 0;
+#endif /* ! __MINGW32CE__ */
+ }
+
+ if (cmd == F_SETFD)
+ {
+ long flag;
+
+ flag = va_arg(va, long);
+ if (flag == FD_CLOEXEC)
+ {
+#ifndef __MINGW32CE__
+ if (SetHandleInformation(h, HANDLE_FLAG_INHERIT, 0))
+ res = 0;
+#endif /* ! __MINGW32CE__ */
+ }
+ }
+ else if (cmd == F_SETFL)
+ {
+ long flag;
+
+ flag = va_arg(va, long);
+ if (flag == O_NONBLOCK)
+ {
+ u_long arg = 1;
+ int type;
+ int len;
+ int ret;
+
+ len = (int)sizeof(int);
+ ret = getsockopt((SOCKET)fd, SOL_SOCKET, SO_TYPE, (char *)&type, &len);
+ if (!ret && (type == SOCK_STREAM))
+ {
+ if (!ioctlsocket((SOCKET)fd, FIONBIO, &arg) == SOCKET_ERROR)
+ res = 0;
+ }
+ }
+ }
+#ifndef __MINGW32CE__
+ else if ((cmd == F_SETLK) || (cmd == F_SETLKW))
+ {
+ struct flock *fl;
+ off_t length = 0;
+ long pos;
+
+ fl = va_arg(va, struct flock *);
+
+ if (fl->l_len == 0)
+ {
+ length = _lseek(fd, 0L, SEEK_END);
+ if (length != -1L)
+ res = 0;
+ }
+ fl->l_len = length - fl->l_start - 1;
+
+ pos = _lseek(fd, fl->l_start, fl->l_whence);
+ if (pos != -1L)
+ res = 0;
+
+ if ((fl->l_type == F_RDLCK) || (fl->l_type == F_WRLCK))
+ {
+ if (cmd == F_SETLK)
+ res = _locking(fd, _LK_NBLCK, fl->l_len); /* if cannot be locked, we return immediatly */
+ else /* F_SETLKW */
+ res = _locking(fd, _LK_LOCK, fl->l_len); /* otherwise, we try several times */
+ }
+
+ if (fl->l_type == F_UNLCK)
+ res = _locking(fd, _LK_UNLCK, fl->l_len);
+ }
+
+#endif /* ! __MINGW32CE__ */
+
+ va_end(va);
+
+ return res;
+}
diff --git a/src/lib/evil/evil_fcntl.h b/src/lib/evil/evil_fcntl.h
new file mode 100644
index 0000000000..194341b369
--- /dev/null
+++ b/src/lib/evil/evil_fcntl.h
@@ -0,0 +1,110 @@
+#ifndef __EVIL_FCNTL_H__
+#define __EVIL_FCNTL_H__
+
+
+# include <sys/types.h>
+
+
+/**
+ * @def FD_CLOEXEC
+ * Specifies that the file descriptor should be closed when an exec()
+ * function is invoked.
+ */
+# define FD_CLOEXEC 1
+
+/**
+ * @def O_NONBLOCK
+ * Specifies that the socket is in non-blocking mode.
+ */
+# define O_NONBLOCK 04000
+
+/**
+ * @def F_SETFD
+ * Specifies that fcntl() should set the file descriptor flags
+ * associated with the filedes argument.
+ */
+
+/**
+ * @def F_SETLK
+ * Specifies that fcntl() should set or clear a file segment lock
+ * according to the lock description pointed to by the third argument.
+ */
+
+/**
+ * @def F_SETLKW
+ * Equivalent to F_SETLK except that if a shared or exclusive lock
+ * is blocked by other locks, the thread shall wait until the request
+ * can be satisfied.
+ */
+
+# define F_GETFD 1
+# define F_SETFD 2
+# define F_SETFL 4
+# define F_SETLK 6
+# define F_SETLKW 7
+
+/**
+ * @def F_RDLCK
+ * Read (or shared) lock
+ */
+
+/**
+ * @def F_WRLCK
+ * Write (or exclusive) lock
+ */
+
+/**
+ * @def F_UNLCK
+ * Remove lock
+ */
+
+# ifndef F_RDLCK
+# define F_RDLCK 0
+# define F_WRLCK 1
+# define F_UNLCK 2
+# endif /* ! F_RDLCK */
+
+/**
+ * @struct flock
+ * @brief A structure that controls the lock of a file descriptor.
+ */
+struct flock
+{
+ short int l_type; /**< lock type: read, write, ... */
+ short int l_whence; /**< type of l_start */
+ off_t l_start; /**< starting offset */
+ off_t l_len; /**< 0 means end of the file */
+ pid_t l_pid; /**< lock owner */
+};
+
+
+/**
+ * @brief Provide control over file descriptors.
+ *
+ * @param fd The file descriptor.
+ * @param cmd The type of control.
+ * @return 0 on success, -1 otherwise.
+ *
+ * Performs one of various miscellaneous operations on @p fd.
+ * The operation in question is determined by @p cmd:
+ *
+ * - F_SETFD: Set the close-on-exec flag to the value specified
+ * by the argument after command (only the least significant
+ * bit is used).
+ * - F_SETLK and F_SETLKW: used to manage discretionary file locks.
+ * The third argument must be a pointer to a struct flock (that
+ * may be overwritten by this call).
+ *
+ * This function returns 0 on success, -1 otherwise.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows Vista, Windows XP or Windows 2000
+ * Professional.
+ *
+ * @ingroup Evil
+ */
+EAPI int fcntl(int fd, int cmd, ...);
+
+
+#endif /* __EVIL_FCNTL_H__ */
diff --git a/src/lib/evil/evil_fnmatch.c b/src/lib/evil/evil_fnmatch.c
new file mode 100644
index 0000000000..0b4af7bfb0
--- /dev/null
+++ b/src/lib/evil/evil_fnmatch.c
@@ -0,0 +1,231 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <assert.h>
+#include <string.h>
+
+#include "fnmatch.h"
+#include "evil_fnmatch_private.h"
+
+enum fnmatch_status
+{
+ fnmatch_not_found = 0,
+ fnmatch_found = 1,
+ fnmatch_syntax_error = 2
+};
+
+static
+size_t
+fnmatch_match_class_token(enum fnmatch_status *status,
+ const char *class_token,
+ char c)
+{
+ if (! *class_token)
+ {
+ *status = fnmatch_syntax_error;
+ return 0;
+ }
+ else if (class_token[1] == '-' && class_token[2] != ']')
+ {
+ if (class_token[0] <= c && c <= class_token[2])
+ *status = fnmatch_found;
+ return 3;
+ }
+ else
+ {
+ if (c == *class_token)
+ *status = fnmatch_found;
+ return 1;
+ }
+}
+
+static
+size_t
+fnmatch_complement_class(const char *class_token)
+{
+ switch (*class_token)
+ {
+ case 0:
+ return FNM_SYNTAXERR;
+
+ case '!':
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static
+size_t
+fnmatch_match_class(const char *class,
+ char c)
+{
+ const size_t complement = fnmatch_complement_class(class + 1);
+ enum fnmatch_status status;
+ size_t pos;
+
+ if (complement == FNM_SYNTAXERR)
+ return FNM_SYNTAXERR;
+
+ status = fnmatch_not_found;
+ pos = 1 + complement;
+
+ do
+ pos += fnmatch_match_class_token(&status, class + pos, c);
+ while (class[pos] && class[pos] != ']');
+
+ if (status == fnmatch_syntax_error || ! class[pos])
+ return FNM_SYNTAXERR;
+
+ if (status == fnmatch_found)
+ return complement ? 0 : pos + 1;
+ else
+ return complement ? pos + 1 : 0;
+}
+
+static
+size_t
+fnmatch_chrcasecmp(char a,
+ char b)
+{
+ if ('A' <= a && a <= 'Z')
+ a += 'a' - 'A';
+ if ('A' <= b && b <= 'Z')
+ b += 'a' - 'A';
+ return a == b;
+}
+
+static
+size_t
+fnmatch_match_token(const char *token,
+ char c,
+ e_bool leading,
+ int flags)
+{
+ if (*token == '\\' && !(flags & FNM_NOESCAPE))
+ return token[1] ? (token[1] == c ? 2 : 0) : FNM_SYNTAXERR;
+
+ if (c == '/' && (flags & FNM_PATHNAME))
+ return *token == '/';
+
+ if (c == '.' && leading && (flags & FNM_PERIOD))
+ return *token == '.';
+
+ switch (*token)
+ {
+ case '?':
+ return 1;
+
+ case '[':
+ return fnmatch_match_class(token, c);
+
+ default:
+ if (flags & FNM_CASEFOLD)
+ return fnmatch_chrcasecmp(*token, c);
+ return *token == c ? 1 : 0;
+ }
+}
+
+static
+void
+fnmatch_init_states(struct list_of_states *states)
+{
+ states->size = 1;
+ states->states[0] = 0;
+ memset(states->has, 0, states->reserved * sizeof (*states->has));
+ states->has[0] = 1;
+}
+
+static
+size_t
+fnmatch_check_finals(const char *pattern,
+ const struct list_of_states *states)
+{
+ size_t i, j;
+ for (i = 0; i < states->size; ++i)
+ {
+ e_bool match = 1;
+
+ for (j = states->states[i]; pattern[j]; ++j)
+ if (pattern[j] != '*')
+ {
+ match = 0;
+ break;
+ }
+
+ if (match)
+ return 0;
+ }
+ return FNM_NOMATCH;
+}
+
+int
+fnmatch(const char *pattern,
+ const char *string,
+ int flags)
+{
+ struct list_of_states *states;
+ struct list_of_states *new_states;
+ e_bool leading = 1;
+ char *c;
+ size_t r;
+
+ assert(pattern);
+ assert(string);
+
+ states = fnmatch_list_of_states_alloc(2, strlen(pattern));
+ new_states = states + 1;
+
+ if (! states)
+ return FNM_NOMEM;
+ fnmatch_init_states(states);
+
+
+ for (c = (char *)string; *c && states->size; ++c)
+ {
+ size_t i;
+ fnmatch_list_of_states_clear(new_states);
+
+ for (i = 0; i < states->size; ++i)
+ {
+ const size_t pos = states->states[i];
+
+ if (! pattern[pos])
+ {
+ if (*c == '/' && (flags & FNM_LEADING_DIR))
+ return 0;
+ continue;
+ }
+ else if (pattern[pos] == '*')
+ {
+ fnmatch_list_of_states_insert(states, pos + 1);
+ if ((*c != '/' || !(flags & FNM_PATHNAME)) &&
+ (*c != '.' || !leading || !(flags & FNM_PERIOD)))
+ fnmatch_list_of_states_insert(new_states, pos);
+ }
+ else
+ {
+ const size_t m = fnmatch_match_token(pattern + pos, *c,
+ leading, flags);
+
+ if (m == FNM_SYNTAXERR)
+ return FNM_SYNTAXERR;
+ else if (m)
+ fnmatch_list_of_states_insert(new_states, pos + m);
+ }
+ }
+ {
+ struct list_of_states *tmp = states;
+
+ states = new_states;
+ new_states = tmp;
+ }
+ leading = *c == '/' && (flags & FNM_PATHNAME);
+ }
+
+ r = fnmatch_check_finals(pattern, states);
+ fnmatch_list_of_states_free(states < new_states ? states : new_states, 2);
+ return (int)r;
+}
diff --git a/src/lib/evil/evil_fnmatch_list_of_states.c b/src/lib/evil/evil_fnmatch_list_of_states.c
new file mode 100644
index 0000000000..c6cfb7fe81
--- /dev/null
+++ b/src/lib/evil/evil_fnmatch_list_of_states.c
@@ -0,0 +1,77 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "evil_fnmatch_private.h"
+
+struct list_of_states*
+fnmatch_list_of_states_alloc(size_t n,
+ size_t pattern_len)
+{
+ struct list_of_states *l;
+
+ const size_t reserved = pattern_len + 1;
+ const size_t states_size = sizeof (*l->states) * reserved;
+ const size_t has_size = sizeof (*l->has) * reserved;
+ const size_t states_has_size = states_size + has_size;
+ const size_t struct_size = sizeof (*l) + states_has_size;
+
+ unsigned char *states;
+ unsigned char *has;
+ size_t i;
+
+ l = malloc(n * struct_size);
+ if (!l)
+ return 0;
+
+ states = (unsigned char *) (l + n);
+ has = states + states_size;
+
+ for (i = 0; i < n; ++i)
+ {
+ l[i].reserved = reserved;
+ l[i].states = (size_t *) states;
+ l[i].has = (e_bool *) has;
+ states += states_has_size;
+ has += states_has_size;
+ }
+
+ return l;
+}
+
+void
+fnmatch_list_of_states_free(struct list_of_states *lists,
+ size_t n)
+{
+ assert(lists);
+
+ (void) n;
+ free(lists);
+}
+
+void
+fnmatch_list_of_states_insert(struct list_of_states *list,
+ size_t state)
+{
+ assert(list);
+ assert(state < list->reserved);
+
+ if (list->has[state])
+ return;
+
+ list->states[list->size++] = state;
+ list->has[state] = 1;
+}
+
+void
+fnmatch_list_of_states_clear(struct list_of_states *list)
+{
+ assert(list);
+
+ list->size = 0;
+ memset(list->has, 0, list->reserved * sizeof (*list->has));
+}
diff --git a/src/lib/evil/evil_fnmatch_private.h b/src/lib/evil/evil_fnmatch_private.h
new file mode 100644
index 0000000000..f5ced5d68f
--- /dev/null
+++ b/src/lib/evil/evil_fnmatch_private.h
@@ -0,0 +1,24 @@
+#ifndef __EVIL_FNMATCH_PRIVATE_H__
+#define __EVIL_FNMATCH_PRIVATE_H__
+
+
+typedef int e_bool;
+
+struct list_of_states
+{
+ size_t reserved;
+ size_t size;
+ size_t *states;
+ e_bool *has;
+};
+
+struct list_of_states *fnmatch_list_of_states_alloc(size_t n, size_t pattern_len);
+
+void fnmatch_list_of_states_free(struct list_of_states *lists, size_t n);
+
+void fnmatch_list_of_states_insert(struct list_of_states *list, size_t state);
+
+void fnmatch_list_of_states_clear(struct list_of_states *list);
+
+
+#endif /* __EVIL_FNMATCH_PRIVATE_H__ */
diff --git a/src/lib/evil/evil_inet.c b/src/lib/evil/evil_inet.c
new file mode 100644
index 0000000000..99ce14edc2
--- /dev/null
+++ b/src/lib/evil/evil_inet.c
@@ -0,0 +1,648 @@
+
+/*
+ * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (c) 1996,1999 by Internet Software Consortium.
+ *
+ * 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 ISC DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
+ */
+
+/*
+ * Modifications: Vincent Torri, for the integration in Evil
+ * - modification of the name of some functions
+ * * modification of the management of the error
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif /* HAVE_ERRNO_H */
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <winsock2.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include "evil_macro.h"
+#include "evil_inet.h"
+#include "evil_private.h"
+#define APICHAR char
+#include "evil_print.h"
+
+#ifndef EMSGSIZE
+# define EMSGSIZE WSAEMSGSIZE
+#endif
+
+#ifndef EAFNOSUPPORT
+# define EAFNOSUPPORT WSAEAFNOSUPPORT
+#endif
+
+#define SPRINTF(x) ((size_t)sprintf x)
+
+#define ERRNO ((int)GetLastError())
+#define SET_ERRNO(x) (SetLastError((DWORD)(x)))
+
+#define ISDIGIT(x) (isdigit((int) ((unsigned char)x)))
+#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
+#define ISUPPER(x) (isupper((int) ((unsigned char)x)))
+
+#define NS_IN6ADDRSZ 16
+#define NS_INT16SZ 2
+#define NS_INADDRSZ sizeof(IN_ADDR)
+
+
+struct ares_in6_addr {
+ union {
+ unsigned char _S6_u8[16];
+ } _S6_un;
+};
+
+const struct ares_in6_addr ares_in6addr_any = { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } };
+
+
+/*
+ * static int
+ * inet_net_pton_ipv4(src, dst, size)
+ * convert IPv4 network number from presentation to network format.
+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
+ * "size" is in bytes and describes "dst".
+ * return:
+ * number of bits, either imputed classfully or specified with /CIDR,
+ * or -1 if some failure occurred (check errno). ENOENT means it was
+ * not an IPv4 network specification.
+ * note:
+ * network byte order assumed. this means 192.5.5.240/28 has
+ * 0b11110000 in its fourth octet.
+ * note:
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid loosing the
+ * actual last winsock error. So use macro ERRNO to fetch the
+ * errno this funtion sets when returning (-1), not SOCKERRNO.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+static int
+inet_net_pton_ipv4(const char *src, unsigned char *dst, size_t size)
+{
+ static const char xdigits[] = "0123456789abcdef";
+ static const char digits[] = "0123456789";
+ int n, ch, tmp = 0, dirty, bits;
+ const unsigned char *odst = dst;
+
+ ch = *src++;
+ if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
+ && ISXDIGIT(src[1])) {
+ /* Hexadecimal: Eat nybble string. */
+ if (!size)
+ goto emsgsize;
+ dirty = 0;
+ src++; /* skip x or X. */
+ while ((ch = *src++) != '\0' && ISXDIGIT(ch)) {
+ if (ISUPPER(ch))
+ ch = tolower(ch);
+ n = (int)(strchr(xdigits, ch) - xdigits);
+ if (dirty == 0)
+ tmp = n;
+ else
+ tmp = (tmp << 4) | n;
+ if (++dirty == 2) {
+ if (!size--)
+ goto emsgsize;
+ *dst++ = (unsigned char) tmp;
+ dirty = 0;
+ }
+ }
+ if (dirty) { /* Odd trailing nybble? */
+ if (!size--)
+ goto emsgsize;
+ *dst++ = (unsigned char) (tmp << 4);
+ }
+ } else if (ISDIGIT(ch)) {
+ /* Decimal: eat dotted digit string. */
+ for (;;) {
+ tmp = 0;
+ do {
+ n = (int)(strchr(digits, ch) - digits);
+ tmp *= 10;
+ tmp += n;
+ if (tmp > 255)
+ goto enoent;
+ } while ((ch = *src++) != '\0' &&
+ ISDIGIT(ch));
+ if (!size--)
+ goto emsgsize;
+ *dst++ = (unsigned char) tmp;
+ if (ch == '\0' || ch == '/')
+ break;
+ if (ch != '.')
+ goto enoent;
+ ch = *src++;
+ if (!ISDIGIT(ch))
+ goto enoent;
+ }
+ } else
+ goto enoent;
+
+ bits = -1;
+ if (ch == '/' &&
+ ISDIGIT(src[0]) && dst > odst) {
+ /* CIDR width specifier. Nothing can follow it. */
+ ch = *src++; /* Skip over the /. */
+ bits = 0;
+ do {
+ n = (int)(strchr(digits, ch) - digits);
+ bits *= 10;
+ bits += n;
+ } while ((ch = *src++) != '\0' && ISDIGIT(ch));
+ if (ch != '\0')
+ goto enoent;
+ if (bits > 32)
+ goto emsgsize;
+ }
+
+ /* Firey death and destruction unless we prefetched EOS. */
+ if (ch != '\0')
+ goto enoent;
+
+ /* If nothing was written to the destination, we found no address. */
+ if (dst == odst)
+ goto enoent;
+ /* If no CIDR spec was given, infer width from net class. */
+ if (bits == -1) {
+ if (*odst >= 240) /* Class E */
+ bits = 32;
+ else if (*odst >= 224) /* Class D */
+ bits = 8;
+ else if (*odst >= 192) /* Class C */
+ bits = 24;
+ else if (*odst >= 128) /* Class B */
+ bits = 16;
+ else /* Class A */
+ bits = 8;
+ /* If imputed mask is narrower than specified octets, widen. */
+ if (bits < ((dst - odst) * 8))
+ bits = (int)(dst - odst) * 8;
+ /*
+ * If there are no additional bits specified for a class D
+ * address adjust bits to 4.
+ */
+ if (bits == 8 && *odst == 224)
+ bits = 4;
+ }
+ /* Extend network to cover the actual mask. */
+ while (bits > ((dst - odst) * 8)) {
+ if (!size--)
+ goto emsgsize;
+ *dst++ = '\0';
+ }
+ return (bits);
+
+ enoent:
+ SET_ERRNO(ENOENT);
+ return (-1);
+
+ emsgsize:
+ SET_ERRNO(EMSGSIZE);
+ return (-1);
+}
+
+static int
+getbits(const char *src, int *bitsp)
+{
+ static const char digits[] = "0123456789";
+ int n;
+ int val;
+ char ch;
+
+ val = 0;
+ n = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ pch = strchr(digits, ch);
+ if (pch != NULL) {
+ if (n++ != 0 && val == 0) /* no leading zeros */
+ return (0);
+ val *= 10;
+ val += (pch - digits);
+ if (val > 128) /* range */
+ return (0);
+ continue;
+ }
+ return (0);
+ }
+ if (n == 0)
+ return (0);
+ *bitsp = val;
+ return (1);
+}
+
+static int
+getv4(const char *src, unsigned char *dst, int *bitsp)
+{
+ static const char digits[] = "0123456789";
+ unsigned char *odst = dst;
+ int n;
+ unsigned int val;
+ char ch;
+
+ val = 0;
+ n = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ pch = strchr(digits, ch);
+ if (pch != NULL) {
+ if (n++ != 0 && val == 0) /* no leading zeros */
+ return (0);
+ val *= 10;
+ val += (pch - digits);
+ if (val > 255) /* range */
+ return (0);
+ continue;
+ }
+ if (ch == '.' || ch == '/') {
+ if (dst - odst > 3) /* too many octets? */
+ return (0);
+ *dst++ = (unsigned char)val;
+ if (ch == '/')
+ return (getbits(src, bitsp));
+ val = 0;
+ n = 0;
+ continue;
+ }
+ return (0);
+ }
+ if (n == 0)
+ return (0);
+ if (dst - odst > 3) /* too many octets? */
+ return (0);
+ *dst++ = (unsigned char)val;
+ return (1);
+}
+
+static int
+inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ unsigned int val;
+ int digits;
+ int bits;
+ size_t bytes;
+ int words;
+ int ipv4;
+
+ memset((tp = tmp), '\0', NS_IN6ADDRSZ);
+ endp = tp + NS_IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if (*src == ':')
+ if (*++src != ':')
+ goto enoent;
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ digits = 0;
+ bits = -1;
+ ipv4 = 0;
+ while ((ch = *src++) != '\0') {
+ const char *pch;
+
+ if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if (pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if (++digits > 4)
+ goto enoent;
+ saw_xdigit = 1;
+ continue;
+ }
+ if (ch == ':') {
+ curtok = src;
+ if (!saw_xdigit) {
+ if (colonp)
+ goto enoent;
+ colonp = tp;
+ continue;
+ } else if (*src == '\0')
+ goto enoent;
+ if (tp + NS_INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char)((val >> 8) & 0xff);
+ *tp++ = (unsigned char)(val & 0xff);
+ saw_xdigit = 0;
+ digits = 0;
+ val = 0;
+ continue;
+ }
+ if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
+ getv4(curtok, tp, &bits) > 0) {
+ tp += NS_INADDRSZ;
+ saw_xdigit = 0;
+ ipv4 = 1;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ if (ch == '/' && getbits(src, &bits) > 0)
+ break;
+ goto enoent;
+ }
+ if (saw_xdigit) {
+ if (tp + NS_INT16SZ > endp)
+ goto enoent;
+ *tp++ = (unsigned char)((val >> 8) & 0xff);
+ *tp++ = (unsigned char)(val & 0xff);
+ }
+ if (bits == -1)
+ bits = 128;
+
+ words = (bits + 15) / 16;
+ if (words < 2)
+ words = 2;
+ if (ipv4)
+ words = 8;
+ endp = tmp + 2 * words;
+
+ if (colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const ssize_t n = tp - colonp;
+ ssize_t i;
+
+ if (tp == endp)
+ goto enoent;
+ for (i = 1; i <= n; i++) {
+ *(endp - i) = *(colonp + n - i);
+ *(colonp + n - i) = 0;
+ }
+ tp = endp;
+ }
+ if (tp != endp)
+ goto enoent;
+
+ bytes = (bits + 7) / 8;
+ if (bytes > size)
+ goto emsgsize;
+ memcpy(dst, tmp, bytes);
+ return (bits);
+
+ enoent:
+ SET_ERRNO(ENOENT);
+ return (-1);
+
+ emsgsize:
+ SET_ERRNO(EMSGSIZE);
+ return (-1);
+}
+
+/*
+ * int
+ * inet_net_pton(af, src, dst, size)
+ * convert network number from presentation to network format.
+ * accepts hex octets, hex strings, decimal octets, and /CIDR.
+ * "size" is in bytes and describes "dst".
+ * return:
+ * number of bits, either imputed classfully or specified with /CIDR,
+ * or -1 if some failure occurred (check errno). ENOENT means it was
+ * not a valid network specification.
+ * note:
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid loosing the
+ * actual last winsock error. So use macro ERRNO to fetch the
+ * errno this funtion sets when returning (-1), not SOCKERRNO.
+ * author:
+ * Paul Vixie (ISC), June 1996
+ */
+static int
+ares_inet_net_pton(int af, const char *src, void *dst, size_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_net_pton_ipv4(src, dst, size));
+ case AF_INET6:
+ return (inet_net_pton_ipv6(src, dst, size));
+ default:
+ SET_ERRNO(EAFNOSUPPORT);
+ return (-1);
+ }
+}
+
+int
+evil_inet_pton(int af, const char *src, void *dst)
+{
+ int result;
+ size_t size;
+
+ if (af == AF_INET)
+ size = sizeof(struct in_addr);
+ else if (af == AF_INET6)
+ size = sizeof(struct ares_in6_addr);
+ else
+ {
+ SET_ERRNO(EAFNOSUPPORT);
+ return -1;
+ }
+ result = ares_inet_net_pton(af, src, dst, size);
+ if ((result == -1) && (ERRNO == ENOENT))
+ return 0;
+ return (result > -1 ? 1 : -1);
+}
+
+
+/* const char *
+ * inet_ntop4(src, dst, size)
+ * format an IPv4 address, more or less like inet_ntoa()
+ * return:
+ * `dst' (as a const)
+ * notes:
+ * (1) uses no statics
+ * (2) takes a unsigned char* not an in_addr as input
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop4(const unsigned char *src, char *dst, size_t size)
+{
+ static const char fmt[] = "%u.%u.%u.%u";
+ char tmp[sizeof "255.255.255.255"];
+
+ if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size)
+ {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/* const char *
+ * inet_ntop6(src, dst, size)
+ * convert IPv6 binary address into presentation (printable) format
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+inet_ntop6(const unsigned char *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+ char *tp;
+ struct {
+ long base;
+ long len;
+ } best, cur;
+ unsigned long words[NS_IN6ADDRSZ / NS_INT16SZ];
+ int i;
+
+ /*
+ * Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof(words));
+ for (i = 0; i < NS_IN6ADDRSZ; i++)
+ words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
+
+ best.base = -1;
+ cur.base = -1;
+ best.len = 0;
+ cur.len = 0;
+
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
+ {
+ if (words[i] == 0)
+ {
+ if (cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ }
+ else
+ {
+ if (cur.base != -1)
+ {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ }
+ if (cur.base != -1)
+ {
+ if (best.base == -1 || cur.len > best.len)
+ best = cur;
+ }
+ if (best.base != -1 && best.len < 2)
+ best.base = -1;
+
+ /*
+ * Format the result.
+ */
+ tp = tmp;
+ for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++)
+ {
+ /* Are we inside the best run of 0x00's? */
+ if (best.base != -1 && i >= best.base &&
+ i < (best.base + best.len))
+ {
+ if (i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+ /* Are we following an initial run of 0x00s or any real hex? */
+ if (i != 0)
+ *tp++ = ':';
+ /* Is this address an encapsulated IPv4? */
+ if (i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff)))
+ {
+ if (!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp)))
+ return (NULL);
+ tp += strlen(tp);
+ break;
+ }
+ tp += SPRINTF((tp, "%lx", words[i]));
+ }
+
+ /* Was it a trailing run of 0x00's? */
+ if (best.base != -1 && (best.base + best.len) == (NS_IN6ADDRSZ / NS_INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /*
+ * Check for overflow, copy, and we're done.
+ */
+ if ((size_t)(tp - tmp) > size)
+ {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return (dst);
+}
+
+/* char *
+ * inet_ntop(af, src, dst, size)
+ * convert a network format address to presentation format.
+ * return:
+ * pointer to presentation format address (`dst'), or NULL (see errno).
+ * note:
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid loosing the
+ * actual last winsock error. So use macro ERRNO to fetch the
+ * errno this funtion sets when returning NULL, not SOCKERRNO.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static const char *
+ares_inet_ntop(int af, const void *src, char *dst, size_t size)
+{
+ switch (af)
+ {
+ case AF_INET:
+ return (inet_ntop4(src, dst, size));
+ case AF_INET6:
+ return (inet_ntop6(src, dst, size));
+ default:
+ SET_ERRNO(EAFNOSUPPORT);
+ return (NULL);
+ }
+ /* NOTREACHED */
+}
+
+const char *evil_inet_ntop(int af, const char *src, void *dst, size_t size)
+{
+ const char *result;
+ result = ares_inet_ntop(af, src, dst, size);
+ if ((result == NULL) && (ERRNO == ENOSPC))
+ return NULL;
+ return result;
+}
diff --git a/src/lib/evil/evil_inet.h b/src/lib/evil/evil_inet.h
new file mode 100644
index 0000000000..b81b8ff715
--- /dev/null
+++ b/src/lib/evil/evil_inet.h
@@ -0,0 +1,149 @@
+
+/* Copyright (C) 2005 by Daniel Stenberg
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#ifndef __EVIL_INET_H__
+#define __EVIL_INET_H__
+
+
+/**
+ * @file evil_inet.h
+ * @brief The file that provides functions ported from Unix in arpa/inet.h.
+ * @defgroup Evil_Inet_Group Inet.h functions
+ *
+ * This header provides functions ported from Unix in arpa/inet.h.
+ *
+ * @{
+ */
+
+/**
+ * @brief Convert IPv4 and IPv6 addresses from text to binary form.
+ *
+ * @param af The address family.
+ * @param src The address to convert.
+ * @param dst The converted address structure.
+ * @return 1 on success, 0 or -1 otherwise.
+ *
+ * This function converts IPv4 and IPv6 addresses from @p src to the
+ * binary form @p dst. The following address families to pass to @p af
+ * are currently supported:
+ *
+ * <ul>
+ * <li>i AF_INET: @p src points to a character string containing an IPv4
+ * network address in dotted-decimal format, "ddd.ddd.ddd.ddd", where
+ * ddd is a decimal number of up to three digits in the range 0 to
+ * 255. The address is converted to a struct in_addr and copied to
+ * dst, which must be sizeof(struct in_addr) (4) bytes (32 bits) long.
+ * <li> AF_INET6: @p src points to a character string containing an
+ * IPv6 network address. The address is converted to a struct in6_addr
+ * and copied to dst, which must be sizeof(struct in6_addr) (16) bytes
+ * (128 bits) long. The allowed formats for IPv6 addresses follow
+ * these rules:
+ * <ol>
+ * <li>The preferred format is x:x:x:x:x:x:x:x. This form consists of
+ * eight hexadecimal numbers, each of which expresses a 16-bit value
+ * (i.e., each x can be up to 4 hex digits).
+ * <li>A series of contiguous zero values in the preferred format can
+ * be abbreviated to ::. Only one instance of :: can occur in an
+ * address. For example, the loopback address 0:0:0:0:0:0:0:1 can be
+ * abbreviated as ::1. The wildcard address, consisting of all zeros,
+ * can be written as ::.
+ * <li>An alternate format is useful for expressing IPv4-mapped IPv6
+ * addresses. This form is written as x:x:x:x:x:x:d.d.d.d, where the
+ * six leading xs are hexadecimal values that define the six
+ * most-significant 16-bit pieces of the address (i.e., 96 bits), and
+ * the ds express a value in dotted-decimal notation that defines the
+ * least significant 32 bits of the address. An example of such an
+ * address is :: FFFF:204.152.189.116.
+ * </ul>
+ * </ul>
+ * On success this function returns 1 (network address was successfully
+ * converted). 0 is returned if @p src does not contain a character
+ * string representing a valid network address in the specified
+ * address family. If af does not contain a valid address family, -1
+ * is returned and errno is set to EAFNOSUPPORT.
+ *
+ * @see evil_inet_ntop()
+ * @see inet_ntop()
+ *
+ * Conformity: POSIX.1-2001.
+ *
+ * Supported OS: Windows XP, CE.
+ *
+ */
+EAPI int evil_inet_pton(int af, const char *src, void *dst);
+
+/**
+ * @def inet_pton(x,y,z)
+ *
+ * Wrapper around evil_inet_pton().
+ */
+#define inet_pton(x,y,z) evil_inet_pton(x,y,z)
+
+/**
+ * @brief Convert IPv4 and IPv6 addresses from binary to text form.
+ *
+ * @param af The address family.
+ * @param src The address structure to convert.
+ * @param dst A buffer containing the converted string.
+ * @param size The size of the buffer.
+ * @return 1 on success, 0 otherwise.
+ *
+ * This function converts the network address structure @p src in the
+ * @p af address family into a character string. The resulting string
+ * is copied to the buffer pointed to by @p dst, which must be a
+ * non-NULL pointer. The caller specifies the number of bytes
+ * available in this buffer in the argument @p size. The following
+ * address families to pass to @p af are currently supported:
+ *
+ * @li AF_INET: @p src points to a struct in_addr (in network byte
+ * order) which is converted to an IPv4 network address in the
+ * dotted-decimal format, "ddd.ddd.ddd.ddd". The buffer @p dst must be
+ * at least INET_ADDRSTRLEN bytes long.
+ * @li AF_INET6: @p src points to a struct in6_addr (in network byte
+ * order) which is converted to a representation of this address in
+ * the most appropriate IPv6 network address format for this
+ * address. The buffer @p dst must be at least INET6_ADDRSTRLEN bytes
+ * long.
+ *
+ * On success, this function returns a non-NULL pointer to @p dst. NULL is
+ * returned if there was an error, with errno set to indicate the
+ * error.
+ *
+ * @see evil_inet_pton()
+ * @see inet_pton()
+ *
+ * Conformity: POSIX.1-2001.
+ *
+ * Supported OS: Windows XP, CE.
+ *
+ */
+EAPI const char *evil_inet_ntop(int af, const char *src, void *dst, size_t size);
+
+/**
+ * @def inet_ntop(x,y,z,s)
+ *
+ * Wrapper around evil_inet_ntop().
+ */
+#define inet_ntop(x,y,z,s) evil_inet_ntop(x,y,z,s)
+
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_INET_H__ */
diff --git a/src/lib/evil/evil_langinfo.c b/src/lib/evil/evil_langinfo.c
new file mode 100644
index 0000000000..32b1f41386
--- /dev/null
+++ b/src/lib/evil/evil_langinfo.c
@@ -0,0 +1,53 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "Evil.h"
+
+
+#ifndef __MINGW32CE__
+
+static char *
+replace(char *prev, char *value)
+{
+ if (!value)
+ return prev;
+
+ if (prev)
+ free (prev);
+ return strdup (value);
+}
+
+char *
+nl_langinfo(nl_item index)
+{
+ static char *result = NULL;
+ static char *nothing = "";
+
+ switch (index)
+ {
+ case CODESET:
+ {
+ char *p;
+ result = replace(result, setlocale(LC_CTYPE, NULL));
+ if (!(p = strrchr(result, '.')))
+ return nothing;
+
+ if ((++p - result) > 2)
+ strcpy(result, "cp");
+ else
+ *result = '\0';
+ strcat(result, p);
+
+ return result;
+ }
+ case RADIXCHAR:
+ {
+ return localeconv()->decimal_point;
+ }
+ }
+
+ return nothing;
+}
+
+#endif /* ! __MINGW32CE__ */
diff --git a/src/lib/evil/evil_langinfo.h b/src/lib/evil/evil_langinfo.h
new file mode 100644
index 0000000000..0e9485a5c1
--- /dev/null
+++ b/src/lib/evil/evil_langinfo.h
@@ -0,0 +1,41 @@
+#ifndef __EVIL_LANGINFO_H__
+#define __EVIL_LANGINFO_H__
+
+
+#ifndef __MINGW32CE__
+
+#include <locale.h>
+
+
+typedef int nl_item;
+
+#define __NL_ITEM( CATEGORY, INDEX ) ((CATEGORY << 16) | INDEX)
+#define __NL_ITEM_CATEGORY( ITEM ) (ITEM >> 16)
+#define __NL_ITEM_INDEX( ITEM ) (ITEM & 0xffff)
+
+enum {
+ /*
+ * LC_CTYPE category...
+ * Character set classification items.
+ */
+ _NL_CTYPE_CODESET = __NL_ITEM( LC_CTYPE, 0 ),
+ _NL_NUMERIC_RADIXCHAR = __NL_ITEM( LC_NUMERIC, 0 ),
+
+ /*
+ * Dummy entry, to terminate the list.
+ */
+ _NL_ITEM_CLASSIFICATION_END
+};
+
+/*
+ * Define the public aliases for the enumerated classification indices...
+ */
+# define CODESET _NL_CTYPE_CODESET
+# define RADIXCHAR _NL_NUMERIC_RADIXCHAR
+
+EAPI char *nl_langinfo(nl_item index);
+
+#endif /* __MINGW32CE__ */
+
+
+#endif /*__EVIL_LANGINFO_H__ */
diff --git a/src/lib/evil/evil_libgen.c b/src/lib/evil/evil_libgen.c
new file mode 100644
index 0000000000..7e98f74386
--- /dev/null
+++ b/src/lib/evil/evil_libgen.c
@@ -0,0 +1,103 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+
+#include "Evil.h"
+
+char _evil_basename_buf[PATH_MAX];
+char _evil_dirname_buf[PATH_MAX];
+
+char *
+evil_basename(char *path)
+{
+ char *p1;
+ char *p2;
+ size_t length;
+
+ /* path must begin by "?:\" or "?:/" */
+ if ((!path) || !evil_path_is_absolute(path))
+ {
+ memcpy(_evil_basename_buf, "C:\\", 4);
+ return _evil_basename_buf;
+ }
+
+ /* '/' --> '\\' */
+ length = strlen(path);
+ p1 = strdup(path);
+ if (!p1)
+ {
+ memcpy(_evil_basename_buf, "C:\\", 4);
+ return _evil_basename_buf;
+ }
+ p2 = p1;
+ while (*p2)
+ {
+ if (*p2 == '/') *p2 = '\\';
+ p2++;
+ }
+
+ /* remove trailing backslashes */
+ p2 = p1 + (length - 1);
+ if (*p2 == '\\')
+ {
+ while (*p2 == '\\')
+ p2--;
+ }
+ *(p2 + 1) = '\0';
+
+ p2 = strrchr(p1, '\\');
+ memcpy(_evil_basename_buf, p2 + 1, (p1 + length + 1) - p2);
+
+ free(p1);
+
+ return _evil_basename_buf;
+}
+
+char *
+evil_dirname(char *path)
+{
+ char *p1;
+ char *p2;
+ size_t length;
+
+ /* path must begin by "?:\" or "?:/" */
+ if ((!path) || !evil_path_is_absolute(path))
+ {
+ memcpy(_evil_dirname_buf, "C:\\", 4);
+ return _evil_dirname_buf;
+ }
+
+ /* '/' --> '\\' */
+ length = strlen(path);
+ p1 = strdup(path);
+ if (!p1)
+ {
+ memcpy(_evil_dirname_buf, "C:\\", 4);
+ return _evil_dirname_buf;
+ }
+ p2 = p1;
+ while (*p2)
+ {
+ if (*p2 == '/') *p2 = '\\';
+ p2++;
+ }
+
+ /* remove trailing backslashes */
+ p2 = p1 + (length - 1);
+ if (*p2 == '\\')
+ {
+ while (*p2 == '\\')
+ p2--;
+ }
+ *(p2 + 1) = '\0';
+
+ p2 = strrchr(p1, '\\');
+ *p2 = '\0';
+ memcpy(_evil_dirname_buf, p1, strlen(p1) + 1);
+
+ free(p1);
+
+ return _evil_dirname_buf;
+}
diff --git a/src/lib/evil/evil_libgen.h b/src/lib/evil/evil_libgen.h
new file mode 100644
index 0000000000..4ca977ce86
--- /dev/null
+++ b/src/lib/evil/evil_libgen.h
@@ -0,0 +1,88 @@
+#ifndef __EVIL_LIBGEN_H__
+#define __EVIL_LIBGEN_H__
+
+
+/**
+ * @file evil_libgen.h
+ * @brief The file that provides functions ported from Unix in libgen.h.
+ * @defgroup Evil_Libgen_Group Libgen.h functions.
+ *
+ * This header provides functions ported from Unix in libgen.h.
+ *
+ * @{
+ */
+
+/**
+ * @brief Parse the base name component of a path.
+ *
+ * @param path The path to parse.
+ * @return The component following the final '/'.
+ *
+ * This function parses @p path and returns its component following
+ * the final '\'. Trailing '\' are not taken into account. On Windows
+ * XP, @p path must beginning by a drive letter followed by ':/' or
+ * ':\', otherwise "C:\" is returned. All characters '/' are replaced by '\'. On
+ * error (memory allocation failure), "C:\" is returned, otherwise the
+ * component following the final '\' is returned as a statically
+ * allocated memory. Hence the returns value must not be freed.
+ *
+ * Concatenating the string returned by dirname(), a "\", and the
+ * string returned by basename() yields a complete pathname.
+ *
+ * @see evil_dirname()
+ * @see dirname()
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP.
+ */
+EAPI char *evil_basename(char *path);
+
+/**
+ * @def basename(p)
+ *
+ * Wrapper around evil_basename().
+ */
+#define basename(p) evil_basename(p)
+
+/**
+ * @brief Parse the dir name component of a path.
+ *
+ * @param path The path to parse.
+ * @return The component up to, but not including, the final '/'.
+ *
+ * This function parses @p path and returns its component up to, but
+ * not including, the final '/'. Trailing '\' are not taken into
+ * account. On Windows XP, @p path must beginning by a drive letter
+ * followed by ':/' or ':\', otherwise "C:\" is returned. All
+ * characters '/' are replaced by '\'. On error (memory allocation
+ * failure), "C:\" is returned, otherwise, the component up to, but
+ * not including, the final '/' is returned as a statically allocated
+ * memory. Hence the returns value must not be freed.
+ *
+ * Concatenating the string returned by dirname(), a "\", and the
+ * string returned by basename() yields a complete pathname.
+ *
+ * @see evil_basename()
+ * @see basename()
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP.
+ */
+EAPI char *evil_dirname(char *path);
+
+/**
+ * @def dirname(p)
+ *
+ * Wrapper around evil_dirname().
+ */
+#define dirname(p) evil_dirname(p)
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_LIBGEN_H__ */
diff --git a/src/lib/evil/evil_link_ce.c b/src/lib/evil/evil_link_ce.c
new file mode 100644
index 0000000000..17532cc4d6
--- /dev/null
+++ b/src/lib/evil/evil_link_ce.c
@@ -0,0 +1,90 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <shellapi.h>
+
+#include "Evil.h"
+#include "evil_private.h"
+
+
+/*
+ * Symbolic links and directory related functions
+ *
+ */
+
+
+/* REMARK: Windows has no symbolic link. */
+/* Nevertheless, it can create and read .lnk files */
+
+int
+symlink(const char *oldpath, const char *newpath)
+{
+ wchar_t *w_oldpath;
+ wchar_t *w_newpath;
+ BOOL res;
+
+ w_oldpath = evil_char_to_wchar(oldpath);
+ if (!w_oldpath)
+ return -1;
+
+ w_newpath = evil_char_to_wchar(newpath);
+ if (!w_newpath)
+ {
+ free(w_oldpath);
+ return -1;
+ }
+
+ res = SHCreateShortcut(w_newpath, w_oldpath);
+ if (!res)
+ _evil_last_error_display(__FUNCTION__);
+
+ free(w_oldpath);
+ free(w_newpath);
+
+ return res ? 0 : -1;
+}
+
+ssize_t
+readlink(const char *path, char *buf, size_t bufsiz)
+{
+ wchar_t *w_path;
+ wchar_t w_newpath[1024];
+ char *newpath;
+ size_t length;
+ BOOL res;
+
+ w_path = evil_char_to_wchar(path);
+ if (!w_path)
+ return -1;
+
+ res = SHGetShortcutTarget(w_path, w_newpath, 1024);
+ if (!res)
+ _evil_last_error_display(__FUNCTION__);
+
+ free(w_path);
+
+ if (!res)
+ return -1;
+
+ newpath = evil_wchar_to_char(w_newpath);
+ if (!newpath)
+ return -1;
+
+ /* That stupid SHGetShortcutTarget add " around the file name... */
+ length = strlen(newpath) - 2;
+ if (length > bufsiz)
+ length = bufsiz;
+
+ memcpy(buf, newpath + 1, length);
+
+ free(newpath);
+
+ return length;
+}
diff --git a/src/lib/evil/evil_link_xp.cpp b/src/lib/evil/evil_link_xp.cpp
new file mode 100644
index 0000000000..675908f75b
--- /dev/null
+++ b/src/lib/evil/evil_link_xp.cpp
@@ -0,0 +1,151 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif /* HAVE_ERRNO_H */
+
+#include <shlobj.h>
+#include <objidl.h>
+#include <cstdio>
+
+#include "Evil.h"
+
+
+/*
+ * Symbolic links and directory related functions
+ *
+ */
+
+
+/* REMARK: Windows has no symbolic link. */
+/* Nevertheless, it can create and read .lnk files */
+int
+symlink(const char *oldpath, const char *newpath)
+{
+ char fullname[PATH_MAX];
+ wchar_t *wnewpath;
+ IShellLink *pISL;
+ IPersistFile *pIPF;
+ HRESULT res;
+ size_t size;
+
+ realpath(oldpath, fullname);
+
+ res = CoInitialize(NULL);
+ if (FAILED(res))
+ {
+ if (res == E_OUTOFMEMORY)
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (FAILED(CoCreateInstance(CLSID_ShellLink,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IShellLink,
+ (void **)&pISL)))
+ goto no_instance;
+
+ if (FAILED(pISL->SetPath(fullname)))
+ goto no_setpath;
+
+ if (FAILED(pISL->QueryInterface(IID_IPersistFile, (void **)&pIPF)))
+ goto no_queryinterface;
+
+ size = mbstowcs(NULL, newpath, 0);
+ wnewpath = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
+ if (!wnewpath)
+ goto malloc_failure;
+ if (mbstowcs(wnewpath, newpath, size + 1) == (size_t)(-1))
+ goto translation_failure;
+ if (FAILED(pIPF->Save(wnewpath, FALSE)))
+ goto no_save;
+
+ free(wnewpath);
+ pIPF->Release();
+ pISL->Release();
+ CoUninitialize();
+
+ return 0;
+
+ no_save:
+ translation_failure:
+ malloc_failure:
+ pIPF->Release();
+ no_queryinterface:
+ no_setpath:
+ pISL->Release();
+ no_instance:
+ CoUninitialize();
+ return -1;
+}
+
+ssize_t
+readlink(const char *path, char *buf, size_t bufsiz)
+{
+ wchar_t *wpath;
+ char new_path[PATH_MAX];
+ IShellLink *pISL;
+ IPersistFile *pIPF;
+ size_t length;
+ HRESULT res;
+ size_t size;
+
+ res = CoInitialize(NULL);
+ if (FAILED(res))
+ {
+ if (res == E_OUTOFMEMORY)
+ errno = ENOMEM;
+ return -1;
+ }
+
+ if (FAILED(CoCreateInstance(CLSID_ShellLink,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IShellLink,
+ (void **)&pISL)))
+ goto couninitialize;
+
+ if (FAILED(pISL->QueryInterface(IID_IPersistFile, (void **)&pIPF)))
+ goto release_shell_link;
+
+ size = mbstowcs(NULL, path, 0);
+ wpath = (wchar_t *)malloc((size + 1) * sizeof(wchar_t));
+ if (!wpath)
+ goto release_persist_file;
+
+ mbstowcs(wpath, path, size + 1);
+ if (FAILED(pIPF->Load(wpath, STGM_READ)))
+ goto free_wpath;
+
+ if (FAILED(pISL->Resolve(NULL, SLR_UPDATE | SLR_NO_UI)))
+ goto free_wpath;
+
+ if (FAILED(pISL->GetPath(new_path, PATH_MAX, NULL, 0)))
+ goto free_wpath;
+
+ length = strlen(new_path);
+ if (length > bufsiz)
+ length = bufsiz;
+
+ memcpy(buf, new_path, length);
+
+ free(wpath);
+ pISL->Release();
+ pIPF->Release();
+ CoUninitialize();
+
+ return length;
+
+ free_wpath:
+ free(wpath);
+ release_persist_file:
+ pIPF->Release();
+ release_shell_link:
+ pISL->Release();
+ couninitialize:
+ CoUninitialize();
+ return -1;
+}
diff --git a/src/lib/evil/evil_macro.h b/src/lib/evil/evil_macro.h
new file mode 100644
index 0000000000..b2500d33c7
--- /dev/null
+++ b/src/lib/evil/evil_macro.h
@@ -0,0 +1,193 @@
+#ifndef __EVIL_MACRO_H__
+#define __EVIL_MACRO_H__
+
+
+#ifndef __cdecl
+# define EVIL_CDECL_IS_DEFINED
+# ifdef __GNUC__
+# define __cdecl __attribute__((__cdecl__))
+# else
+# define __cdecl
+# endif
+#endif /* __cdecl */
+
+
+#ifdef EAPI
+# undef EAPI
+#endif /* EAPI */
+
+#ifdef _WIN32
+# ifdef EFL_EVIL_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_EVIL_BUILD */
+#endif /* _WIN32 */
+
+
+#ifndef __EVIL_GNUC_PREREQ
+# if defined __GNUC__ && defined __GNUC_MINOR__
+# define __EVIL_GNUC_PREREQ( major, minor )\
+ (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
+# else
+# define __EVIL_GNUC_PREREQ( major, minor )
+# endif
+#endif /* __EVIL_GNUC_PREREQ */
+
+
+#ifndef __EVIL_NOTHROW
+# if __EVIL_GNUC_PREREQ( 3, 3 )
+# define __EVIL_NOTHROW __attribute__((__nothrow__))
+# else
+# define __EVIL_NOTHROW
+# endif
+#endif /* __EVIL_NOTHROW */
+
+
+#ifndef __EVIL_PRINTF
+# if __EVIL_GNUC_PREREQ( 2, 4 )
+# define __EVIL_PRINTF(fmt, arg) __attribute__((__format__ (__gnu_printf__, fmt, arg)))
+# else
+# define __EVIL_PRINTF(fmt, arg)
+# endif
+#endif /* __EVIL_PRINTF */
+
+
+#ifndef PATH_MAX
+# define PATH_MAX MAX_PATH
+#endif /* PATH_MAX */
+#ifdef fprintf
+# undef fprintf
+#endif
+
+#ifdef printf
+# undef printf
+#endif
+
+#ifdef sprintf
+# undef sprintf
+#endif
+
+#ifdef snprintf
+# undef snprintf
+#endif
+
+#ifdef vfprintf
+# undef vfprintf
+#endif
+
+#ifdef vprintf
+# undef vprintf
+#endif
+
+#ifdef vsprintf
+# undef vsprintf
+#endif
+
+#ifdef vsnprintf
+# undef vsnprintf
+#endif
+
+#ifdef fscanf
+# undef fscanf
+#endif
+
+#ifdef scanf
+# undef scanf
+#endif
+
+#ifdef sscanf
+# undef sscanf
+#endif
+
+#ifdef vfscanf
+# undef vfscanf
+#endif
+
+#ifdef vscanf
+# undef vscanf
+#endif
+
+#ifdef vsscanf
+# undef vsscanf
+#endif
+
+#ifdef asprintf
+# undef asprintf
+#endif
+
+#ifdef vasprintf
+# undef vasprintf
+#endif
+
+
+#if defined(_INTTYPES_H_) && defined(PRId64)
+
+#undef PRId64
+#undef PRIdLEAST64
+#undef PRIdFAST64
+#undef PRIdMAX
+#undef PRIi64
+#undef PRIiLEAST64
+#undef PRIiFAST64
+#undef PRIiMAX
+#undef PRIo64
+#undef PRIoLEAST64
+#undef PRIoFAST64
+#undef PRIoMAX
+#undef PRIu64
+#undef PRIuLEAST64
+#undef PRIuFAST64
+#undef PRIuMAX
+#undef PRIx64
+#undef PRIxLEAST64
+#undef PRIxFAST64
+#undef PRIxMAX
+#undef PRIX64
+#undef PRIXLEAST64
+#undef PRIXFAST64
+#undef PRIXMAX
+
+#undef SCNd64
+#undef SCNdLEAST64
+#undef SCNdFAST64
+#undef SCNdMAX
+#undef SCNi64
+#undef SCNiLEAST64
+#undef SCNiFAST64
+#undef SCNiMAX
+#undef SCNo64
+#undef SCNoLEAST64
+#undef SCNoFAST64
+#undef SCNoMAX
+#undef SCNx64
+#undef SCNxLEAST64
+#undef SCNxFAST64
+#undef SCNxMAX
+#undef SCNu64
+#undef SCNuLEAST64
+#undef SCNuFAST64
+#undef SCNuMAX
+
+#ifdef _WIN64
+#undef PRIdPTR
+#undef PRIiPTR
+#undef PRIoPTR
+#undef PRIuPTR
+#undef PRIxPTR
+#undef PRIXPTR
+
+#undef SCNdPTR
+#undef SCNiPTR
+#undef SCNoPTR
+#undef SCNxPTR
+#undef SCNuPTR
+#endif /* _WIN64 */
+
+#endif /* defined(_INTTYPES_H_) && defined(PRId64) */
+
+#endif /* __EVIL_MACRO_H__ */
diff --git a/src/lib/evil/evil_macro_pop.h b/src/lib/evil/evil_macro_pop.h
new file mode 100644
index 0000000000..a82818da9b
--- /dev/null
+++ b/src/lib/evil/evil_macro_pop.h
@@ -0,0 +1,93 @@
+#ifndef __EVIL_MACRO_POP_H__
+#define __EVIL_MACRO_POP_H__
+
+
+#ifdef EVIL_CDECL_IS_DEFINED
+# undef __cdecl
+# undef EVIL_CDECL_IS_DEFINED
+#endif
+
+#define fprintf _evil_fprintfa
+#define printf _evil_printfa
+#define snprintf _evil_snprintfa
+#define sprintf _evil_sprintfa
+#define vfprintf _evil_vfprintfa
+#define vprintf _evil_vprintfa
+#define vsnprintf _evil_vsnprintfa
+#define vsprintf _evil_vsprintfa
+
+#define fscanf _evil_fscanf
+#define scanf _evil_scanf
+#define sscanf _evil_sscanf
+#define vfscanf _evil_vfscanf
+#define vscanf _evil_vscanf
+#define vsscanf _evil_vsscanf
+
+#define asprintf _evil_asprintf
+#define vasprintf _evil_vasprintf
+
+/* Redefine to GNU specific PRI... and SCN... macros. */
+
+#define PRId64 "lld"
+#define PRIdLEAST64 "lld"
+#define PRIdFAST64 "lld"
+#define PRIdMAX "lld"
+#define PRIi64 "lli"
+#define PRIiLEAST64 "lli"
+#define PRIiFAST64 "lli"
+#define PRIiMAX "lli"
+#define PRIo64 "llo"
+#define PRIoLEAST64 "llo"
+#define PRIoFAST64 "llo"
+#define PRIoMAX "llo"
+#define PRIu64 "llu"
+#define PRIuLEAST64 "llu"
+#define PRIuFAST64 "llu"
+#define PRIuMAX "llu"
+#define PRIx64 "llx"
+#define PRIxLEAST64 "llx"
+#define PRIxFAST64 "llx"
+#define PRIxMAX "llx"
+#define PRIX64 "llX"
+#define PRIXLEAST64 "llX"
+#define PRIXFAST64 "llX"
+#define PRIXMAX "llX"
+
+#define SCNd64 "lld"
+#define SCNdLEAST64 "lld"
+#define SCNdFAST64 "lld"
+#define SCNdMAX "lld"
+#define SCNi64 "lli"
+#define SCNiLEAST64 "lli"
+#define SCNiFAST64 "lli"
+#define SCNiMAX "lli"
+#define SCNo64 "llo"
+#define SCNoLEAST64 "llo"
+#define SCNoFAST64 "llo"
+#define SCNoMAX "llo"
+#define SCNx64 "llx"
+#define SCNxLEAST64 "llx"
+#define SCNxFAST64 "llx"
+#define SCNxMAX "llx"
+#define SCNu64 "llu"
+#define SCNuLEAST64 "llu"
+#define SCNuFAST64 "llu"
+#define SCNuMAX "llu"
+
+#ifdef _WIN64
+#define PRIdPTR "lld"
+#define PRIiPTR "lli"
+#define PRIoPTR "llo"
+#define PRIuPTR "llu"
+#define PRIxPTR "llx"
+#define PRIXPTR "llX"
+
+#define SCNdPTR "lld"
+#define SCNiPTR "lli"
+#define SCNoPTR "llo"
+#define SCNxPTR "llx"
+#define SCNuPTR "llu"
+#endif /* _WIN64 */
+
+
+#endif /* __EVIL_MACRO_POP_H__ */
diff --git a/src/lib/evil/evil_main.c b/src/lib/evil/evil_main.c
new file mode 100644
index 0000000000..ee1eb1d113
--- /dev/null
+++ b/src/lib/evil/evil_main.c
@@ -0,0 +1,74 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <winsock2.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include "Evil.h"
+#include "evil_private.h"
+
+
+static int _evil_init_count = 0;
+
+extern LONGLONG _evil_time_freq;
+extern LONGLONG _evil_time_count;
+extern long _evil_time_second;
+
+int
+evil_init(void)
+{
+ SYSTEMTIME st;
+ LARGE_INTEGER freq;
+ LARGE_INTEGER count;
+ WORD second = 59;
+
+ if (++_evil_init_count != 1)
+ return _evil_init_count;
+
+ if (!QueryPerformanceFrequency(&freq))
+ return 0;
+
+ _evil_time_freq = freq.QuadPart;
+
+ /* be sure that second + 1 != 0 */
+ while (second == 59)
+ {
+ GetSystemTime(&st);
+ second = st.wSecond;
+ }
+
+ /* retrieve the tick corresponding to the time we retrieve above */
+ while (1)
+ {
+ GetSystemTime(&st);
+ QueryPerformanceCounter(&count);
+ if (st.wSecond == second + 1)
+ break;
+ }
+
+ _evil_time_second = _evil_systemtime_to_time(st);
+ if (_evil_time_second < 0)
+ return --_evil_init_count;
+
+ _evil_time_count = count.QuadPart;
+
+ if (!evil_sockets_init())
+ return --_evil_init_count;
+
+ return _evil_init_count;
+}
+
+int
+evil_shutdown(void)
+{
+ if (--_evil_init_count != 0)
+ return _evil_init_count;
+
+ evil_sockets_shutdown();
+
+ return _evil_init_count;
+}
diff --git a/src/lib/evil/evil_main.h b/src/lib/evil/evil_main.h
new file mode 100644
index 0000000000..157e6028b7
--- /dev/null
+++ b/src/lib/evil/evil_main.h
@@ -0,0 +1,52 @@
+#ifndef __EVIL_MAIN_H__
+#define __EVIL_MAIN_H__
+
+
+/**
+ * @file evil_main.h
+ * @brief The file that provides functions to initialize and shut down Evil.
+ * @defgroup Evil_Main_Group Main
+ *
+ * This header provides functions to initialize and shut down the Evil
+ * library.
+ *
+ * @{
+ */
+
+
+/**
+ * @brief Initialize the Evil library.
+ *
+ * This function initializes the Evil library. It must be called before
+ * using evil_time_get(), gettimeofday() or pipe(). It returns 0 on
+ * failure, otherwise it returns the number of times it has already been
+ * called.
+ *
+ * When Evil is not used anymore, call evil_shutdown() to shut down
+ * the Evil library.
+ */
+EAPI int evil_init(void);
+
+/**
+ * @brief Shut down the Evil library.
+ *
+ * @return 0 when the Evil library is completely shut down, 1 or
+ * greater otherwise.
+ *
+ * This function shuts down the Evil library. It returns 0 when it has
+ * been called the same number of times than evil_init().
+ *
+ * Once this function succeeds (that is, @c 0 is returned), you must
+ * not call any of the Evil function listed in evil_init()
+ * documentation anymore . You must call evil_init() again to use these
+ * functions again.
+ */
+EAPI int evil_shutdown(void);
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_MAIN_H__ */
diff --git a/src/lib/evil/evil_mman.c b/src/lib/evil/evil_mman.c
new file mode 100644
index 0000000000..8898357cfc
--- /dev/null
+++ b/src/lib/evil/evil_mman.c
@@ -0,0 +1,234 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#ifndef _MSC_VER
+# include <unistd.h>
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+# include <io.h>
+
+#include "evil_macro.h"
+#include "sys/mman.h"
+#include "evil_util.h"
+#include "evil_private.h"
+#define APICHAR char
+#include "evil_print.h"
+
+#ifdef __MINGW32CE__
+# define _get_osfhandle(FILEDES) ((long)FILEDES)
+#endif /* __MINGW32CE__ */
+
+
+/***** API *****/
+
+
+void *
+mmap(void *addr __UNUSED__,
+ size_t len,
+ int prot,
+ int flags,
+ int fd,
+ off_t offset)
+{
+ OSVERSIONINFO os_version;
+
+ os_version.dwOSVersionInfoSize = sizeof(os_version);
+ if (!GetVersionEx(&os_version))
+ {
+ char *str;
+
+ str = evil_last_error_get();
+ fprintf(stderr, "[Evil] [mmap] GetVersionEx failed: %s\n", str);
+ free(str);
+
+ return MAP_FAILED;
+ }
+
+#ifdef _WIN32_WCE
+ if ((os_version.dwPlatformId == VER_PLATFORM_WIN32_CE) &&
+ (os_version.dwMajorVersion < 5))
+ {
+ void *data;
+ size_t size;
+
+ data = malloc(len);
+ if (!data)
+ {
+ fprintf (stderr, "[Evil] [mmap] malloc failed\n");
+ return MAP_FAILED;
+ }
+
+ size = read(fd, data, len);
+ if (size != len)
+ {
+ fprintf (stderr, "[Evil] [mmap] read failed\n");
+ free(data);
+ return MAP_FAILED;
+ }
+
+ if (lseek(fd, 0, SEEK_SET) == -1)
+ {
+ fprintf (stderr, "[Evil] [mmap] lseek failed\n");
+ free(data);
+ return MAP_FAILED;
+ }
+
+ return data;
+ }
+ else
+#endif /* ! _WIN32_WCE */
+ {
+ HANDLE fm;
+ DWORD protect = PAGE_NOACCESS;
+ DWORD acs = 0;
+ HANDLE handle;
+ void *data;
+
+ /* support only MAP_SHARED */
+ if (!(flags & MAP_SHARED))
+ return MAP_FAILED;
+
+ if (prot & PROT_EXEC)
+ {
+ if (prot & PROT_READ)
+ {
+ if (prot & PROT_WRITE)
+ protect = PAGE_EXECUTE_READWRITE;
+ else
+ protect = PAGE_EXECUTE_READ;
+ }
+ else
+ {
+ if (prot & PROT_WRITE)
+ protect = PAGE_EXECUTE_WRITECOPY;
+ else
+ protect = PAGE_EXECUTE;
+ }
+ }
+ else
+ {
+ if (prot & PROT_READ)
+ {
+ if (prot & PROT_WRITE)
+ protect = PAGE_READWRITE;
+ else
+ protect = PAGE_READONLY;
+ }
+ else if (prot & PROT_WRITE)
+ protect = PAGE_WRITECOPY;
+ }
+
+ handle = (HANDLE)_get_osfhandle(fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ fprintf(stderr, "[Evil] [mmap] _get_osfhandle failed\n");
+
+ return MAP_FAILED;
+ }
+
+ fm = CreateFileMapping(handle, NULL, protect, 0, 0, NULL);
+ if (!fm)
+ {
+ char *str;
+
+ str = evil_last_error_get();
+ fprintf(stderr, "[Evil] [mmap] CreateFileMapping failed: %s\n", str);
+ free(str);
+
+ return MAP_FAILED;
+ }
+
+ if (protect & PAGE_READWRITE)
+ acs = FILE_MAP_ALL_ACCESS;
+ if (protect & PAGE_WRITECOPY)
+ acs = FILE_MAP_COPY;
+#if 0
+ if (protect & (PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_READ))
+ acs = FILE_MAP_EXECUTE;
+#endif
+ if (protect & (PAGE_READWRITE | PAGE_READONLY))
+ acs = FILE_MAP_READ;
+ else
+ {
+ if (protect & PAGE_READWRITE)
+ acs = FILE_MAP_WRITE;
+ }
+
+ data = MapViewOfFile(fm,
+ acs,
+ offset & 0xffff0000,
+ offset & 0x0000ffff,
+ len);
+ CloseHandle(fm);
+
+ if (!data)
+ {
+ char *str;
+
+ str = evil_last_error_get();
+ fprintf(stderr, "[Evil] [mmap] MapViewOfFile failed: %s\n", str);
+ free(str);
+
+ return MAP_FAILED;
+ }
+
+ return data;
+ }
+}
+
+int
+munmap(void *addr,
+ size_t len __UNUSED__)
+{
+#ifdef _WIN32_WCE
+ OSVERSIONINFO os_version;
+
+ os_version.dwOSVersionInfoSize = sizeof(os_version);
+ if (!GetVersionEx(&os_version))
+ {
+ char *str;
+
+ str = evil_last_error_get();
+ fprintf(stderr, "[Evil] [munmap] GetVersionEx failed: %s\n", str);
+ free(str);
+
+ return -1;
+ }
+
+ if ((os_version.dwPlatformId == VER_PLATFORM_WIN32_CE) &&
+ (os_version.dwMajorVersion < 5))
+ {
+ if (addr && (addr != MAP_FAILED))
+ free(addr);
+
+ return 0;
+ }
+ else
+#endif /* ! _WIN32_WCE */
+ {
+ BOOL res;
+
+ res = UnmapViewOfFile(addr);
+ if (!res)
+ {
+ char *str;
+
+ str = evil_last_error_get();
+ fprintf(stderr, "[Evil] [munmap] UnmapViewOfFile failed: %s\n", str);
+ free(str);
+ }
+
+ return (res == 0) ? -1 : 0;
+ }
+}
diff --git a/src/lib/evil/evil_pformat.h b/src/lib/evil/evil_pformat.h
new file mode 100644
index 0000000000..ad9b61e024
--- /dev/null
+++ b/src/lib/evil/evil_pformat.h
@@ -0,0 +1,61 @@
+#ifndef __EVIL_PRIVATE_H__
+#define __EVIL_PRIVATE_H__
+
+
+#include "evil_macro.h"
+
+
+#ifdef __BUILD_WIDEAPI
+#define APICHAR wchar_t
+#else
+#define APICHAR char
+#endif
+
+/* The following are the declarations specific to the `pformat' API...
+ */
+#define PFORMAT_TO_FILE 0x1000
+#define PFORMAT_NOLIMIT 0x2000
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#ifdef __BUILD_WIDEAPI
+# define __fputc(X,STR) fputwc((wchar_t) (X), (STR))
+# define _evil_pformat _evil_pformatw
+
+# define _evil_fprintf _evil_fprintfw
+# define _evil_printf _evil_printfw
+# define _evil_snprintf _evil_snprintfw
+# define _evil_sprintf _evil_sprintfw
+
+# define _evil_vfprintf _evil_vfprintfw
+# define _evil_vprintf _evil_vprintfw
+# define _evil_vsnprintf _evil_vsnprintfw
+# define _evil_vsprintf _evil_vsprintfw
+#else
+# define __fputc(X,STR) fputc((X), (STR))
+# define _evil_pformat _evil_pformata
+
+# define _evil_fprintf _evil_fprintfa
+# define _evil_printf _evil_printfa
+# define _evil_snprintf _evil_snprintfa
+# define _evil_sprintf _evil_sprintfa
+
+# define _evil_vfprintf _evil_vfprintfa
+# define _evil_vprintf _evil_vprintfa
+# define _evil_vsnprintf _evil_vsnprintfa
+# define _evil_vsprintf _evil_vsprintfa
+#endif
+
+int __cdecl _evil_pformat(int, void *, int, const APICHAR *, va_list) __EVIL_NOTHROW;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __EVIL_PRIVATE_H__ */
diff --git a/src/lib/evil/evil_pformata.c b/src/lib/evil/evil_pformata.c
new file mode 100644
index 0000000000..ee1d68e772
--- /dev/null
+++ b/src/lib/evil/evil_pformata.c
@@ -0,0 +1,2493 @@
+/* pformat.c
+ *
+ * $Id: pformat.c,v 1.9 2011/01/07 22:57:00 keithmarshall Exp $
+ *
+ * Provides a core implementation of the formatting capabilities
+ * common to the entire `printf()' family of functions; it conforms
+ * generally to C99 and SUSv3/POSIX specifications, with extensions
+ * to support Microsoft's non-standard format specifications.
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ *
+ * This is free software. You may redistribute and/or modify it as you
+ * see fit, without restriction of copyright.
+ *
+ * This software is provided "as is", in the hope that it may be useful,
+ * but WITHOUT WARRANTY OF ANY KIND, not even any implied warranty of
+ * MERCHANTABILITY, nor of FITNESS FOR ANY PARTICULAR PURPOSE. At no
+ * time will the author accept any form of liability for any damages,
+ * however caused, resulting from the use of this software.
+ *
+ * The elements of this implementation which deal with the formatting
+ * of floating point numbers, (i.e. the `%e', `%E', `%f', `%F', `%g'
+ * and `%G' format specifiers, but excluding the hexadecimal floating
+ * point `%a' and `%A' specifiers), make use of the `__gdtoa' function
+ * written by David M. Gay, and are modelled on his sample code, which
+ * has been deployed under its accompanying terms of use:--
+ *
+ ******************************************************************
+ * Copyright (C) 1997, 1999, 2001 Lucent Technologies
+ * All Rights Reserved
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation for any purpose and without fee is hereby
+ * granted, provided that the above copyright notice appear in all
+ * copies and that both that the copyright notice and this
+ * permission notice and warranty disclaimer appear in supporting
+ * documentation, and that the name of Lucent or any of its entities
+ * not be used in advertising or publicity pertaining to
+ * distribution of the software without specific, written prior
+ * permission.
+ *
+ * LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+ * IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+ * SPECIAL, 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.
+ ******************************************************************
+ *
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <locale.h>
+#include <wchar.h>
+#include <math.h>
+
+/* FIXME: The following belongs in values.h, but current MinGW
+ * has nothing useful there! OTOH, values.h is not a standard
+ * header, and it's use may be considered obsolete; perhaps it
+ * is better to just keep these definitions here.
+ */
+#ifndef _VALUES_H
+/*
+ * values.h
+ *
+ */
+#define _VALUES_H
+
+#include <limits.h>
+
+#define _TYPEBITS(type) (sizeof(type) * CHAR_BIT)
+
+#define LLONGBITS _TYPEBITS(long long)
+
+#endif /* !defined _VALUES_H -- end of file */
+
+#include "evil_pformat.h"
+#include "gdtoa/gdtoa.h"
+
+/* Bit-map constants, defining the internal format control
+ * states, which propagate through the flags.
+ */
+#define PFORMAT_GROUPED 0x1000
+#define PFORMAT_HASHED 0x0800
+#define PFORMAT_LJUSTIFY 0x0400
+#define PFORMAT_ZEROFILL 0x0200
+
+#define PFORMAT_JUSTIFY (PFORMAT_LJUSTIFY | PFORMAT_ZEROFILL)
+#define PFORMAT_IGNORE -1
+
+#define PFORMAT_SIGNED 0x01C0
+#define PFORMAT_POSITIVE 0x0100
+#define PFORMAT_NEGATIVE 0x0080
+#define PFORMAT_ADDSPACE 0x0040
+
+#define PFORMAT_XCASE 0x0020
+
+#define PFORMAT_LDOUBLE 0x0004
+
+/* `%o' format digit extraction mask, and shift count...
+ * (These are constant, and do not propagate through the flags).
+ */
+#define PFORMAT_OMASK 0x0007
+#define PFORMAT_OSHIFT 0x0003
+
+/* `%x' and `%X' format digit extraction mask, and shift count...
+ * (These are constant, and do not propagate through the flags).
+ */
+#define PFORMAT_XMASK 0x000F
+#define PFORMAT_XSHIFT 0x0004
+
+/* The radix point character, used in floating point formats, is
+ * localised on the basis of the active LC_NUMERIC locale category.
+ * It is stored locally, as a `wchar_t' entity, which is converted
+ * to a (possibly multibyte) character on output. Initialisation
+ * of the stored `wchar_t' entity, together with a record of its
+ * effective multibyte character length, is required each time
+ * `__pformat()' is entered, (static storage would not be thread
+ * safe), but this initialisation is deferred until it is actually
+ * needed; on entry, the effective character length is first set to
+ * the following value, (and the `wchar_t' entity is zeroed), to
+ * indicate that a call of `localeconv()' is needed, to complete
+ * the initialisation.
+ */
+#define PFORMAT_RPINIT -3
+
+/* The floating point format handlers return the following value
+ * for the radix point position index, when the argument value is
+ * infinite, or not a number.
+ */
+#define PFORMAT_INFNAN -32768
+
+#ifdef _WIN32
+/*
+ * The Microsoft standard for printing `%e' format exponents is
+ * with a minimum of three digits, unless explicitly set otherwise,
+ * by a prior invocation of the `_set_output_format()' function.
+ *
+ * The following macro allows us to replicate this behaviour.
+ */
+# define PFORMAT_MINEXP __pformat_exponent_digits()
+ /*
+ * However, this feature is unsupported for versions of the
+ * MSVC runtime library prior to msvcr80.dll, and by default,
+ * MinGW uses an earlier version, (equivalent to msvcr60.dll),
+ * for which `_TWO_DIGIT_EXPONENT' will be undefined.
+ */
+# ifndef _TWO_DIGIT_EXPONENT
+ /*
+ * This hack works around the lack of the `_set_output_format()'
+ * feature, when supporting versions of the MSVC runtime library
+ * prior to msvcr80.dll; it simply enforces Microsoft's original
+ * convention, for all cases where the feature is unsupported.
+ */
+# define _get_output_format() 0
+# define _TWO_DIGIT_EXPONENT 1
+# endif
+/*
+ * Irrespective of the MSVCRT version supported, *we* will add
+ * an additional capability, through the following inline function,
+ * which will allow the user to choose his own preferred default
+ * for `PRINTF_EXPONENT_DIGITS', through the simple expedient
+ * of defining it as an environment variable.
+ */
+static
+int __pformat_exponent_digits( void )
+{
+ char *exponent_digits = getenv( "PRINTF_EXPONENT_DIGITS" );
+ return ((exponent_digits != NULL) && ((unsigned)(*exponent_digits - '0') < 3))
+ || (_get_output_format() & _TWO_DIGIT_EXPONENT)
+ ? 2
+ : 3
+ ;
+}
+#else
+/*
+ * When we don't care to mimic Microsoft's standard behaviour,
+ * we adopt the C99/POSIX standard of two digit exponents.
+ */
+# define PFORMAT_MINEXP 2
+#endif
+
+typedef union
+{
+ /* A data type agnostic representation,
+ * for printf arguments of any integral data type...
+ */
+ signed long __pformat_long_t;
+ signed long long __pformat_llong_t;
+ unsigned long __pformat_ulong_t;
+ unsigned long long __pformat_ullong_t;
+ unsigned short __pformat_ushort_t;
+ unsigned char __pformat_uchar_t;
+ signed short __pformat_short_t;
+ signed char __pformat_char_t;
+ void * __pformat_ptr_t;
+} __pformat_intarg_t;
+
+typedef enum
+{
+ /* Format interpreter state indices...
+ * (used to identify the active phase of format string parsing).
+ */
+ PFORMAT_INIT = 0,
+ PFORMAT_SET_WIDTH,
+ PFORMAT_GET_PRECISION,
+ PFORMAT_SET_PRECISION,
+ PFORMAT_END
+} __pformat_state_t;
+
+typedef enum
+{
+ /* Argument length classification indices...
+ * (used for arguments representing integer data types).
+ */
+ PFORMAT_LENGTH_INT = 0,
+ PFORMAT_LENGTH_SHORT,
+ PFORMAT_LENGTH_LONG,
+ PFORMAT_LENGTH_LLONG,
+ PFORMAT_LENGTH_CHAR
+} __pformat_length_t;
+/*
+ * And a macro to map any arbitrary data type to an appropriate
+ * matching index, selected from those above; the compiler should
+ * collapse this to a simple assignment.
+ */
+#define __pformat_arg_length( type ) \
+ sizeof( type ) == sizeof( long long ) ? PFORMAT_LENGTH_LLONG : \
+ sizeof( type ) == sizeof( long ) ? PFORMAT_LENGTH_LONG : \
+ sizeof( type ) == sizeof( short ) ? PFORMAT_LENGTH_SHORT : \
+ sizeof( type ) == sizeof( char ) ? PFORMAT_LENGTH_CHAR : \
+ /* should never need this default */ PFORMAT_LENGTH_INT
+
+typedef struct
+{
+ /* Formatting and output control data...
+ * An instance of this control block is created, (on the stack),
+ * for each call to `__pformat()', and is passed by reference to
+ * each of the output handlers, as required.
+ */
+ void * dest;
+ int flags;
+ int width;
+ int precision;
+ int rplen;
+ wchar_t rpchr;
+ int thousands_chr_len;
+ wchar_t thousands_chr;
+ int count;
+ int quota;
+ int expmin;
+} __pformat_t;
+
+static
+void __pformat_putc( int c, __pformat_t *stream )
+{
+ /* Place a single character into the `__pformat()' output queue,
+ * provided any specified output quota has not been exceeded.
+ */
+ if( (stream->flags & PFORMAT_NOLIMIT) || (stream->quota > stream->count) )
+ {
+ /* Either there was no quota specified,
+ * or the active quota has not yet been reached.
+ */
+ if( stream->flags & PFORMAT_TO_FILE )
+ /*
+ * This is single character output to a FILE stream...
+ */
+ __fputc(c, (FILE *)(stream->dest));
+
+ else
+ /* Whereas, this is to an internal memory buffer...
+ */
+ ((APICHAR *)(stream->dest))[stream->count] = c;
+ }
+ ++stream->count;
+}
+
+static
+void __pformat_putchars( const char *s, int count, __pformat_t *stream )
+{
+ /* Handler for `%c' and (indirectly) `%s' conversion specifications.
+ *
+ * Transfer characters from the string buffer at `s', character by
+ * character, up to the number of characters specified by `count', or
+ * if `precision' has been explicitly set to a value less than `count',
+ * stopping after the number of characters specified for `precision',
+ * to the `__pformat()' output stream.
+ *
+ * Characters to be emitted are passed through `__pformat_putc()', to
+ * ensure that any specified output quota is honoured.
+ */
+ if( (stream->precision >= 0) && (count > stream->precision) )
+ /*
+ * Ensure that the maximum number of characters transferred doesn't
+ * exceed any explicitly set `precision' specification.
+ */
+ count = stream->precision;
+
+ /* Establish the width of any field padding required...
+ */
+ if( stream->width > count )
+ /*
+ * as the number of spaces equivalent to the number of characters
+ * by which those to be emitted is fewer than the field width...
+ */
+ stream->width -= count;
+
+ else
+ /* ignoring any width specification which is insufficient.
+ */
+ stream->width = PFORMAT_IGNORE;
+
+ if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
+ /*
+ * When not doing flush left justification, (i.e. the `-' flag
+ * is not set), any residual unreserved field width must appear
+ * as blank padding, to the left of the output string.
+ */
+ while( stream->width-- )
+ __pformat_putc( '\x20', stream );
+
+ /* Emit the data...
+ */
+#ifdef __BUILD_WIDEAPI
+ {
+ /* mbrtowc */
+ size_t l;
+ wchar_t w[12], *p;
+ while( count > 0 )
+ {
+ mbstate_t ps;
+ memset(&ps, 0, sizeof(ps) );
+ --count;
+ p = &w[0];
+ l = mbrtowc (p, s, strlen (s), &ps);
+ if (!l)
+ break;
+ if ((ssize_t)l < 0)
+ {
+ l = 1;
+ w[0] = (wchar_t) *s;
+ }
+ s += l;
+ __pformat_putc((int)w[0], stream);
+ }
+ }
+#else
+ while( count-- )
+ /*
+ * copying the requisite number of characters from the input.
+ */
+ __pformat_putc( *s++, stream );
+#endif
+
+ /* If we still haven't consumed the entire specified field width,
+ * we must be doing flush left justification; any residual width
+ * must be filled with blanks, to the right of the output value.
+ */
+ while( stream->width-- > 0 )
+ __pformat_putc( '\x20', stream );
+}
+
+static
+void __pformat_puts( const char *s, __pformat_t *stream )
+{
+ /* Handler for `%s' conversion specifications.
+ *
+ * Transfer a NUL terminated character string, character by character,
+ * stopping when the end of the string is encountered, or if `precision'
+ * has been explicitly set, when the specified number of characters has
+ * been emitted, if that is less than the length of the input string,
+ * to the `__pformat()' output stream.
+ *
+ * This is implemented as a trivial call to `__pformat_putchars()',
+ * passing the length of the input string as the character count,
+ * (after first verifying that the input pointer is not NULL).
+ */
+ if( s == NULL ) s = "(null)";
+ __pformat_putchars( s, strlen( s ), stream );
+}
+
+static
+void __pformat_wputchars( const wchar_t *s, int count, __pformat_t *stream )
+{
+ /* Handler for `%C'(`%lc') and `%S'(`%ls') conversion specifications;
+ * (this is a wide character variant of `__pformat_putchars()').
+ *
+ * Each multibyte character sequence to be emitted is passed, byte
+ * by byte, through `__pformat_putc()', to ensure that any specified
+ * output quota is honoured.
+ */
+ char buf[16];
+ mbstate_t state;
+ int len = wcrtomb(buf, L'\0', &state);
+
+ if( (stream->precision >= 0) && (count > stream->precision) )
+ /*
+ * Ensure that the maximum number of characters transferred doesn't
+ * exceed any explicitly set `precision' specification.
+ */
+ count = stream->precision;
+
+ /* Establish the width of any field padding required...
+ */
+ if( stream->width > count )
+ /*
+ * as the number of spaces equivalent to the number of characters
+ * by which those to be emitted is fewer than the field width...
+ */
+ stream->width -= count;
+
+ else
+ /* ignoring any width specification which is insufficient.
+ */
+ stream->width = PFORMAT_IGNORE;
+
+ if( (stream->width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
+ /*
+ * When not doing flush left justification, (i.e. the `-' flag
+ * is not set), any residual unreserved field width must appear
+ * as blank padding, to the left of the output string.
+ */
+ while( stream->width-- )
+ __pformat_putc( '\x20', stream );
+
+ /* Emit the data, converting each character from the wide
+ * to the multibyte domain as we go...
+ */
+#ifdef __BUILD_WIDEAPI
+ len = count;
+ while(len-- > 0 && *s != 0)
+ {
+ __pformat_putc(*s++, stream);
+ }
+ count = len;
+#else
+ while( (count-- > 0) && ((len = wcrtomb( buf, *s++, &state )) > 0) )
+ {
+ char *p = buf;
+ while( len-- > 0 )
+ __pformat_putc( *p++, stream );
+ }
+#endif
+ /* If we still haven't consumed the entire specified field width,
+ * we must be doing flush left justification; any residual width
+ * must be filled with blanks, to the right of the output value.
+ */
+ while( stream->width-- > 0 )
+ __pformat_putc( '\x20', stream );
+}
+
+static
+void __pformat_wcputs( const wchar_t *s, __pformat_t *stream )
+{
+ /* Handler for `%S' (`%ls') conversion specifications.
+ *
+ * Transfer a NUL terminated wide character string, character by
+ * character, converting to its equivalent multibyte representation
+ * on output, and stopping when the end of the string is encountered,
+ * or if `precision' has been explicitly set, when the specified number
+ * of characters has been emitted, if that is less than the length of
+ * the input string, to the `__pformat()' output stream.
+ *
+ * This is implemented as a trivial call to `__pformat_wputchars()',
+ * passing the length of the input string as the character count,
+ * (after first verifying that the input pointer is not NULL).
+ */
+ if( s == NULL ) s = L"(null)";
+ __pformat_wputchars( s, wcslen( s ), stream );
+}
+
+static
+int __pformat_int_bufsiz( int bias, int size, __pformat_t *stream )
+{
+ /* Helper to establish the size of the internal buffer, which
+ * is required to queue the ASCII decomposition of an integral
+ * data value, prior to transfer to the output stream.
+ */
+ size = ((size - 1 + LLONGBITS) / size) + bias;
+ size += (stream->precision > 0) ? stream->precision : 0;
+ if ((stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0)
+ size += (size / 3);
+ return (size > stream->width) ? size : stream->width;
+}
+
+static
+void __pformat_int( __pformat_intarg_t value, __pformat_t *stream )
+{
+ /* Handler for `%d', `%i' and `%u' conversion specifications.
+ *
+ * Transfer the ASCII representation of an integer value parameter,
+ * formatted as a decimal number, to the `__pformat()' output queue;
+ * output will be truncated, if any specified quota is exceeded.
+ */
+ char buf[__pformat_int_bufsiz(1, PFORMAT_OSHIFT, stream)];
+ char *p = buf; int precision;
+
+ if( stream->flags & PFORMAT_NEGATIVE )
+ {
+ /* The input value might be negative, (i.e. it is a signed value)...
+ */
+ if( value.__pformat_llong_t < 0LL )
+ /*
+ * It IS negative, but we want to encode it as unsigned,
+ * displayed with a leading minus sign, so convert it...
+ */
+ value.__pformat_llong_t = -value.__pformat_llong_t;
+
+ else
+ /* It is unequivocally a POSITIVE value, so turn off the
+ * request to prefix it with a minus sign...
+ */
+ stream->flags &= ~PFORMAT_NEGATIVE;
+ }
+
+ /* Encode the input value for display...
+ */
+ while( value.__pformat_ullong_t )
+ {
+ /* decomposing it into its constituent decimal digits,
+ * in order from least significant to most significant, using
+ * the local buffer as a LIFO queue in which to store them.
+ */
+ if (p != buf && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0
+ && ((p - buf) % 4) == 3)
+ {
+ *p++ = ',';
+ }
+ *p++ = '0' + (unsigned char)(value.__pformat_ullong_t % 10LL);
+ value.__pformat_ullong_t /= 10LL;
+ }
+
+ if( (stream->precision > 0)
+ && ((precision = stream->precision - (p - buf)) > 0) )
+ /*
+ * We have not yet queued sufficient digits to fill the field width
+ * specified for minimum `precision'; pad with zeros to achieve this.
+ */
+ while( precision-- > 0 )
+ *p++ = '0';
+
+ if( (p == buf) && (stream->precision != 0) )
+ /*
+ * Input value was zero; make sure we print at least one digit,
+ * unless the precision is also explicitly zero.
+ */
+ *p++ = '0';
+
+ if( (stream->width > 0) && ((stream->width -= p - buf) > 0) )
+ {
+ /* We have now queued sufficient characters to display the input value,
+ * at the desired precision, but this will not fill the output field...
+ */
+ if( stream->flags & PFORMAT_SIGNED )
+ /*
+ * We will fill one additional space with a sign...
+ */
+ stream->width--;
+
+ if( (stream->precision < 0)
+ && ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL) )
+ /*
+ * and the `0' flag is in effect, so we pad the remaining spaces,
+ * to the left of the displayed value, with zeros.
+ */
+ while( stream->width-- > 0 )
+ *p++ = '0';
+
+ else if( (stream->flags & PFORMAT_LJUSTIFY) == 0 )
+ /*
+ * the `0' flag is not in effect, and neither is the `-' flag,
+ * so we pad to the left of the displayed value with spaces, so that
+ * the value appears right justified within the output field.
+ */
+ while( stream->width-- > 0 )
+ __pformat_putc( '\x20', stream );
+ }
+
+ if( stream->flags & PFORMAT_NEGATIVE )
+ /*
+ * A negative value needs a sign...
+ */
+ *p++ = '-';
+
+ else if( stream->flags & PFORMAT_POSITIVE )
+ /*
+ * A positive value may have an optionally displayed sign...
+ */
+ *p++ = '+';
+
+ else if( stream->flags & PFORMAT_ADDSPACE )
+ /*
+ * Space was reserved for displaying a sign, but none was emitted...
+ */
+ *p++ = '\x20';
+
+ while( p > buf )
+ /*
+ * Emit the accumulated constituent digits,
+ * in order from most significant to least significant...
+ */
+ __pformat_putc( *--p, stream );
+
+ while( stream->width-- > 0 )
+ /*
+ * The specified output field has not yet been completely filled;
+ * the `-' flag must be in effect, resulting in a displayed value which
+ * appears left justified within the output field; we must pad the field
+ * to the right of the displayed value, by emitting additional spaces,
+ * until we reach the rightmost field boundary.
+ */
+ __pformat_putc( '\x20', stream );
+}
+
+static
+void __pformat_xint( int fmt, __pformat_intarg_t value, __pformat_t *stream )
+{
+ /* Handler for `%o', `%p', `%x' and `%X' conversions.
+ *
+ * These can be implemented using a simple `mask and shift' strategy;
+ * set up the mask and shift values appropriate to the conversion format,
+ * and allocate a suitably sized local buffer, in which to queue encoded
+ * digits of the formatted value, in preparation for output.
+ */
+ int width;
+ int mask = (fmt == 'o') ? PFORMAT_OMASK : PFORMAT_XMASK;
+ int shift = (fmt == 'o') ? PFORMAT_OSHIFT : PFORMAT_XSHIFT;
+ char buf[__pformat_int_bufsiz(2, shift, stream)];
+ char *p = buf;
+
+ while( value.__pformat_ullong_t )
+ {
+ /* Encode the specified non-zero input value as a sequence of digits,
+ * in the appropriate `base' encoding and in reverse digit order, each
+ * encoded in its printable ASCII form, with no leading zeros, using
+ * the local buffer as a LIFO queue in which to store them.
+ */
+ char *q;
+ if( (*(q = p++) = '0' + (value.__pformat_ullong_t & mask)) > '9' )
+ *q = (*q + 'A' - '9' - 1) | (fmt & PFORMAT_XCASE);
+ value.__pformat_ullong_t >>= shift;
+ }
+
+ if( p == buf )
+ /*
+ * Nothing was queued; input value must be zero, which should never be
+ * emitted in the `alternative' PFORMAT_HASHED style.
+ */
+ stream->flags &= ~PFORMAT_HASHED;
+
+ if( ((width = stream->precision) > 0) && ((width -= p - buf) > 0) )
+ /*
+ * We have not yet queued sufficient digits to fill the field width
+ * specified for minimum `precision'; pad with zeros to achieve this.
+ */
+ while( width-- > 0 )
+ *p++ = '0';
+
+ else if( (fmt == 'o') && (stream->flags & PFORMAT_HASHED) )
+ /*
+ * The field width specified for minimum `precision' has already
+ * been filled, but the `alternative' PFORMAT_HASHED style for octal
+ * output requires at least one initial zero; that will not have
+ * been queued, so add it now.
+ */
+ *p++ = '0';
+
+ if( (p == buf) && (stream->precision != 0) )
+ /*
+ * Still nothing queued for output, but the `precision' has not been
+ * explicitly specified as zero, (which is necessary if no output for
+ * an input value of zero is desired); queue exactly one zero digit.
+ */
+ *p++ = '0';
+
+ if( stream->width > (width = p - buf) )
+ /*
+ * Specified field width exceeds the minimum required...
+ * Adjust so that we retain only the additional padding width.
+ */
+ stream->width -= width;
+
+ else
+ /* Ignore any width specification which is insufficient.
+ */
+ stream->width = PFORMAT_IGNORE;
+
+ if( ((width = stream->width) > 0)
+ && (fmt != 'o') && (stream->flags & PFORMAT_HASHED) )
+ /*
+ * For `%#x' or `%#X' formats, (which have the `#' flag set),
+ * further reduce the padding width to accommodate the radix
+ * indicating prefix.
+ */
+ width -= 2;
+
+ if( (width > 0) && (stream->precision < 0)
+ && ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL) )
+ /*
+ * When the `0' flag is set, and not overridden by the `-' flag,
+ * or by a specified precision, add sufficient leading zeros to
+ * consume the remaining field width.
+ */
+ while( width-- > 0 )
+ *p++ = '0';
+
+ if( (fmt != 'o') && (stream->flags & PFORMAT_HASHED) )
+ {
+ /* For formats other than octal, the PFORMAT_HASHED output style
+ * requires the addition of a two character radix indicator, as a
+ * prefix to the actual encoded numeric value.
+ */
+ *p++ = fmt;
+ *p++ = '0';
+ }
+
+ if( (width > 0) && ((stream->flags & PFORMAT_LJUSTIFY) == 0) )
+ /*
+ * When not doing flush left justification, (i.e. the `-' flag
+ * is not set), any residual unreserved field width must appear
+ * as blank padding, to the left of the output value.
+ */
+ while( width-- > 0 )
+ __pformat_putc( '\x20', stream );
+
+ while( p > buf )
+ /*
+ * Move the queued output from the local buffer to the ultimate
+ * destination, in LIFO order.
+ */
+ __pformat_putc( *--p, stream );
+
+ /* If we still haven't consumed the entire specified field width,
+ * we must be doing flush left justification; any residual width
+ * must be filled with blanks, to the right of the output value.
+ */
+ while( width-- > 0 )
+ __pformat_putc( '\x20', stream );
+}
+
+typedef union
+{
+ /* A multifaceted representation of an IEEE extended precision,
+ * (80-bit), floating point number, facilitating access to its
+ * component parts.
+ */
+ double __pformat_fpreg_double_t;
+ long double __pformat_fpreg_ldouble_t;
+ struct
+ { unsigned long long __pformat_fpreg_mantissa;
+ signed short __pformat_fpreg_exponent;
+ };
+ unsigned short __pformat_fpreg_bitmap[5];
+ unsigned long __pformat_fpreg_bits;
+} __pformat_fpreg_t;
+
+
+static
+char *__pformat_cvt( int mode, __pformat_fpreg_t x, int nd, int *dp, int *sign )
+{
+ /* Helper function, derived from David M. Gay's `g_xfmt()', calling
+ * his `__gdtoa()' function in a manner to provide extended precision
+ * replacements for `ecvt()' and `fcvt()'.
+ */
+ int k; unsigned int e = 0; char *ep;
+ static FPI fpi = { 64, 1-16383-64+1, 32766-16383-64+1, FPI_Round_near, 0, 14 /* Int_max */ };
+
+ /* Classify the argument into an appropriate `__gdtoa()' category...
+ */
+ if( (k = __fpclassifyl( x.__pformat_fpreg_ldouble_t )) & FP_NAN )
+ /*
+ * identifying infinities or not-a-number...
+ */
+ k = (k & FP_NORMAL) ? STRTOG_Infinite : STRTOG_NaN;
+
+ else if( k & FP_NORMAL )
+ {
+ /* normal and near-zero `denormals'...
+ */
+ if( k & FP_ZERO )
+ {
+ /* with appropriate exponent adjustment for a `denormal'...
+ */
+ k = STRTOG_Denormal;
+ e = 1 - 0x3FFF - 63;
+ }
+ else
+ {
+ /* or with `normal' exponent adjustment...
+ */
+ k = STRTOG_Normal;
+ e = (x.__pformat_fpreg_exponent & 0x7FFF) - 0x3FFF - 63;
+ }
+ }
+
+ else
+ /* or, if none of the above, it's a zero, (positive or negative).
+ */
+ k = STRTOG_Zero;
+
+ /* Check for negative values, always treating NaN as unsigned...
+ * (return value is zero for positive/unsigned; non-zero for negative).
+ */
+ *sign = (k == STRTOG_NaN) ? 0 : x.__pformat_fpreg_exponent & 0x8000;
+
+ /* Finally, get the raw digit string, and radix point position index.
+ */
+ return __gdtoa( &fpi, e, &x.__pformat_fpreg_bits, &k, mode, nd, dp, &ep );
+}
+
+static
+char *__pformat_ecvt( long double x, int precision, int *dp, int *sign )
+{
+ /* A convenience wrapper for the above...
+ * it emulates `ecvt()', but takes a `long double' argument.
+ */
+ __pformat_fpreg_t z; z.__pformat_fpreg_ldouble_t = x;
+ return __pformat_cvt( 2, z, precision, dp, sign );
+}
+
+static
+char *__pformat_fcvt( long double x, int precision, int *dp, int *sign )
+{
+ /* A convenience wrapper for the above...
+ * it emulates `fcvt()', but takes a `long double' argument.
+ */
+ __pformat_fpreg_t z; z.__pformat_fpreg_ldouble_t = x;
+ return __pformat_cvt( 3, z, precision, dp, sign );
+}
+
+/* The following are required, to clean up the `__gdtoa()' memory pool,
+ * after processing the data returned by the above.
+ */
+#define __pformat_ecvt_release( value ) __freedtoa( value )
+#define __pformat_fcvt_release( value ) __freedtoa( value )
+
+static
+void __pformat_emit_radix_point( __pformat_t *stream )
+{
+ /* Helper to place a localised representation of the radix point
+ * character at the ultimate destination, when formatting fixed or
+ * floating point numbers.
+ */
+ if( stream->rplen == PFORMAT_RPINIT )
+ {
+ /* Radix point initialisation not yet completed;
+ * establish a multibyte to `wchar_t' converter...
+ */
+ int len; wchar_t rpchr; mbstate_t state;
+
+ /* Initialise the conversion state...
+ */
+ memset( &state, 0, sizeof( state ) );
+
+ /* Fetch and convert the localised radix point representation...
+ */
+ if( (len = mbrtowc( &rpchr, localeconv()->decimal_point, 16, &state )) > 0 )
+ /*
+ * and store it, if valid.
+ */
+ stream->rpchr = rpchr;
+
+ /* In any case, store the reported effective multibyte length,
+ * (or the error flag), marking initialisation as `done'.
+ */
+ stream->rplen = len;
+ }
+
+ if( stream->rpchr != (wchar_t)(0) )
+ {
+ /* We have a localised radix point mark;
+ * establish a converter to make it a multibyte character...
+ */
+#ifdef __BUILD_WIDEAPI
+ __pformat_putc (stream->rpchr, stream);
+#else
+ int len; char buf[len = stream->rplen]; mbstate_t state;
+
+ /* Initialise the conversion state...
+ */
+ memset( &state, 0, sizeof( state ) );
+
+ /* Convert the `wchar_t' representation to multibyte...
+ */
+ if( (len = wcrtomb( buf, stream->rpchr, &state )) > 0 )
+ {
+ /* and copy to the output destination, when valid...
+ */
+ char *p = buf;
+ while( len-- > 0 )
+ __pformat_putc( *p++, stream );
+ }
+
+ else
+ /* otherwise fall back to plain ASCII '.'...
+ */
+ __pformat_putc( '.', stream );
+#endif
+ }
+ else
+ /* No localisation: just use ASCII '.'...
+ */
+ __pformat_putc( '.', stream );
+}
+
+static
+void __pformat_emit_numeric_value( int c, __pformat_t *stream )
+{
+ /* Convenience helper to transfer numeric data from an internal
+ * formatting buffer to the ultimate destination...
+ */
+ if( c == '.' )
+ /*
+ * converting this internal representation of the the radix
+ * point to the appropriately localised representation...
+ */
+ __pformat_emit_radix_point( stream );
+ else if (c == ',')
+ {
+ wchar_t wcs;
+ if ((wcs = stream->thousands_chr) != 0)
+ __pformat_wputchars (&wcs, 1, stream);
+ }
+ else
+ /* and passing all other characters through, unmodified.
+ */
+ __pformat_putc( c, stream );
+}
+
+static
+void __pformat_emit_inf_or_nan( int sign, char *value, __pformat_t *stream )
+{
+ /* Helper to emit INF or NAN where a floating point value
+ * resolves to one of these special states.
+ */
+ int i;
+ char buf[4];
+ char *p = buf;
+
+ /* We use the string formatting helper to display INF/NAN,
+ * but we don't want truncation if the precision set for the
+ * original floating point output request was insufficient;
+ * ignore it!
+ */
+ stream->precision = PFORMAT_IGNORE;
+
+ if( sign )
+ /*
+ * Negative infinity: emit the sign...
+ */
+ *p++ = '-';
+
+ else if( stream->flags & PFORMAT_POSITIVE )
+ /*
+ * Not negative infinity, but '+' flag is in effect;
+ * thus, we emit a positive sign...
+ */
+ *p++ = '+';
+
+ else if( stream->flags & PFORMAT_ADDSPACE )
+ /*
+ * No sign required, but space was reserved for it...
+ */
+ *p++ = '\x20';
+
+ /* Copy the appropriate status indicator, up to a maximum of
+ * three characters, transforming to the case corresponding to
+ * the format specification...
+ */
+ for( i = 3; i > 0; --i )
+ *p++ = (*value++ & ~PFORMAT_XCASE) | (stream->flags & PFORMAT_XCASE);
+
+ /* and emit the result.
+ */
+ __pformat_putchars( buf, p - buf, stream );
+}
+
+static
+void __pformat_emit_float( int sign, char *value, int len, __pformat_t *stream )
+{
+ /* Helper to emit a fixed point representation of numeric data,
+ * as encoded by a prior call to `ecvt()' or `fcvt()'; (this does
+ * NOT include the exponent, for floating point format).
+ */
+ if( len > 0 )
+ {
+ /* The magnitude of `x' is greater than or equal to 1.0...
+ * reserve space in the output field, for the required number of
+ * decimal digits to be placed before the decimal point...
+ */
+ if( stream->width > len )
+ /*
+ * adjusting as appropriate, when width is sufficient...
+ */
+ stream->width -= len;
+
+ else
+ /* or simply ignoring the width specification, if not.
+ */
+ stream->width = PFORMAT_IGNORE;
+ }
+
+ else if( stream->width > 0 )
+ /*
+ * The magnitude of `x' is less than 1.0...
+ * reserve space for exactly one zero before the decimal point.
+ */
+ stream->width--;
+
+ /* Reserve additional space for the digits which will follow the
+ * decimal point...
+ */
+ if( (stream->width >= 0) && (stream->width > stream->precision) )
+ /*
+ * adjusting appropriately, when sufficient width remains...
+ * (note that we must check both of these conditions, because
+ * precision may be more negative than width, as a result of
+ * adjustment to provide extra padding when trailing zeros
+ * are to be discarded from "%g" format conversion with a
+ * specified field width, but if width itself is negative,
+ * then there is explicitly to be no padding anyway).
+ */
+ stream->width -= stream->precision;
+
+ else
+ /* or again, ignoring the width specification, if not.
+ */
+ stream->width = PFORMAT_IGNORE;
+
+ /* Reserve space in the output field, for display of the decimal point,
+ * unless the precision is explicity zero, with the `#' flag not set.
+ */
+ if ((stream->width > 0)
+ && ((stream->precision > 0) || (stream->flags & PFORMAT_HASHED)))
+ stream->width--;
+
+ if (len > 0 && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0)
+ {
+ int cths = ((len + 2) / 3) - 1;
+ while (cths > 0 && stream->width > 0)
+ {
+ --cths; stream->width--;
+ }
+ }
+
+ /* Reserve space in the output field, for display of the sign of the
+ * formatted value, if required; (i.e. if the value is negative, or if
+ * either the `space' or `+' formatting flags are set).
+ */
+ if( (stream->width > 0) && (sign || (stream->flags & PFORMAT_SIGNED)) )
+ stream->width--;
+
+ /* Emit any padding space, as required to correctly right justify
+ * the output within the alloted field width.
+ */
+ if( (stream->width > 0) && ((stream->flags & PFORMAT_JUSTIFY) == 0) )
+ while( stream->width-- > 0 )
+ __pformat_putc( '\x20', stream );
+
+ /* Emit the sign indicator, as appropriate...
+ */
+ if( sign )
+ /*
+ * mandatory, for negative values...
+ */
+ __pformat_putc( '-', stream );
+
+ else if( stream->flags & PFORMAT_POSITIVE )
+ /*
+ * optional, for positive values...
+ */
+ __pformat_putc( '+', stream );
+
+ else if( stream->flags & PFORMAT_ADDSPACE )
+ /*
+ * or just fill reserved space, when the space flag is in effect.
+ */
+ __pformat_putc( '\x20', stream );
+
+ /* If the `0' flag is in effect, and not overridden by the `-' flag,
+ * then zero padding, to fill out the field, goes here...
+ */
+ if( (stream->width > 0)
+ && ((stream->flags & PFORMAT_JUSTIFY) == PFORMAT_ZEROFILL) )
+ while( stream->width-- > 0 )
+ __pformat_putc( '0', stream );
+
+ /* Emit the digits of the encoded numeric value...
+ */
+ if( len > 0 )
+ {
+ /*
+ * ...beginning with those which precede the radix point,
+ * and appending any necessary significant trailing zeros.
+ */
+ do {
+ __pformat_putc( *value ? *value++ : '0', stream);
+ --len;
+ if (len != 0 && (stream->flags & PFORMAT_GROUPED) != 0 && stream->thousands_chr != 0
+ && (len % 3) == 0)
+ __pformat_wputchars (&stream->thousands_chr, 1, stream);
+ }
+ while (len > 0);
+ }
+ else
+ /* The magnitude of the encoded value is less than 1.0, so no
+ * digits precede the radix point; we emit a mandatory initial
+ * zero, followed immediately by the radix point.
+ */
+ __pformat_putc( '0', stream );
+
+ /* Unless the encoded value is integral, AND the radix point
+ * is not expressly demanded by the `#' flag, we must insert
+ * the appropriately localised radix point mark here...
+ */
+ if( (stream->precision > 0) || (stream->flags & PFORMAT_HASHED) )
+ __pformat_emit_radix_point( stream );
+
+ /* When the radix point offset, `len', is negative, this implies
+ * that additional zeros must appear, following the radix point,
+ * and preceding the first significant digit...
+ */
+ if( len < 0 )
+ {
+ /* To accommodate these, we adjust the precision, (reducing it
+ * by adding a negative value), and then we emit as many zeros
+ * as are required.
+ */
+ stream->precision += len;
+ do __pformat_putc( '0', stream );
+ while( ++len < 0 );
+ }
+
+ /* Now we emit any remaining significant digits, or trailing zeros,
+ * until the required precision has been achieved.
+ */
+ while( stream->precision-- > 0 )
+ __pformat_putc( *value ? *value++ : '0', stream );
+}
+
+static
+void __pformat_emit_efloat( int sign, char *value, int e, __pformat_t *stream )
+{
+ /* Helper to emit a floating point representation of numeric data,
+ * as encoded by a prior call to `ecvt()' or `fcvt()'; (this DOES
+ * include the following exponent).
+ */
+ int exp_width = 1;
+ __pformat_intarg_t exponent; exponent.__pformat_llong_t = e -= 1;
+
+ /* Determine how many digit positions are required for the exponent.
+ */
+ while( (e /= 10) != 0 )
+ exp_width++;
+
+ /* Ensure that this is at least as many as the standard requirement.
+ */
+ if( exp_width < stream->expmin )
+ exp_width = stream->expmin;
+
+ /* Adjust the residual field width allocation, to allow for the
+ * number of exponent digits to be emitted, together with a sign
+ * and exponent separator...
+ */
+ if( stream->width > (exp_width += 2) )
+ stream->width -= exp_width;
+
+ else
+ /* ignoring the field width specification, if insufficient.
+ */
+ stream->width = PFORMAT_IGNORE;
+
+ /* Emit the significand, as a fixed point value with one digit
+ * preceding the radix point.
+ */
+ __pformat_emit_float( sign, value, 1, stream );
+
+ /* Reset precision, to ensure the mandatory minimum number of
+ * exponent digits will be emitted, and set the flags to ensure
+ * the sign is displayed.
+ */
+ stream->precision = stream->expmin;
+ stream->flags |= PFORMAT_SIGNED;
+
+ /* Emit the exponent separator.
+ */
+ __pformat_putc( ('E' | (stream->flags & PFORMAT_XCASE)), stream );
+
+ /* Readjust the field width setting, such that it again allows
+ * for the digits of the exponent, (which had been discounted when
+ * computing any left side padding requirement), so that they are
+ * correctly included in the computation of any right side padding
+ * requirement, (but here we exclude the exponent separator, which
+ * has been emitted, and so counted already).
+ */
+ stream->width += exp_width - 1;
+
+ /* And finally, emit the exponent itself, as a signed integer,
+ * with any padding required to achieve flush left justification,
+ * (which will be added automatically, by `__pformat_int()').
+ */
+ __pformat_int( exponent, stream );
+}
+
+static
+void __pformat_float( long double x, __pformat_t *stream )
+{
+ /* Handler for `%f' and `%F' format specifiers.
+ *
+ * This wraps calls to `__pformat_cvt()', `__pformat_emit_float()'
+ * and `__pformat_emit_inf_or_nan()', as appropriate, to achieve
+ * output in fixed point format.
+ */
+ int sign, intlen; char *value;
+
+ /* Establish the precision for the displayed value, defaulting to six
+ * digits following the decimal point, if not explicitly specified.
+ */
+ if( stream->precision < 0 )
+ stream->precision = 6;
+
+ /* Encode the input value as ASCII, for display...
+ */
+ value = __pformat_fcvt( x, stream->precision, &intlen, &sign );
+
+ if( intlen == PFORMAT_INFNAN )
+ /*
+ * handle cases of `infinity' or `not-a-number'...
+ */
+ __pformat_emit_inf_or_nan( sign, value, stream );
+
+ else
+ { /* or otherwise, emit the formatted result.
+ */
+ __pformat_emit_float( sign, value, intlen, stream );
+
+ /* and, if there is any residual field width as yet unfilled,
+ * then we must be doing flush left justification, so pad out to
+ * the right hand field boundary.
+ */
+ while( stream->width-- > 0 )
+ __pformat_putc( '\x20', stream );
+ }
+
+ /* Clean up `__pformat_fcvt()' memory allocation for `value'...
+ */
+ __pformat_fcvt_release( value );
+}
+
+static
+void __pformat_efloat( long double x, __pformat_t *stream )
+{
+ /* Handler for `%e' and `%E' format specifiers.
+ *
+ * This wraps calls to `__pformat_cvt()', `__pformat_emit_efloat()'
+ * and `__pformat_emit_inf_or_nan()', as appropriate, to achieve
+ * output in floating point format.
+ */
+ int sign, intlen; char *value;
+
+ /* Establish the precision for the displayed value, defaulting to six
+ * digits following the decimal point, if not explicitly specified.
+ */
+ if( stream->precision < 0 )
+ stream->precision = 6;
+
+ /* Encode the input value as ASCII, for display...
+ */
+ value = __pformat_ecvt( x, stream->precision + 1, &intlen, &sign );
+
+ if( intlen == PFORMAT_INFNAN )
+ /*
+ * handle cases of `infinity' or `not-a-number'...
+ */
+ __pformat_emit_inf_or_nan( sign, value, stream );
+
+ else
+ /* or otherwise, emit the formatted result.
+ */
+ __pformat_emit_efloat( sign, value, intlen, stream );
+
+ /* Clean up `__pformat_ecvt()' memory allocation for `value'...
+ */
+ __pformat_ecvt_release( value );
+}
+
+static
+void __pformat_gfloat( long double x, __pformat_t *stream )
+{
+ /* Handler for `%g' and `%G' format specifiers.
+ *
+ * This wraps calls to `__pformat_cvt()', `__pformat_emit_float()',
+ * `__pformat_emit_efloat()' and `__pformat_emit_inf_or_nan()', as
+ * appropriate, to achieve output in the more suitable of either
+ * fixed or floating point format.
+ */
+ int sign, intlen; char *value;
+
+ /* Establish the precision for the displayed value, defaulting to
+ * six significant digits, if not explicitly specified...
+ */
+ if( stream->precision < 0 )
+ stream->precision = 6;
+
+ /* or to a minimum of one digit, otherwise...
+ */
+ else if( stream->precision == 0 )
+ stream->precision = 1;
+
+ /* Encode the input value as ASCII, for display.
+ */
+ value = __pformat_ecvt( x, stream->precision, &intlen, &sign );
+
+ if( intlen == PFORMAT_INFNAN )
+ /*
+ * Handle cases of `infinity' or `not-a-number'.
+ */
+ __pformat_emit_inf_or_nan( sign, value, stream );
+
+ else if( (-4 < intlen) && (intlen <= stream->precision) )
+ {
+ /* Value lies in the acceptable range for fixed point output,
+ * (i.e. the exponent is no less than minus four, and the number
+ * of significant digits which precede the radix point is fewer
+ * than the least number which would overflow the field width,
+ * specified or implied by the established precision).
+ */
+ if( (stream->flags & PFORMAT_HASHED) == PFORMAT_HASHED )
+ /*
+ * The `#' flag is in effect...
+ * Adjust precision to retain the specified number of significant
+ * digits, with the proper number preceding the radix point, and
+ * the balance following it...
+ */
+ stream->precision -= intlen;
+
+ else
+ /* The `#' flag is not in effect...
+ * Here we adjust the precision to accommodate all digits which
+ * precede the radix point, but we truncate any balance following
+ * it, to suppress output of non-significant trailing zeros...
+ */
+ if( ((stream->precision = strlen( value ) - intlen) < 0)
+ /*
+ * This may require a compensating adjustment to the field
+ * width, to accommodate significant trailing zeros, which
+ * precede the radix point...
+ */
+ && (stream->width > 0) )
+ stream->width += stream->precision;
+
+ /* Now, we format the result as any other fixed point value.
+ */
+ __pformat_emit_float( sign, value, intlen, stream );
+
+ /* If there is any residual field width as yet unfilled, then
+ * we must be doing flush left justification, so pad out to the
+ * right hand field boundary.
+ */
+ while( stream->width-- > 0 )
+ __pformat_putc( '\x20', stream );
+ }
+
+ else
+ { /* Value lies outside the acceptable range for fixed point;
+ * one significant digit will precede the radix point, so we
+ * decrement the precision to retain only the appropriate number
+ * of additional digits following it, when we emit the result
+ * in floating point format.
+ */
+ if( (stream->flags & PFORMAT_HASHED) == PFORMAT_HASHED )
+ /*
+ * The `#' flag is in effect...
+ * Adjust precision to emit the specified number of significant
+ * digits, with one preceding the radix point, and the balance
+ * following it, retaining any non-significant trailing zeros
+ * which are required to exactly match the requested precision...
+ */
+ stream->precision--;
+
+ else
+ /* The `#' flag is not in effect...
+ * Adjust precision to emit only significant digits, with one
+ * preceding the radix point, and any others following it, but
+ * suppressing non-significant trailing zeros...
+ */
+ stream->precision = strlen( value ) - 1;
+
+ /* Now, we format the result as any other floating point value.
+ */
+ __pformat_emit_efloat( sign, value, intlen, stream );
+ }
+
+ /* Clean up `__pformat_ecvt()' memory allocation for `value'.
+ */
+ __pformat_ecvt_release( value );
+}
+
+static
+void __pformat_emit_xfloat( __pformat_fpreg_t value, __pformat_t *stream )
+{
+ /* Helper for emitting floating point data, originating as
+ * either `double' or `long double' type, as a hexadecimal
+ * representation of the argument value.
+ */
+ char buf[18 + 6], *p = buf;
+ __pformat_intarg_t exponent; short exp_width = 2;
+
+ /* The mantissa field of the argument value representation can
+ * accommodate at most 16 hexadecimal digits, of which one will
+ * be placed before the radix point, leaving at most 15 digits
+ * to satisfy any requested precision; thus...
+ */
+ if( (stream->precision >= 0) && (stream->precision < 15) )
+ {
+ /* When the user specifies a precision within this range,
+ * we want to adjust the mantissa, to retain just the number
+ * of digits required, rounding up when the high bit of the
+ * leftmost discarded digit is set; (mask of 0x08 accounts
+ * for exactly one digit discarded, shifting 4 bits per
+ * digit, with up to 14 additional digits, to consume the
+ * full availability of 15 precision digits).
+ *
+ * However, before we perform the rounding operation, we
+ * normalise the mantissa, shifting it to the left by as many
+ * bit positions may be necessary, until its highest order bit
+ * is set, thus preserving the maximum number of bits in the
+ * rounded result as possible.
+ */
+ while( value.__pformat_fpreg_mantissa < (LLONG_MAX + 1ULL) )
+ value.__pformat_fpreg_mantissa <<= 1;
+
+ /* We then shift the mantissa one bit position back to the
+ * right, to guard against possible overflow when the rounding
+ * adjustment is added.
+ */
+ value.__pformat_fpreg_mantissa >>= 1;
+
+ /* We now add the rounding adjustment, noting that to keep the
+ * 0x08 mask aligned with the shifted mantissa, we also need to
+ * shift it right by one bit initially, changing its starting
+ * value to 0x04...
+ */
+ value.__pformat_fpreg_mantissa += 0x04LL << (4 * (14 - stream->precision));
+ if( (value.__pformat_fpreg_mantissa & (LLONG_MAX + 1ULL)) == 0ULL )
+ /*
+ * When the rounding adjustment would not have overflowed,
+ * then we shift back to the left again, to fill the vacated
+ * bit we reserved to accommodate the carry.
+ */
+ value.__pformat_fpreg_mantissa <<= 1;
+
+ else
+ /* Otherwise the rounding adjustment would have overflowed,
+ * so the carry has already filled the vacated bit; the effect
+ * of this is equivalent to an increment of the exponent.
+ */
+ value.__pformat_fpreg_exponent++;
+
+ /* We now complete the rounding to the required precision, by
+ * shifting the unwanted digits out, from the right hand end of
+ * the mantissa.
+ */
+ value.__pformat_fpreg_mantissa >>= 4 * (15 - stream->precision);
+ }
+
+ /* Encode the significant digits of the mantissa in hexadecimal
+ * ASCII notation, ready for transfer to the output stream...
+ */
+ while( value.__pformat_fpreg_mantissa )
+ {
+ /* taking the rightmost digit in each pass...
+ */
+ int c = value.__pformat_fpreg_mantissa & 0xF;
+ if( c == (int) value.__pformat_fpreg_mantissa)
+ {
+ /* inserting the radix point, when we reach the last,
+ * (i.e. the most significant digit), unless we found no
+ * less significant digits, with no mandatory radix point
+ * inclusion, and no additional required precision...
+ */
+ if( (p > buf)
+ || (stream->flags & PFORMAT_HASHED) || (stream->precision > 0) )
+ {
+ /*
+ * Internally, we represent the radix point as an ASCII '.';
+ * we will replace it with any locale specific alternative,
+ * at the time of transfer to the ultimate destination.
+ */
+ *p++ = '.';
+ }
+
+ /* If the most significant hexadecimal digit of the encoded
+ * output value is greater than one, then the indicated value
+ * will appear too large, by an additional binary exponent
+ * corresponding to the number of higher order bit positions
+ * which it occupies...
+ */
+ while( value.__pformat_fpreg_mantissa > 1 )
+ {
+ /* so reduce the exponent value to compensate...
+ */
+ value.__pformat_fpreg_exponent--;
+ value.__pformat_fpreg_mantissa >>= 1;
+ }
+ }
+
+ else if( stream->precision > 0 )
+ /*
+ * we have not yet fulfilled the desired precision,
+ * and we have not yet found the most significant digit,
+ * so account for the current digit, within the field
+ * width required to meet the specified precision.
+ */
+ stream->precision--;
+
+ if( (c > 0) || (p > buf) || (stream->precision >= 0) )
+ {
+ /*
+ * Ignoring insignificant trailing zeros, (unless required to
+ * satisfy specified precision), store the current encoded digit
+ * into the pending output buffer, in LIFO order, and using the
+ * appropriate case for digits in the `A'..`F' range.
+ */
+ *p++ = c > 9 ? (c - 10 + 'A') | (stream->flags & PFORMAT_XCASE) : c + '0';
+ }
+ /* Shift out the current digit, (4-bit logical shift right),
+ * to align the next more significant digit to be extracted,
+ * and encoded in the next pass.
+ */
+ value.__pformat_fpreg_mantissa >>= 4;
+ }
+
+ if( p == buf )
+ {
+ /* Nothing has been queued for output...
+ * We need at least one zero, and possibly a radix point.
+ */
+ if( (stream->precision > 0) || (stream->flags & PFORMAT_HASHED) )
+ *p++ = '.';
+
+ *p++ = '0';
+ }
+
+ if( stream->width > 0 )
+ {
+ /* Adjust the user specified field width, to account for the
+ * number of digits minimally required, to display the encoded
+ * value, at the requested precision.
+ *
+ * FIXME: this uses the minimum number of digits possible for
+ * representation of the binary exponent, in strict conformance
+ * with C99 and POSIX specifications. Although there appears to
+ * be no Microsoft precedent for doing otherwise, we may wish to
+ * relate this to the `_get_output_format()' result, to maintain
+ * consistency with `%e', `%f' and `%g' styles.
+ */
+ int min_width = p - buf;
+ int exponent2 = value.__pformat_fpreg_exponent;
+
+ /* If we have not yet queued sufficient digits to fulfil the
+ * requested precision, then we must adjust the minimum width
+ * specification, to accommodate the additional digits which
+ * are required to do so.
+ */
+ if( stream->precision > 0 )
+ min_width += stream->precision;
+
+ /* Adjust the minimum width requirement, to accomodate the
+ * sign, radix indicator and at least one exponent digit...
+ */
+ min_width += stream->flags & PFORMAT_SIGNED ? 6 : 5;
+ while( (exponent2 = exponent2 / 10) != 0 )
+ {
+ /* and increase as required, if additional exponent digits
+ * are needed, also saving the exponent field width adjustment,
+ * for later use when that is emitted.
+ */
+ min_width++;
+ exp_width++;
+ }
+
+ if( stream->width > min_width )
+ {
+ /* When specified field width exceeds the minimum required,
+ * adjust to retain only the excess...
+ */
+ stream->width -= min_width;
+
+ /* and then emit any required left side padding spaces.
+ */
+ if( (stream->flags & PFORMAT_JUSTIFY) == 0 )
+ while( stream->width-- > 0 )
+ __pformat_putc( '\x20', stream );
+ }
+
+ else
+ /* Specified field width is insufficient; just ignore it!
+ */
+ stream->width = PFORMAT_IGNORE;
+ }
+
+ /* Emit the sign of the encoded value, as required...
+ */
+ if( stream->flags & PFORMAT_NEGATIVE )
+ /*
+ * this is mandatory, to indicate a negative value...
+ */
+ __pformat_putc( '-', stream );
+
+ else if( stream->flags & PFORMAT_POSITIVE )
+ /*
+ * but this is optional, for a positive value...
+ */
+ __pformat_putc( '+', stream );
+
+ else if( stream->flags & PFORMAT_ADDSPACE )
+ /*
+ * with this optional alternative.
+ */
+ __pformat_putc( '\x20', stream );
+
+ /* Prefix a `0x' or `0X' radix indicator to the encoded value,
+ * with case appropriate to the format specification.
+ */
+ __pformat_putc( '0', stream );
+ __pformat_putc( 'X' | (stream->flags & PFORMAT_XCASE), stream );
+
+ /* If the `0' flag is in effect...
+ * Zero padding, to fill out the field, goes here...
+ */
+ if( (stream->width > 0) && (stream->flags & PFORMAT_ZEROFILL) )
+ while( stream->width-- > 0 )
+ __pformat_putc( '0', stream );
+
+ /* Next, we emit the encoded value, without its exponent...
+ */
+ while( p > buf )
+ __pformat_emit_numeric_value( *--p, stream );
+
+ /* followed by any additional zeros needed to satisfy the
+ * precision specification...
+ */
+ while( stream->precision-- > 0 )
+ __pformat_putc( '0', stream );
+
+ /* then the exponent prefix, (C99 and POSIX specify `p'),
+ * in the case appropriate to the format specification...
+ */
+ __pformat_putc( 'P' | (stream->flags & PFORMAT_XCASE), stream );
+
+ /* and finally, the decimal representation of the binary exponent,
+ * as a signed value with mandatory sign displayed, in a field width
+ * adjusted to accommodate it, LEFT justified, with any additional
+ * right side padding remaining from the original field width.
+ */
+ stream->width += exp_width;
+ stream->flags |= PFORMAT_SIGNED;
+ exponent.__pformat_llong_t = value.__pformat_fpreg_exponent;
+ __pformat_int( exponent, stream );
+}
+
+static
+void __pformat_xldouble( long double x, __pformat_t *stream )
+{
+ /* Handler for `%La' and `%LA' format specifiers, (with argument
+ * value specified as `long double' type).
+ */
+ unsigned sign_bit = 0;
+ __pformat_fpreg_t z; z.__pformat_fpreg_ldouble_t = x;
+
+ /* First check for NaN; it is emitted unsigned...
+ */
+ if( isnan( x ) )
+ __pformat_emit_inf_or_nan( sign_bit, "NaN", stream );
+
+ else
+ { /* Capture the sign bit up-front, so we can show it correctly
+ * even when the argument value is zero or infinite.
+ */
+ if( (sign_bit = (z.__pformat_fpreg_exponent & 0x8000)) != 0 )
+ stream->flags |= PFORMAT_NEGATIVE;
+
+ /* Check for infinity, (positive or negative)...
+ */
+ if( isinf( x ) )
+ /*
+ * displaying the appropriately signed indicator,
+ * when appropriate.
+ */
+ __pformat_emit_inf_or_nan( sign_bit, "Inf", stream );
+
+ else
+ { /* The argument value is a representable number...
+ * extract the effective value of the biased exponent...
+ */
+ z.__pformat_fpreg_exponent &= 0x7FFF;
+ if( z.__pformat_fpreg_exponent == 0 )
+ {
+ /* A biased exponent value of zero means either a
+ * true zero value, if the mantissa field also has
+ * a zero value, otherwise...
+ */
+ if( z.__pformat_fpreg_mantissa != 0 )
+ {
+ /* ...this mantissa represents a subnormal value;
+ * adjust the exponent, while shifting the mantissa
+ * to the left, until its leading bit is 1.
+ */
+ z.__pformat_fpreg_exponent = 1-0x3FFF;
+ while( (z.__pformat_fpreg_mantissa & (LLONG_MAX + 1ULL)) == 0 )
+ {
+ z.__pformat_fpreg_mantissa <<= 1;
+ --z.__pformat_fpreg_exponent;
+ }
+ }
+ }
+ else
+ /* This argument represents a non-zero normal number;
+ * eliminate the bias from the exponent...
+ */
+ z.__pformat_fpreg_exponent -= 0x3FFF;
+
+ /* Finally, hand the adjusted representation off to the
+ * generalised hexadecimal floating point format handler...
+ */
+ __pformat_emit_xfloat( z, stream );
+ }
+ }
+}
+
+int __cdecl
+_evil_pformat (int flags, void *dest, int max, const APICHAR *fmt, va_list argv)
+{
+ int c;
+ int saved_errno = errno;
+
+ __pformat_t stream =
+ {
+ /* Create and initialise a format control block
+ * for this output request.
+ */
+ dest, /* output goes to here */
+ flags &= PFORMAT_TO_FILE | PFORMAT_NOLIMIT, /* only these valid initially */
+ PFORMAT_IGNORE, /* no field width yet */
+ PFORMAT_IGNORE, /* nor any precision spec */
+ PFORMAT_RPINIT, /* radix point uninitialised */
+ (wchar_t)(0), /* leave it unspecified */
+ 0,
+ (wchar_t)(0), /* leave it unspecified */
+ 0, /* zero output char count */
+ max, /* establish output limit */
+ PFORMAT_MINEXP /* exponent chars preferred */
+ };
+
+ format_scan: while( (c = *fmt++) != 0 )
+ {
+ /* Format string parsing loop...
+ * The entry point is labelled, so that we can return to the start state
+ * from within the inner `conversion specification' interpretation loop,
+ * as soon as a conversion specification has been resolved.
+ */
+ if( c == '%' )
+ {
+ /* Initiate parsing of a `conversion specification'...
+ */
+ __pformat_intarg_t argval;
+ __pformat_state_t state = PFORMAT_INIT;
+ __pformat_length_t length = PFORMAT_LENGTH_INT;
+
+ /* Save the current format scan position, so that we can backtrack
+ * in the event of encountering an invalid format specification...
+ */
+ const APICHAR *backtrack = fmt;
+
+ /* Restart capture for dynamic field width and precision specs...
+ */
+ int *width_spec = &stream.width;
+
+ /* Reset initial state for flags, width and precision specs...
+ */
+ stream.flags = flags;
+ stream.width = stream.precision = PFORMAT_IGNORE;
+
+ while( *fmt )
+ {
+ switch( c = *fmt++ )
+ {
+ /* Data type specifiers...
+ * All are terminal, so exit the conversion spec parsing loop
+ * with a `goto format_scan', thus resuming at the outer level
+ * in the regular format string parser.
+ */
+ case '%':
+ /*
+ * Not strictly a data type specifier...
+ * it simply converts as a literal `%' character.
+ *
+ * FIXME: should we require this to IMMEDIATELY follow the
+ * initial `%' of the "conversion spec"? (glibc `printf()'
+ * on GNU/Linux does NOT appear to require this, but POSIX
+ * and SUSv3 do seem to demand it).
+ */
+ __pformat_putc( c, &stream );
+ goto format_scan;
+
+ case 'C':
+ /*
+ * Equivalent to `%lc'; set `length' accordingly,
+ * and simply fall through.
+ */
+ length = PFORMAT_LENGTH_LONG;
+
+ case 'c':
+ /*
+ * Single, (or single multibyte), character output...
+ *
+ * We handle these by copying the argument into our local
+ * `argval' buffer, and then we pass the address of that to
+ * either `__pformat_putchars()' or `__pformat_wputchars()',
+ * as appropriate, effectively formatting it as a string of
+ * the appropriate type, with a length of one.
+ *
+ * A side effect of this method of handling character data
+ * is that, if the user sets a precision of zero, then no
+ * character is actually emitted; we don't want that, so we
+ * forcibly override any user specified precision.
+ */
+ stream.precision = PFORMAT_IGNORE;
+
+ /* Now we invoke the appropriate format handler...
+ */
+ if( (length == PFORMAT_LENGTH_LONG)
+ || (length == PFORMAT_LENGTH_LLONG) )
+ {
+ /* considering any `long' type modifier as a reference to
+ * `wchar_t' data, (which is promoted to an `int' argument)...
+ */
+ wchar_t iargval = (wchar_t)(va_arg( argv, int ));
+ __pformat_wputchars( &iargval, 1, &stream );
+ }
+ else
+ { /* while anything else is simply taken as `char', (which
+ * is also promoted to an `int' argument)...
+ */
+ argval.__pformat_uchar_t = (unsigned char)(va_arg( argv, int ));
+ __pformat_putchars( (char *)(&argval), 1, &stream );
+ }
+ goto format_scan;
+
+ case 'S':
+ /*
+ * Equivalent to `%ls'; set `length' accordingly,
+ * and simply fall through.
+ */
+ length = PFORMAT_LENGTH_LONG;
+
+ case 's':
+ if( (length == PFORMAT_LENGTH_LONG)
+ || (length == PFORMAT_LENGTH_LLONG))
+ {
+ /* considering any `long' type modifier as a reference to
+ * a `wchar_t' string...
+ */
+ __pformat_wcputs( va_arg( argv, wchar_t * ), &stream );
+ }
+ else
+ /* This is normal string output;
+ * we simply invoke the appropriate handler...
+ */
+ __pformat_puts( va_arg( argv, char * ), &stream );
+ goto format_scan;
+ case 'm': /* strerror (errno) */
+ __pformat_puts (strerror (saved_errno), &stream);
+ goto format_scan;
+
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ /*
+ * Unsigned integer values; octal, decimal or hexadecimal format...
+ */
+ if( length == PFORMAT_LENGTH_LLONG )
+ /*
+ * with an `unsigned long long' argument, which we
+ * process `as is'...
+ */
+ argval.__pformat_ullong_t = va_arg( argv, unsigned long long );
+
+ else if( length == PFORMAT_LENGTH_LONG )
+ /*
+ * or with an `unsigned long', which we promote to
+ * `unsigned long long'...
+ */
+ argval.__pformat_ullong_t = va_arg( argv, unsigned long );
+
+ else
+ { /* or for any other size, which will have been promoted
+ * to `unsigned int', we select only the appropriately sized
+ * least significant segment, and again promote to the same
+ * size as `unsigned long long'...
+ */
+ argval.__pformat_ullong_t = va_arg( argv, unsigned int );
+ if( length == PFORMAT_LENGTH_SHORT )
+ /*
+ * from `unsigned short'...
+ */
+ argval.__pformat_ullong_t = argval.__pformat_ushort_t;
+
+ else if( length == PFORMAT_LENGTH_CHAR )
+ /*
+ * or even from `unsigned char'...
+ */
+ argval.__pformat_ullong_t = argval.__pformat_uchar_t;
+ }
+
+ /* so we can pass any size of argument to either of two
+ * common format handlers...
+ */
+ if( c == 'u' )
+ /*
+ * depending on whether output is to be encoded in
+ * decimal format...
+ */
+ __pformat_int( argval, &stream );
+
+ else
+ /* or in octal or hexadecimal format...
+ */
+ __pformat_xint( c, argval, &stream );
+
+ goto format_scan;
+
+ case 'd':
+ case 'i':
+ /*
+ * Signed integer values; decimal format...
+ * This is similar to `u', but must process `argval' as signed,
+ * and be prepared to handle negative numbers.
+ */
+ stream.flags |= PFORMAT_NEGATIVE;
+
+ if( length == PFORMAT_LENGTH_LLONG )
+ /*
+ * The argument is a `long long' type...
+ */
+ argval.__pformat_llong_t = va_arg( argv, long long );
+
+ else if( length == PFORMAT_LENGTH_LONG )
+ /*
+ * or here, a `long' type...
+ */
+ argval.__pformat_llong_t = va_arg( argv, long );
+
+ else
+ { /* otherwise, it's an `int' type...
+ */
+ argval.__pformat_llong_t = va_arg( argv, int );
+ if( length == PFORMAT_LENGTH_SHORT )
+ /*
+ * but it was promoted from a `short' type...
+ */
+ argval.__pformat_llong_t = argval.__pformat_short_t;
+ else if( length == PFORMAT_LENGTH_CHAR )
+ /*
+ * or even from a `char' type...
+ */
+ argval.__pformat_llong_t = argval.__pformat_char_t;
+ }
+
+ /* In any case, all share a common handler...
+ */
+ __pformat_int( argval, &stream );
+ goto format_scan;
+
+ case 'p':
+ /*
+ * Pointer argument; format as hexadecimal, subject to...
+ */
+ if( (state == PFORMAT_INIT) && (stream.flags == flags) )
+ {
+ /* Here, the user didn't specify any particular
+ * formatting attributes. We must choose a default
+ * which will be compatible with Microsoft's (broken)
+ * scanf() implementation, (i.e. matching the default
+ * used by MSVCRT's printf(), which appears to resemble
+ * "%0.8X" for 32-bit pointers); in particular, we MUST
+ * NOT adopt a GNU-like format resembling "%#x", because
+ * Microsoft's scanf() will choke on the "0x" prefix.
+ */
+ stream.flags |= PFORMAT_ZEROFILL;
+ stream.precision = 2 * sizeof( uintptr_t );
+ }
+ argval.__pformat_ullong_t = va_arg( argv, uintptr_t );
+ __pformat_xint( 'x', argval, &stream );
+ goto format_scan;
+
+ case 'e':
+ /*
+ * Floating point format, with lower case exponent indicator
+ * and lower case `inf' or `nan' representation when required;
+ * select lower case mode, and simply fall through...
+ */
+ stream.flags |= PFORMAT_XCASE;
+
+ case 'E':
+ /*
+ * Floating point format, with upper case exponent indicator
+ * and upper case `INF' or `NAN' representation when required,
+ * (or lower case for all of these, on fall through from above);
+ * select lower case mode, and simply fall through...
+ */
+ if( stream.flags & PFORMAT_LDOUBLE )
+ /*
+ * for a `long double' argument...
+ */
+ __pformat_efloat( va_arg( argv, long double ), &stream );
+
+ else
+ /* or just a `double', which we promote to `long double',
+ * so the two may share a common format handler.
+ */
+ __pformat_efloat( (long double)(va_arg( argv, double )), &stream );
+
+ goto format_scan;
+
+ case 'f':
+ /*
+ * Fixed point format, using lower case for `inf' and
+ * `nan', when appropriate; select lower case mode, and
+ * simply fall through...
+ */
+ stream.flags |= PFORMAT_XCASE;
+
+ case 'F':
+ /*
+ * Fixed case format using upper case, or lower case on
+ * fall through from above, for `INF' and `NAN'...
+ */
+ if( stream.flags & PFORMAT_LDOUBLE )
+ /*
+ * for a `long double' argument...
+ */
+ __pformat_float( va_arg( argv, long double ), &stream );
+
+ else
+ /* or just a `double', which we promote to `long double',
+ * so the two may share a common format handler.
+ */
+ __pformat_float( (long double)(va_arg( argv, double )), &stream );
+
+ goto format_scan;
+
+ case 'g':
+ /*
+ * Generalised floating point format, with lower case
+ * exponent indicator when required; select lower case
+ * mode, and simply fall through...
+ */
+ stream.flags |= PFORMAT_XCASE;
+
+ case 'G':
+ /*
+ * Generalised floating point format, with upper case,
+ * or on fall through from above, with lower case exponent
+ * indicator when required...
+ */
+ if( stream.flags & PFORMAT_LDOUBLE )
+ /*
+ * for a `long double' argument...
+ */
+ __pformat_gfloat( va_arg( argv, long double ), &stream );
+
+ else
+ /* or just a `double', which we promote to `long double',
+ * so the two may share a common format handler.
+ */
+ __pformat_gfloat( (long double)(va_arg( argv, double )), &stream );
+
+ goto format_scan;
+
+ case 'a':
+ /*
+ * Hexadecimal floating point format, with lower case radix
+ * and exponent indicators; select the lower case mode, and
+ * fall through...
+ */
+ stream.flags |= PFORMAT_XCASE;
+
+ case 'A':
+ /*
+ * Hexadecimal floating point format; handles radix and
+ * exponent indicators in either upper or lower case...
+ */
+ if( stream.flags & PFORMAT_LDOUBLE )
+ /*
+ * with a `long double' argument...
+ */
+ __pformat_xldouble( va_arg( argv, long double ), &stream );
+
+ else
+ /* or just a `double'.
+ */
+ __pformat_xldouble( (long double)(va_arg( argv, double )), &stream );
+
+ goto format_scan;
+
+ case 'n':
+ /*
+ * Save current output character count...
+ */
+ if( length == PFORMAT_LENGTH_CHAR )
+ /*
+ * to a signed `char' destination...
+ */
+ *va_arg( argv, char * ) = stream.count;
+
+ else if( length == PFORMAT_LENGTH_SHORT )
+ /*
+ * or to a signed `short'...
+ */
+ *va_arg( argv, short * ) = stream.count;
+
+ else if( length == PFORMAT_LENGTH_LONG )
+ /*
+ * or to a signed `long'...
+ */
+ *va_arg( argv, long * ) = stream.count;
+
+ else if( length == PFORMAT_LENGTH_LLONG )
+ /*
+ * or to a signed `long long'...
+ */
+ *va_arg( argv, long long * ) = stream.count;
+
+ else
+ /*
+ * or, by default, to a signed `int'.
+ */
+ *va_arg( argv, int * ) = stream.count;
+
+ goto format_scan;
+
+ /* Argument length modifiers...
+ * These are non-terminal; each sets the format parser
+ * into the PFORMAT_END state, and ends with a `break'.
+ */
+ case 'h':
+ /*
+ * Interpret the argument as explicitly of a `short'
+ * or `char' data type, truncated from the standard
+ * length defined for integer promotion.
+ */
+ if( *fmt == 'h' )
+ {
+ /* Modifier is `hh'; data type is `char' sized...
+ * Skip the second `h', and set length accordingly.
+ */
+ ++fmt;
+ length = PFORMAT_LENGTH_CHAR;
+ }
+
+ else
+ /* Modifier is `h'; data type is `short' sized...
+ */
+ length = PFORMAT_LENGTH_SHORT;
+
+ state = PFORMAT_END;
+ break;
+
+ case 'j':
+ /*
+ * Interpret the argument as being of the same size as
+ * a `intmax_t' entity...
+ */
+ length = __pformat_arg_length( intmax_t );
+ state = PFORMAT_END;
+ break;
+
+# ifdef _WIN32
+
+ case 'I':
+ /*
+ * The MSVCRT implementation of the printf() family of
+ * functions explicitly uses...
+ */
+ if( (fmt[0] == '6') && (fmt[1] == '4') )
+ {
+ /* I64' instead of `ll',
+ * when referring to `long long' integer types...
+ */
+ length = PFORMAT_LENGTH_LLONG;
+ fmt += 2;
+ }
+
+ else if( (fmt[0] == '3') && (fmt[1] == '2') )
+ {
+ /* and `I32' instead of `l',
+ * when referring to `long' integer types...
+ */
+ length = PFORMAT_LENGTH_LONG;
+ fmt += 2;
+ }
+
+ else
+ /* or unqualified `I' instead of `t' or `z',
+ * when referring to `ptrdiff_t' or `size_t' entities;
+ * (we will choose to map it to `ptrdiff_t').
+ */
+ length = __pformat_arg_length( ptrdiff_t );
+
+ state = PFORMAT_END;
+ break;
+
+# endif
+
+ case 'l':
+ /*
+ * Interpret the argument as explicitly of a
+ * `long' or `long long' data type.
+ */
+ if( *fmt == 'l' )
+ {
+ /* Modifier is `ll'; data type is `long long' sized...
+ * Skip the second `l', and set length accordingly.
+ */
+ ++fmt;
+ length = PFORMAT_LENGTH_LLONG;
+ }
+
+ else
+ /* Modifier is `l'; data type is `long' sized...
+ */
+ length = PFORMAT_LENGTH_LONG;
+
+ state = PFORMAT_END;
+ break;
+
+ case 'L':
+ /*
+ * Identify the appropriate argument as a `long double',
+ * when associated with `%a', `%A', `%e', `%E', `%f', `%F',
+ * `%g' or `%G' format specifications.
+ */
+ stream.flags |= PFORMAT_LDOUBLE;
+ state = PFORMAT_END;
+ break;
+
+ case 't':
+ /*
+ * Interpret the argument as being of the same size as
+ * a `ptrdiff_t' entity...
+ */
+ length = __pformat_arg_length( ptrdiff_t );
+ state = PFORMAT_END;
+ break;
+
+ case 'z':
+ /*
+ * Interpret the argument as being of the same size as
+ * a `size_t' entity...
+ */
+ length = __pformat_arg_length( size_t );
+ state = PFORMAT_END;
+ break;
+
+ /* Precision indicator...
+ * May appear once only; it must precede any modifier
+ * for argument length, or any data type specifier.
+ */
+ case '.':
+ if( state < PFORMAT_GET_PRECISION )
+ {
+ /* We haven't seen a precision specification yet,
+ * so initialise it to zero, (in case no digits follow),
+ * and accept any following digits as the precision.
+ */
+ stream.precision = 0;
+ width_spec = &stream.precision;
+ state = PFORMAT_GET_PRECISION;
+ }
+
+ else
+ /* We've already seen a precision specification,
+ * so this is just junk; proceed to end game.
+ */
+ state = PFORMAT_END;
+
+ /* Either way, we must not fall through here.
+ */
+ break;
+
+ /* Variable field width, or precision specification,
+ * derived from the argument list...
+ */
+ case '*':
+ /*
+ * When this appears...
+ */
+ if( width_spec
+ && ((state == PFORMAT_INIT) || (state == PFORMAT_GET_PRECISION)) )
+ {
+ /* in proper context; assign to field width
+ * or precision, as appropriate.
+ */
+ if( (*width_spec = va_arg( argv, int )) < 0 )
+ {
+ /* Assigned value was negative...
+ */
+ if( state == PFORMAT_INIT )
+ {
+ /* For field width, this is equivalent to
+ * a positive value with the `-' flag...
+ */
+ stream.flags |= PFORMAT_LJUSTIFY;
+ stream.width = -stream.width;
+ }
+
+ else
+ /* while as a precision specification,
+ * it should simply be ignored.
+ */
+ stream.precision = PFORMAT_IGNORE;
+ }
+ }
+
+ else
+ /* out of context; give up on width and precision
+ * specifications for this conversion.
+ */
+ state = PFORMAT_END;
+
+ /* Mark as processed...
+ * we must not see `*' again, in this context.
+ */
+ width_spec = NULL;
+ break;
+
+ /* Formatting flags...
+ * Must appear while in the PFORMAT_INIT state,
+ * and are non-terminal, so again, end with `break'.
+ */
+ case '#':
+ /*
+ * Select alternate PFORMAT_HASHED output style.
+ */
+ if( state == PFORMAT_INIT )
+ stream.flags |= PFORMAT_HASHED;
+ break;
+
+ case '+':
+ /*
+ * Print a leading sign with numeric output,
+ * for both positive and negative values.
+ */
+ if( state == PFORMAT_INIT )
+ stream.flags |= PFORMAT_POSITIVE;
+ break;
+
+ case '-':
+ /*
+ * Select left justification of displayed output
+ * data, within the output field width, instead of
+ * the default flush right justification.
+ */
+ if( state == PFORMAT_INIT )
+ stream.flags |= PFORMAT_LJUSTIFY;
+ break;
+
+ case '\'':
+ /*
+ * This is an XSI extension to the POSIX standard,
+ * which we do not support, at present.
+ */
+ if (state == PFORMAT_INIT)
+ {
+ int len; wchar_t rpchr; mbstate_t cstate;
+ stream.flags |= PFORMAT_GROUPED; /* $$$$ */
+ memset (&cstate, 0, sizeof(state));
+ if ((len = mbrtowc( &rpchr, localeconv()->thousands_sep, 16, &cstate)) > 0)
+ stream.thousands_chr = rpchr;
+ stream.thousands_chr_len = len;
+ }
+ break;
+
+ case '\x20':
+ /*
+ * Reserve a single space, within the output field,
+ * for display of the sign of signed data; this will
+ * be occupied by the minus sign, if the data value
+ * is negative, or by a plus sign if the data value
+ * is positive AND the `+' flag is also present, or
+ * by a space otherwise. (Technically, this flag
+ * is redundant, if the `+' flag is present).
+ */
+ if( state == PFORMAT_INIT )
+ stream.flags |= PFORMAT_ADDSPACE;
+ break;
+
+ case '0':
+ /*
+ * May represent a flag, to activate the `pad with zeros'
+ * option, or it may simply be a digit in a width or in a
+ * precision specification...
+ */
+ if( state == PFORMAT_INIT )
+ {
+ /* This is the flag usage...
+ */
+ stream.flags |= PFORMAT_ZEROFILL;
+ break;
+ }
+
+ default:
+ /*
+ * If we didn't match anything above, then we will check
+ * for digits, which we may accumulate to generate field
+ * width or precision specifications...
+ */
+ if( (state < PFORMAT_END) && ('9' >= c) && (c >= '0') )
+ {
+ if( state == PFORMAT_INIT )
+ /*
+ * Initial digits explicitly relate to field width...
+ */
+ state = PFORMAT_SET_WIDTH;
+
+ else if( state == PFORMAT_GET_PRECISION )
+ /*
+ * while those following a precision indicator
+ * explicitly relate to precision.
+ */
+ state = PFORMAT_SET_PRECISION;
+
+ if( width_spec )
+ {
+ /* We are accepting a width or precision specification...
+ */
+ if( *width_spec < 0 )
+ /*
+ * and accumulation hasn't started yet; we simply
+ * initialise the accumulator with the current digit
+ * value, converting from ASCII to decimal.
+ */
+ *width_spec = c - '0';
+
+ else
+ /* Accumulation has already started; we perform a
+ * `leftwise decimal digit shift' on the accumulator,
+ * (i.e. multiply it by ten), then add the decimal
+ * equivalent value of the current digit.
+ */
+ *width_spec = *width_spec * 10 + c - '0';
+ }
+ }
+
+ else
+ {
+ /* We found a digit out of context, or some other character
+ * with no designated meaning; reject this format specification,
+ * backtrack, and emit it as literal text...
+ */
+ fmt = backtrack;
+ __pformat_putc( '%', &stream );
+ goto format_scan;
+ }
+ }
+ }
+ }
+
+ else
+ /* We just parsed a character which is not included within any format
+ * specification; we simply emit it as a literal.
+ */
+ __pformat_putc( c, &stream );
+ }
+
+ /* When we have fully dispatched the format string, the return value is the
+ * total number of bytes we transferred to the output destination.
+ */
+ return stream.count;
+}
+
+/* $RCSfile: pformat.c,v $Revision: 1.9 $: end of file */
diff --git a/src/lib/evil/evil_pformatw.c b/src/lib/evil/evil_pformatw.c
new file mode 100644
index 0000000000..592b56881c
--- /dev/null
+++ b/src/lib/evil/evil_pformatw.c
@@ -0,0 +1,9 @@
+/**
+ * This file has no copyright assigned and is placed in the Public Domain.
+ * This file is part of the w64 mingw-runtime package.
+ * No warranty is given; refer to the file DISCLAIMER.PD within this package.
+ */
+#define __BUILD_WIDEAPI 1
+
+#include "evil_pformata.c"
+
diff --git a/src/lib/evil/evil_print.h b/src/lib/evil/evil_print.h
new file mode 100644
index 0000000000..511247bcbd
--- /dev/null
+++ b/src/lib/evil/evil_print.h
@@ -0,0 +1,37 @@
+#ifndef __EVIL_PRINT_H__
+#define __EVIL_PRINT_H__
+
+
+#include "evil_macro.h"
+
+
+EAPI int __cdecl _evil_fprintfa(FILE *, const char *, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_printfa(const char *, ...) __EVIL_PRINTF(1, 2) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_sprintfa(char *, const char *, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_snprintfa(char *, size_t, const char *, ...) __EVIL_PRINTF(3, 4) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vfprintfa(FILE *, const char *, va_list) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vprintfa(const char *, va_list) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vsprintfa(char *, const char *, va_list) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vsnprintfa(char *, size_t, const char *, va_list) __EVIL_NOTHROW;
+
+EAPI int __cdecl _evil_fscanf (FILE *, const char *, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_scanf (const char *, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_sscanf (const char *, const char *, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vfscanf(FILE *, const char *, va_list) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vscanf (const char *, va_list) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vsscanf(const char *, const char *, va_list) __EVIL_NOTHROW;
+
+EAPI int __cdecl _evil_asprintf(char ** __restrict__, const char * __restrict__, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vasprintf(char ** __restrict__, const char * __restrict__, va_list) __EVIL_NOTHROW;
+
+EAPI int __cdecl _evil_fprintfw(FILE *, const wchar_t *, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_printfw(const wchar_t *, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_sprintfw(wchar_t *, const wchar_t *, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_snprintfw(wchar_t *, size_t, const wchar_t *, ...) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vfprintfw(FILE *, const wchar_t *, va_list) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vprintfw(const wchar_t *, va_list) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vsprintfw(wchar_t *, const wchar_t *, va_list) __EVIL_NOTHROW;
+EAPI int __cdecl _evil_vsnprintfw(wchar_t *, size_t, const wchar_t *, va_list) __EVIL_NOTHROW;
+
+
+#endif /* __EVIL_PRINT_H__ */
diff --git a/src/lib/evil/evil_printa.c b/src/lib/evil/evil_printa.c
new file mode 100644
index 0000000000..e6f6eb8227
--- /dev/null
+++ b/src/lib/evil/evil_printa.c
@@ -0,0 +1,1786 @@
+#define __CRT__NO_INLINE
+
+#include <limits.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <ctype.h>
+#include <wctype.h>
+#include <locale.h>
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif /* HAVE_ERRNO_H */
+
+#include "evil_pformat.h"
+#include "evil_print.h"
+#include "gdtoa/gdtoa.h"
+
+
+/*============================================================================*
+ * Local *
+ *============================================================================*/
+
+
+/* Helper flags for conversion. */
+#define IS_C 0x0001
+#define IS_S 0x0002
+#define IS_L 0x0004
+#define IS_LL 0x0008
+#define IS_SIGNED_NUM 0x0010
+#define IS_POINTER 0x0020
+#define IS_HEX_FLOAT 0x0040
+#define IS_SUPPRESSED 0x0080
+#define USE_GROUP 0x0100
+#define USE_GNU_ALLOC 0x0200
+#define USE_POSIX_ALLOC 0x0400
+
+#define IS_ALLOC_USED (USE_GNU_ALLOC | USE_POSIX_ALLOC)
+
+#ifndef __BUILD_WIDEAPI
+
+/* internal stream structure with back-buffer. */
+typedef struct _IFP
+{
+ __extension__ union {
+ void *fp;
+ const char *str;
+ };
+ int bch[1024];
+ int is_string : 1;
+ int back_top;
+ int seen_eof : 1;
+} _IFP;
+
+static void *
+get_va_nth (va_list argp, unsigned int n)
+{
+ va_list ap;
+ if (!n) abort ();
+ va_copy (ap, argp);
+ while (--n > 0)
+ (void) va_arg(ap, void *);
+ return va_arg (ap, void *);
+}
+
+static void
+optimize_alloc (char **p, char *end, size_t alloc_sz)
+{
+ size_t need_sz;
+ char *h;
+
+ if (!p || !*p)
+ return;
+
+ need_sz = end - *p;
+ if (need_sz == alloc_sz)
+ return;
+
+ if ((h = (char *) realloc (*p, need_sz)) != NULL)
+ *p = h;
+}
+
+static void
+back_ch (int c, _IFP *s, size_t *rin, int not_eof)
+{
+ if (!not_eof && c == EOF)
+ return;
+ if (s->is_string == 0)
+ {
+ FILE *fp = s->fp;
+ ungetc (c, fp);
+ rin[0] -= 1;
+ return;
+ }
+ rin[0] -= 1;
+ s->bch[s->back_top] = c;
+ s->back_top += 1;
+}
+
+static int
+in_ch (_IFP *s, size_t *rin)
+{
+ int r;
+ if (s->back_top)
+ {
+ s->back_top -= 1;
+ r = s->bch[s->back_top];
+ rin[0] += 1;
+ }
+ else if (s->seen_eof)
+ {
+ return EOF;
+ }
+ else if (s->is_string)
+ {
+ const char *ps = s->str;
+ r = ((int) *ps) & 0xff;
+ ps++;
+ if (r != 0)
+ {
+ rin[0] += 1;
+ s->str = ps;
+ return r;
+ }
+ s->seen_eof = 1;
+ return EOF;
+ }
+ else
+ {
+ FILE *fp = (FILE *) s->fp;
+ r = getc (fp);
+ if (r != EOF)
+ rin[0] += 1;
+ else s->seen_eof = 1;
+ }
+ return r;
+}
+
+static int
+match_string (_IFP *s, size_t *rin, int *c, const char *str)
+{
+ int ch = *c;
+
+ if (*str == 0)
+ return 1;
+
+ if (*str != (char) tolower (ch))
+ return 0;
+ ++str;
+ while (*str != 0)
+ {
+ if ((ch = in_ch (s, rin)) == EOF)
+ {
+ c[0] = ch;
+ return 0;
+ }
+
+ if (*str != (char) tolower (ch))
+ {
+ c[0] = ch;
+ return 0;
+ }
+ ++str;
+ }
+ c[0] = ch;
+ return 1;
+}
+
+struct gcollect
+{
+ size_t count;
+ struct gcollect *next;
+ char **ptrs[32];
+};
+
+static void
+release_ptrs (struct gcollect **pt, char **wbuf)
+{
+ struct gcollect *pf;
+ size_t cnt;
+
+ if (!pt || (pf = *pt) == NULL)
+ return;
+ while (pf != NULL)
+ {
+ struct gcollect *pf_sv = pf;
+ for (cnt = 0; cnt < pf->count; ++cnt)
+ {
+ free (*pf->ptrs[cnt]);
+ *pf->ptrs[cnt] = NULL;
+ }
+ pf = pf->next;
+ free (pf_sv);
+ }
+ *pt = NULL;
+ if (wbuf)
+ {
+ free (*wbuf);
+ *wbuf = NULL;
+ }
+}
+
+static int
+cleanup_return (int rval, struct gcollect **pfree, char **strp, char **wbuf)
+{
+ if (rval == EOF)
+ release_ptrs (pfree, wbuf);
+ else
+ {
+ if (pfree)
+ {
+ struct gcollect *pf = *pfree, *pf_sv;
+ while (pf != NULL)
+ {
+ pf_sv = pf;
+ pf = pf->next;
+ free (pf_sv);
+ }
+ *pfree = NULL;
+ }
+ if (strp != NULL)
+ {
+ free (*strp);
+ *strp = NULL;
+ }
+ if (wbuf)
+ {
+ free (*wbuf);
+ *wbuf = NULL;
+ }
+ }
+ return rval;
+}
+
+static struct gcollect *
+resize_gcollect (struct gcollect *pf)
+{
+ struct gcollect *np;
+ if (pf && pf->count < 32)
+ return pf;
+ np = malloc (sizeof (struct gcollect));
+ np->count = 0;
+ np->next = pf;
+ return np;
+}
+
+static char *
+resize_wbuf (size_t wpsz, size_t *wbuf_max_sz, char *old)
+{
+ char *wbuf;
+ size_t nsz;
+ if (*wbuf_max_sz != wpsz)
+ return old;
+ nsz = (256 > (2 * wbuf_max_sz[0]) ? 256 : (2 * wbuf_max_sz[0]));
+ if (!old)
+ wbuf = (char *) malloc (nsz);
+ else
+ wbuf = (char *) realloc (old, nsz);
+ if (!wbuf)
+ {
+ if (old)
+ free (old);
+ }
+ else
+ *wbuf_max_sz = nsz;
+ return wbuf;
+}
+
+static int
+_evil_sformat (_IFP *s, const char *format, va_list argp)
+{
+ const char *f = format;
+ struct gcollect *gcollect = NULL;
+ size_t read_in = 0, wbuf_max_sz = 0, cnt;
+ ssize_t str_sz = 0;
+ char *str = NULL, **pstr = NULL, *wbuf = NULL;
+ wchar_t *wstr = NULL;
+ int rval = 0, c = 0, ignore_ws = 0;
+ va_list arg;
+ unsigned char fc;
+ unsigned int npos;
+ int width, flags, base = 0, errno_sv;
+ size_t wbuf_cur_sz, read_in_sv, new_sz, n;
+ char seen_dot, seen_exp, is_neg, not_in;
+ char *tmp_wbuf_ptr, buf[MB_LEN_MAX];
+ const char *lc_decimal_point, *lc_thousands_sep;
+ mbstate_t state, cstate;
+ union {
+ unsigned long long ull;
+ unsigned long ul;
+ long long ll;
+ long l;
+ } cv_val;
+
+ arg = argp;
+
+ if (!s || s->fp == NULL || !format)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EINVAL;
+#endif /* HAVE_ERRNO_H */
+ return EOF;
+ }
+
+ memset (&state, 0, sizeof (state));
+
+ lc_decimal_point = localeconv()->decimal_point;
+ lc_thousands_sep = localeconv()->thousands_sep;
+ if (lc_thousands_sep != NULL && *lc_thousands_sep == 0)
+ lc_thousands_sep = NULL;
+
+ while (*f != 0)
+ {
+ if (!isascii ((unsigned char) *f))
+ {
+ int len;
+
+ if ((len = mbrlen (f, strlen (f), &state)) > 0)
+ {
+ do
+ {
+ if ((c = in_ch (s, &read_in)) == EOF || c != (unsigned char) *f++)
+ {
+ back_ch (c, s, &read_in, 1);
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+ }
+ }
+ while (--len > 0);
+
+ continue;
+ }
+ }
+
+ fc = *f++;
+ if (fc != '%')
+ {
+ if (isspace (fc))
+ ignore_ws = 1;
+ else
+ {
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ if (ignore_ws)
+ {
+ ignore_ws = 0;
+ if (isspace (c))
+ {
+ do
+ {
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+ }
+ while (isspace (c));
+ }
+ }
+
+ if (c != fc)
+ {
+ back_ch (c, s, &read_in, 0);
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ }
+
+ continue;
+ }
+
+ width = flags = 0;
+ npos = 0;
+ wbuf_cur_sz = 0;
+
+ if (isdigit ((unsigned char) *f))
+ {
+ const char *svf = f;
+ npos = (unsigned char) *f++ - '0';
+ while (isdigit ((unsigned char) *f))
+ npos = npos * 10 + ((unsigned char) *f++ - '0');
+ if (*f != '$')
+ {
+ npos = 0;
+ f = svf;
+ }
+ else
+ f++;
+ }
+
+ do
+ {
+ if (*f == '*')
+ flags |= IS_SUPPRESSED;
+ else if (*f == '\'')
+ {
+ if (lc_thousands_sep)
+ flags |= USE_GROUP;
+ }
+ else if (*f == 'I')
+ /* we don't support locale's digits (i18N), but ignore it for now silently. */
+ ;
+ else
+ break;
+ ++f;
+ }
+ while (1);
+
+ while (isdigit ((unsigned char) *f))
+ width = width * 10 + ((unsigned char) *f++ - '0');
+
+ if (!width)
+ width = -1;
+
+ switch (*f)
+ {
+ case 'h':
+ ++f;
+ flags |= (*f == 'h' ? IS_C : IS_S);
+ if (*f == 'h')
+ ++f;
+ break;
+ case 'l':
+ ++f;
+ flags |= (*f == 'l' ? IS_LL : 0) | IS_L;
+ if (*f == 'l')
+ ++f;
+ break;
+ case 'q': case 'L':
+ ++f;
+ flags |= IS_LL | IS_L;
+ break;
+ case 'a':
+ if (f[1] != 's' && f[1] != 'S' && f[1] != '[')
+ break;
+ ++f;
+ flags |= USE_GNU_ALLOC;
+ break;
+ case 'm':
+ flags |= USE_POSIX_ALLOC;
+ ++f;
+ if (*f == 'l')
+ {
+ flags |= IS_L;
+ f++;
+ }
+ break;
+ case 'z':
+#ifdef _WIN64
+ flags |= IS_LL;
+#else
+ flags |= IS_L;
+#endif
+ ++f;
+ break;
+ case 'j':
+ if (sizeof (uintmax_t) > sizeof (unsigned long))
+ flags |= IS_LL;
+ else if (sizeof (uintmax_t) > sizeof (unsigned int))
+ flags |= IS_L;
+ ++f;
+ break;
+ case 't':
+#ifdef _WIN64
+ flags |= IS_LL;
+#else
+ flags |= IS_L;
+#endif
+ ++f;
+ break;
+ case 0:
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ default:
+ break;
+ }
+
+ if (*f == 0)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ fc = *f++;
+ if (ignore_ws || (fc != '[' && fc != 'c' && fc != 'C' && fc != 'n'))
+ {
+ errno_sv = errno;
+ errno = 0;
+ do
+ {
+ if ((c == EOF || (c = in_ch (s, &read_in)) == EOF)
+#ifdef HAVE_ERRNO_H
+ && errno == EINTR
+#endif /* HAVE_ERRNO_H */
+ )
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+ }
+ while (isspace (c));
+
+ ignore_ws = 0;
+ errno = errno_sv;
+ back_ch (c, s, &read_in, 0);
+ }
+
+ switch (fc)
+ {
+ case 'c':
+ if ((flags & IS_L) != 0)
+ fc = 'C';
+ break;
+ case 's':
+ if ((flags & IS_L) != 0)
+ fc = 'S';
+ break;
+ }
+
+ switch (fc)
+ {
+ case '%':
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+ if (c != fc)
+ {
+ back_ch (c, s, &read_in, 1);
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ break;
+
+ case 'n':
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ if ((flags & IS_LL) != 0)
+ *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = read_in;
+ else if ((flags & IS_L) != 0)
+ *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = read_in;
+ else if ((flags & IS_S) != 0)
+ *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = read_in;
+ else if ((flags & IS_C) != 0)
+ *(npos != 0 ? (char *) get_va_nth (argp, npos) : va_arg (arg, char *)) = read_in;
+ else
+ *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = read_in;
+ }
+ break;
+
+ case 'c':
+ if (width == -1)
+ width = 1;
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ if ((flags & IS_ALLOC_USED) != 0)
+ {
+ if (npos != 0)
+ pstr = (char **) get_va_nth (argp, npos);
+ else
+ pstr = va_arg (arg, char **);
+
+ if (!pstr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ str_sz = (width > 1024 ? 1024 : width);
+ if ((str = *pstr = (char *) malloc (str_sz)) == NULL)
+ return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ gcollect = resize_gcollect (gcollect);
+ gcollect->ptrs[gcollect->count++] = pstr;
+ }
+ else
+ {
+ if (npos != 0)
+ str = (char *) get_va_nth (argp, npos);
+ else
+ str = va_arg (arg, char *);
+ if (!str)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ }
+
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ do
+ {
+ if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
+ {
+ new_sz = str_sz + (str_sz >= width ? width - 1 : str_sz);
+ while ((str = (char *) realloc (*pstr, new_sz)) == NULL
+ && new_sz > (size_t) (str_sz + 1))
+ new_sz = str_sz + 1;
+ if (!str)
+ {
+ release_ptrs (&gcollect, &wbuf);
+ return EOF;
+ }
+ *pstr = str;
+ str += str_sz;
+ str_sz = new_sz;
+ }
+ *str++ = c;
+ }
+ while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
+ }
+ else
+ while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ optimize_alloc (pstr, str, str_sz);
+ pstr = NULL;
+ ++rval;
+ }
+
+ break;
+
+ case 'C':
+ if (width == -1)
+ width = 1;
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ if ((flags & IS_ALLOC_USED) != 0)
+ {
+ if (npos != 0)
+ pstr = (char **) get_va_nth (argp, npos);
+ else
+ pstr = va_arg (arg, char **);
+
+ if (!pstr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ str_sz = (width > 1024 ? 1024 : width);
+ *pstr = (char *) malloc (str_sz * sizeof (wchar_t));
+ if ((wstr = (wchar_t *) *pstr) == NULL)
+ return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+ gcollect = resize_gcollect (gcollect);
+ gcollect->ptrs[gcollect->count++] = pstr;
+ }
+ else
+ {
+ if (npos != 0)
+ wstr = (wchar_t *) get_va_nth (argp, npos);
+ else
+ wstr = va_arg (arg, wchar_t *);
+ if (!wstr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ }
+
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ memset (&cstate, 0, sizeof (cstate));
+
+ do
+ {
+ buf[0] = c;
+
+ if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
+ && wstr == ((wchar_t *) *pstr + str_sz))
+ {
+ new_sz = str_sz + (str_sz > width ? width - 1 : str_sz);
+
+ while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
+ && new_sz > (size_t) (str_sz + 1))
+ new_sz = str_sz + 1;
+ if (!wstr)
+ {
+ release_ptrs (&gcollect, &wbuf);
+ return EOF;
+ }
+ *pstr = (char *) wstr;
+ wstr += str_sz;
+ str_sz = new_sz;
+ }
+
+ while (1)
+ {
+ n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate);
+
+ if (n == (size_t) -2)
+ {
+ if ((c = in_ch (s, &read_in)) == EOF)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EILSEQ;
+#endif /* HAVE_ERRNO_H */
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+
+ buf[0] = c;
+ continue;
+ }
+
+ if (n != 1)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EILSEQ;
+#endif /* HAVE_ERRNO_H */
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ break;
+ }
+
+ ++wstr;
+ }
+ while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
+ pstr = NULL;
+ ++rval;
+ }
+ break;
+
+ case 's':
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ if ((flags & IS_ALLOC_USED) != 0)
+ {
+ if (npos != 0)
+ pstr = (char **) get_va_nth (argp, npos);
+ else
+ pstr = va_arg (arg, char **);
+
+ if (!pstr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ str_sz = 100;
+ if ((str = *pstr = (char *) malloc (100)) == NULL)
+ return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+ gcollect = resize_gcollect (gcollect);
+ gcollect->ptrs[gcollect->count++] = pstr;
+ }
+ else
+ {
+ if (npos != 0)
+ str = (char *) get_va_nth (argp, npos);
+ else
+ str = va_arg (arg, char *);
+ if (!str)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ }
+
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ do
+ {
+ if (isspace (c))
+ {
+ back_ch (c, s, &read_in, 1);
+ break;
+ }
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ *str++ = c;
+ if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
+ {
+ new_sz = str_sz * 2;
+
+ while ((str = (char *) realloc (*pstr, new_sz)) == NULL
+ && new_sz > (size_t) (str_sz + 1))
+ new_sz = str_sz + 1;
+ if (!str)
+ {
+ if ((flags & USE_POSIX_ALLOC) == 0)
+ {
+ (*pstr)[str_sz - 1] = 0;
+ pstr = NULL;
+ ++rval;
+ }
+ return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+ }
+ *pstr = str;
+ str += str_sz;
+ str_sz = new_sz;
+ }
+ }
+ }
+ while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != EOF);
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ *str++ = 0;
+ optimize_alloc (pstr, str, str_sz);
+ pstr = NULL;
+ ++rval;
+ }
+ break;
+
+ case 'S':
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ if ((flags & IS_ALLOC_USED) != 0)
+ {
+ if (npos != 0)
+ pstr = (char **) get_va_nth (argp, npos);
+ else
+ pstr = va_arg (arg, char **);
+
+ if (!pstr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ str_sz = 100;
+ *pstr = (char *) malloc (100 * sizeof (wchar_t));
+ if ((wstr = (wchar_t *) *pstr) == NULL)
+ return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+ gcollect = resize_gcollect (gcollect);
+ gcollect->ptrs[gcollect->count++] = pstr;
+ }
+ else
+ {
+ if (npos != 0)
+ wstr = (wchar_t *) get_va_nth (argp, npos);
+ else
+ wstr = va_arg (arg, wchar_t *);
+ if (!wstr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ }
+
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ memset (&cstate, 0, sizeof (cstate));
+
+ do
+ {
+ if (isspace (c))
+ {
+ back_ch (c, s, &read_in, 1);
+ break;
+ }
+
+ buf[0] = c;
+
+ while (1)
+ {
+ n = mbrtowc ((flags & IS_SUPPRESSED) == 0 ? wstr : NULL, buf, 1, &cstate);
+
+ if (n == (size_t) -2)
+ {
+ if ((c = in_ch (s, &read_in)) == EOF)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EILSEQ;
+#endif /* HAVE_ERRNO_H */
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+
+ buf[0] = c;
+ continue;
+ }
+
+ if (n != 1)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EILSEQ;
+#endif /* HAVE_ERRNO_H */
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+
+ ++wstr;
+ break;
+ }
+
+ if ((flags & IS_SUPPRESSED) == 0 && (flags & IS_ALLOC_USED) != 0
+ && wstr == ((wchar_t *) *pstr + str_sz))
+ {
+ new_sz = str_sz * 2;
+ while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
+ && new_sz > (size_t) (str_sz + 1))
+ new_sz = str_sz + 1;
+ if (!wstr)
+ {
+ if ((flags & USE_POSIX_ALLOC) == 0)
+ {
+ ((wchar_t *) (*pstr))[str_sz - 1] = 0;
+ pstr = NULL;
+ ++rval;
+ }
+ return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+ }
+ *pstr = (char *) wstr;
+ wstr += str_sz;
+ str_sz = new_sz;
+ }
+ }
+ while ((width <= 0 || --width > 0) && (c = in_ch (s, &read_in)) != EOF);
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ *wstr++ = 0;
+ optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
+ pstr = NULL;
+ ++rval;
+ }
+ break;
+
+ case 'd': case 'i':
+ case 'o': case 'p':
+ case 'u':
+ case 'x': case 'X':
+ switch (fc)
+ {
+ case 'd':
+ flags |= IS_SIGNED_NUM;
+ base = 10;
+ break;
+ case 'i':
+ flags |= IS_SIGNED_NUM;
+ base = 0;
+ break;
+ case 'o':
+ base = 8;
+ break;
+ case 'p':
+ base = 16;
+ flags &= ~(IS_S | IS_LL | IS_L);
+ #ifdef _WIN64
+ flags |= IS_LL;
+ #endif
+ flags |= IS_L | IS_POINTER;
+ break;
+ case 'u':
+ base = 10;
+ break;
+ case 'x': case 'X':
+ base = 16;
+ break;
+ }
+
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+ if (c == '+' || c == '-')
+ {
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+ if (width > 0)
+ --width;
+ c = in_ch (s, &read_in);
+ }
+ if (width != 0 && c == '0')
+ {
+ if (width > 0)
+ --width;
+
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+ c = in_ch (s, &read_in);
+
+ if (width != 0 && tolower (c) == 'x')
+ {
+ if (!base)
+ base = 16;
+ if (base == 16)
+ {
+ if (width > 0)
+ --width;
+ c = in_ch (s, &read_in);
+ }
+ }
+ else if (!base)
+ base = 8;
+ }
+
+ if (!base)
+ base = 10;
+
+ while (c != EOF && width != 0)
+ {
+ if (base == 16)
+ {
+ if (!isxdigit (c))
+ break;
+ }
+ else if (!isdigit (c) || (int) (c - '0') >= base)
+ {
+ const char *p = lc_thousands_sep;
+ int remain;
+
+ if (base != 10 || (flags & USE_GROUP) == 0)
+ break;
+ remain = width > 0 ? width : INT_MAX;
+ while ((unsigned char) *p == c && remain >= 0)
+ {
+ /* As our conversion routines aren't supporting thousands
+ separators, we are filtering them here. */
+
+ ++p;
+ if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
+ break;
+ --remain;
+ }
+
+ if (*p != 0)
+ {
+ if (p > lc_thousands_sep)
+ {
+ back_ch (c, s, &read_in, 0);
+ while (--p > lc_thousands_sep)
+ back_ch ((unsigned char) *p, s, &read_in, 1);
+ c = (unsigned char) *p;
+ }
+ break;
+ }
+
+ if (width > 0)
+ width = remain;
+ --wbuf_cur_sz;
+ }
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+ if (width > 0)
+ --width;
+
+ c = in_ch (s, &read_in);
+ }
+
+ if (!wbuf_cur_sz || (wbuf_cur_sz == 1 && (wbuf[0] == '+' || wbuf[0] == '-')))
+ {
+ if (!wbuf_cur_sz && (flags & IS_POINTER) != 0
+ && match_string (s, &read_in, &c, "(nil)"))
+ {
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = '0';
+ }
+ else
+ {
+ back_ch (c, s, &read_in, 0);
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ }
+ else
+ back_ch (c, s, &read_in, 0);
+
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = 0;
+
+ if ((flags & IS_LL))
+ {
+ if (flags & IS_SIGNED_NUM)
+ cv_val.ll = strtoll (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
+ else
+ cv_val.ull = strtoull (wbuf, &tmp_wbuf_ptr, base);
+ }
+ else
+ {
+ if (flags & IS_SIGNED_NUM)
+ cv_val.l = strtol (wbuf, &tmp_wbuf_ptr, base/*, flags & USE_GROUP*/);
+ else
+ cv_val.ul = strtoul (wbuf, &tmp_wbuf_ptr, base);
+ }
+ if (wbuf == tmp_wbuf_ptr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ if ((flags & IS_SIGNED_NUM) != 0)
+ {
+ if ((flags & IS_LL) != 0)
+ *(npos != 0 ? (long long *) get_va_nth (argp, npos) : va_arg (arg, long long *)) = cv_val.ll;
+ else if ((flags & IS_L) != 0)
+ *(npos != 0 ? (long *) get_va_nth (argp, npos) : va_arg (arg, long *)) = cv_val.l;
+ else if ((flags & IS_S) != 0)
+ *(npos != 0 ? (short *) get_va_nth (argp, npos) : va_arg (arg, short *)) = (short) cv_val.l;
+ else if ((flags & IS_C) != 0)
+ *(npos != 0 ? (signed char *) get_va_nth (argp, npos) : va_arg (arg, signed char *)) = (signed char) cv_val.ul;
+ else
+ *(npos != 0 ? (int *) get_va_nth (argp, npos) : va_arg (arg, int *)) = (int) cv_val.l;
+ }
+ else
+ {
+ if ((flags & IS_LL) != 0)
+ *(npos != 0 ? (unsigned long long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long long *)) = cv_val.ull;
+ else if ((flags & IS_L) != 0)
+ *(npos != 0 ? (unsigned long *) get_va_nth (argp, npos) : va_arg (arg, unsigned long *)) = cv_val.ul;
+ else if ((flags & IS_S) != 0)
+ *(npos != 0 ? (unsigned short *) get_va_nth (argp, npos) : va_arg (arg, unsigned short *))
+ = (unsigned short) cv_val.ul;
+ else if ((flags & IS_C) != 0)
+ *(npos != 0 ? (unsigned char *) get_va_nth (argp, npos) : va_arg (arg, unsigned char *)) = (unsigned char) cv_val.ul;
+ else
+ *(npos != 0 ? (unsigned int *) get_va_nth (argp, npos) : va_arg (arg, unsigned int *)) = (unsigned int) cv_val.ul;
+ }
+ ++rval;
+ }
+ break;
+
+ case 'e': case 'E':
+ case 'f': case 'F':
+ case 'g': case 'G':
+ case 'a': case 'A':
+ if (width > 0)
+ --width;
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ seen_dot = seen_exp = 0;
+ is_neg = (c == '-' ? 1 : 0);
+
+ if (c == '-' || c == '+')
+ {
+ if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ if (width > 0)
+ --width;
+ }
+
+ if (tolower (c) == 'n')
+ {
+ const char *match_txt = "nan";
+
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+
+ ++match_txt;
+ do
+ {
+ if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ if (width > 0)
+ --width;
+
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+ ++match_txt;
+ }
+ while (*match_txt != 0);
+ }
+ else if (tolower (c) == 'i')
+ {
+ const char *match_txt = "inf";
+
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+
+ ++match_txt;
+ do
+ {
+ if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ if (width > 0)
+ --width;
+
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+ ++match_txt;
+ }
+ while (*match_txt != 0);
+
+ if (width != 0 && (c = in_ch (s, &read_in)) != EOF && tolower (c) == 'i')
+ {
+ match_txt = "inity";
+
+ if (width > 0)
+ --width;
+
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+ ++match_txt;
+
+ do
+ {
+ if (width == 0 || (c = in_ch (s, &read_in)) == EOF || tolower (c) != match_txt[0])
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ if (width > 0)
+ --width;
+
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+ ++match_txt;
+ }
+ while (*match_txt != 0);
+ }
+ else if (width != 0 && c != EOF)
+ back_ch (c, s, &read_in, 0);
+ }
+ else
+ {
+ not_in = 'e';
+ if (width != 0 && c == '0')
+ {
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+
+ c = in_ch (s, &read_in);
+ if (width > 0)
+ --width;
+ if (width != 0 && tolower (c) == 'x')
+ {
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+
+ flags |= IS_HEX_FLOAT;
+ not_in = 'p';
+
+ flags &= ~USE_GROUP;
+ c = in_ch (s, &read_in);
+ if (width > 0)
+ --width;
+ }
+ }
+
+ while (1)
+ {
+ if (isdigit (c) || (!seen_exp && (flags & IS_HEX_FLOAT) != 0 && isxdigit (c))
+ || (seen_exp && wbuf[wbuf_cur_sz - 1] == not_in && (c == '-' || c == '+')))
+ {
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = c;
+ }
+ else if (wbuf_cur_sz > 0 && !seen_exp && (char) tolower (c) == not_in)
+ {
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = not_in;
+ seen_exp = seen_dot = 1;
+ }
+ else
+ {
+ const char *p = lc_decimal_point;
+ int remain = width > 0 ? width : INT_MAX;
+
+ if (! seen_dot)
+ {
+ while ((unsigned char) *p == c && remain >= 0)
+ {
+ ++p;
+ if (*p == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
+ break;
+ --remain;
+ }
+ }
+
+ if (*p == 0)
+ {
+ for (p = lc_decimal_point; *p != 0; ++p)
+ {
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = (unsigned char) *p;
+ }
+ if (width > 0)
+ width = remain;
+ seen_dot = 1;
+ }
+ else
+ {
+ const char *pp = lc_thousands_sep;
+
+ if (!seen_dot && (flags & USE_GROUP) != 0)
+ {
+ while ((pp - lc_thousands_sep) < (p - lc_decimal_point)
+ && *pp == lc_decimal_point[(pp - lc_thousands_sep)])
+ ++pp;
+ if ((pp - lc_thousands_sep) == (p - lc_decimal_point))
+ {
+ while ((unsigned char) *pp == c && remain >= 0)
+ {
+ ++pp;
+ if (*pp == 0 || !remain || (c = in_ch (s, &read_in)) == EOF)
+ break;
+ --remain;
+ }
+ }
+ }
+
+ if (pp != NULL && *pp == 0)
+ {
+ /* As our conversion routines aren't supporting thousands
+ separators, we are filtering them here. */
+ if (width > 0)
+ width = remain;
+ }
+ else
+ {
+ back_ch (c, s, &read_in, 0);
+ break;
+ }
+ }
+ }
+
+ if (width == 0 || (c = in_ch (s, &read_in)) == EOF)
+ break;
+
+ if (width > 0)
+ --width;
+ }
+
+ if (!wbuf_cur_sz || ((flags & IS_HEX_FLOAT) != 0 && wbuf_cur_sz == 2))
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+
+ wbuf = resize_wbuf (wbuf_cur_sz, &wbuf_max_sz, wbuf);
+ wbuf[wbuf_cur_sz++] = 0;
+
+ if ((flags & IS_LL) != 0)
+ {
+ long double ld;
+ ld = __evil_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
+ if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
+ *(npos != 0 ? (long double *) get_va_nth (argp, npos) : va_arg (arg, long double *)) = is_neg ? -ld : ld;
+ }
+ else if ((flags & IS_L) != 0)
+ {
+ double d;
+ d = (double) __evil_strtold (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
+ if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
+ *(npos != 0 ? (double *) get_va_nth (argp, npos) : va_arg (arg, double *)) = is_neg ? -d : d;
+ }
+ else
+ {
+ float d = __evil_strtof (wbuf, &tmp_wbuf_ptr/*, flags & USE_GROUP*/);
+ if ((flags & IS_SUPPRESSED) == 0 && tmp_wbuf_ptr != wbuf)
+ *(npos != 0 ? (float *) get_va_nth (argp, npos) : va_arg (arg, float *)) = is_neg ? -d : d;
+ }
+
+ if (wbuf == tmp_wbuf_ptr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ ++rval;
+ break;
+
+ case '[':
+ if ((flags & IS_L) != 0)
+ {
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ if ((flags & IS_ALLOC_USED) != 0)
+ {
+ if (npos != 0)
+ pstr = (char **) get_va_nth (argp, npos);
+ else
+ pstr = va_arg (arg, char **);
+
+ if (!pstr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ str_sz = 100;
+ *pstr = (char *) malloc (100 * sizeof (wchar_t));
+
+ if ((wstr = (wchar_t *) *pstr) == NULL)
+ return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+ gcollect = resize_gcollect (gcollect);
+ gcollect->ptrs[gcollect->count++] = pstr;
+ }
+ else
+ {
+ if (npos != 0)
+ wstr = (wchar_t *) get_va_nth (argp, npos);
+ else
+ wstr = va_arg (arg, wchar_t *);
+ if (!wstr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ }
+ }
+ else if ((flags & IS_SUPPRESSED) == 0)
+ {
+ if ((flags & IS_ALLOC_USED) != 0)
+ {
+ if (npos != 0)
+ pstr = (char **) get_va_nth (argp, npos);
+ else
+ pstr = va_arg (arg, char **);
+
+ if (!pstr)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ str_sz = 100;
+ if ((str = *pstr = (char *) malloc (100)) == NULL)
+ return cleanup_return (((flags & USE_POSIX_ALLOC) != 0 ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ gcollect = resize_gcollect (gcollect);
+ gcollect->ptrs[gcollect->count++] = pstr;
+ }
+ else
+ {
+ if (npos != 0)
+ str = (char *) get_va_nth (argp, npos);
+ else
+ str = va_arg (arg, char *);
+ if (!str)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ }
+
+ not_in = (*f == '^' ? 1 : 0);
+ if (*f == '^')
+ f++;
+
+ if (width < 0)
+ width = INT_MAX;
+
+ if (wbuf_max_sz < 256)
+ {
+ wbuf_max_sz = 256;
+ if (wbuf)
+ free (wbuf);
+ wbuf = (char *) malloc (wbuf_max_sz);
+ }
+ memset (wbuf, 0, 256);
+
+ fc = *f;
+ if (fc == ']' || fc == '-')
+ {
+ wbuf[fc] = 1;
+ ++f;
+ }
+
+ while ((fc = *f++) != 0 && fc != ']')
+ {
+ if (fc == '-' && *f != 0 && *f != ']' && (unsigned char) f[-2] <= (unsigned char) *f)
+ {
+ for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
+ wbuf[fc] = 1;
+ }
+ else
+ wbuf[fc] = 1;
+ }
+
+ if (!fc)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ if ((flags & IS_L) != 0)
+ {
+ read_in_sv = read_in;
+ cnt = 0;
+
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ memset (&cstate, 0, sizeof (cstate));
+
+ do
+ {
+ if (wbuf[c] == not_in)
+ {
+ back_ch (c, s, &read_in, 1);
+ break;
+ }
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ buf[0] = c;
+ n = mbrtowc (wstr, buf, 1, &cstate);
+
+ if (n == (size_t) -2)
+ {
+ ++cnt;
+ continue;
+ }
+ cnt = 0;
+
+ ++wstr;
+ if ((flags & IS_ALLOC_USED) != 0 && wstr == ((wchar_t *) *pstr + str_sz))
+ {
+ new_sz = str_sz * 2;
+ while ((wstr = (wchar_t *) realloc (*pstr, new_sz * sizeof (wchar_t))) == NULL
+ && new_sz > (size_t) (str_sz + 1))
+ new_sz = str_sz + 1;
+ if (!wstr)
+ {
+ if ((flags & USE_POSIX_ALLOC) == 0)
+ {
+ ((wchar_t *) (*pstr))[str_sz - 1] = 0;
+ pstr = NULL;
+ ++rval;
+ }
+ else
+ rval = EOF;
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ *pstr = (char *) wstr;
+ wstr += str_sz;
+ str_sz = new_sz;
+ }
+ }
+
+ if (--width <= 0)
+ break;
+ }
+ while ((c = in_ch (s, &read_in)) != EOF);
+
+ if (cnt != 0)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EILSEQ;
+#endif /* HAVE_ERRNO_H */
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+
+ if (read_in_sv == read_in)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ *wstr++ = 0;
+ optimize_alloc (pstr, (char *) wstr, str_sz * sizeof (wchar_t));
+ pstr = NULL;
+ ++rval;
+ }
+ }
+ else
+ {
+ read_in_sv = read_in;
+
+ if ((c = in_ch (s, &read_in)) == EOF)
+ return cleanup_return ((!rval ? EOF : rval), &gcollect, pstr, &wbuf);
+
+ do
+ {
+ if (wbuf[c] == not_in)
+ {
+ back_ch (c, s, &read_in, 1);
+ break;
+ }
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ *str++ = c;
+ if ((flags & IS_ALLOC_USED) != 0 && str == (*pstr + str_sz))
+ {
+ new_sz = str_sz * 2;
+
+ while ((str = (char *) realloc (*pstr, new_sz)) == NULL
+ && new_sz > (size_t) (str_sz + 1))
+ new_sz = str_sz + 1;
+ if (!str)
+ {
+ if ((flags & USE_POSIX_ALLOC) == 0)
+ {
+ (*pstr)[str_sz - 1] = 0;
+ pstr = NULL;
+ ++rval;
+ }
+ else
+ rval = EOF;
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ *pstr = str;
+ str += str_sz;
+ str_sz = new_sz;
+ }
+ }
+ }
+ while (--width > 0 && (c = in_ch (s, &read_in)) != EOF);
+
+ if (read_in_sv == read_in)
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+
+ if ((flags & IS_SUPPRESSED) == 0)
+ {
+ *str++ = 0;
+ optimize_alloc (pstr, str, str_sz);
+ pstr = NULL;
+ ++rval;
+ }
+ }
+ break;
+
+ default:
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+ }
+ }
+
+ if (ignore_ws)
+ {
+ while (isspace ((c = in_ch (s, &read_in))));
+ back_ch (c, s, &read_in, 0);
+ }
+
+ return cleanup_return (rval, &gcollect, pstr, &wbuf);
+}
+
+#endif
+
+/*============================================================================*
+ * API *
+ *============================================================================*/
+
+/**** printf family ****/
+
+int __cdecl _evil_fprintf(FILE *stream, const APICHAR *fmt, ...)
+{
+ register int retval;
+ va_list argv;
+
+ va_start( argv, fmt );
+ retval = _evil_pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stream, 0, fmt, argv );
+ va_end( argv );
+
+ return retval;
+}
+
+int __cdecl _evil_printf(const APICHAR *fmt, ...)
+{
+ register int retval;
+ va_list argv;
+
+ va_start( argv, fmt );
+ retval = _evil_pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stdout, 0, fmt, argv );
+ va_end( argv );
+
+ return retval;
+}
+
+int __cdecl _evil_sprintf(APICHAR *buf, const APICHAR *fmt, ...)
+{
+ register int retval;
+ va_list argv;
+
+ va_start( argv, fmt );
+ buf[retval = _evil_pformat( PFORMAT_NOLIMIT, buf, 0, fmt, argv )] = '\0';
+ va_end( argv );
+
+ return retval;
+}
+
+int __cdecl _evil_snprintf(APICHAR *buf, size_t length, const APICHAR *fmt, ...)
+{
+ register int retval;
+ va_list argv;
+
+ va_start( argv, fmt );
+ retval = _evil_vsnprintf( buf, length, fmt, argv );
+ va_end( argv );
+
+ return retval;
+}
+
+int __cdecl _evil_vfprintf(FILE *stream, const APICHAR *fmt, va_list argv)
+{
+ return _evil_pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stream, 0, fmt, argv );
+}
+
+int __cdecl _evil_vprintf(const APICHAR *fmt, va_list argv)
+{
+ return _evil_pformat( PFORMAT_TO_FILE | PFORMAT_NOLIMIT, stdout, 0, fmt, argv );
+}
+
+int __cdecl _evil_vsprintf(APICHAR *buf, const APICHAR *fmt, va_list argv)
+{
+ register int retval;
+ buf[retval = _evil_pformat( PFORMAT_NOLIMIT, buf, 0, fmt, argv )] = '\0';
+ return retval;
+}
+
+int __cdecl _evil_vsnprintf(APICHAR *buf, size_t length, const APICHAR *fmt, va_list argv )
+{
+ register int retval;
+
+ if( length == (size_t)(0) )
+ /*
+ * No buffer; simply compute and return the size required,
+ * without actually emitting any data.
+ */
+ return _evil_pformat( 0, buf, 0, fmt, argv);
+
+ /* If we get to here, then we have a buffer...
+ * Emit data up to the limit of buffer length less one,
+ * then add the requisite NUL terminator.
+ */
+ retval = _evil_pformat( 0, buf, --length, fmt, argv );
+ buf[retval < (int) length ? retval : (int)length] = '\0';
+
+ return retval;
+}
+
+
+/**** scanf family ****/
+
+#ifndef __BUILD_WIDEAPI
+
+int __cdecl _evil_fscanf (FILE *stream, const APICHAR *format, ...)
+{
+ va_list argp;
+ int r;
+
+ va_start (argp, format);
+ r = _evil_vfscanf (stream, format, argp);
+ va_end (argp);
+
+ return r;
+}
+
+int __cdecl _evil_scanf (const APICHAR *format, ...)
+{
+ va_list argp;
+ int r;
+
+ va_start (argp, format);
+ r = _evil_vfscanf (stdin, format, argp);
+ va_end (argp);
+
+ return r;
+}
+
+int __cdecl _evil_sscanf (const APICHAR *buf, const APICHAR *format, ...)
+{
+ va_list argp;
+ int r;
+
+ va_start (argp, format);
+ r = _evil_vsscanf (buf, format, argp);
+ va_end (argp);
+
+ return r;
+}
+
+int __cdecl _evil_vfscanf (FILE *s, const APICHAR *format, va_list argp)
+{
+ _IFP ifp;
+
+ memset (&ifp, 0, sizeof (_IFP));
+ ifp.fp = s;
+
+ return _evil_sformat (&ifp, format, argp);
+}
+
+int __cdecl _evil_vscanf (const APICHAR *format, va_list argp)
+{
+ return _evil_vfscanf (stdin, format, argp);
+}
+
+int __cdecl _evil_vsscanf (const APICHAR *s, const APICHAR *format, va_list argp)
+{
+ _IFP ifp;
+
+ memset (&ifp, 0, sizeof (_IFP));
+ ifp.str = s;
+ ifp.is_string = 1;
+
+ return _evil_sformat (&ifp, format, argp);
+}
+
+#endif
+
+/**** asprintf family ****/
+
+#ifndef __BUILD_WIDEAPI
+
+int _evil_asprintf(char ** __restrict__ ret, const char * __restrict__ format, ...)
+{
+ va_list ap;
+ int len;
+ va_start(ap,format);
+ /* Get Length */
+ len = _evil_vsnprintf(NULL,0,format,ap);
+ if (len < 0) goto _end;
+ /* +1 for \0 terminator. */
+ *ret = malloc(len + 1);
+ /* Check malloc fail*/
+ if (!*ret) {
+ len = -1;
+ goto _end;
+ }
+ /* Write String */
+ _evil_vsnprintf(*ret,len+1,format,ap);
+ /* Terminate explicitly */
+ (*ret)[len] = '\0';
+ _end:
+ va_end(ap);
+ return len;
+}
+
+int __cdecl _evil_vasprintf(char ** __restrict__ ret, const char * __restrict__ format, va_list ap)
+{
+ int len;
+ /* Get Length */
+ len = _evil_vsnprintf(NULL,0,format,ap);
+ if (len < 0) return -1;
+ /* +1 for \0 terminator. */
+ *ret = malloc(len + 1);
+ /* Check malloc fail*/
+ if (!*ret) return -1;
+ /* Write String */
+ _evil_vsnprintf(*ret,len+1,format,ap);
+ /* Terminate explicitly */
+ (*ret)[len] = '\0';
+ return len;
+}
+
+#endif
diff --git a/src/lib/evil/evil_printw.c b/src/lib/evil/evil_printw.c
new file mode 100644
index 0000000000..8e8fa182dd
--- /dev/null
+++ b/src/lib/evil/evil_printw.c
@@ -0,0 +1,4 @@
+
+#define __BUILD_WIDEAPI 1
+
+#include "evil_printa.c"
diff --git a/src/lib/evil/evil_private.h b/src/lib/evil/evil_private.h
new file mode 100644
index 0000000000..d46a379d01
--- /dev/null
+++ b/src/lib/evil/evil_private.h
@@ -0,0 +1,20 @@
+#ifndef __EVIL_PRIVATE_H__
+#define __EVIL_PRIVATE_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+long _evil_systemtime_to_time(SYSTEMTIME st);
+
+void _evil_error_display(const char *fct, LONG res);
+
+void _evil_last_error_display(const char *fct);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __EVIL_PRIVATE_H__ */
diff --git a/src/lib/evil/evil_pwd.c b/src/lib/evil/evil_pwd.c
new file mode 100644
index 0000000000..0830b5b26a
--- /dev/null
+++ b/src/lib/evil/evil_pwd.c
@@ -0,0 +1,65 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <windows.h>
+#include <security.h>
+
+#include "Evil.h"
+#include "pwd.h"
+
+
+static struct passwd pw;
+
+struct passwd *
+getpwuid (uid_t uid)
+{
+ static char user_name[PATH_MAX];
+ TCHAR name[PATH_MAX];
+ ULONG length;
+ BOOLEAN res;
+#ifdef UNICODE
+ char *a_name;
+# endif /* UNICODE */
+
+ length = PATH_MAX;
+#ifdef _WIN32_WINNT
+ res = GetUserNameEx(NameDisplay, name, &length);
+#else
+ res = GetUserNameEx(NameWindowsCeLocal, name, &length);
+#endif
+#ifdef UNICODE
+ if (res)
+ {
+ a_name = evil_wchar_to_char(name);
+ if (a_name)
+ {
+ int l;
+
+ l = strlen(a_name);
+ if (l >= PATH_MAX)
+ l = PATH_MAX;
+ memcpy(user_name, a_name, l);
+ user_name[l] = '\0';
+ free(a_name);
+ }
+ else
+ res = 0;
+ }
+#endif /* UNICODE */
+ pw.pw_name = (res ? user_name : NULL);
+ pw.pw_passwd = NULL;
+ pw.pw_uid = uid;
+ pw.pw_gid = 0;
+ pw.pw_change = 0;
+ pw.pw_class = NULL;
+ pw.pw_gecos = (res ? user_name : NULL);
+ pw.pw_dir = (char *)evil_homedir_get();
+ pw.pw_shell = getenv("SHELL");
+ if (!pw.pw_shell)
+ pw.pw_shell = "sh";
+ pw.pw_expire = 0;
+ pw.pw_fields = 0;
+
+ return &pw;
+}
diff --git a/src/lib/evil/evil_stdio.c b/src/lib/evil/evil_stdio.c
new file mode 100644
index 0000000000..594d281159
--- /dev/null
+++ b/src/lib/evil/evil_stdio.c
@@ -0,0 +1,215 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "Evil.h"
+#include "evil_private.h"
+
+#undef fopen
+
+
+#ifdef _WIN32_WCE
+
+/*
+ * Error related functions
+ *
+ */
+
+void evil_perror (const char *s __UNUSED__)
+{
+ fprintf(stderr, "[Windows CE] error\n");
+}
+
+/*
+ * Stream related functions
+ *
+ */
+
+FILE *evil_fopen(const char *path, const char *mode)
+{
+ FILE *f;
+ char *filename;
+ char *tmp;
+
+ if (!path || !*path)
+ return NULL;
+
+ if ((*path != '\\') && (*path != '/'))
+ {
+ char buf[PATH_MAX];
+ int l1;
+ int l2;
+
+ if (!evil_getcwd(buf, PATH_MAX))
+ return NULL;
+
+ l1 = strlen(buf);
+ l2 = strlen(path);
+ filename = (char *)malloc(l1 + 1 + l2 + 1);
+ if (!filename)
+ return NULL;
+ memcpy(filename, buf, l1);
+ filename[l1] = '\\';
+ memcpy(filename + l1 + 1, path, l2);
+ filename[l1 + 1 + l2] = '\0';
+ }
+ else
+ filename = _strdup(path);
+
+ tmp = filename;
+ while (*tmp)
+ {
+ if (*tmp == '/')
+ *tmp = '\\';
+ tmp++;
+ }
+
+ printf ("fopen : %s\n", filename);
+
+ f = fopen(filename, mode);
+ free(filename);
+
+ return f;
+}
+
+void evil_rewind(FILE *stream)
+{
+ fseek(stream, 0, SEEK_SET);
+}
+
+int evil_remove(const char *path)
+{
+ struct stat st;
+
+ if (stat(path, &st) < 0) return -1;
+
+ if (S_ISDIR(st.st_mode))
+ {
+ if (rmdir(path) < 0) return -1;
+ return 0;
+ }
+
+ if (S_ISREG(st.st_mode))
+ {
+ if (unlink(path) < 0) return -1;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+#endif /* _WIN32_WCE */
+
+
+#ifdef _WIN32_WCE
+
+FILE *evil_fopen_native(const char *path, const char *mode)
+{
+ HANDLE handle;
+ char *filename;
+ char *tmp;
+ wchar_t *wfilename;
+ DWORD acs = GENERIC_READ;
+ DWORD creation;
+
+ if (!path || !*path || !mode || !*mode)
+ return NULL;
+
+ if ((*path != '\\') && (*path != '/'))
+ {
+ char buf[PATH_MAX];
+ int l1;
+ int l2;
+
+ if (!evil_getcwd(buf, PATH_MAX))
+ return NULL;
+
+ l1 = strlen(buf);
+ l2 = strlen(path);
+ filename = (char *)malloc(l1 + 1 + l2 + 1);
+ if (!filename)
+ return NULL;
+ memcpy(filename, buf, l1);
+ filename[l1] = '\\';
+ memcpy(filename + l1 + 1, path, l2);
+ filename[l1 + 1 + l2] = '\0';
+ }
+ else
+ filename = _strdup(path);
+
+ tmp = filename;
+ while (*tmp)
+ {
+ if (*tmp == '/')
+ *tmp = '\\';
+ tmp++;
+ }
+ printf ("fopen native : %s\n", filename);
+
+ wfilename = evil_char_to_wchar(filename);
+ free(filename);
+
+ if (!wfilename)
+ return NULL;
+
+ if (*mode == 'r')
+ {
+ acs = GENERIC_READ;
+ creation = OPEN_EXISTING;
+ }
+ if (*mode == 'w')
+ {
+ acs = GENERIC_WRITE;
+ creation = CREATE_ALWAYS;
+ }
+
+ handle = CreateFile(wfilename,
+ acs,
+ 0, NULL,
+ creation,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ free(wfilename);
+
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ _evil_last_error_display(__FUNCTION__);
+ return NULL;
+ }
+
+ return (FILE *)handle;
+}
+
+size_t evil_fread_native(void* buffer, size_t size, size_t count, FILE* stream)
+{
+ HANDLE handle;
+ DWORD bytes_read;
+ BOOL res;
+
+ if ((size == 0) || (count == 0))
+ return 0;
+
+ handle = (HANDLE)stream;
+ res = ReadFile(handle, buffer, size * count, &bytes_read, NULL);
+ if (!res)
+ {
+ _evil_last_error_display(__FUNCTION__);
+ return 0;
+ }
+
+ return (bytes_read != size * count) ? 0 : bytes_read;
+}
+
+int evil_fclose_native(FILE *stream)
+{
+ if (!CloseHandle((HANDLE)stream))
+ {
+ _evil_last_error_display(__FUNCTION__);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif /* _WIN32_WCE */
diff --git a/src/lib/evil/evil_stdio.h b/src/lib/evil/evil_stdio.h
new file mode 100644
index 0000000000..533d31e4fe
--- /dev/null
+++ b/src/lib/evil/evil_stdio.h
@@ -0,0 +1,196 @@
+#ifndef __EVIL_STDIO_H__
+#define __EVIL_STDIO_H__
+
+
+/**
+ * @file evil_stdio.h
+ * @brief The file that provides functions ported from Unix in stdio.h.
+ * @defgroup Evil_Stdio_Group Stdio.h functions
+ *
+ * This header provides functions ported from Unix in stdio.h.
+ *
+ * @{
+ */
+
+
+#ifdef _WIN32_WCE
+
+/*
+ * Error related functions
+ *
+ */
+
+/**
+ * @brief Print the given string to stderr.
+ *
+ * @param s The string to print.
+ *
+ * This function just printf the string @p s to stderr.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows CE.
+ */
+EAPI void evil_perror (const char *s);
+
+/**
+ * @def perror(s)
+ *
+ * Wrapper around evil_perror().
+ */
+# define perror(s) evil_perror(s)
+
+/*
+ * Stream related functions
+ *
+ */
+
+/**
+ * @brief Emulate the fopen() function on Windows CE.
+ *
+ * @param path The file to open.
+ * @param mode The mode.
+ * @return A FILE pointer on success, @c NULL otherwise.
+ *
+ * This function emulates the fopen() function on Windows CE using the
+ * Windows libc. The main problem is that the filesytem on Windows CE
+ * is like on Sys V : the top level directory is beginning by '/' or
+ * '\' and the full path must be calculated.. This function takes care
+ * of this feature, and replace all the '/' by '/'. Otherwise, it
+ * calls the Windows CE fopen() function once the filename has been
+ * correctly set. If @p path is @c NULL or empty, this function
+ * returns @c NULL. On success, this function returns a FILE stream,
+ * @c NULL otherwise.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows CE.
+ */
+EAPI FILE *evil_fopen(const char *path, const char *mode);
+
+/**
+ * @def fopen(path, mode)
+ *
+ * Wrapper around evil_fopen().
+ */
+# define fopen(path, mode) evil_fopen(path, mode)
+
+/**
+ * @brief Emulate the rewind() function on Windows CE.
+ *
+ * @param stream The FILE stream.
+ *
+ * This function emulates the rewind() function on Windows CE by just
+ * calling fseek().
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows CE.
+ */
+EAPI void evil_rewind(FILE *stream);
+
+/**
+ * @def rewind(f)
+ *
+ * Wrapper around evil_rewind().
+ */
+# define rewind(f) evil_rewind(f)
+
+/**
+ * @brief Emulate the remove() function on Windows CE.
+ *
+ * @param path The path to remove.
+ * @return 0 on success, -1 otherwise.
+ *
+ * This function emulates the remove() function on Windows CE. If
+ * @p path is an empty directory, it removes it. If @p path is a file,
+ * it deletes it. On success, 0 is returns, -1 otherwise.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows CE.
+ */
+EAPI int evil_remove(const char *path);
+
+/**
+ * @def remove(p)
+ *
+ * Wrapper around evil_remove().
+ */
+# define remove(p) evil_remove(p)
+
+#endif /* _WIN32_WCE */
+
+
+#ifdef _WIN32_WCE
+
+/**
+ * @brief Emulate the fopen() function on Windows CE using Windows API.
+ *
+ * @param path The file to open.
+ * @param mode The mode.
+ * @return A FILE pointer on success, @c NULL otherwise.
+ *
+ * This function emulates the fopen() function on Windows CE using the
+ * Windows API and not the libc. It is similar to evil_fopen().
+ *
+ * @see evil_fopen()
+ * @see evil_fread_native()
+ * @see evil_fclose_native()
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows CE.
+ */
+EAPI FILE *evil_fopen_native(const char *path, const char *mode);
+
+/**
+ * @brief Read the given stream on Windows CE using Windows API.
+ *
+ * @param buffer The buffer to store the data.
+ * @param size The size of each element of data to read.
+ * @param count The number of elements of data to read.
+ * @param stream The stream to read.
+ * @return The size read on success, 0 otherwise.
+ *
+ * This function read @p stream using the Windows API. It reads
+ * @p size elements of data, each @ size bytes long. The data is
+ * stored in the buffer @p buffer. On success, the size read is
+ * returned, 0 otherwise.
+ *
+ * @see evil_fopen_native()
+ * @see evil_fclose_native()
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows CE.
+ */
+EAPI size_t evil_fread_native(void* buffer, size_t size, size_t count, FILE* stream);
+
+/**
+ * @brief Close the given stream on Windows CE using Windows API.
+ *
+ * @param stream The stream to close.
+ * @return 0 on success, -1 otherwise.
+ *
+ * This function closes @p stream using the Windows API. On success, 0
+ * is returned, -1 otherwise.
+ *
+ * @see evil_fopen_native()
+ * @see evil_fread_native()
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows CE.
+ */
+EAPI int evil_fclose_native(FILE *stream);
+
+#endif /* _WIN32_WCE */
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_STDIO_H__ */
diff --git a/src/lib/evil/evil_stdlib.c b/src/lib/evil/evil_stdlib.c
new file mode 100644
index 0000000000..d22a7dc71e
--- /dev/null
+++ b/src/lib/evil/evil_stdlib.c
@@ -0,0 +1,453 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <io.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif /* HAVE_ERRNO_H */
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include "evil_macro.h"
+#include "evil_stdlib.h"
+#include "evil_private.h"
+#define APICHAR char
+#include "evil_print.h"
+
+/*
+ * Environment variable related functions
+ *
+ * char *getenv (const char *name);
+ * int putenv (const char *string);
+ * int setenv (const char *name, const char *value, int overwrite);
+ * void unsetenv (const char *name);
+ *
+ */
+
+#ifdef _WIN32_WCE
+
+static char _evil_stdlib_getenv_buffer[PATH_MAX];
+
+char *
+getenv(const char *name)
+{
+ HKEY key;
+ wchar_t *wname;
+ LONG res;
+ DWORD type;
+ DWORD disposition;
+ DWORD size = PATH_MAX;
+
+ if (!name || !*name)
+ return NULL;
+
+ if ((res = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("Software\\Efl\\Environment"),
+ 0, NULL,
+ REG_OPTION_VOLATILE,
+ 0, NULL,
+ &key, &disposition)) != ERROR_SUCCESS)
+ {
+ _evil_error_display(__FUNCTION__, res);
+ return NULL;
+ }
+
+ wname = evil_char_to_wchar(name);
+ if (!wname)
+ {
+ if ((res = RegCloseKey (key)) != ERROR_SUCCESS)
+ _evil_error_display(__FUNCTION__, res);
+ return NULL;
+ }
+
+ if ((res = RegQueryValueEx(key, wname,
+ NULL, &type,
+ (LPBYTE)&_evil_stdlib_getenv_buffer,
+ &size)) != ERROR_SUCCESS)
+ {
+ if ((res = RegCloseKey (key)) != ERROR_SUCCESS)
+ _evil_error_display(__FUNCTION__, res);
+ free(wname);
+ return NULL;
+ }
+
+ free(wname);
+
+ if ((res = RegCloseKey (key)) != ERROR_SUCCESS)
+ {
+ _evil_error_display(__FUNCTION__, res);
+ return NULL;
+ }
+
+ if (_evil_stdlib_getenv_buffer[0] == '\0')
+ return NULL;
+ else
+ {
+ return _evil_stdlib_getenv_buffer;
+ }
+}
+
+#endif /* _WIN32_WCE */
+
+#ifdef __MINGW32CE__
+
+int
+putenv(const char *string)
+{
+ char *str;
+ char *egal;
+ char *name;
+ char *value;
+
+ str = strdup(string);
+ if (!str)
+ return -1;
+ egal = strchr(str, '=');
+ if (!egal)
+ return -1;
+
+ value = egal + 1;
+ *egal = '\0';
+ name = str;
+ setenv(name, value, 1);
+ free(str);
+
+ return 0;
+}
+
+#endif /* __MINGW32CE__ */
+
+
+
+int
+setenv(const char *name,
+ const char *value,
+ int overwrite)
+{
+#ifndef __MINGW32CE__
+
+ char *old_name;
+ char *str;
+ size_t length;
+ int res;
+
+ if (!name || !*name)
+ return -1;
+
+ /* if '=' is found, return EINVAL */
+ if (strchr (name, '='))
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EINVAL;
+#endif /* HAVE_ERRNO_H */
+ return -1;
+ }
+
+ /* if name is already set and overwrite is 0, we exit with success */
+ old_name = getenv(name);
+ if (!overwrite && old_name)
+ return 0;
+
+ length = value ? strlen(value) : 0;
+ length += strlen(name) + 2;
+ str = (char *)malloc(length);
+ if (!str)
+ {
+#ifdef HAVE_ERRNO_H
+ errno = ENOMEM;
+#endif /* HAVE_ERRNO_H */
+ return -1;
+ }
+ if (!value)
+ sprintf(str, "%s=", name);
+ else
+ sprintf(str, "%s=%s", name, value);
+ res = _putenv(str);
+ free(str);
+
+ return res;
+
+#else /* __MINGW32CE__ */
+
+ HKEY key;
+ LONG res;
+ DWORD disposition;
+ wchar_t *wname;
+ char *data;
+ DWORD size;
+
+ if (!name || !*name)
+ return -1;
+
+ /* if '=' is found, return an error */
+ if (strchr (name, '='))
+ return -1;
+
+ if ((res = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
+ TEXT("Software\\Efl\\Environment"),
+ 0, NULL,
+ REG_OPTION_VOLATILE,
+ 0, NULL,
+ &key,
+ &disposition)) != ERROR_SUCCESS)
+ {
+ _evil_error_display(__FUNCTION__, res);
+ return -1;
+ }
+
+ /* if name is already set and overwrite is 0, we exit with success */
+ if (!overwrite && (disposition == REG_OPENED_EXISTING_KEY))
+ return 0;
+
+ wname = evil_char_to_wchar(name);
+ if (!wname)
+ {
+ if ((res = RegCloseKey (key)) != ERROR_SUCCESS)
+ _evil_error_display(__FUNCTION__, res);
+ return -1;
+ }
+
+ if (value)
+ {
+ size = strlen(value);
+ data = malloc(sizeof(char) * (size + 1));
+ if (!data)
+ return -1;
+ memcpy((void *)data, value, size);
+ data[size] = '\0';
+ }
+ else
+ {
+ size = 0;
+ data = malloc(sizeof(char));
+ if (!data)
+ return -1;
+ data[0] = '\0';
+ }
+ if (!data)
+ return -1;
+
+ if ((res = RegSetValueEx(key,
+ (LPCWSTR)wname,
+ 0, REG_SZ,
+ (const BYTE *)data,
+ size + 1)) != ERROR_SUCCESS)
+ {
+ free(wname);
+ _evil_error_display(__FUNCTION__, res);
+ if ((res = RegCloseKey (key)) != ERROR_SUCCESS)
+ _evil_error_display(__FUNCTION__, res);
+ return -1;
+ }
+
+ free(data);
+ free(wname);
+
+ if ((res = RegCloseKey (key)) != ERROR_SUCCESS)
+ {
+ _evil_error_display(__FUNCTION__, res);
+ return -1;
+ }
+
+ return 0;
+
+#endif /* ! __MINGW32CE__ */
+}
+
+int
+unsetenv(const char *name)
+{
+ return setenv(name, NULL, 1);
+}
+
+
+/*
+ * Files related functions
+ *
+ */
+
+int
+mkstemp(char *__template)
+{
+ const char lookup[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ char *suffix;
+ DWORD val;
+ size_t length;
+ int i;
+
+ if (!__template)
+ return 0;
+
+ length = strlen(__template);
+ if ((length < 6) ||
+ (strncmp (__template + length - 6, "XXXXXX", 6)))
+ {
+#ifdef HAVE_ERRNO_H
+ errno = EINVAL;
+#endif /* HAVE_ERRNO_H */
+ return -1;
+ }
+
+ suffix = __template + length - 6;
+
+ val = GetTickCount();
+ val += GetCurrentProcessId();
+
+ for (i = 0; i < 32768; i++)
+ {
+ DWORD v;
+ int fd;
+
+ v = val;
+
+ suffix[0] = lookup[v % 62];
+ v /= 62;
+ suffix[1] = lookup[v % 62];
+ v /= 62;
+ suffix[2] = lookup[v % 62];
+ v /= 62;
+ suffix[3] = lookup[v % 62];
+ v /= 62;
+ suffix[4] = lookup[v % 62];
+ v /= 62;
+ suffix[5] = lookup[v % 62];
+ v /= 62;
+
+#ifndef __MINGW32CE__
+ fd = _open(__template, _O_RDWR | _O_BINARY | _O_CREAT | _O_EXCL, _S_IREAD | _S_IWRITE);
+#else /* ! __MINGW32CE__ */
+ {
+ FILE *f;
+ wchar_t *wtemplate;
+
+ wtemplate = evil_char_to_wchar(__template);
+ if (!wtemplate)
+ return -1;
+ f = _wfopen(wtemplate, L"rwb");
+ free(wtemplate);
+ if (!f)
+ {
+# ifdef HAVE_ERRNO_H
+ errno = EEXIST;
+# endif /* HAVE_ERRNO_H */
+ return -1;
+ }
+ fd = (int)_fileno(f);
+ }
+#endif /* __MINGW32CE__ */
+ if (fd >= 0)
+ return fd;
+
+ val += 7777;
+ }
+
+#ifdef HAVE_ERRNO_H
+ errno = EEXIST;
+#endif /* HAVE_ERRNO_H */
+ return -1;
+}
+
+
+char *
+realpath(const char *file_name, char *resolved_name)
+{
+#ifndef __MINGW32CE__
+ char *retname = NULL; /* we will return this, if we fail */
+
+ /* SUSv3 says we must set `errno = EINVAL', and return NULL,
+ * if `name' is passed as a NULL pointer.
+ */
+
+ if (file_name == NULL)
+ errno = EINVAL;
+
+ /* Otherwise, `name' must refer to a readable filesystem object,
+ * if we are going to resolve its absolute path name.
+ */
+
+ else if (access(file_name, 4) == 0)
+ {
+ /* If `name' didn't point to an existing entity,
+ * then we don't get to here; we simply fall past this block,
+ * returning NULL, with `errno' appropriately set by `access'.
+ *
+ * When we _do_ get to here, then we can use `_fullpath' to
+ * resolve the full path for `name' into `resolved', but first,
+ * check that we have a suitable buffer, in which to return it.
+ */
+
+ if ((retname = resolved_name) == NULL)
+ {
+ /* Caller didn't give us a buffer, so we'll exercise the
+ * option granted by SUSv3, and allocate one.
+ *
+ * `_fullpath' would do this for us, but it uses `malloc', and
+ * Microsoft's implementation doesn't set `errno' on failure.
+ * If we don't do this explicitly ourselves, then we will not
+ * know if `_fullpath' fails on `malloc' failure, or for some
+ * other reason, and we want to set `errno = ENOMEM' for the
+ * `malloc' failure case.
+ */
+
+ retname = malloc(_MAX_PATH);
+ }
+
+ /* By now, we should have a valid buffer.
+ * If we don't, then we know that `malloc' failed,
+ * so we can set `errno = ENOMEM' appropriately.
+ */
+
+ if (retname == NULL)
+ errno = ENOMEM;
+
+ /* Otherwise, when we do have a valid buffer,
+ * `_fullpath' should only fail if the path name is too long.
+ */
+
+ else if ((retname = _fullpath(retname, file_name, _MAX_PATH)) == NULL)
+ errno = ENAMETOOLONG;
+ }
+
+ /* By the time we get to here,
+ * `retname' either points to the required resolved path name,
+ * or it is NULL, with `errno' set appropriately, either of which
+ * is our required return condition.
+ */
+
+ return retname;
+#else
+ char cwd[PATH_MAX];
+ size_t l1;
+ size_t l2;
+ size_t l;
+
+ if (!file_name || !resolved_name)
+ return NULL;
+
+ if (!getcwd(cwd, PATH_MAX))
+ return NULL;
+
+ l1 = strlen(cwd);
+ l2 = strlen(file_name);
+ l = l1 + l2 + 2;
+
+ if (l > PATH_MAX)
+ l = PATH_MAX - 1;
+ memcpy(resolved_name, cwd, l1);
+ resolved_name[l1] = '\\';
+ memcpy(resolved_name + l1 + 1, file_name, l2);
+ resolved_name[l] = '\0';
+
+ return resolved_name;
+#endif /* __MINGW32CE__ */
+}
diff --git a/src/lib/evil/evil_stdlib.h b/src/lib/evil/evil_stdlib.h
new file mode 100644
index 0000000000..81d564f86f
--- /dev/null
+++ b/src/lib/evil/evil_stdlib.h
@@ -0,0 +1,199 @@
+#ifndef __EVIL_STDLIB_H__
+#define __EVIL_STDLIB_H__
+
+
+/**
+ * @file evil_stdlib.h
+ * @brief The file that provides functions ported from Unix in stdlib.h.
+ * @defgroup Evil_Stdlib_Group Stdlib.h functions.
+ *
+ * This header provides functions ported from Unix in stdlib.h.
+ *
+ * @{
+ */
+
+
+/*
+ * Environment variable related functions
+ *
+ */
+
+#ifdef _WIN32_WCE
+
+/**
+ * @brief Retrieve the value of environment variables.
+ *
+ * @param name The name of the environment variable.
+ * @return The value of the environment variable.
+ *
+ * This function searches the environment variable @p name if it
+ * exists and return a pointer to the value of the environment
+ * variable. If the specified environment variable cannot be found,
+ * @c NULL is returned.
+ *
+ * The returned value may be overwritten by a subsequent call to
+ * getenv(), setenv(), or unsetenv().
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows CE.
+ *
+ * @note On Windows CE, there is no environment variable. This is
+ * faked by storing a value in a key in the base registry.
+ */
+EAPI char *getenv(const char *name);
+
+#endif /* _WIN32_WCE */
+
+
+#ifdef __MINGW32CE__
+
+/**
+ * @brief Set the value of environment variables.
+ *
+ * @param string A formatted string.
+ * @return 0 in success, non-zero otherwise.
+ *
+ * This function uses @p string to set environment variable values.
+ * @p string should point to a string of the form "name=value". This
+ * function makes the value of the environment variable name equal to
+ * value by altering an existing variable or creating a new one. In
+ * either case, the string pointed to by @p string becomes part of the
+ * environment, so altering @p string shall change the environment.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows CE.
+ *
+ * @note On Windows CE, there is no environment variable. This is
+ * faked by storing a value in a key in the base registry.
+ */
+EAPI int putenv(const char *string);
+
+#endif /* __MINGW32CE__ */
+
+/**
+ * @brief Create, modify, or remove environment variables.
+ *
+ * @param name The name of the environment variable.
+ * @param value The value of the environment variable to set.
+ * @param overwrite 0 to let the environment variable unchanged, 1 otherwise.
+ * @return 0 on success, -1 otherwise.
+ *
+ * Add the new environment variable @p name or modify its value if it
+ * exists, and set it to @p value. Environment variables define the
+ * environment in which a process executes. If @p value is @c NULL, the
+ * variable is removed (unset) and that call is equivalent to
+ * unsetenv().If the environment variable named by @p name already
+ * exists and the value of @p overwrite is 0, the function shall
+ * return success and the environment shall remain unchanged.
+ * If the function succeeds, it returns 0, otherwise it returns -1.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ *
+ * @note On Windows CE, there is no environment variable. This is
+ * faked by storing a value in a key in the base registry.
+ */
+EAPI int setenv(const char *name,
+ const char *value,
+ int overwrite);
+
+/**
+ * @brief Remove environment variables.
+ *
+ * @param name The name of the environment variable.
+ * @return 0 on success, -1 otherwise.
+ *
+ * Remove the new environment variable @p name if it exists. That
+ * function is equivalent to setenv() with its second parameter to
+ * @c NULL and the third to 1. If the function succeeds, it returns 0,
+ * otherwise it returns -1.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP, Windows CE (not cegcc).
+ *
+ * @note On Windows CE, there is no environment variable. This is
+ * faked by storing a value in a key in the base registry.
+ */
+EAPI int unsetenv(const char *name);
+
+
+/*
+ * Files related functions
+ *
+ */
+
+/**
+ * @brief Make temporay unique file name.
+ *
+ * @param __template Template of the file to create.
+ * @return A file descriptor on success, -1 otherwise.
+ *
+ * Take the given file name @p template and overwrite a portion of it
+ * to create a file name. This file is guaranted not to exist at the
+ * time invocation and is suitable for use by the function.
+ *
+ * The @p template parameter can be any file name with some number of
+ * 'Xs' appended to it, for example @em baseXXXXXX, where @em base is
+ * the part of the new file that you supply and eacg 'X' is a placeholder
+ * for a character supplied by mkstemp(). The trailing 'Xs' are replaced
+ * with a five-digit value; this value is a unique number. Each successful
+ * call to mkstemp() modifes @p template.
+ *
+ * When mkstemp() succeeds, it creates and opens the template file for
+ * reading and writing.
+ *
+ * On success, the function returns the file descriptor of the
+ * temporary file. Otherwise, it returns -1 and errno is set to the
+ * following values:
+ * - EINVAL: @p template has an invalid format.
+ * - EEXISTS: File name already exists.
+ *
+ * Conformity: Should follow BSD conformity.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI int mkstemp(char *__template);
+
+/**
+ * @brief Return an absolute or full path name for a specified relative path name.
+ *
+ * @param file_name The absolute path name.
+ * @param resolved_name The relative path name.
+ * @return @c NULL on failure, a pointer to the absolute path name otherwise.
+ *
+ * The function expands the relative path name @p file_name to its
+ * fully qualified or absolute path and store it in the buffer pointed
+ * by @p resolved_name. The buffer is at most @c PATH_MAX bytes long.
+ * If @p resolved_name is @c NULL, malloc() is used to allocate a
+ * buffer of sufficient length to hold the path name. In that case, it
+ * is the responsability of the caller to free this buffer with free().
+ *
+ * That function can be used to obtain the absolute path name for
+ * relative paths (relPath) that include "./" or "../" in their names.
+ *
+ * On Windows XP, errno is set in the following cases:
+ *
+ * @li EACCESS: if @p file_name can not be accessed.
+ * @li EINVAL: if @p file_name is @c NULL.
+ * @li ENAMETOOLONG: if the path name is too long.
+ * @li ENOENT: @p file_name does not exist
+ * @li ENOMEM: if memory allocation fails.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI char *realpath(const char *file_name, char *resolved_name);
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_STDLIB_H__ */
+
diff --git a/src/lib/evil/evil_string.c b/src/lib/evil/evil_string.c
new file mode 100644
index 0000000000..ffbe308b67
--- /dev/null
+++ b/src/lib/evil/evil_string.c
@@ -0,0 +1,128 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "Evil.h"
+
+
+#ifdef _WIN32_WCE
+
+/*
+ * Error related functions
+ *
+ */
+
+char *strerror (int errnum __UNUSED__)
+{
+ return "[Windows CE] error\n";
+}
+
+#endif /* _WIN32_WCE */
+
+
+/*
+ * bit related functions
+ *
+ */
+
+int ffs(int i)
+{
+ int size;
+ int x;
+
+ if (!i) return 1;
+
+ /* remove the sign bit */
+ x = i & -i;
+ size = sizeof(int) << 3;
+ for (i = size; i > 0; --i, x <<= 1)
+ if (x & (1 << (size - 1))) return i;
+
+ return x;
+}
+
+
+#ifdef _WIN32_WCE
+
+/*
+ * String manipulation related functions
+ *
+ */
+
+int
+strcoll (const char *s1, const char *s2)
+{
+#ifdef UNICODE
+ wchar_t *ws1;
+ wchar_t *ws2;
+ int res;
+
+ ws1 = evil_char_to_wchar(s1);
+ ws2 = evil_char_to_wchar(s2);
+ res = wcscmp(ws1, ws2);
+ if (ws1) free(ws1);
+ if (ws2) free(ws2);
+
+ return res;
+#else
+ return strcmp(s1, s2);
+#endif /* ! UNICODE */
+}
+
+
+#endif /* _WIN32_WCE */
+
+char *
+strrstr (const char *str, const char *substr)
+{
+ char *it;
+ char *ret = NULL;
+
+ while ((it = strstr(str, substr)))
+ ret = it;
+
+ return ret;
+}
+
+#ifdef _MSC_VER
+
+int strcasecmp(const char *s1, const char *s2)
+{
+ return lstrcmpi(s1, s2);
+}
+
+#endif /* _MSC_VER */
+
+char *strcasestr(const char *haystack, const char *needle)
+{
+ size_t length_needle;
+ size_t length_haystack;
+ size_t i;
+
+ if (!haystack || !needle)
+ return NULL;
+
+ length_needle = strlen(needle);
+ length_haystack = strlen(haystack) - length_needle + 1;
+
+ for (i = 0; i < length_haystack; i++)
+ {
+ size_t j;
+
+ for (j = 0; j < length_needle; j++)
+ {
+ unsigned char c1;
+ unsigned char c2;
+
+ c1 = haystack[i+j];
+ c2 = needle[j];
+ if (toupper(c1) != toupper(c2))
+ goto next;
+ }
+ return (char *) haystack + i;
+ next:
+ ;
+ }
+
+ return NULL;
+}
diff --git a/src/lib/evil/evil_string.h b/src/lib/evil/evil_string.h
new file mode 100644
index 0000000000..9141eba762
--- /dev/null
+++ b/src/lib/evil/evil_string.h
@@ -0,0 +1,152 @@
+#ifndef __EVIL_STRING_H__
+#define __EVIL_STRING_H__
+
+
+/**
+ * @file evil_string.h
+ * @brief The file that provides functions ported from Unix in string.h.
+ * @defgroup Evil_String_Group String.h functions.
+ *
+ * This header provides functions ported from Unix in string.h.
+ *
+ * @{
+ */
+
+
+#ifdef _WIN32_WCE
+
+/*
+ * Environment variable related functions
+ *
+ */
+
+/**
+ * @brief Return the static string "[Windows CE] error\n".
+ *
+ * @param errnum Unused parameter.
+ * @return The static string "[Windows CE] error\n".
+ *
+ * This function just returns the static string "[Windows CE]
+ * error\n".
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows CE (not cegcc).
+ */
+EAPI char *strerror (int errnum);
+
+#endif /* _WIN32_WCE */
+
+/*
+ * bit related functions
+ *
+ */
+
+/**
+ * @brief Return the position of the first (least significant) bit set in a word
+ *
+ * @param i Word to take the first bit.
+ * @return The position of the first bit set, or 0 if no bits are set.
+ *
+ * This function returns the position of the first (least significant)
+ * bit set in @p i. The least significant bit is position 1 and the
+ * most significant position e.g. 32 or 64. The function returns 0 if
+ * no bits are set in @p i, or the position of the first bit set
+ * otherwise.
+ *
+ * Conformity: BSD
+ *
+ * Supported OS: Windows XP, Windows CE (not cegcc).
+ */
+EAPI int ffs(int i);
+
+
+#ifdef _WIN32_WCE
+
+/*
+ * String manipulation related functions
+ *
+ */
+
+/**
+ * @brief Compare two strings.
+ *
+ * @param s1 The first string to compare.
+ * @param s2 The second string to compare.
+ * @return < 0 if s1 < s2, >0 if s1 > s2, 0 otherwise.
+ *
+ * This function is exactly the same as strcmp(). No possible way to
+ * achieve the behavior of strcoll() on Windows CE.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows CE.
+ */
+EAPI int strcoll (const char *s1, const char *s2);
+
+#endif /* _WIN32_WCE */
+
+/**
+ * @brief Get the last substring occurence.
+ *
+ * @param str The string to search from.
+ * @param substr The substring to search.
+ * @return The last occurrence of the substring if found, @c NULL otherwise.
+ *
+ * This function retrieves the last occurrence of @p substring in the
+ * string @p str. If @p str or @p substr are @c NULL, of if @p substr
+ * is not found in @p str, @c NULL is returned.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI char *strrstr (const char *str, const char *substr);
+
+#ifdef _MSC_VER
+
+/**
+ * @brief Compare two string, ignoring case.
+ *
+ * @param s1 The first string to compare.
+ * @param s2 The first string to compare.
+ * @return
+ *
+ * This function compares the two strings @p s1 and @p s2, ignoring
+ * the case of the characters. It returns an integer less than, equal
+ * to, or greater than zero if s1 is found, respectively, to be less
+ * than, to match, or be greater than s2.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP (vc++ only)
+ */
+EAPI int strcasecmp(const char *s1, const char *s2);
+
+#endif /* _MSC_VER */
+
+/**
+ * @brief Locatea substring into a string, ignoring case.
+ *
+ * @param haystack The string to search in.
+ * @param needle The substring to find.
+ * @return
+ *
+ * This function locates the string @p needle into the string @p haystack,
+ * ignoring the case of the characters. It returns apointer to the
+ * beginning of the substring, or NULL if the substring is not found.
+ * If @p haystack or @p needle are @c NULL, this function returns @c NULL.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP, Windows CE
+ */
+EAPI char *strcasestr(const char *haystack, const char *needle);
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_STRING_H__ */
diff --git a/src/lib/evil/evil_time.c b/src/lib/evil/evil_time.c
new file mode 100644
index 0000000000..bcff29eb05
--- /dev/null
+++ b/src/lib/evil/evil_time.c
@@ -0,0 +1,45 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include "Evil.h"
+#include "evil_private.h"
+
+#ifndef localtime_r
+
+struct tm *
+localtime_r(const time_t *timep, struct tm *result)
+{
+# ifndef _MSC_VER
+ struct tm *tmp;
+# endif /* ! _MSC_VER */
+
+ if (!timep || !result)
+ return NULL;
+
+# ifdef _MSC_VER
+ if (localtime_s(result, timep) != 0)
+ return NULL;
+# else
+ tmp = localtime(timep);
+ if (!tmp)
+ return NULL;
+
+ memcpy(result, tmp, sizeof(struct tm));
+
+# endif /* ! _MSC_VER */
+
+ return result;
+}
+
+#endif /* localtime_r */
+
+#ifdef UNDER_CE
+
+void
+tzset(void)
+{
+ /* does nothing... */
+}
+
+#endif /* UNDER_CE */
diff --git a/src/lib/evil/evil_time.h b/src/lib/evil/evil_time.h
new file mode 100644
index 0000000000..13fc909024
--- /dev/null
+++ b/src/lib/evil/evil_time.h
@@ -0,0 +1,61 @@
+#ifndef __EVIL_TIME_H__
+#define __EVIL_TIME_H__
+
+
+/**
+ * @file evil_time.h
+ * @brief The file that provides functions ported from Unix in time.h.
+ * @defgroup Evil_Time_Group Time.h functions
+ *
+ * This header provides functions ported from Unix in time.h.
+ *
+ * @{
+ */
+
+
+#ifndef localtime_r
+
+/**
+ * @brief Convert the calendar time to broken-time representation in a
+ * user supplied data.
+ *
+ * @param timep The calender time.
+ * @param result The broken-down time representation.
+ * @return The broken-down time representation.
+ *
+ * This function converts the calendar time @p timep to a broken-time
+ * representation. The result is stored in the buffer @p result
+ * supplied by the user. If @p timep or @p result are @c NULL, or if
+ * an error occurred, this function returns @c NULL and the values in
+ * @p result might be undefined. Otherwise it returns @p result.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP.
+ */
+EAPI struct tm *localtime_r(const time_t *timep, struct tm *result);
+
+#endif /* localtime_r */
+
+#ifdef UNDER_CE
+
+/**
+ * @brief Stub implementation of tzset().
+ *
+ * This function does nothing.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows CE.
+ */
+EAPI void tzset(void);
+
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_TIME_H__ */
diff --git a/src/lib/evil/evil_unistd.c b/src/lib/evil/evil_unistd.c
new file mode 100644
index 0000000000..e1498509df
--- /dev/null
+++ b/src/lib/evil/evil_unistd.c
@@ -0,0 +1,431 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif /* HAVE_ERRNO_H */
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <winsock2.h>
+#undef WIN32_LEAN_AND_MEAN
+
+# include <sys/time.h>
+
+#ifdef _MSC_VER
+# include <direct.h> /* for _getcwd */
+#endif
+
+#include "Evil.h"
+#include "evil_private.h"
+
+
+LONGLONG _evil_time_freq;
+LONGLONG _evil_time_count;
+long _evil_time_second;
+
+
+long
+_evil_systemtime_to_time(SYSTEMTIME st)
+{
+ int days[] = {
+ -1, 30, 58, 89, 119, 150, 180, 211, 242, 272, 303, 333, 364
+ };
+ int day;
+ time_t t;
+
+ st.wYear -= 1900;
+ if ((st.wYear < 70) || (st.wYear > 138))
+ return -1;
+
+ day = st.wDay + days[st.wMonth - 1];
+
+ if (!(st.wYear & 3) && (st.wMonth > 2) )
+ day++;
+
+ t = ((st.wYear - 70) * 365 + ((st.wYear - 1) >> 2) - 17 + day) * 24 + st.wHour;
+ t = (t * 60 + st.wMinute) * 60 + st.wSecond;
+
+ return (long)t;
+}
+
+/*
+ * Time related functions
+ *
+ */
+
+double
+evil_time_get(void)
+{
+ LARGE_INTEGER count;
+
+ QueryPerformanceCounter(&count);
+
+ return (double)_evil_time_second + (double)(count.QuadPart - _evil_time_count)/ (double)_evil_time_freq;
+}
+
+#ifdef _MSC_VER
+int
+evil_gettimeofday(struct timeval *tp, void *tzp __UNUSED__)
+{
+ LARGE_INTEGER count;
+ LONGLONG diff;
+
+ QueryPerformanceCounter(&count);
+ diff = count.QuadPart - _evil_time_count;
+ tp->tv_sec = _evil_time_second + (long)(diff / _evil_time_freq);
+ tp->tv_usec = (long)(((diff % _evil_time_freq) * 1000000ll) / _evil_time_freq);
+
+ return 1;
+}
+
+int
+evil_usleep(unsigned long usec)
+{
+ Sleep(usec / 1000);
+ return 0;
+}
+#endif
+
+
+/*
+ * Process identifer related functions
+ *
+ */
+
+#if defined (_MSC_VER) || defined (_WIN32_WCE)
+pid_t
+getpid(void)
+{
+ return (pid_t)GetCurrentProcessId();
+}
+#endif
+
+/*
+ * File related functions
+ *
+ */
+
+char *
+evil_getcwd(char *buffer, size_t size)
+{
+#ifdef _WIN32_WCE
+ wchar_t wpath[PATH_MAX];
+ char *cpath;
+ char *delim;
+ DWORD ret = 0;
+
+ if (size <= 0)
+ return NULL;
+
+ ret = GetModuleFileName(GetModuleHandle(NULL), (LPWSTR)&wpath, PATH_MAX);
+
+ if (!ret)
+ {
+ _evil_error_display(__FUNCTION__, ret);
+ return NULL;
+ }
+
+ cpath = evil_wchar_to_char(wpath);
+ if (!cpath)
+ return NULL;
+
+ if (strlen(cpath) >= (size - 1))
+ {
+ free(cpath);
+ return NULL;
+ }
+
+ delim = strrchr(cpath, '\\');
+ if (delim)
+ *delim = '\0';
+
+ if (!buffer)
+ {
+ buffer = (char *)malloc(sizeof(char) * size);
+ if (!buffer)
+ {
+ free(cpath);
+ return NULL;
+ }
+ }
+
+ strcpy(buffer, cpath);
+ free(cpath);
+
+ return buffer;
+#else
+ return _getcwd(buffer, (int)size);
+#endif /* ! _WIN32_WCE */
+}
+
+#ifdef _WIN32_WCE
+
+int
+evil_stat(const char *file_name, struct stat *st)
+{
+ SYSTEMTIME system_time;
+ FILETIME local_time;
+ WIN32_FIND_DATA data;
+ HANDLE handle;
+ char *f;
+ char *tmp;
+ wchar_t *file;
+ int permission = 0;
+
+ if (!file_name || !*file_name)
+ return -1;
+
+ f = strdup(file_name);
+ if (!f)
+ return -1;
+
+ tmp = f;
+ while (*tmp)
+ {
+ if (*tmp == '/') *tmp = '\\';
+ tmp++;
+ }
+
+ if (!strcmp(file_name, "\\"))
+ {
+ st->st_size = 1024;
+ st->st_mode = S_IFDIR;
+ permission = S_IREAD|S_IWRITE|S_IEXEC;
+
+ st->st_mode |= permission | (permission >> 3) | (permission >> 6);
+ return 0;
+ }
+
+ if (*f != '\\')
+ {
+ char buf[PATH_MAX];
+ int l1;
+ int l2;
+
+ evil_getcwd(buf, PATH_MAX);
+ l1 = strlen(buf);
+ l2 = strlen(file_name);
+ tmp = (char *)malloc(l1 + 1 + l2 + 1);
+ if (!tmp)
+ return -1;
+ memcpy(tmp, buf, l1);
+ tmp[l1] = '\\';
+ memcpy(tmp + l1 + 1, file_name, l2);
+ tmp[l1 + 1 + l2] = '\0';
+ file = evil_char_to_wchar(tmp);
+ free(tmp);
+ if (!file)
+ return -1;
+ }
+ else
+ {
+ file = evil_char_to_wchar(f);
+ if (!file)
+ return -1;
+ }
+
+ free(f);
+
+ handle = FindFirstFile(file, &data);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ free(file);
+ return -1;
+ }
+
+ free(file);
+
+ if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ st->st_size = 1024;
+ st->st_mode = S_IFDIR;
+ st->st_nlink = 2;
+ }
+ else
+ {
+ st->st_size = data.nFileSizeLow;
+ st->st_mode = S_IFREG;
+ st->st_nlink = 1;
+ }
+
+ permission |= S_IREAD;
+
+ if (!(data.dwFileAttributes & FILE_ATTRIBUTE_READONLY))
+ permission |= S_IWRITE;
+
+ if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+ permission |= S_IEXEC;
+
+ st->st_mode |= permission | (permission >> 3) | (permission >> 6);
+
+ FileTimeToLocalFileTime(&data.ftLastWriteTime, &local_time);
+ FileTimeToSystemTime(&local_time, &system_time);
+
+ st->st_mtime = _evil_systemtime_to_time(system_time);
+
+ FileTimeToLocalFileTime(&data.ftCreationTime, &local_time);
+ FileTimeToSystemTime(&local_time, &system_time);
+
+ st->st_ctime = _evil_systemtime_to_time(system_time);
+
+ FileTimeToLocalFileTime(&data.ftLastAccessTime, &local_time);
+ FileTimeToSystemTime(&local_time, &system_time);
+
+ st->st_atime = _evil_systemtime_to_time(system_time);
+
+ if(st->st_atime == 0)
+ st->st_atime = st->st_mtime;
+ if (st->st_ctime == 0)
+ st->st_ctime = st->st_mtime;
+
+ st->st_rdev = 1;
+ st->st_ino = 0;
+
+ FindClose(handle);
+
+ return 0;
+}
+
+#endif /* _WIN32_WCE */
+
+
+
+/*
+ * Sockets and pipe related functions
+ *
+ */
+
+int
+evil_sockets_init(void)
+{
+ WSADATA wsa_data;
+
+ return (WSAStartup(MAKEWORD(2, 2), &wsa_data) == 0) ? 1 : 0;
+}
+
+void
+evil_sockets_shutdown(void)
+{
+ WSACleanup();
+}
+
+/*
+ * The code of the following functions has been kindly offered
+ * by Tor Lillqvist.
+ */
+int
+evil_pipe(int *fds)
+{
+ struct sockaddr_in saddr;
+ SOCKET temp;
+ SOCKET socket1 = INVALID_SOCKET;
+ SOCKET socket2 = INVALID_SOCKET;
+ u_long arg;
+ fd_set read_set;
+ fd_set write_set;
+ int len;
+
+ temp = socket (AF_INET, SOCK_STREAM, 0);
+
+ if (temp == INVALID_SOCKET)
+ goto out0;
+
+ arg = 1;
+ if (ioctlsocket (temp, FIONBIO, &arg) == SOCKET_ERROR)
+ goto out0;
+
+ memset (&saddr, 0, sizeof (saddr));
+ saddr.sin_family = AF_INET;
+ saddr.sin_port = 0;
+ saddr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
+
+ if (bind (temp, (struct sockaddr *)&saddr, sizeof (saddr)))
+ goto out0;
+
+ if (listen (temp, 1) == SOCKET_ERROR)
+ goto out0;
+
+ len = sizeof (saddr);
+ if (getsockname (temp, (struct sockaddr *)&saddr, &len))
+ goto out0;
+
+ socket1 = socket (AF_INET, SOCK_STREAM, 0);
+
+ if (socket1 == INVALID_SOCKET)
+ goto out0;
+
+ arg = 1;
+ if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR)
+ goto out1;
+
+ if ((connect (socket1, (struct sockaddr *)&saddr, len) == SOCKET_ERROR) &&
+ (WSAGetLastError () != WSAEWOULDBLOCK))
+ goto out1;
+
+ FD_ZERO (&read_set);
+ FD_SET (temp, &read_set);
+
+ if (select (0, &read_set, NULL, NULL, NULL) == SOCKET_ERROR)
+ goto out1;
+
+ if (!FD_ISSET (temp, &read_set))
+ goto out1;
+
+ socket2 = accept (temp, (struct sockaddr *) &saddr, &len);
+ if (socket2 == INVALID_SOCKET)
+ goto out1;
+
+ FD_ZERO (&write_set);
+ FD_SET (socket1, &write_set);
+
+ if (select (0, NULL, &write_set, NULL, NULL) == SOCKET_ERROR)
+ goto out2;
+
+ if (!FD_ISSET (socket1, &write_set))
+ goto out2;
+
+ arg = 0;
+ if (ioctlsocket (socket1, FIONBIO, &arg) == SOCKET_ERROR)
+ goto out2;
+
+ arg = 0;
+ if (ioctlsocket (socket2, FIONBIO, &arg) == SOCKET_ERROR)
+ goto out2;
+
+ fds[0] = socket1;
+ fds[1] = socket2;
+
+ closesocket (temp);
+
+ return 0;
+
+ out2:
+ closesocket (socket2);
+ out1:
+ closesocket (socket1);
+ out0:
+ closesocket (temp);
+
+ fds[0] = INVALID_SOCKET;
+ fds[1] = INVALID_SOCKET;
+
+ return -1;
+}
+
+
+/*
+ * Exec related functions
+ *
+ */
+
+#ifdef _WIN32_WCE
+
+int execvp (const char *file __UNUSED__, char *const argv[] __UNUSED__)
+{
+ return 1;
+}
+
+#endif /* _WIN32_WCE */
diff --git a/src/lib/evil/evil_unistd.h b/src/lib/evil/evil_unistd.h
new file mode 100644
index 0000000000..db6cd022fc
--- /dev/null
+++ b/src/lib/evil/evil_unistd.h
@@ -0,0 +1,326 @@
+#ifndef __EVIL_UNISTD_H__
+#define __EVIL_UNISTD_H__
+
+
+/**
+ * @file evil_unistd.h
+ * @brief The file that provides functions ported from Unix in unistd.h.
+ * @defgroup Evil_Unistd_Group Unistd.h functions
+ *
+ * This header provides functions ported from Unix in unistd.h.
+ *
+ * @{
+ */
+
+
+/*
+ * Time related functions
+ *
+ */
+
+/**
+ * @brief Return the time spent since the Evil library has been initialized.
+ *
+ * @return The time spent since the Evil library has been initialized.
+ *
+ * This function returns the time spent since the Evil library has
+ * been initialized. It uses a high-resolution timer and then can have
+ * a precision up to the nano-second. The precision is processor
+ * dependant. This function can be used to benchmark parts of code in
+ * with high precision.
+ *
+ * Conformity: Not appliclable.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI double evil_time_get(void);
+
+#ifdef _MSC_VER
+
+/**
+ * @brief Retrieve the time since the Evil library has been
+ * initialized.
+ *
+ * @param tp Structure to fill.
+ * @param tzp Unused.
+ * @return Always 1.
+ *
+ * The function fills @p tp with the time spent since the Evil library
+ * has been initialized. It uses a high-resolution timer and then can
+ * have a precision up to the nano-second. The precision is processor
+ * dependant. This function can be used to benchmark parts of code in
+ * with high precision. This function always returns 1.
+ *
+ * Conformity: Not appliclable.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI int evil_gettimeofday(struct timeval * tp, void * tzp);
+
+/**
+ * @def gettimeofday(tp,tzp)
+ *
+ * Wrapper around evil_gettimeofday().
+ */
+#define gettimeofday(tp,tzp) evil_gettimeofday((tp),(tzp))
+
+/**
+ * @brief Suspend the execution of the calling process for microsecond
+ * intervals.
+ *
+ * @param usec The interval in microseconds.
+ * @return Always 0 (success).
+ *
+ * This function suspends the execution of the calling process for (at
+ * least) @p usec microseconds.
+ *
+ * Conformity: Not appliclable.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI int evil_usleep(unsigned long usec);
+
+/**
+ * @def usleep(usec)
+ *
+ * Wrapper around evil_usleep().
+ */
+#define usleep(usec) evil_usleep(usec);
+
+#endif /* _MSC_VER */
+
+/*
+ * Process identifer related functions
+ *
+ */
+
+#if defined (_MSC_VER) || defined (_WIN32_WCE)
+/**
+ * @brief Return the process identifier of the calling process.
+ *
+ * @return The process ID.
+ *
+ * Return the process identifier of the calling process. Until
+ * the process terminates, the process identifier uniquely
+ * identifies the process throughout the system.
+ *
+ * Conformity: Not appliclable.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI pid_t getpid(void);
+#endif
+
+
+/*
+ * Symbolic links and directory related functions
+ *
+ */
+
+/**
+ * @brief Create a shell link.
+ *
+ * @param oldpath The file name to be linked.
+ * @param newpath The file name to create.
+ * @return 0 on success, -1 otherwise.
+ *
+ * Create a shell link @p newpath to @p oldpath (@p newpath is the
+ * name of the file created, @p oldpath is the string used in
+ * creating the shell link).
+ *
+ * On success, this function returns 0. Otherwise, it returns -1 and
+ * errno may be set to the following value:
+ * - ENOMEM: Not enough memory.
+ *
+ * On Windows, the symbolic links do not exist. Nevertheless
+ * shell links can be created. This function is named like the Unix
+ * function for portability reasons.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI int symlink(const char *oldpath, const char *newpath);
+
+/**
+ * @brief Read value of a shell link.
+ *
+ * @param path The file name to be linked.
+ * @param buf The file name to create.
+ * @param bufsiz The size of the buffer.
+ * @return 0 on success, -1 otherwise.
+ *
+ * Place the content of the shell link @p path in the buffer
+ * @p buf, which has size @p bufzsiz.
+ *
+ * On success, this function returns 0. Otherwise, it returns -1 and
+ * errno may be set to the following value:
+ * - ENOMEM: Not enough memory.
+ *
+ * On Windows, the symbolic links do not exist. Nevertheless
+ * shell links can be managed. This function is named like the Unix
+ * function for portability reasons.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI ssize_t readlink(const char *path, char *buf, size_t bufsiz);
+
+
+/*
+ * file related functions
+ *
+ */
+
+
+#ifdef _WIN32_WCE
+
+/**
+ * @brief Return information about a file.
+ *
+ * @param file_name The file to retrieve information from.
+ * @param st Buffer to fill
+ * @return 0 on success, -1 otherwise.
+ *
+ * This function retrieves information about the file named
+ * @p file_name and fill the structure @p st. If the function
+ * succeeds, 0 is returned, otherwise -1 is returned.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows CE (not cegcc).
+ */
+EAPI int evil_stat(const char *file_name, struct stat *st);
+
+/**
+ * @def stat(f,st)
+ *
+ * Wrapper around evil_stat().
+ */
+# define stat(f,st) evil_stat((f),(st))
+
+#endif /* _WIN32_WCE */
+
+/**
+ * @brief Get the current directory.
+ *
+ * @param buffer Buffer to store the current directory.
+ * @param size Size of the buffer.
+ * @return The current directory.
+ *
+ * On Windows desktop, use the _getcwd function in MSVCRT.
+ *
+ * On Windows CE, get the current directory by extracting the path
+ * from the executable that is running and put the result in @p buffer
+ * of length @p size. If @p size is less or equal than 0, return NULL.
+ * If the current absolute path would require a buffer longer than
+ * @p size elements, NULL is returned. If @p buffer is NULL, a buffer
+ * of length @p size is allocated and is returned. If the allocation
+ * fails, NULL is returned. On success, @p buffer is returned and
+ * contains the current directory. The last '\' is not included.
+ * If @p buffer is NULL, the returned value must be freed if not NULL.
+ *
+ * Specially usefull on WinCE where the current directory functionality
+ * is not supported.
+ *
+ * Conformity: Almost POSIX.1 (no errno set)
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI char *evil_getcwd(char *buffer, size_t size);
+
+/**
+ * @def getcwd(b,s)
+ *
+ * Wrapper around evil_getcwd().
+ */
+#define getcwd(b,s) evil_getcwd((b),(s))
+
+/*
+ * Sockets and pipe related functions
+ *
+ */
+
+/**
+ * @brief Initiates the use of Windows sockets.
+ *
+ * @return 1 on success, 0 otherwise.
+ *
+ * Initiates the use of Windows sockets. If the function succeeds,
+ * it returns 1, otherwise it returns 0.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI int evil_sockets_init(void);
+
+/**
+ * @brief Shutdown the Windows socket system.
+ *
+ * Shutdown the Windows socket system.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI void evil_sockets_shutdown(void);
+
+/**
+ * @brief Create a pair of sockets.
+ *
+ * @param fds A pointer that contains two sockets.
+ *
+ * Create a pair of sockets that can be use with select().
+ * Hence, evil_sockets_init() must have been caled at least
+ * once before. Contrary to Unix, that functions does not
+ * create a pair of file descriptors.
+ *
+ * Conformity: Not applicable.
+ *
+ * Supported OS: Windows XP, Windows CE.
+ */
+EAPI int evil_pipe(int *fds);
+
+/**
+ * @def pipe(fds)
+ *
+ * Wrapper around evil_pipe().
+ */
+#define pipe(fds) evil_pipe(fds)
+
+
+/*
+ * Exec related functions
+ *
+ */
+
+
+#ifdef _WIN32_WCE
+
+/**
+ * @brief Replace the current process image with a new process image.
+ *
+ * @param file The file name of the file being executed.
+ * @param argv A @c NULL terminated array of strings.
+ * @return Always 1.
+ *
+ * This function does nothing and returns always 1. It is defined for
+ * ecore_app only for native Windows CE code.
+ *
+ * Conformity: Not appliclable.
+ *
+ * Supported OS: Windows CE (not cegcc).
+ */
+EAPI int execvp( const char *file, char *const argv[]);
+
+#endif /* _WIN32_WCE */
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_UNISTD_H__ */
diff --git a/src/lib/evil/evil_util.c b/src/lib/evil/evil_util.c
new file mode 100644
index 0000000000..ad42559a71
--- /dev/null
+++ b/src/lib/evil/evil_util.c
@@ -0,0 +1,247 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <limits.h>
+#include <wchar.h>
+
+#ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include "evil_macro.h"
+#include "evil_util.h"
+#include "evil_private.h"
+#define APICHAR char
+#include "evil_print.h"
+
+
+wchar_t *
+evil_char_to_wchar(const char *text)
+{
+ wchar_t *wtext;
+ int wsize;
+
+ if (!text)
+ return NULL;
+
+ wsize = MultiByteToWideChar(CP_ACP, 0, text, (int)strlen(text) + 1, NULL, 0);
+ if ((wsize == 0) ||
+ (wsize > (int)(ULONG_MAX / sizeof(wchar_t))))
+ {
+ if (wsize == 0)
+ _evil_last_error_display(__FUNCTION__);
+ return NULL;
+ }
+
+ wtext = malloc(wsize * sizeof(wchar_t));
+ if (wtext)
+ if (!MultiByteToWideChar(CP_ACP, 0, text, (int)strlen(text) + 1, wtext, wsize))
+ {
+ _evil_last_error_display(__FUNCTION__);
+ return NULL;
+ }
+
+ return wtext;
+}
+
+char *
+evil_wchar_to_char(const wchar_t *text)
+{
+ char *atext;
+ int asize;
+
+ if (!text)
+ return NULL;
+
+ asize = WideCharToMultiByte(CP_ACP, 0, text, -1, NULL, 0, NULL, NULL);
+ if (asize == 0)
+ {
+ _evil_last_error_display(__FUNCTION__);
+ return NULL;
+ }
+
+ atext = (char*)malloc(asize * sizeof(char));
+ if (!atext)
+ return NULL;
+
+ asize = WideCharToMultiByte(CP_ACP, 0, text, -1, atext, asize, NULL, NULL);
+ if (asize == 0)
+ {
+ _evil_last_error_display(__FUNCTION__);
+ return NULL;
+ }
+
+ return atext;
+}
+
+char *
+evil_utf16_to_utf8(const wchar_t *text16)
+{
+ char *text8;
+ DWORD flag = 0;
+ int size8;
+
+ if (!text16)
+ return NULL;
+
+#if _WIN32_WINNT >= 0x0600
+ flag = WC_ERR_INVALID_CHARS;;
+#endif
+
+ size8 = WideCharToMultiByte(CP_UTF8, flag, text16, -1, NULL, 0, NULL, NULL);
+ if (size8 == 0)
+ {
+ _evil_last_error_display(__FUNCTION__);
+ return NULL;
+ }
+
+ text8 = (char*)malloc(size8 * sizeof(char));
+ if (!text8)
+ return NULL;
+
+ size8 = WideCharToMultiByte(CP_UTF8, flag, text16, -1, text8, size8, NULL, NULL);
+ if (size8 == 0)
+ {
+ _evil_last_error_display(__FUNCTION__);
+ return NULL;
+ }
+
+ return text8;
+}
+
+char *
+evil_format_message(long err)
+{
+ LPTSTR msg;
+ char *str;
+ char *disp;
+
+ if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ 0, /* Default language */
+ (LPTSTR)&msg,
+ 0,
+ NULL))
+ {
+ char buf[4096];
+
+ snprintf(buf, 4096, "FormatMessage failed with error %ld\n", GetLastError());
+ return strdup(buf);
+ }
+
+#ifdef UNICODE
+ str = evil_wchar_to_char(msg);
+#else
+ str = msg;
+#endif /* UNICODE */
+
+ disp = (char *)malloc((strlen(str) + strlen("(00000) ") + 1) * sizeof(char));
+ if (!disp)
+ {
+ LocalFree(msg);
+ return NULL;
+ }
+
+ snprintf(disp, strlen(str) + strlen("(00000) ") + 1,
+ "(%5ld) %s", err, str);
+
+#ifdef UNICODE
+ free(str);
+#endif /* UNICODE */
+
+ LocalFree(msg);
+
+ return disp;
+}
+
+void
+_evil_error_display(const char *fct, LONG res)
+{
+ char *error;
+
+ error = evil_format_message(res);
+ fprintf(stderr, "[Evil] [%s] ERROR (%ld): %s\n", fct, res, error);
+ free(error);
+}
+
+char *
+evil_last_error_get(void)
+{
+ DWORD err;
+
+ err = GetLastError();
+ return evil_format_message(err);
+}
+
+void
+_evil_last_error_display(const char *fct)
+{
+ char *error;
+
+ error = evil_last_error_get();
+ fprintf(stderr, "[Evil] [%s] ERROR: %s\n", fct, error);
+ free(error);
+}
+
+
+const char *
+evil_tmpdir_get(void)
+{
+#ifdef _WIN32_WCE
+ return "\\temp";
+#else
+ char *tmpdir;
+
+ tmpdir = getenv("TMP");
+ if (!tmpdir) tmpdir = getenv("TEMP");
+ if (!tmpdir) tmpdir = getenv("USERPROFILE");
+ if (!tmpdir) tmpdir = getenv("WINDIR");
+ if (!tmpdir) tmpdir="C:\\";
+
+ return tmpdir;
+#endif /* ! _WIN32_WCE */
+}
+
+const char *
+evil_homedir_get(void)
+{
+#ifdef _WIN32_WCE
+ return "\\my documents";
+#else
+ char *homedir;
+
+ homedir = getenv("HOME");
+ if (!homedir) homedir = getenv("USERPROFILE");
+ if (!homedir) homedir = getenv("WINDIR");
+ if (!homedir) homedir="C:\\";
+
+ return homedir;
+#endif /* ! _WIN32_WCE */
+}
+
+int
+evil_path_is_absolute(const char *path)
+{
+ size_t length;
+
+ if (!path)
+ return 0;
+
+ length = strlen(path);
+ if (length < 3) return 0;
+
+ if ((((*path >= 'a') && (*path <= 'z')) ||
+ ((*path >= 'A') && (*path <= 'Z'))) &&
+ (path[1] == ':') &&
+ ((path[2] == '/') || (path[2] == '\\')))
+ return 1;
+
+ return 0;
+}
diff --git a/src/lib/evil/evil_util.h b/src/lib/evil/evil_util.h
new file mode 100644
index 0000000000..7d488a9a5c
--- /dev/null
+++ b/src/lib/evil/evil_util.h
@@ -0,0 +1,134 @@
+#ifndef __EVIL_UTIL_H__
+#define __EVIL_UTIL_H__
+
+
+/**
+ * @brief Convert a string from char * to wchar_t *.
+ *
+ * @param text The string to convert.
+ * @return The converted string.
+ *
+ * Convert a string from char * to wchar_t * and return it. If the
+ * allocation or conversion fails, NULL is returned. On success, the
+ * returned value must be freed when it is not used anymore.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows 95, Windows 98, Windows Me, Windows NT, Windows 2000,
+ * Windows XP.
+ *
+ * @ingroup Evil
+ */
+EAPI wchar_t *evil_char_to_wchar(const char *text);
+
+/**
+ * @brief Convert a string from wchar_t * to char *.
+ *
+ * @param text The string to convert.
+ * @return The converted string.
+ *
+ * Convert a string from wchar_t * to char * and return it. If the
+ * allocation or conversion fails, NULL is returned. On success, the
+ * returned value must be freed when it is not used anymore.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows 95, Windows 98, Windows Me, Windows NT, Windows 2000,
+ * Windows XP.
+ *
+ * @ingroup Evil
+ */
+EAPI char *evil_wchar_to_char(const wchar_t *text);
+
+/**
+ * @brief Convert a string from UTF-16 to UTF-8.
+ *
+ * @param text The string to convert in UTF-16.
+ * @return The converted string in UTF-8.
+ *
+ * Convert a string from UTF-16 to UTF-8 and return it. If the
+ * allocation or conversion fails, NULL is returned. On success, the
+ * returned value must be freed when it is not used anymore.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows 95, Windows 98, Windows Me, Windows NT, Windows 2000,
+ * Windows XP.
+ *
+ * @ingroup Evil
+ */
+EAPI char *evil_utf16_to_utf8(const wchar_t *text);
+
+EAPI char *evil_format_message(long err);
+
+EAPI char *evil_last_error_get(void);
+
+/**
+ * @brief Return a dir to store temporary files.
+ *
+ * @return The directory to store temporary files.
+ *
+ * Return a directory to store temporary files. The function gets
+ * the value of the following environment variables, and in that order:
+ * - TMP
+ * - TEMP
+ * - USERPROFILE
+ * - WINDIR
+ * and returns its value if it exists. If none exists, the function
+ * returns "C:\".
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows 95, Windows 98, Windows Me, Windows NT, Windows 2000,
+ * Windows XP.
+ *
+ * @ingroup Evil
+ */
+EAPI const char *evil_tmpdir_get(void);
+
+/**
+ * @brief Return a dir to store personal files.
+ *
+ * @return The directory to store personal files.
+ *
+ * Return a directory to store personal files. The function gets
+ * the value of the following environment variables, and in that order:
+ * - HOME
+ * - USERPROFILE
+ * - WINDIR
+ * and returns its value if it exists. If none exists, the function
+ * returns "C:\".
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows 95, Windows 98, Windows Me, Windows NT, Windows 2000,
+ * Windows XP.
+ *
+ * @ingroup Evil
+ */
+EAPI const char *evil_homedir_get(void);
+
+/**
+ * @brief check if the given path is absolute.
+ *
+ * @param path The path to check.
+ * @return 1 if the given path is absolute, 0 otherwise.
+ *
+ * Check if the path @p path is absolute or not. An absolute path must
+ * begin with a letter (upper or lower case), followed by by the char
+ * ':', followed by the char '/' or '\'. If @p path is absolute this
+ * function returns 1, otherwise it returns 0. If @p path is @c NULL,
+ * it returns 0.
+ *
+ * Conformity: Non applicable.
+ *
+ * Supported OS: Windows 95, Windows 98, Windows Me, Windows NT, Windows 2000,
+ * Windows XP, Windows CE.
+ *
+ * @since 1.7
+ *
+ * @ingroup Evil
+ */
+EAPI int evil_path_is_absolute(const char *path);
+
+#endif /* __EVIL_UTIL_H__ */
diff --git a/src/lib/evil/evil_uuid.c b/src/lib/evil/evil_uuid.c
new file mode 100644
index 0000000000..cfdb4302bb
--- /dev/null
+++ b/src/lib/evil/evil_uuid.c
@@ -0,0 +1,12 @@
+#ifndef __MINGW32CE__
+/*
+ * Defines the windows UUID IID_IPersistFile used for links in
+ * evil. This is here since uuid.lib is a static only library and
+ * libtool does not allow you to link a DLL against a static library.
+ */
+
+# define INITGUID
+# include <basetyps.h>
+DEFINE_OLEGUID(IID_IPersistFile, 0x0000010BL, 0, 0);
+
+#endif /* ! __MINGW32CE__ */
diff --git a/src/lib/evil/fnmatch.h b/src/lib/evil/fnmatch.h
new file mode 100644
index 0000000000..f2a9266e53
--- /dev/null
+++ b/src/lib/evil/fnmatch.h
@@ -0,0 +1,54 @@
+#ifndef __EVIL_FNMATCH_H__
+#define __EVIL_FNMATCH_H__
+
+#ifdef EAPI
+# undef EAPI
+#endif /* EAPI */
+
+#ifdef _WIN32
+# ifdef EFL_EVIL_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_EVIL_BUILD */
+#endif /* _WIN32 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* We #undef these before defining them because some losing systems
+ (HP-UX A.08.07 for example) define these in <unistd.h>. */
+#undef FNM_PATHNAME
+#undef FNM_NOESCAPE
+#undef FNM_PERIOD
+
+/* Bits set in the FLAGS argument to `fnmatch'. */
+#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */
+#define FNM_NOESCAPE (1 << 1) /* Backslashes don't quote special chars. */
+#define FNM_PERIOD (1 << 2) /* Leading `.' is matched only explicitly. */
+
+#if !defined (_POSIX_C_SOURCE) || _POSIX_C_SOURCE < 2 || defined (_GNU_SOURCE)
+#define FNM_FILE_NAME FNM_PATHNAME /* Preferred GNU name. */
+#define FNM_LEADING_DIR (1 << 3) /* Ignore `/...' after a match. */
+#define FNM_CASEFOLD (1 << 4) /* Compare without regard to case. */
+#endif
+
+/* Value returned by `fnmatch' if STRING does not match PATTERN. */
+#define FNM_NOMATCH 1
+#define FNM_SYNTAXERR 2
+#define FNM_NOMEM 3
+
+/* Match STRING against the filename pattern PATTERN,
+ returning zero if it matches, FNM_NOMATCH if not. */
+EAPI int fnmatch(const char *__pattern, const char *__string, int __flags);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EVIL_FNMATCH_H__ */
diff --git a/src/lib/evil/gdtoa/README b/src/lib/evil/gdtoa/README
new file mode 100644
index 0000000000..ce8be55888
--- /dev/null
+++ b/src/lib/evil/gdtoa/README
@@ -0,0 +1,357 @@
+This directory contains source for a library of binary -> decimal
+and decimal -> binary conversion routines, for single-, double-,
+and extended-precision IEEE binary floating-point arithmetic, and
+other IEEE-like binary floating-point, including "double double",
+as in
+
+ T. J. Dekker, "A Floating-Point Technique for Extending the
+ Available Precision", Numer. Math. 18 (1971), pp. 224-242
+
+and
+
+ "Inside Macintosh: PowerPC Numerics", Addison-Wesley, 1994
+
+The conversion routines use double-precision floating-point arithmetic
+and, where necessary, high precision integer arithmetic. The routines
+are generalizations of the strtod and dtoa routines described in
+
+ David M. Gay, "Correctly Rounded Binary-Decimal and
+ Decimal-Binary Conversions", Numerical Analysis Manuscript
+ No. 90-10, Bell Labs, Murray Hill, 1990;
+ http://cm.bell-labs.com/cm/cs/what/ampl/REFS/rounding.ps.gz
+
+(based in part on papers by Clinger and Steele & White: see the
+references in the above paper).
+
+The present conversion routines should be able to use any of IEEE binary,
+VAX, or IBM-mainframe double-precision arithmetic internally, but I (dmg)
+have so far only had a chance to test them with IEEE double precision
+arithmetic.
+
+The core conversion routines are strtodg for decimal -> binary conversions
+and gdtoa for binary -> decimal conversions. These routines operate
+on arrays of unsigned 32-bit integers of type ULong, a signed 32-bit
+exponent of type Long, and arithmetic characteristics described in
+struct FPI; FPI, Long, and ULong are defined in gdtoa.h. File arith.h
+is supposed to provide #defines that cause gdtoa.h to define its
+types correctly. File arithchk.c is source for a program that
+generates a suitable arith.h on all systems where I've been able to
+test it.
+
+The core conversion routines are meant to be called by helper routines
+that know details of the particular binary arithmetic of interest and
+convert. The present directory provides helper routines for 5 variants
+of IEEE binary floating-point arithmetic, each indicated by one or
+two letters:
+
+ f IEEE single precision
+ d IEEE double precision
+ x IEEE extended precision, as on Intel 80x87
+ and software emulations of Motorola 68xxx chips
+ that do not pad the way the 68xxx does, but
+ only store 80 bits
+ xL IEEE extended precision, as on Motorola 68xxx chips
+ Q quad precision, as on Sun Sparc chips
+ dd double double, pairs of IEEE double numbers
+ whose sum is the desired value
+
+For decimal -> binary conversions, there are three families of
+helper routines: one for round-nearest (or the current rounding
+mode on IEEE-arithmetic systems that provide the C99 fegetround()
+function, if compiled with -DHonor_FLT_ROUNDS):
+
+ strtof
+ strtod
+ strtodd
+ strtopd
+ strtopf
+ strtopx
+ strtopxL
+ strtopQ
+
+one with rounding direction specified:
+
+ strtorf
+ strtord
+ strtordd
+ strtorx
+ strtorxL
+ strtorQ
+
+and one for computing an interval (at most one bit wide) that contains
+the decimal number:
+
+ strtoIf
+ strtoId
+ strtoIdd
+ strtoIx
+ strtoIxL
+ strtoIQ
+
+The latter call strtoIg, which makes one call on strtodg and adjusts
+the result to provide the desired interval. On systems where native
+arithmetic can easily make one-ulp adjustments on values in the
+desired floating-point format, it might be more efficient to use the
+native arithmetic. Routine strtodI is a variant of strtoId that
+illustrates one way to do this for IEEE binary double-precision
+arithmetic -- but whether this is more efficient remains to be seen.
+
+Functions strtod and strtof have "natural" return types, float and
+double -- strtod is specified by the C standard, and strtof appears
+in the stdlib.h of some systems, such as (at least some) Linux systems.
+The other functions write their results to their final argument(s):
+to the final two argument for the strtoI... (interval) functions,
+and to the final argument for the others (strtop... and strtor...).
+Where possible, these arguments have "natural" return types (double*
+or float*), to permit at least some type checking. In reality, they
+are viewed as arrays of ULong (or, for the "x" functions, UShort)
+values. On systems where long double is the appropriate type, one can
+pass long double* final argument(s) to these routines. The int value
+that these routines return is the return value from the call they make
+on strtodg; see the enum of possible return values in gdtoa.h.
+
+Source files g_ddfmt.c, misc.c, smisc.c, strtod.c, strtodg.c, and ulp.c
+should use true IEEE double arithmetic (not, e.g., double extended),
+at least for storing (and viewing the bits of) the variables declared
+"double" within them.
+
+One detail indicated in struct FPI is whether the target binary
+arithmetic departs from the IEEE standard by flushing denormalized
+numbers to 0. On systems that do this, the helper routines for
+conversion to double-double format (when compiled with
+Sudden_Underflow #defined) penalize the bottom of the exponent
+range so that they return a nonzero result only when the least
+significant bit of the less significant member of the pair of
+double values returned can be expressed as a normalized double
+value. An alternative would be to drop to 53-bit precision near
+the bottom of the exponent range. To get correct rounding, this
+would (in general) require two calls on strtodg (one specifying
+126-bit arithmetic, then, if necessary, one specifying 53-bit
+arithmetic).
+
+By default, the core routine strtodg and strtod set errno to ERANGE
+if the result overflows to +Infinity or underflows to 0. Compile
+these routines with NO_ERRNO #defined to inhibit errno assignments.
+
+Routine strtod is based on netlib's "dtoa.c from fp", and
+(f = strtod(s,se)) is more efficient for some conversions than, say,
+strtord(s,se,1,&f). Parts of strtod require true IEEE double
+arithmetic with the default rounding mode (round-to-nearest) and, on
+systems with IEEE extended-precision registers, double-precision
+(53-bit) rounding precision. If the machine uses (the equivalent of)
+Intel 80x87 arithmetic, the call
+ _control87(PC_53, MCW_PC);
+does this with many compilers. Whether this or another call is
+appropriate depends on the compiler; for this to work, it may be
+necessary to #include "float.h" or another system-dependent header
+file.
+
+Source file strtodnrp.c gives a strtod that does not require 53-bit
+rounding precision on systems (such as Intel IA32 systems) that may
+suffer double rounding due to use of extended-precision registers.
+For some conversions this variant of strtod is less efficient than the
+one in strtod.c when the latter is run with 53-bit rounding precision.
+
+The values that the strto* routines return for NaNs are determined by
+gd_qnan.h, which the makefile generates by running the program whose
+source is qnan.c. Note that the rules for distinguishing signaling
+from quiet NaNs are system-dependent. For cross-compilation, you need
+to determine arith.h and gd_qnan.h suitably, e.g., using the
+arithmetic of the target machine.
+
+C99's hexadecimal floating-point constants are recognized by the
+strto* routines (but this feature has not yet been heavily tested).
+Compiling with NO_HEX_FP #defined disables this feature.
+
+When compiled with -DINFNAN_CHECK, the strto* routines recognize C99's
+NaN and Infinity syntax. Moreover, unless No_Hex_NaN is #defined, the
+strto* routines also recognize C99's NaN(...) syntax: they accept
+(case insensitively) strings of the form NaN(x), where x is a string
+of hexadecimal digits and spaces; if there is only one string of
+hexadecimal digits, it is taken for the fraction bits of the resulting
+NaN; if there are two or more strings of hexadecimal digits, each
+string is assigned to the next available sequence of 32-bit words of
+fractions bits (starting with the most significant), right-aligned in
+each sequence.
+
+For binary -> decimal conversions, I've provided just one family
+of helper routines:
+
+ g_ffmt
+ g_dfmt
+ g_ddfmt
+ g_xfmt
+ g_xLfmt
+ g_Qfmt
+
+which do a "%g" style conversion either to a specified number of decimal
+places (if their ndig argument is positive), or to the shortest
+decimal string that rounds to the given binary floating-point value
+(if ndig <= 0). They write into a buffer supplied as an argument
+and return either a pointer to the end of the string (a null character)
+in the buffer, if the buffer was long enough, or 0. Other forms of
+conversion are easily done with the help of gdtoa(), such as %e or %f
+style and conversions with direction of rounding specified (so that, if
+desired, the decimal value is either >= or <= the binary value).
+On IEEE-arithmetic systems that provide the C99 fegetround() function,
+if compiled with -DHonor_FLT_ROUNDS, these routines honor the current
+rounding mode.
+
+For an example of more general conversions based on dtoa(), see
+netlib's "printf.c from ampl/solvers".
+
+For double-double -> decimal, g_ddfmt() assumes IEEE-like arithmetic
+of precision max(126, #bits(input)) bits, where #bits(input) is the
+number of mantissa bits needed to represent the sum of the two double
+values in the input.
+
+The makefile creates a library, gdtoa.a. To use the helper
+routines, a program only needs to include gdtoa.h. All the
+source files for gdtoa.a include a more extensive gdtoaimp.h;
+among other things, gdtoaimp.h has #defines that make "internal"
+names end in _D2A. To make a "system" library, one could modify
+these #defines to make the names start with __.
+
+Various comments about possible #defines appear in gdtoaimp.h,
+but for most purposes, arith.h should set suitable #defines.
+
+Systems with preemptive scheduling of multiple threads require some
+manual intervention. On such systems, it's necessary to compile
+dmisc.c, dtoa.c gdota.c, and misc.c with MULTIPLE_THREADS #defined,
+and to provide (or suitably #define) two locks, acquired by
+ACQUIRE_DTOA_LOCK(n) and freed by FREE_DTOA_LOCK(n) for n = 0 or 1.
+(The second lock, accessed in pow5mult, ensures lazy evaluation of
+only one copy of high powers of 5; omitting this lock would introduce
+a small probability of wasting memory, but would otherwise be harmless.)
+Routines that call dtoa or gdtoa directly must also invoke freedtoa(s)
+to free the value s returned by dtoa or gdtoa. It's OK to do so whether
+or not MULTIPLE_THREADS is #defined, and the helper g_*fmt routines
+listed above all do this indirectly (in gfmt_D2A(), which they all call).
+
+By default, there is a private pool of memory of length 2000 bytes
+for intermediate quantities, and MALLOC (see gdtoaimp.h) is called only
+if the private pool does not suffice. 2000 is large enough that MALLOC
+is called only under very unusual circumstances (decimal -> binary
+conversion of very long strings) for conversions to and from double
+precision. For systems with preemptively scheduled multiple threads
+or for conversions to extended or quad, it may be appropriate to
+#define PRIVATE_MEM nnnn, where nnnn is a suitable value > 2000.
+For extended and quad precisions, -DPRIVATE_MEM=20000 is probably
+plenty even for many digits at the ends of the exponent range.
+Use of the private pool avoids some overhead.
+
+Directory test provides some test routines. See its README.
+I've also tested this stuff (except double double conversions)
+with Vern Paxson's testbase program: see
+
+ V. Paxson and W. Kahan, "A Program for Testing IEEE Binary-Decimal
+ Conversion", manuscript, May 1991,
+ ftp://ftp.ee.lbl.gov/testbase-report.ps.Z .
+
+(The same ftp directory has source for testbase.)
+
+Some system-dependent additions to CFLAGS in the makefile:
+
+ HU-UX: -Aa -Ae
+ OSF (DEC Unix): -ieee_with_no_inexact
+ SunOS 4.1x: -DKR_headers -DBad_float_h
+
+If you want to put this stuff into a shared library and your
+operating system requires export lists for shared libraries,
+the following would be an appropriate export list:
+
+ dtoa
+ freedtoa
+ g_Qfmt
+ g_ddfmt
+ g_dfmt
+ g_ffmt
+ g_xLfmt
+ g_xfmt
+ gdtoa
+ strtoIQ
+ strtoId
+ strtoIdd
+ strtoIf
+ strtoIx
+ strtoIxL
+ strtod
+ strtodI
+ strtodg
+ strtof
+ strtopQ
+ strtopd
+ strtopdd
+ strtopf
+ strtopx
+ strtopxL
+ strtorQ
+ strtord
+ strtordd
+ strtorf
+ strtorx
+ strtorxL
+
+When time permits, I (dmg) hope to write in more detail about the
+present conversion routines; for now, this README file must suffice.
+Meanwhile, if you wish to write helper functions for other kinds of
+IEEE-like arithmetic, some explanation of struct FPI and the bits
+array may be helpful. Both gdtoa and strtodg operate on a bits array
+described by FPI *fpi. The bits array is of type ULong, a 32-bit
+unsigned integer type. Floating-point numbers have fpi->nbits bits,
+with the least significant 32 bits in bits[0], the next 32 bits in
+bits[1], etc. These numbers are regarded as integers multiplied by
+2^e (i.e., 2 to the power of the exponent e), where e is the second
+argument (be) to gdtoa and is stored in *exp by strtodg. The minimum
+and maximum exponent values fpi->emin and fpi->emax for normalized
+floating-point numbers reflect this arrangement. For example, the
+P754 standard for binary IEEE arithmetic specifies doubles as having
+53 bits, with normalized values of the form 1.xxxxx... times 2^(b-1023),
+with 52 bits (the x's) and the biased exponent b represented explicitly;
+b is an unsigned integer in the range 1 <= b <= 2046 for normalized
+finite doubles, b = 0 for denormals, and b = 2047 for Infinities and NaNs.
+To turn an IEEE double into the representation used by strtodg and gdtoa,
+we multiply 1.xxxx... by 2^52 (to make it an integer) and reduce the
+exponent e = (b-1023) by 52:
+
+ fpi->emin = 1 - 1023 - 52
+ fpi->emax = 1046 - 1023 - 52
+
+In various wrappers for IEEE double, we actually write -53 + 1 rather
+than -52, to emphasize that there are 53 bits including one implicit bit.
+Field fpi->rounding indicates the desired rounding direction, with
+possible values
+ FPI_Round_zero = toward 0,
+ FPI_Round_near = unbiased rounding -- the IEEE default,
+ FPI_Round_up = toward +Infinity, and
+ FPI_Round_down = toward -Infinity
+given in gdtoa.h.
+
+Field fpi->sudden_underflow indicates whether strtodg should return
+denormals or flush them to zero. Normal floating-point numbers have
+bit fpi->nbits in the bits array on. Denormals have it off, with
+exponent = fpi->emin. Strtodg provides distinct return values for normals
+and denormals; see gdtoa.h.
+
+Compiling g__fmt.c, strtod.c, and strtodg.c with -DUSE_LOCALE causes
+the decimal-point character to be taken from the current locale; otherwise
+it is '.'.
+
+Source files dtoa.c and strtod.c in this directory are derived from
+netlib's "dtoa.c from fp" and are meant to function equivalently.
+When compiled with Honor_FLT_ROUNDS #defined (on systems that provide
+FLT_ROUNDS and fegetround() as specified in the C99 standard), they
+honor the current rounding mode. Because FLT_ROUNDS is buggy on some
+(Linux) systems -- not reflecting calls on fesetround(), as the C99
+standard says it should -- when Honor_FLT_ROUNDS is #defined, the
+current rounding mode is obtained from fegetround() rather than from
+FLT_ROUNDS, unless Trust_FLT_ROUNDS is also #defined.
+
+Compile with -DUSE_LOCALE to use the current locale; otherwise
+decimal points are assumed to be '.'. With -DUSE_LOCALE, unless
+you also compile with -DNO_LOCALE_CACHE, the details about the
+current "decimal point" character string are cached and assumed not
+to change during the program's execution.
+
+Please send comments to David M. Gay (dmg at acm dot org, with " at "
+changed at "@" and " dot " changed to ".").
diff --git a/src/lib/evil/gdtoa/README.mingw b/src/lib/evil/gdtoa/README.mingw
new file mode 100644
index 0000000000..b41d1fdae0
--- /dev/null
+++ b/src/lib/evil/gdtoa/README.mingw
@@ -0,0 +1,20 @@
+The gdtoa code here is based on David M. Gay's original
+gdtoa source at http://www.netlib.org/fp/ from Sep. 27,
+2010. The major changes between the original source and
+the mingw port here include:
+
+* IBM, CRAY and VAX code removed.
+* KR_headers, ANSI, Void and Char ifdefs are removed.
+* gdtoa symbols are prepended with "__".
+* g_xfmt() uses __fpclassifyl() instead of interpreting
+ the flags bit-wise.
+* lo0bits() and hi0bits() of misc.c replaced by wrappers
+ to gcc's __builtin_clz()
+* The double/ulong union renamed from U to dbl_union
+ (grep'ped better..)
+* A few compiler warning fixes here and there.
+* A few other insignificant changes (if any..)
+
+MinGW specific compile-time definitions are at the top of
+gdtoaimp.h and gdtoa.h headers.
+
diff --git a/src/lib/evil/gdtoa/arithchk.c b/src/lib/evil/gdtoa/arithchk.c
new file mode 100644
index 0000000000..901bab1fb3
--- /dev/null
+++ b/src/lib/evil/gdtoa/arithchk.c
@@ -0,0 +1,192 @@
+/****************************************************************
+Copyright (C) 1997, 1998 Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+****************************************************************/
+
+/* Try to deduce arith.h from arithmetic properties. */
+#ifdef MINGW_BUILD_GEN
+
+#include <stdio.h>
+
+ static int dalign;
+ typedef struct
+Akind {
+ char *name;
+ int kind;
+ } Akind;
+
+ static Akind
+IEEE_8087 = { "IEEE_8087", 1 },
+IEEE_MC68k = { "IEEE_MC68k", 2 },
+IBM = { "IBM", 3 },
+VAX = { "VAX", 4 },
+CRAY = { "CRAY", 5};
+
+ static Akind *
+Lcheck()
+{
+ union {
+ double d;
+ long L[2];
+ } u;
+ struct {
+ double d;
+ long L;
+ } x[2];
+
+ if (sizeof(x) > 2*(sizeof(double) + sizeof(long)))
+ dalign = 1;
+ u.L[0] = u.L[1] = 0;
+ u.d = 1e13;
+ if (u.L[0] == 1117925532 && u.L[1] == -448790528)
+ return &IEEE_MC68k;
+ if (u.L[1] == 1117925532 && u.L[0] == -448790528)
+ return &IEEE_8087;
+ if (u.L[0] == -2065213935 && u.L[1] == 10752)
+ return &VAX;
+ if (u.L[0] == 1267827943 && u.L[1] == 704643072)
+ return &IBM;
+ return 0;
+ }
+
+ static Akind *
+icheck()
+{
+ union {
+ double d;
+ int L[2];
+ } u;
+ struct {
+ double d;
+ int L;
+ } x[2];
+
+ if (sizeof(x) > 2*(sizeof(double) + sizeof(int)))
+ dalign = 1;
+ u.L[0] = u.L[1] = 0;
+ u.d = 1e13;
+ if (u.L[0] == 1117925532 && u.L[1] == -448790528)
+ return &IEEE_MC68k;
+ if (u.L[1] == 1117925532 && u.L[0] == -448790528)
+ return &IEEE_8087;
+ if (u.L[0] == -2065213935 && u.L[1] == 10752)
+ return &VAX;
+ if (u.L[0] == 1267827943 && u.L[1] == 704643072)
+ return &IBM;
+ return 0;
+ }
+
+char *emptyfmt = ""; /* avoid possible warning message with printf("") */
+
+ static Akind *
+ccheck()
+{
+ union {
+ double d;
+ long L;
+ } u;
+ long Cray1;
+
+ /* Cray1 = 4617762693716115456 -- without overflow on non-Crays */
+ Cray1 = printf(emptyfmt) < 0 ? 0 : 4617762;
+ if (printf(emptyfmt, Cray1) >= 0)
+ Cray1 = 1000000*Cray1 + 693716;
+ if (printf(emptyfmt, Cray1) >= 0)
+ Cray1 = 1000000*Cray1 + 115456;
+ u.d = 1e13;
+ if (u.L == Cray1)
+ return &CRAY;
+ return 0;
+ }
+
+ static int
+fzcheck()
+{
+ double a, b;
+ int i;
+
+ a = 1.;
+ b = .1;
+ for(i = 155;; b *= b, i >>= 1) {
+ if (i & 1) {
+ a *= b;
+ if (i == 1)
+ break;
+ }
+ }
+ b = a * a;
+ return b == 0.;
+ }
+
+ int
+main()
+{
+ Akind *a = 0;
+ int Ldef = 0;
+ FILE *f;
+
+#ifdef WRITE_ARITH_H /* for Symantec's buggy "make" */
+ f = fopen("arith.h", "w");
+ if (!f) {
+ printf("Cannot open arith.h\n");
+ return 1;
+ }
+#else
+ f = stdout;
+#endif
+
+ if (sizeof(double) == 2*sizeof(long))
+ a = Lcheck();
+ else if (sizeof(double) == 2*sizeof(int)) {
+ Ldef = 1;
+ a = icheck();
+ }
+ else if (sizeof(double) == sizeof(long))
+ a = ccheck();
+ if (a) {
+ fprintf(f, "#define %s\n#define Arith_Kind_ASL %d\n",
+ a->name, a->kind);
+ if (Ldef)
+ fprintf(f, "#define Long int\n#define Intcast (int)(long)\n");
+ if (dalign)
+ fprintf(f, "#define Double_Align\n");
+ if (sizeof(char*) == 8)
+ fprintf(f, "#define X64_bit_pointers\n");
+#ifndef NO_LONG_LONG
+ if (sizeof(long long) < 8)
+#endif
+ fprintf(f, "#define NO_LONG_LONG\n");
+ if (a->kind <= 2 && fzcheck())
+ fprintf(f, "#define Sudden_Underflow\n");
+#ifdef WRITE_ARITH_H /* for Symantec's buggy "make" */
+ fclose(f);
+#endif
+ return 0;
+ }
+ fprintf(f, "/* Unknown arithmetic */\n");
+#ifdef WRITE_ARITH_H /* for Symantec's buggy "make" */
+ fclose(f);
+#endif
+ return 1;
+ }
+#endif /* MINGW_BUILD_GEN */
+
diff --git a/src/lib/evil/gdtoa/dmisc.c b/src/lib/evil/gdtoa/dmisc.c
new file mode 100644
index 0000000000..c61e9fa8a5
--- /dev/null
+++ b/src/lib/evil/gdtoa/dmisc.c
@@ -0,0 +1,196 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+#ifndef MULTIPLE_THREADS
+char *dtoa_result;
+#endif
+
+char *rv_alloc (int i)
+{
+ int j, k, *r;
+
+ j = sizeof(ULong);
+ for(k = 0;
+ (int) (sizeof(Bigint) - sizeof(ULong) - sizeof(int)) + j <= i;
+ j <<= 1)
+ k++;
+ r = (int*)Balloc(k);
+ *r = k;
+ return
+#ifndef MULTIPLE_THREADS
+ dtoa_result =
+#endif
+ (char *)(r+1);
+}
+
+char *nrv_alloc (char *s, char **rve, int n)
+{
+ char *rv, *t;
+
+ t = rv = rv_alloc(n);
+ while((*t = *s++) !=0)
+ t++;
+ if (rve)
+ *rve = t;
+ return rv;
+}
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined. It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+void __freedtoa (char *s)
+{
+ Bigint *b = (Bigint *)((int *)s - 1);
+ b->maxwds = 1 << (b->k = *(int*)b);
+ Bfree(b);
+#ifndef MULTIPLE_THREADS
+ if (s == dtoa_result)
+ dtoa_result = 0;
+#endif
+}
+
+int quorem (Bigint *b, Bigint *S)
+{
+ int n;
+ ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+ ULLong borrow, carry, y, ys;
+#else
+ ULong borrow, carry, y, ys;
+#ifdef Pack_32
+ ULong si, z, zs;
+#endif
+#endif
+
+ n = S->wds;
+#ifdef DEBUG
+ /*debug*/ if (b->wds > n)
+ /*debug*/ Bug("oversize b in quorem");
+#endif
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+#ifdef DEBUG
+ /*debug*/ if (q > 9)
+ /*debug*/ Bug("oversized quotient in quorem");
+#endif
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef ULLong
+ ys = *sx++ * (ULLong)q + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & 0xffffffffUL) - borrow;
+ borrow = y >> 32 & 1UL;
+ *bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ * q + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ } while(sx <= sxe);
+
+ if (!*bxe) {
+ bx = b->x;
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+#ifdef ULLong
+ ys = *sx++ + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & 0xffffffffUL) - borrow;
+ borrow = y >> 32 & 1UL;
+ *bx++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ } while(sx <= sxe);
+
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return q;
+}
diff --git a/src/lib/evil/gdtoa/dtoa.c b/src/lib/evil/gdtoa/dtoa.c
new file mode 100644
index 0000000000..2906bd99f6
--- /dev/null
+++ b/src/lib/evil/gdtoa/dtoa.c
@@ -0,0 +1,750 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the Long
+ * calculation.
+ */
+
+#ifdef Honor_FLT_ROUNDS
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+char *__dtoa (double d0, int mode, int ndigits, int *decpt, int *sign, char **rve)
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4,5 ==> similar to 2 and 3, respectively, but (in
+ round-nearest mode) with the tests of mode 0 to
+ possibly return a shorter string that rounds to d.
+ With IEEE arithmetic and compilation with
+ -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+ as modes 2 and 3 when FLT_ROUNDS != 1.
+ 6-9 ==> Debugging modes similar to mode - 4: don't try
+ fast floating-point estimate (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int bbits, b2, b5, be, dig, i, ieps, ilim, ilim0, ilim1,
+ j, j2, k, k0, k_check, leftright, m2, m5, s2, s5,
+ spec_case, try_quick;
+ Long L;
+#ifndef Sudden_Underflow
+ int denorm;
+ ULong x;
+#endif
+ Bigint *b, *b1, *delta, *mlo, *mhi, *S;
+ union _dbl_union d, d2, eps;
+ double ds;
+ char *s, *s0;
+#ifdef SET_INEXACT
+ int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS /*{*/
+ int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+ Rounding = Flt_Rounds;
+#else /*}{*/
+ Rounding = 1;
+ switch(fegetround()) {
+ case FE_TOWARDZERO: Rounding = 0; break;
+ case FE_UPWARD: Rounding = 2; break;
+ case FE_DOWNWARD: Rounding = 3;
+ }
+#endif /*}}*/
+#endif /*}*/
+
+#ifndef MULTIPLE_THREADS
+ if (dtoa_result) {
+ __freedtoa(dtoa_result);
+ dtoa_result = 0;
+ }
+#endif
+ d.d = d0;
+ if (word0(&d) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(&d) &= ~Sign_bit; /* clear sign bit */
+ }
+ else
+ *sign = 0;
+
+ if ((word0(&d) & Exp_mask) == Exp_mask)
+ {
+ /* Infinity or NaN */
+ *decpt = 9999;
+ if (!word1(&d) && !(word0(&d) & 0xfffff))
+ return nrv_alloc("Infinity", rve, 8);
+ return nrv_alloc("NaN", rve, 3);
+ }
+ if (!dval(&d)) {
+ *decpt = 1;
+ return nrv_alloc("0", rve, 1);
+ }
+
+#ifdef SET_INEXACT
+ try_quick = oldinexact = get_inexact();
+ inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ if (Rounding >= 2) {
+ if (*sign)
+ Rounding = Rounding == 2 ? 0 : 2;
+ else
+ if (Rounding != 2)
+ Rounding = 0;
+ }
+#endif
+
+ b = d2b(dval(&d), &be, &bbits);
+#ifdef Sudden_Underflow
+ i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+ if (( i = (int)(word0(&d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)) )!=0) {
+#endif
+ dval(&d2) = dval(&d);
+ word0(&d2) &= Frac_mask1;
+ word0(&d2) |= Exp_11;
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(&d) = (i-Bias)*log(2)/log(10) + log10(&d2)
+ *
+ * This suggests computing an approximation k to log10(&d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+#ifndef Sudden_Underflow
+ denorm = 0;
+ }
+ else {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P-1) - 1);
+ x = i > 32 ? word0(&d) << (64 - i) | word1(&d) >> (i - 32)
+ : word1(&d) << (32 - i);
+ dval(&d2) = x;
+ word0(&d2) -= 31*Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P-1) - 1) + 1;
+ denorm = 1;
+ }
+#endif
+ ds = (dval(&d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+ k = (int)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (dval(&d) < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ }
+ else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ }
+ else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ if (mode < 0 || mode > 9)
+ mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+ try_quick = Rounding == 1;
+#else
+ try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ leftright = 1;
+ ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */
+ /* silence erroneous "gcc -Wall" warning. */
+ switch(mode) {
+ case 0:
+ case 1:
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ s = s0 = rv_alloc(i);
+
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1 && Rounding != 1)
+ leftright = 0;
+#endif
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ dval(&d2) = dval(&d);
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ dval(&d) /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for(; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ dval(&d) /= ds;
+ }
+ else if (( j2 = -k )!=0) {
+ dval(&d) *= tens[j2 & 0xf];
+ for(j = j2 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ dval(&d) *= bigtens[i];
+ }
+ }
+ if (k_check && dval(&d) < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ dval(&d) *= 10.;
+ ieps++;
+ }
+ dval(&eps) = ieps*dval(&d) + 7.;
+ word0(&eps) -= (P-1)*Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ dval(&d) -= 5.;
+ if (dval(&d) > dval(&eps))
+ goto one_digit;
+ if (dval(&d) < -dval(&eps))
+ goto no_digits;
+ goto fast_failed;
+ }
+#ifndef No_leftright
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ dval(&eps) = 0.5/tens[ilim-1] - dval(&eps);
+ for(i = 0;;) {
+ L = dval(&d);
+ dval(&d) -= L;
+ *s++ = '0' + (int)L;
+ if (dval(&d) < dval(&eps))
+ goto ret1;
+ if (1. - dval(&d) < dval(&eps))
+ goto bump_up;
+ if (++i >= ilim)
+ break;
+ dval(&eps) *= 10.;
+ dval(&d) *= 10.;
+ }
+ }
+ else {
+#endif
+ /* Generate ilim digits, then fix them up. */
+ dval(&eps) *= tens[ilim-1];
+ for(i = 1;; i++, dval(&d) *= 10.) {
+ L = (Long)(dval(&d));
+ if (!(dval(&d) -= L))
+ ilim = i;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (dval(&d) > 0.5 + dval(&eps))
+ goto bump_up;
+ else if (dval(&d) < 0.5 - dval(&eps)) {
+ while(*--s == '0');
+ s++;
+ goto ret1;
+ }
+ break;
+ }
+ }
+#ifndef No_leftright
+ }
+#endif
+ fast_failed:
+ s = s0;
+ dval(&d) = dval(&d2);
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || dval(&d) <= 5*ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for(i = 1;; i++, dval(&d) *= 10.) {
+ L = (Long)(dval(&d) / ds);
+ dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+ /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+ if (dval(&d) < 0) {
+ L--;
+ dval(&d) += ds;
+ }
+#endif
+ *s++ = '0' + (int)L;
+ if (!dval(&d)) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch(Rounding) {
+ case 0: goto ret1;
+ case 2: goto bump_up;
+ }
+#endif
+ dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+ if (dval(&d) >= ds)
+#else
+ if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+ {
+ bump_up:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ mhi = mlo = 0;
+ if (leftright) {
+ i =
+#ifndef Sudden_Underflow
+ denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+ 1 + P - bbits;
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1);
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5);
+ b1 = mult(mhi, b);
+ Bfree(b);
+ b = b1;
+ }
+ if (( j = b5 - m5 )!=0)
+ b = pow5mult(b, j);
+ }
+ else
+ b = pow5mult(b, b5);
+ }
+ S = i2b(1);
+ if (s5 > 0)
+ S = pow5mult(S, s5);
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ spec_case = 0;
+ if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+ && Rounding == 1
+#endif
+ ) {
+ if (!word1(&d) && !(word0(&d) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(&d) & (Exp_mask & ~Exp_msk1)
+#endif
+ ) {
+ /* The special case */
+ b2 += Log2P;
+ s2 += Log2P;
+ spec_case = 1;
+ }
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+#ifdef Pack_32
+ if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f )!=0)
+ i = 32 - i;
+#else
+ if (( i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf )!=0)
+ i = 16 - i;
+#endif
+ if (i > 4) {
+ i -= 4;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ else if (i < 4) {
+ i += 28;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ if (b2 > 0)
+ b = lshift(b, b2);
+ if (s2 > 0)
+ S = lshift(S, s2);
+ if (k_check) {
+ if (cmp(b,S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (leftright)
+ mhi = multadd(mhi, 10, 0);
+ ilim = ilim1;
+ }
+ }
+ if (ilim <= 0 && (mode == 3 || mode == 5)) {
+ if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+ /* no digits, fcvt style */
+ no_digits:
+ k = -1 - ndigits;
+ goto ret;
+ }
+ one_digit:
+ *s++ = '1';
+ k++;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0)
+ mhi = lshift(mhi, m2);
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P);
+ }
+
+ for(i = 1;;i++) {
+ dig = quorem(b,S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi);
+ j2 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+#ifndef ROUND_BIASED
+ if (j2 == 0 && mode != 1 && !(word1(&d) & 1)
+#ifdef Honor_FLT_ROUNDS
+ && Rounding >= 1
+#endif
+ ) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+#ifdef SET_INEXACT
+ else if (!b->x[0] && b->wds <= 1)
+ inexact = 0;
+#endif
+ *s++ = dig;
+ goto ret;
+ }
+#endif
+ if (j < 0 || (j == 0 && mode != 1
+#ifndef ROUND_BIASED
+ && !(word1(&d) & 1)
+#endif
+ )) {
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto accept_dig;
+ }
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch(Rounding) {
+ case 0: goto accept_dig;
+ case 2: goto keep_dig;
+ }
+#endif /*Honor_FLT_ROUNDS*/
+ if (j2 > 0) {
+ b = lshift(b, 1);
+ j2 = cmp(b, S);
+#ifdef ROUND_BIASED
+ if (j2 >= 0 /*)*/
+#else
+ if ((j2 > 0 || (j2 == 0 && dig & 1))
+#endif
+ && dig++ == '9')
+ goto round_9_up;
+ }
+ accept_dig:
+ *s++ = dig;
+ goto ret;
+ }
+ if (j2 > 0) {
+#ifdef Honor_FLT_ROUNDS
+ if (!Rounding)
+ goto accept_dig;
+#endif
+ if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (mlo == mhi)
+ mlo = mhi = multadd(mhi, 10, 0);
+ else {
+ mlo = multadd(mlo, 10, 0);
+ mhi = multadd(mhi, 10, 0);
+ }
+ }
+ }
+ else
+ for(i = 1;; i++) {
+ *s++ = dig = quorem(b,S) + '0';
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto ret;
+ }
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ }
+
+ /* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+ switch(Rounding) {
+ case 0: goto trimzeros;
+ case 2: goto roundoff;
+ }
+#endif
+ b = lshift(b, 1);
+ j = cmp(b, S);
+#ifdef ROUND_BIASED
+ if (j >= 0)
+#else
+ if (j > 0 || (j == 0 && dig & 1))
+#endif
+ {
+ roundoff:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++*s++;
+ }
+ else {
+#ifdef Honor_FLT_ROUNDS
+ trimzeros:
+#endif
+ while(*--s == '0');
+ s++;
+ }
+ ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ ret1:
+#ifdef SET_INEXACT
+ if (inexact) {
+ if (!oldinexact) {
+ word0(&d) = Exp_1 + (70 << Exp_shift);
+ word1(&d) = 0;
+ dval(&d) += 1.;
+ }
+ }
+ else if (!oldinexact)
+ clear_inexact();
+#endif
+ Bfree(b);
+ *s = 0;
+ *decpt = k + 1;
+ if (rve)
+ *rve = s;
+ return s0;
+}
diff --git a/src/lib/evil/gdtoa/g__fmt.c b/src/lib/evil/gdtoa/g__fmt.c
new file mode 100644
index 0000000000..49bd95a845
--- /dev/null
+++ b/src/lib/evil/gdtoa/g__fmt.c
@@ -0,0 +1,142 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+char *__g__fmt (char *b, char *s, char *se, int decpt, ULong sign, size_t blen)
+{
+ int i, j, k;
+ char *be, *s0;
+ size_t len;
+#ifdef USE_LOCALE
+#ifdef NO_LOCALE_CACHE
+ char *decimalpoint = localeconv()->decimal_point;
+ size_t dlen = strlen(decimalpoint);
+#else
+ char *decimalpoint;
+ static char *decimalpoint_cache;
+ static size_t dlen;
+ if (!(s0 = decimalpoint_cache)) {
+ s0 = localeconv()->decimal_point;
+ dlen = strlen(s0);
+ if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
+ strcpy(decimalpoint_cache, s0);
+ s0 = decimalpoint_cache;
+ }
+ }
+ decimalpoint = s0;
+#endif
+#else
+#define dlen 0
+#endif
+ s0 = s;
+ len = (se-s) + dlen + 6; /* 6 = sign + e+dd + trailing null */
+ if (blen < len)
+ goto ret0;
+ be = b + blen - 1;
+ if (sign)
+ *b++ = '-';
+ if (decpt <= -4 || decpt > se - s + 5) {
+ *b++ = *s++;
+ if (*s) {
+#ifdef USE_LOCALE
+ while((*b = *decimalpoint++))
+ ++b;
+#else
+ *b++ = '.';
+#endif
+ while((*b = *s++) !=0)
+ b++;
+ }
+ *b++ = 'e';
+ /* sprintf(b, "%+.2d", decpt - 1); */
+ if (--decpt < 0) {
+ *b++ = '-';
+ decpt = -decpt;
+ }
+ else
+ *b++ = '+';
+ for(j = 2, k = 10; 10*k <= decpt; j++, k *= 10){}
+ for(;;) {
+ i = decpt / k;
+ if (b >= be)
+ goto ret0;
+ *b++ = i + '0';
+ if (--j <= 0)
+ break;
+ decpt -= i*k;
+ decpt *= 10;
+ }
+ *b = 0;
+ }
+ else if (decpt <= 0) {
+#ifdef USE_LOCALE
+ while((*b = *decimalpoint++))
+ ++b;
+#else
+ *b++ = '.';
+#endif
+ if (be < b - decpt + (se - s))
+ goto ret0;
+ for(; decpt < 0; decpt++)
+ *b++ = '0';
+ while((*b = *s++) != 0)
+ b++;
+ }
+ else {
+ while((*b = *s++) != 0) {
+ b++;
+ if (--decpt == 0 && *s) {
+#ifdef USE_LOCALE
+ while((*b = *decimalpoint++))
+ ++b;
+#else
+ *b++ = '.';
+#endif
+ }
+ }
+ if (b + decpt > be) {
+ ret0:
+ b = 0;
+ goto ret;
+ }
+ for(; decpt > 0; decpt--)
+ *b++ = '0';
+ *b = 0;
+ }
+ ret:
+ __freedtoa(s0);
+ return b;
+}
diff --git a/src/lib/evil/gdtoa/g_dfmt.c b/src/lib/evil/gdtoa/g_dfmt.c
new file mode 100644
index 0000000000..50ed708a6c
--- /dev/null
+++ b/src/lib/evil/gdtoa/g_dfmt.c
@@ -0,0 +1,90 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+char *__g_dfmt (char *buf, double *d, int ndig, size_t bufsize)
+{
+ static FPI fpi0 = { 53, 1-1023-53+1, 2046-1023-53+1, 1, 0, Int_max };
+ char *b, *s, *se;
+ ULong bits[2], *L, sign;
+ int decpt, ex, i, mode;
+#ifdef Honor_FLT_ROUNDS
+#include "gdtoa_fltrnds.h"
+#else
+#define fpi &fpi0
+#endif
+
+ if (ndig < 0)
+ ndig = 0;
+ if ((int) bufsize < ndig + 10)
+ return 0;
+
+ L = (ULong*)d;
+ sign = L[_0] & 0x80000000L;
+ if ((L[_0] & 0x7ff00000) == 0x7ff00000) {
+ /* Infinity or NaN */
+ if (bufsize < 10)
+ return 0;
+ if (L[_0] & 0xfffff || L[_1]) {
+ return strcp(buf, "NaN");
+ }
+ b = buf;
+ if (sign)
+ *b++ = '-';
+ return strcp(b, "Infinity");
+ }
+ if (L[_1] == 0 && (L[_0] ^ sign) == 0 /*d == 0.*/) {
+ b = buf;
+#ifndef IGNORE_ZERO_SIGN
+ if (L[_0] & 0x80000000L)
+ *b++ = '-';
+#endif
+ *b++ = '0';
+ *b = 0;
+ return b;
+ }
+ bits[0] = L[_1];
+ bits[1] = L[_0] & 0xfffff;
+ if ( (ex = (L[_0] >> 20) & 0x7ff) !=0)
+ bits[1] |= 0x100000;
+ else
+ ex = 1;
+ ex -= 0x3ff + 52;
+ mode = 2;
+ if (ndig <= 0)
+ mode = 0;
+ i = STRTOG_Normal;
+ if (sign)
+ i = STRTOG_Normal | STRTOG_Neg;
+ s = __gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
+ return __g__fmt(buf, s, se, decpt, sign, bufsize);
+}
diff --git a/src/lib/evil/gdtoa/g_ffmt.c b/src/lib/evil/gdtoa/g_ffmt.c
new file mode 100644
index 0000000000..f3f7c2419c
--- /dev/null
+++ b/src/lib/evil/gdtoa/g_ffmt.c
@@ -0,0 +1,88 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+char *__g_ffmt (char *buf, float *f, int ndig, size_t bufsize)
+{
+ static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, 0, 6 };
+ char *b, *s, *se;
+ ULong bits[1], *L, sign;
+ int decpt, ex, i, mode;
+#ifdef Honor_FLT_ROUNDS
+#include "gdtoa_fltrnds.h"
+#else
+#define fpi &fpi0
+#endif
+
+ if (ndig < 0)
+ ndig = 0;
+ if ((int) bufsize < ndig + 10)
+ return 0;
+
+ L = (ULong*)f;
+ sign = L[0] & 0x80000000L;
+ if ((L[0] & 0x7f800000) == 0x7f800000) {
+ /* Infinity or NaN */
+ if (L[0] & 0x7fffff) {
+ return strcp(buf, "NaN");
+ }
+ b = buf;
+ if (sign)
+ *b++ = '-';
+ return strcp(b, "Infinity");
+ }
+ if (*f == 0.) {
+ b = buf;
+#ifndef IGNORE_ZERO_SIGN
+ if (L[0] & 0x80000000L)
+ *b++ = '-';
+#endif
+ *b++ = '0';
+ *b = 0;
+ return b;
+ }
+ bits[0] = L[0] & 0x7fffff;
+ if ( (ex = (L[0] >> 23) & 0xff) !=0)
+ bits[0] |= 0x800000;
+ else
+ ex = 1;
+ ex -= 0x7f + 23;
+ mode = 2;
+ if (ndig <= 0) {
+ if (bufsize < 16)
+ return 0;
+ mode = 0;
+ }
+ i = STRTOG_Normal;
+ s = __gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
+ return __g__fmt(buf, s, se, decpt, sign, bufsize);
+}
diff --git a/src/lib/evil/gdtoa/g_xfmt.c b/src/lib/evil/gdtoa/g_xfmt.c
new file mode 100644
index 0000000000..da11a5881b
--- /dev/null
+++ b/src/lib/evil/gdtoa/g_xfmt.c
@@ -0,0 +1,143 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+#undef _0
+#undef _1
+
+/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
+
+#ifdef IEEE_MC68k
+#define _0 0
+#define _1 1
+#define _2 2
+#define _3 3
+#define _4 4
+#endif
+#ifdef IEEE_8087
+#define _0 4
+#define _1 3
+#define _2 2
+#define _3 1
+#define _4 0
+#endif
+
+char *__g_xfmt (char *buf, void *V, int ndig, size_t bufsize)
+{
+ static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, 0, Int_max };
+ char *b, *s, *se;
+ ULong bits[2], sign;
+ UShort *L;
+ int decpt, ex, i, mode;
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ int fptype = __fpclassifyl (*(long double*) V);
+#endif /* MinGW */
+#ifdef Honor_FLT_ROUNDS
+#include "gdtoa_fltrnds.h"
+#else
+#define fpi &fpi0
+#endif
+
+ if (ndig < 0)
+ ndig = 0;
+ if ((int) bufsize < ndig + 10)
+ return 0;
+
+ L = (UShort *)V;
+ sign = L[_0] & 0x8000;
+ ex = L[_0] & 0x7fff;
+ bits[1] = (L[_1] << 16) | L[_2];
+ bits[0] = (L[_3] << 16) | L[_4];
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+ if (fptype & FP_NAN) {
+ /* NaN or Inf */
+ if (fptype & FP_NORMAL) {
+ b = buf;
+ *b++ = sign ? '-': '+';
+ strncpy (b, "Infinity", ndig ? ndig : 8);
+ return (buf + strlen (buf));
+ }
+ strncpy (buf, "NaN", ndig ? ndig : 3);
+ return (buf + strlen (buf));
+ }
+ else if (fptype & FP_NORMAL) {
+ /* Normal or subnormal */
+ if (fptype & FP_ZERO) {
+ i = STRTOG_Denormal;
+ ex = 1;
+ }
+ else
+ i = STRTOG_Normal;
+ }
+#else
+ if (ex != 0) {
+ if (ex == 0x7fff) {
+ /* Infinity or NaN */
+ if (bits[0] | bits[1])
+ b = strcp(buf, "NaN");
+ else {
+ b = buf;
+ if (sign)
+ *b++ = '-';
+ b = strcp(b, "Infinity");
+ }
+ return b;
+ }
+ i = STRTOG_Normal;
+ }
+ else if (bits[0] | bits[1]) {
+ i = STRTOG_Denormal;
+ ex = 1;
+ }
+#endif
+ else {
+ /* i = STRTOG_Zero; */
+ b = buf;
+#ifndef IGNORE_ZERO_SIGN
+ if (sign)
+ *b++ = '-';
+#endif
+ *b++ = '0';
+ *b = 0;
+ return b;
+ }
+ ex -= 0x3fff + 63;
+ mode = 2;
+ if (ndig <= 0) {
+ if (bufsize < 32)
+ return 0;
+ mode = 0;
+ }
+ s = __gdtoa(fpi, ex, bits, &i, mode, ndig, &decpt, &se);
+ return __g__fmt(buf, s, se, decpt, sign, bufsize);
+}
diff --git a/src/lib/evil/gdtoa/gd_arith.h b/src/lib/evil/gdtoa/gd_arith.h
new file mode 100644
index 0000000000..f86e633b37
--- /dev/null
+++ b/src/lib/evil/gdtoa/gd_arith.h
@@ -0,0 +1,6 @@
+#define IEEE_8087
+#define Arith_Kind_ASL 1
+#define Double_Align
+#ifdef _WIN64
+#define X64_bit_pointers
+#endif /* w64 */
diff --git a/src/lib/evil/gdtoa/gd_qnan.h b/src/lib/evil/gdtoa/gd_qnan.h
new file mode 100644
index 0000000000..87eba8fb31
--- /dev/null
+++ b/src/lib/evil/gdtoa/gd_qnan.h
@@ -0,0 +1,12 @@
+#define f_QNAN 0xffc00000
+#define d_QNAN0 0x0
+#define d_QNAN1 0xfff80000
+#define ld_QNAN0 0x0
+#define ld_QNAN1 0xc0000000
+#define ld_QNAN2 0xffff
+#define ld_QNAN3 0x0
+#define ldus_QNAN0 0x0
+#define ldus_QNAN1 0x0
+#define ldus_QNAN2 0x0
+#define ldus_QNAN3 0xc000
+#define ldus_QNAN4 0xffff
diff --git a/src/lib/evil/gdtoa/gdtoa.c b/src/lib/evil/gdtoa/gdtoa.c
new file mode 100644
index 0000000000..cf9c290fb4
--- /dev/null
+++ b/src/lib/evil/gdtoa/gdtoa.c
@@ -0,0 +1,733 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+static Bigint *bitstob (ULong *bits, int nbits, int *bbits)
+{
+ int i, k;
+ Bigint *b;
+ ULong *be, *x, *x0;
+
+ i = ULbits;
+ k = 0;
+ while(i < nbits) {
+ i <<= 1;
+ k++;
+ }
+#ifndef Pack_32
+ if (!k)
+ k = 1;
+#endif
+ b = Balloc(k);
+ be = bits + ((nbits - 1) >> kshift);
+ x = x0 = b->x;
+ do {
+ *x++ = *bits & ALL_ON;
+#ifdef Pack_16
+ *x++ = (*bits >> 16) & ALL_ON;
+#endif
+ } while(++bits <= be);
+ i = x - x0;
+ while(!x0[--i])
+ if (!i) {
+ b->wds = 0;
+ *bbits = 0;
+ goto ret;
+ }
+ b->wds = i + 1;
+ *bbits = i*ULbits + 32 - hi0bits(b->x[i]);
+ ret:
+ return b;
+}
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the Long
+ * calculation.
+ */
+
+char *__gdtoa (FPI *fpi, int be, ULong *bits, int *kindp, int mode, int ndigits,
+ int *decpt, char **rve)
+{
+ /* Arguments ndigits and decpt are similar to the second and third
+ arguments of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+ be = exponent: value = (integer represented by bits) * (2 to the power of be).
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4-9 should give the same return values as 2-3, i.e.,
+ 4 <= mode <= 9 ==> same return as mode
+ 2 + (mode & 1). These modes are mainly for
+ debugging; often they run slower but sometimes
+ faster than modes 2-3.
+ 4,5,8,9 ==> left-to-right digit generation.
+ 6-9 ==> don't try fast floating-point estimate
+ (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int bbits, b2, b5, be0, dig, i, ieps, ilim, ilim0, ilim1, inex;
+ int j, j2, k, k0, k_check, kind, leftright, m2, m5, nbits;
+ int rdir, s2, s5, spec_case, try_quick;
+ Long L;
+ Bigint *b, *b1, *delta, *mlo, *mhi, *mhi1, *S;
+ double d2, ds;
+ char *s, *s0;
+ union _dbl_union d, eps;
+
+#ifndef MULTIPLE_THREADS
+ if (dtoa_result) {
+ __freedtoa(dtoa_result);
+ dtoa_result = 0;
+ }
+#endif
+ inex = 0;
+ kind = *kindp &= ~STRTOG_Inexact;
+ switch(kind & STRTOG_Retmask) {
+ case STRTOG_Zero:
+ goto ret_zero;
+ case STRTOG_Normal:
+ case STRTOG_Denormal:
+ break;
+ case STRTOG_Infinite:
+ *decpt = -32768;
+ return nrv_alloc("Infinity", rve, 8);
+ case STRTOG_NaN:
+ *decpt = -32768;
+ return nrv_alloc("NaN", rve, 3);
+ default:
+ return 0;
+ }
+ b = bitstob(bits, nbits = fpi->nbits, &bbits);
+ be0 = be;
+ if ( (i = trailz(b)) !=0) {
+ rshift(b, i);
+ be += i;
+ bbits -= i;
+ }
+ if (!b->wds) {
+ Bfree(b);
+ ret_zero:
+ *decpt = 1;
+ return nrv_alloc("0", rve, 1);
+ }
+
+ dval(&d) = b2d(b, &i);
+ i = be + bbits - 1;
+ word0(&d) &= Frac_mask1;
+ word0(&d) |= Exp_11;
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(&d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(&d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+ ds = (dval(&d)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+
+ /* correct assumption about exponent range */
+ if ((j = i) < 0)
+ j = -j;
+ if ((j -= 1077) > 0)
+ ds += j * 7e-17;
+
+ k = (int)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ word0(&d) += (be + bbits - 1) << Exp_shift;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (dval(&d) < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ }
+ else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ }
+ else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ if (mode < 0 || mode > 9)
+ mode = 0;
+ try_quick = 1;
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ else if (i >= -4 - Emin || i < Emin)
+ try_quick = 0;
+ leftright = 1;
+ ilim = ilim1 = -1; /* Values for cases 0 and 1; done here to */
+ /* silence erroneous "gcc -Wall" warning. */
+ switch(mode) {
+ case 0:
+ case 1:
+ i = (int)(nbits * .30103) + 3;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ s = s0 = rv_alloc(i);
+
+ if ( (rdir = fpi->rounding - 1) !=0) {
+ if (rdir < 0)
+ rdir = 2;
+ if (kind & STRTOG_Neg)
+ rdir = 3 - rdir;
+ }
+
+ /* Now rdir = 0 ==> round near, 1 ==> round up, 2 ==> round down. */
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick && !rdir
+#ifndef IMPRECISE_INEXACT
+ && k == 0
+#endif
+ ) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ d2 = dval(&d);
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ dval(&d) /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for(; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ }
+ else {
+ ds = 1.;
+ if ( (j2 = -k) !=0) {
+ dval(&d) *= tens[j2 & 0xf];
+ for(j = j2 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ dval(&d) *= bigtens[i];
+ }
+ }
+ }
+ if (k_check && dval(&d) < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ dval(&d) *= 10.;
+ ieps++;
+ }
+ dval(&eps) = ieps*dval(&d) + 7.;
+ word0(&eps) -= (P-1)*Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ dval(&d) -= 5.;
+ if (dval(&d) > dval(&eps))
+ goto one_digit;
+ if (dval(&d) < -dval(&eps))
+ goto no_digits;
+ goto fast_failed;
+ }
+#ifndef No_leftright
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ dval(&eps) = ds*0.5/tens[ilim-1] - dval(&eps);
+ for(i = 0;;) {
+ L = (Long)(dval(&d)/ds);
+ dval(&d) -= L*ds;
+ *s++ = '0' + (int)L;
+ if (dval(&d) < dval(&eps)) {
+ if (dval(&d))
+ inex = STRTOG_Inexlo;
+ goto ret1;
+ }
+ if (ds - dval(&d) < dval(&eps))
+ goto bump_up;
+ if (++i >= ilim)
+ break;
+ dval(&eps) *= 10.;
+ dval(&d) *= 10.;
+ }
+ }
+ else {
+#endif
+ /* Generate ilim digits, then fix them up. */
+ dval(&eps) *= tens[ilim-1];
+ for(i = 1;; i++, dval(&d) *= 10.) {
+ if ( (L = (Long)(dval(&d)/ds)) !=0)
+ dval(&d) -= L*ds;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ ds *= 0.5;
+ if (dval(&d) > ds + dval(&eps))
+ goto bump_up;
+ else if (dval(&d) < ds - dval(&eps)) {
+ if (dval(&d))
+ inex = STRTOG_Inexlo;
+ goto clear_trailing0;
+ }
+ break;
+ }
+ }
+#ifndef No_leftright
+ }
+#endif
+ fast_failed:
+ s = s0;
+ dval(&d) = d2;
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= fpi->int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || dval(&d) <= 5*ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for(i = 1;; i++, dval(&d) *= 10.) {
+ L = dval(&d) / ds;
+ dval(&d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+ /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+ if (dval(&d) < 0) {
+ L--;
+ dval(&d) += ds;
+ }
+#endif
+ *s++ = '0' + (int)L;
+ if (dval(&d) == 0.)
+ break;
+ if (i == ilim) {
+ if (rdir) {
+ if (rdir == 1)
+ goto bump_up;
+ inex = STRTOG_Inexlo;
+ goto ret1;
+ }
+ dval(&d) += dval(&d);
+#ifdef ROUND_BIASED
+ if (dval(&d) >= ds)
+#else
+ if (dval(&d) > ds || (dval(&d) == ds && L & 1))
+#endif
+ {
+ bump_up:
+ inex = STRTOG_Inexhi;
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ else {
+ inex = STRTOG_Inexlo;
+ clear_trailing0:
+ while(*--s == '0'){}
+ ++s;
+ }
+ break;
+ }
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ mhi = mlo = 0;
+ if (leftright) {
+ i = nbits - bbits;
+ if (be - i++ < fpi->emin && mode != 3 && mode != 5) {
+ /* denormal */
+ i = be - fpi->emin + 1;
+ if (mode >= 2 && ilim > 0 && ilim < i)
+ goto small_ilim;
+ }
+ else if (mode >= 2) {
+ small_ilim:
+ j = ilim - 1;
+ if (m5 >= j)
+ m5 -= j;
+ else {
+ s5 += j -= m5;
+ b5 += j;
+ m5 = 0;
+ }
+ if ((i = ilim) < 0) {
+ m2 -= i;
+ i = 0;
+ }
+ }
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1);
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5);
+ b1 = mult(mhi, b);
+ Bfree(b);
+ b = b1;
+ }
+ if ( (j = b5 - m5) !=0)
+ b = pow5mult(b, j);
+ }
+ else
+ b = pow5mult(b, b5);
+ }
+ S = i2b(1);
+ if (s5 > 0)
+ S = pow5mult(S, s5);
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ spec_case = 0;
+ if (mode < 2) {
+ if (bbits == 1 && be0 > fpi->emin + 1) {
+ /* The special case */
+ b2++;
+ s2++;
+ spec_case = 1;
+ }
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+ i = ((s5 ? hi0bits(S->x[S->wds-1]) : ULbits - 1) - s2 - 4) & kmask;
+ m2 += i;
+ if ((b2 += i) > 0)
+ b = lshift(b, b2);
+ if ((s2 += i) > 0)
+ S = lshift(S, s2);
+ if (k_check) {
+ if (cmp(b,S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (leftright)
+ mhi = multadd(mhi, 10, 0);
+ ilim = ilim1;
+ }
+ }
+ if (ilim <= 0 && mode > 2) {
+ if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+ /* no digits, fcvt style */
+ no_digits:
+ k = -1 - ndigits;
+ inex = STRTOG_Inexlo;
+ goto ret;
+ }
+ one_digit:
+ inex = STRTOG_Inexhi;
+ *s++ = '1';
+ k++;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0)
+ mhi = lshift(mhi, m2);
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, 1);
+ }
+
+ for(i = 1;;i++) {
+ dig = quorem(b,S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi);
+ j2 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+#ifndef ROUND_BIASED
+ if (j2 == 0 && !mode && !(bits[0] & 1) && !rdir) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j <= 0) {
+ if (b->wds > 1 || b->x[0])
+ inex = STRTOG_Inexlo;
+ }
+ else {
+ dig++;
+ inex = STRTOG_Inexhi;
+ }
+ *s++ = dig;
+ goto ret;
+ }
+#endif
+ if (j < 0 || (j == 0 && !mode
+#ifndef ROUND_BIASED
+ && !(bits[0] & 1)
+#endif
+ )) {
+ if (rdir && (b->wds > 1 || b->x[0])) {
+ if (rdir == 2) {
+ inex = STRTOG_Inexlo;
+ goto accept;
+ }
+ while (cmp(S,mhi) > 0) {
+ *s++ = dig;
+ mhi1 = multadd(mhi, 10, 0);
+ if (mlo == mhi)
+ mlo = mhi1;
+ mhi = mhi1;
+ b = multadd(b, 10, 0);
+ dig = quorem(b,S) + '0';
+ }
+ if (dig++ == '9')
+ goto round_9_up;
+ inex = STRTOG_Inexhi;
+ goto accept;
+ }
+ if (j2 > 0) {
+ b = lshift(b, 1);
+ j2 = cmp(b, S);
+#ifdef ROUND_BIASED
+ if (j2 >= 0 /*)*/
+#else
+ if ((j2 > 0 || (j2 == 0 && dig & 1))
+#endif
+ && dig++ == '9')
+ goto round_9_up;
+ inex = STRTOG_Inexhi;
+ }
+ if (b->wds > 1 || b->x[0])
+ inex = STRTOG_Inexlo;
+ accept:
+ *s++ = dig;
+ goto ret;
+ }
+ if (j2 > 0 && rdir != 2) {
+ if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+ *s++ = '9';
+ inex = STRTOG_Inexhi;
+ goto roundoff;
+ }
+ inex = STRTOG_Inexhi;
+ *s++ = dig + 1;
+ goto ret;
+ }
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (mlo == mhi)
+ mlo = mhi = multadd(mhi, 10, 0);
+ else {
+ mlo = multadd(mlo, 10, 0);
+ mhi = multadd(mhi, 10, 0);
+ }
+ }
+ }
+ else
+ for(i = 1;; i++) {
+ *s++ = dig = quorem(b,S) + '0';
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ }
+
+ /* Round off last digit */
+
+ if (rdir) {
+ if (rdir == 2 || (b->wds <= 1 && !b->x[0]))
+ goto chopzeros;
+ goto roundoff;
+ }
+ b = lshift(b, 1);
+ j = cmp(b, S);
+#ifdef ROUND_BIASED
+ if (j >= 0)
+#else
+ if (j > 0 || (j == 0 && dig & 1))
+#endif
+ {
+ roundoff:
+ inex = STRTOG_Inexhi;
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++*s++;
+ }
+ else {
+ chopzeros:
+ if (b->wds > 1 || b->x[0])
+ inex = STRTOG_Inexlo;
+ while(*--s == '0'){}
+ ++s;
+ }
+ ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ ret1:
+ Bfree(b);
+ *s = 0;
+ *decpt = k + 1;
+ if (rve)
+ *rve = s;
+ *kindp |= inex;
+ return s0;
+}
diff --git a/src/lib/evil/gdtoa/gdtoa.h b/src/lib/evil/gdtoa/gdtoa.h
new file mode 100644
index 0000000000..ef72bf99ed
--- /dev/null
+++ b/src/lib/evil/gdtoa/gdtoa.h
@@ -0,0 +1,121 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+/* Modified by Danny Smith for inclusion in libmingwex.a
+ Aug 2006 */
+
+/* Modified by Vincent Torri for inclusion in Evil
+ February 2012 */
+
+#ifndef GDTOA_H_INCLUDED
+#define GDTOA_H_INCLUDED
+
+#include "gd_arith.h"
+#include <stddef.h> /* for size_t */
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+/* keep the 'Long' definition as 'long' for compatibility
+ * with older/other software. long in w64 is 32 bits anyway..
+ */
+#define Long long /* Windows long is 32 bit */
+#undef NO_LONG_LONG /* we have long long type */
+#endif /* MinGW */
+
+#ifndef Long
+#define Long int
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+#ifndef UShort
+typedef unsigned short UShort;
+#endif
+
+enum { /* return values from strtodg */
+ STRTOG_Zero = 0,
+ STRTOG_Normal = 1,
+ STRTOG_Denormal = 2,
+ STRTOG_Infinite = 3,
+ STRTOG_NaN = 4,
+ STRTOG_NaNbits = 5,
+ STRTOG_NoNumber = 6,
+ STRTOG_Retmask = 7,
+
+ /* The following may be or-ed into one of the above values. */
+
+ STRTOG_Neg = 0x08, /* does not affect STRTOG_Inexlo or STRTOG_Inexhi */
+ STRTOG_Inexlo = 0x10, /* returned result rounded toward zero */
+ STRTOG_Inexhi = 0x20, /* returned result rounded away from zero */
+ STRTOG_Inexact = 0x30,
+ STRTOG_Underflow= 0x40,
+ STRTOG_Overflow = 0x80
+};
+
+typedef struct
+FPI {
+ int nbits;
+ int emin;
+ int emax;
+ int rounding;
+ int sudden_underflow;
+ int int_max;
+} FPI;
+
+enum { /* FPI.rounding values: same as FLT_ROUNDS */
+ FPI_Round_zero = 0,
+ FPI_Round_near = 1,
+ FPI_Round_up = 2,
+ FPI_Round_down = 3
+};
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern char* __dtoa (double d, int mode, int ndigits, int *decpt,
+ int *sign, char **rve);
+extern char* __gdtoa (FPI *fpi, int be, ULong *bits, int *kindp,
+ int mode, int ndigits, int *decpt, char **rve);
+extern void __freedtoa (char *);
+
+extern float __evil_strtof (const char *, char **);
+extern long double __evil_strtold (const char *, char **);
+extern int __strtodg (const char *, char **, FPI *, Long *, ULong *);
+
+extern char* __g__fmt (char*, char*, char*, int, ULong, size_t);
+extern char* __g_dfmt (char*, double*, int, size_t);
+extern char* __g_ffmt (char*, float*, int, size_t);
+extern char* __g_xfmt (char*, void*, int, size_t);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* GDTOA_H_INCLUDED */
diff --git a/src/lib/evil/gdtoa/gdtoa_fltrnds.h b/src/lib/evil/gdtoa/gdtoa_fltrnds.h
new file mode 100644
index 0000000000..28c474e2c2
--- /dev/null
+++ b/src/lib/evil/gdtoa/gdtoa_fltrnds.h
@@ -0,0 +1,18 @@
+ FPI *fpi, fpi1;
+ int Rounding;
+#ifdef Trust_FLT_ROUNDS /*{{ only define this if FLT_ROUNDS really works! */
+ Rounding = Flt_Rounds;
+#else /*}{*/
+ Rounding = 1;
+ switch(fegetround()) {
+ case FE_TOWARDZERO: Rounding = 0; break;
+ case FE_UPWARD: Rounding = 2; break;
+ case FE_DOWNWARD: Rounding = 3;
+ }
+#endif /*}}*/
+ fpi = &fpi0;
+ if (Rounding != 1) {
+ fpi1 = fpi0;
+ fpi = &fpi1;
+ fpi1.rounding = Rounding;
+ }
diff --git a/src/lib/evil/gdtoa/gdtoaimp.h b/src/lib/evil/gdtoa/gdtoaimp.h
new file mode 100644
index 0000000000..3a06c2072f
--- /dev/null
+++ b/src/lib/evil/gdtoa/gdtoaimp.h
@@ -0,0 +1,645 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* This is a variation on dtoa.c that converts arbitary binary
+ floating-point formats to and from decimal notation. It uses
+ double-precision arithmetic internally, so there are still
+ various #ifdefs that adapt the calculations to the native
+ double-precision arithmetic (any of IEEE, VAX D_floating,
+ or IBM mainframe arithmetic).
+
+ Please send bug reports to David M. Gay (dmg at acm dot org,
+ with " at " changed at "@" and " dot " changed to ".").
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa. If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ * _control87(PC_53, MCW_PC);
+ * does this with many compilers. Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE). With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule. Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 112-126].
+ *
+ * Modifications:
+ *
+ * 1. We only require IEEE, IBM, or VAX double-precision
+ * arithmetic (not IEEE double-extended).
+ * 2. We get by with floating-point arithmetic in a case that
+ * Clinger missed -- when we're computing d * 10^n
+ * for a small integer d and the integer n is not too
+ * much larger than 22 (the maximum integer k for which
+ * we can represent 10^k exactly), we may be able to
+ * compute (d*10^k) * 10^(e-k) with just one roundoff.
+ * 3. Rather than a bit-at-a-time adjustment of the binary
+ * result in the hard case, we use floating-point
+ * arithmetic to determine the adjustment to within
+ * one bit; only in really hard cases do we need to
+ * compute a second residual.
+ * 4. Because of 3., we don't need a large table of powers of 10
+ * for ten-to-e (just some small tables, e.g. of 10^k
+ * for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ * significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ * significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ * underflow (i.e., that flush to zero on underflow).
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ * computation of dtoa and gdtoa. This will cause modes 4 and 5 to be
+ * treated the same as modes 2 and 3 for some inputs.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ * that use extended-precision instructions to compute rounded
+ * products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding and arithmetic
+ * that rounds toward +Infinity.
+ * #define ROUND_BIASED_without_Round_Up for IEEE-format with biased
+ * rounding when the underlying floating-point arithmetic uses
+ * unbiased rounding. This prevent using ordinary floating-point
+ * arithmetic when the result could be computed with one rounding error.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ * products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ * integer type (of >= 64 bits). On such machines, you can
+ * #define Just_16 to store 16 bits per 32-bit Long when doing
+ * high-precision integer arithmetic. Whether this speeds things
+ * up or slows things down depends on the machine and the number
+ * being converted. If long long is available and the name is
+ * something other than "long long", #define Llong to be the name,
+ * and if "unsigned Llong" does not work as an unsigned version of
+ * Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ * FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ * if memory is available and otherwise does something you deem
+ * appropriate. If MALLOC is undefined, malloc will be invoked
+ * directly -- and assumed always to succeed.
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ * memory allocations from a private pool of memory when possible.
+ * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes,
+ * unless #defined to be a different length. This default length
+ * suffices to get rid of MALLOC calls except for unusual cases,
+ * such as decimal-to-binary conversion of a very long string of
+ * digits. When converting IEEE double precision values, the
+ * longest string gdtoa can return is about 751 bytes long. For
+ * conversions by strtod of strings of 800 digits and all gdtoa
+ * conversions of IEEE doubles in single-threaded executions with
+ * 8-byte pointers, PRIVATE_MEM >= 7400 appears to suffice; with
+ * 4-byte pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define NO_INFNAN_CHECK if you do not wish to have INFNAN_CHECK
+ * #defined automatically on IEEE systems. On such systems,
+ * when INFNAN_CHECK is #defined, strtod checks
+ * for Infinity and NaN (case insensitively).
+ * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ * strtodg also accepts (case insensitively) strings of the form
+ * NaN(x), where x is a string of hexadecimal digits (optionally
+ * preceded by 0x or 0X) and spaces; if there is only one string
+ * of hexadecimal digits, it is taken for the fraction bits of the
+ * resulting NaN; if there are two or more strings of hexadecimal
+ * digits, each string is assigned to the next available sequence
+ * of 32-bit words of fractions bits (starting with the most
+ * significant), right-aligned in each sequence.
+ * Unless GDTOA_NON_PEDANTIC_NANCHECK is #defined, input "NaN(...)"
+ * is consumed even when ... has the wrong form (in which case the
+ * "(...)" is consumed but ignored).
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ * multiple threads. In this case, you must provide (or suitably
+ * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed
+ * in pow5mult, ensures lazy evaluation of only one copy of high
+ * powers of 5; omitting this lock would introduce a small
+ * probability of wasting memory, but would otherwise be harmless.)
+ * You must also invoke freedtoa(s) to free the value s returned by
+ * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define IMPRECISE_INEXACT if you do not care about the setting of
+ * the STRTOG_Inexact bits in the special case of doing IEEE double
+ * precision conversions (which could also be done by the strtog in
+ * dtoa.c).
+ * #define NO_HEX_FP to disable recognition of C9x's hexadecimal
+ * floating-point constants.
+ * #define -DNO_ERRNO to suppress setting errno (in strtod.c and
+ * strtodg.c).
+ * #define NO_STRING_H to use private versions of memcpy.
+ * On some K&R systems, it may also be necessary to
+ * #define DECLARE_SIZE_T in this case.
+ * #define USE_LOCALE to use the current locale's decimal_point value.
+ */
+
+#ifndef GDTOAIMP_H_INCLUDED
+#define GDTOAIMP_H_INCLUDED
+#include "gdtoa.h"
+#include "gd_qnan.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#define MULTIPLE_THREADS 1
+#define USE_LOCALE 1
+#define NO_LOCALE_CACHE 1
+#endif /* MinGW */
+
+#ifdef Honor_FLT_ROUNDS
+#include <fenv.h>
+#endif
+
+#ifdef DEBUG
+#include <stdio.h>
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef MALLOC
+extern void *MALLOC (size_t);
+#else
+#define MALLOC malloc
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#include <errno.h>
+
+#ifdef NO_ERRNO
+#define SET_ERRNO(x)
+#else
+#define SET_ERRNO(x) \
+ errno = (x)
+#endif
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#define DBL_MAX 1.7976931348623157e+308
+#endif
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#define n_bigtens 2
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include <float.h>
+#endif /* Bad_float_h */
+
+#ifdef IEEE_Arith
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#endif
+
+#ifdef IBM
+#define n_bigtens 3
+#endif
+
+#ifdef VAX
+#define n_bigtens 2
+#endif
+
+#ifndef __MATH_H__
+#include <math.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union _dbl_union { double d; ULong L[2]; } dbl_union;
+
+#ifdef IEEE_8087
+#define word0(x) (x)->L[1]
+#define word1(x) (x)->L[0]
+#else
+#define word0(x) (x)->L[0]
+#define word1(x) (x)->L[1]
+#endif
+#define dval(x) (x)->d
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#else /* ifndef IEEE_Arith */
+#undef Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift 24
+#define Exp_shift1 24
+#define Exp_msk1 0x1000000
+#define Exp_msk11 0x1000000
+#define Exp_mask 0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1 0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask 0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask 0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift 23
+#define Exp_shift1 7
+#define Exp_msk1 0x80
+#define Exp_msk11 0x800000
+#define Exp_mask 0x7f80
+#define P 56
+#define Bias 129
+#define Exp_1 0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask 0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask 0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#else
+#ifdef ROUND_BIASED_without_Round_Up
+#undef ROUND_BIASED
+#define ROUND_BIASED
+#endif
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#undef Pack_16
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+#define Pack_16
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower. Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else /* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifdef Pack_32
+#define ULbits 32
+#define kshift 5
+#define kmask 31
+#define ALL_ON 0xffffffff
+#else
+#define ULbits 16
+#define kshift 4
+#define kmask 15
+#define ALL_ON 0xffff
+#endif
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n) /*nothing*/
+#define FREE_DTOA_LOCK(n) /*nothing*/
+#endif
+
+#define Kmax 9
+
+#define Bigint __Bigint
+struct
+Bigint {
+ struct Bigint *next;
+ int k, maxwds, sign, wds;
+ ULong x[1];
+};
+typedef struct Bigint Bigint;
+
+#ifdef NO_STRING_H
+#ifdef DECLARE_SIZE_T
+typedef unsigned int size_t;
+#endif
+extern void memcpy_D2A (void*, const void*, size_t);
+#define Bcopy(x,y) memcpy_D2A(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#else /* !NO_STRING_H */
+#define Bcopy(x,y) memcpy(&x->sign,&y->sign,y->wds*sizeof(ULong) + 2*sizeof(int))
+#endif /* NO_STRING_H */
+
+#ifdef __GNUC__
+static inline int
+__lo0bits_D2A (ULong *y)
+{
+ int ret = __builtin_ctz(*y);
+ *y = *y >> ret;
+ return ret;
+}
+
+static inline int
+__hi0bits_D2A (ULong y)
+{
+ return __builtin_clz(y);
+}
+#endif
+
+#define Balloc __Balloc_D2A
+#define Bfree __Bfree_D2A
+#define ULtoQ __ULtoQ_D2A
+#define ULtof __ULtof_D2A
+#define ULtod __ULtod_D2A
+#define ULtodd __ULtodd_D2A
+#define ULtox __ULtox_D2A
+#define ULtoxL __ULtoxL_D2A
+#define any_on __any_on_D2A
+#define b2d __b2d_D2A
+#define bigtens __bigtens_D2A
+#define cmp __cmp_D2A
+#define copybits __copybits_D2A
+#define d2b __d2b_D2A
+#define decrement __decrement_D2A
+#define diff __diff_D2A
+#define dtoa_result __dtoa_result_D2A
+#define gethex __gethex_D2A
+#define hexdig __hexdig_D2A
+#define hexnan __hexnan_D2A
+#define hi0bits_D2A __hi0bits_D2A
+#define hi0bits(x) __hi0bits_D2A((ULong)(x))
+#define i2b __i2b_D2A
+#define increment __increment_D2A
+#define lo0bits __lo0bits_D2A
+#define lshift __lshift_D2A
+#define match __match_D2A
+#define mult __mult_D2A
+#define multadd __multadd_D2A
+#define nrv_alloc __nrv_alloc_D2A
+#define pow5mult __pow5mult_D2A
+#define quorem __quorem_D2A
+#define ratio __ratio_D2A
+#define rshift __rshift_D2A
+#define rv_alloc __rv_alloc_D2A
+#define s2b __s2b_D2A
+#define set_ones __set_ones_D2A
+#define strcp_D2A __strcp_D2A
+#define strcp __strcp_D2A
+#define strtoIg __strtoIg_D2A
+#define sum __sum_D2A
+#define tens __tens_D2A
+#define tinytens __tinytens_D2A
+#define tinytens __tinytens_D2A
+#define trailz __trailz_D2A
+#define ulp __ulp_D2A
+
+#define hexdig_init_D2A __mingw_hexdig_init_D2A
+
+extern char *dtoa_result;
+extern const double bigtens[], tens[], tinytens[];
+extern unsigned char hexdig[];
+
+extern Bigint *Balloc (int);
+extern void Bfree (Bigint*);
+extern void ULtof (ULong*, ULong*, Long, int);
+extern void ULtod (ULong*, ULong*, Long, int);
+extern void ULtodd (ULong*, ULong*, Long, int);
+extern void ULtoQ (ULong*, ULong*, Long, int);
+extern void ULtox (UShort*, ULong*, Long, int);
+extern void ULtoxL (ULong*, ULong*, Long, int);
+extern ULong any_on (Bigint*, int);
+extern double b2d (Bigint*, int*);
+extern int cmp (Bigint*, Bigint*);
+extern void copybits (ULong*, int, Bigint*);
+extern Bigint *d2b (double, int*, int*);
+extern void decrement (Bigint*);
+extern Bigint *diff (Bigint*, Bigint*);
+extern int gethex (const char**, FPI*, Long*, Bigint**, int);
+extern void hexdig_init_D2A(void);
+extern int hexnan (const char**, FPI*, ULong*);
+#ifndef __GNUC__
+extern int hi0bits_D2A (ULong);
+#endif
+extern Bigint *i2b (int);
+extern Bigint *increment (Bigint*);
+#ifndef __GNUC__
+extern int lo0bits (ULong*);
+#endif
+extern Bigint *lshift (Bigint*, int);
+extern int match (const char**, char*);
+extern Bigint *mult (Bigint*, Bigint*);
+extern Bigint *multadd (Bigint*, int, int);
+extern char *nrv_alloc (char*, char **, int);
+extern Bigint *pow5mult (Bigint*, int);
+extern int quorem (Bigint*, Bigint*);
+extern double ratio (Bigint*, Bigint*);
+extern void rshift (Bigint*, int);
+extern char *rv_alloc (int);
+extern Bigint *s2b (const char*, int, int, ULong, int);
+extern Bigint *set_ones (Bigint*, int);
+extern char *strcp (char*, const char*);
+extern Bigint *sum (Bigint*, Bigint*);
+extern int trailz (Bigint*);
+extern double ulp (dbl_union *);
+
+#ifdef __cplusplus
+}
+#endif
+/*
+ * NAN_WORD0 and NAN_WORD1 are only referenced in strtod.c. Prior to
+ * 20050115, they used to be hard-wired here (to 0x7ff80000 and 0,
+ * respectively), but now are determined by compiling and running
+ * qnan.c to generate gd_qnan.h, which specifies d_QNAN0 and d_QNAN1.
+ * Formerly gdtoaimp.h recommended supplying suitable -DNAN_WORD0=...
+ * and -DNAN_WORD1=... values if necessary. This should still work.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ */
+#ifdef IEEE_Arith
+#ifndef NO_INFNAN_CHECK
+#undef INFNAN_CHECK
+#define INFNAN_CHECK
+#endif
+#ifdef IEEE_MC68k
+#define _0 0
+#define _1 1
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN0
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN1
+#endif
+#else
+#define _0 1
+#define _1 0
+#ifndef NAN_WORD0
+#define NAN_WORD0 d_QNAN1
+#endif
+#ifndef NAN_WORD1
+#define NAN_WORD1 d_QNAN0
+#endif
+#endif
+#else
+#undef INFNAN_CHECK
+#endif
+
+#undef SI
+#ifdef Sudden_Underflow
+#define SI 1
+#else
+#define SI 0
+#endif
+
+#endif /* GDTOAIMP_H_INCLUDED */
diff --git a/src/lib/evil/gdtoa/gethex.c b/src/lib/evil/gdtoa/gethex.c
new file mode 100644
index 0000000000..276175453e
--- /dev/null
+++ b/src/lib/evil/gdtoa/gethex.c
@@ -0,0 +1,340 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+int gethex (const char **sp, FPI *fpi, Long *expo, Bigint **bp, int sign)
+{
+ Bigint *b;
+ const unsigned char *decpt, *s0, *s, *s1;
+ int big, esign, havedig, irv, j, k, n, n0, nbits, up, zret;
+ ULong L, lostbits, *x;
+ Long e, e1;
+#ifdef USE_LOCALE
+ int i;
+ const unsigned char *decimalpoint;
+#ifdef NO_LOCALE_CACHE
+ decimalpoint = (unsigned char *)localeconv()->decimal_point;
+#else
+ static unsigned char *decimalpoint_cache;
+ if (!(s0 = decimalpoint_cache)) {
+ s0 = (unsigned char *)localeconv()->decimal_point;
+ decimalpoint_cache = (unsigned char *)
+ MALLOC(strlen((char *)s0) + 1);
+ if (decimalpoint_cache) {
+ strcpy((char *)decimalpoint_cache, (char *)s0);
+ s0 = decimalpoint_cache;
+ }
+ }
+ decimalpoint = s0;
+#endif
+#endif
+
+ if (!hexdig['0'])
+ hexdig_init_D2A();
+ *bp = 0;
+ havedig = 0;
+ s0 = *(const unsigned char **)sp + 2;
+ while(s0[havedig] == '0')
+ havedig++;
+ s0 += havedig;
+ s = s0;
+ decpt = 0;
+ zret = 0;
+ e = 0;
+ if (hexdig[*s])
+ havedig++;
+ else {
+ zret = 1;
+#ifdef USE_LOCALE
+ for(i = 0; decimalpoint[i]; ++i) {
+ if (s[i] != decimalpoint[i])
+ goto pcheck;
+ }
+ decpt = s += i;
+#else
+ if (*s != '.')
+ goto pcheck;
+ decpt = ++s;
+#endif
+ if (!hexdig[*s])
+ goto pcheck;
+ while(*s == '0')
+ s++;
+ if (hexdig[*s])
+ zret = 0;
+ havedig = 1;
+ s0 = s;
+ }
+ while(hexdig[*s])
+ s++;
+#ifdef USE_LOCALE
+ if (*s == *decimalpoint && !decpt) {
+ for(i = 1; decimalpoint[i]; ++i) {
+ if (s[i] != decimalpoint[i])
+ goto pcheck;
+ }
+ decpt = s += i;
+#else
+ if (*s == '.' && !decpt) {
+ decpt = ++s;
+#endif
+ while(hexdig[*s])
+ s++;
+ }/*}*/
+ if (decpt)
+ e = -(((Long)(s-decpt)) << 2);
+ pcheck:
+ s1 = s;
+ big = esign = 0;
+ switch(*s) {
+ case 'p':
+ case 'P':
+ switch(*++s) {
+ case '-':
+ esign = 1;
+ /* no break */
+ case '+':
+ s++;
+ }
+ if ((n = hexdig[*s]) == 0 || n > 0x19) {
+ s = s1;
+ break;
+ }
+ e1 = n - 0x10;
+ while((n = hexdig[*++s]) !=0 && n <= 0x19) {
+ if (e1 & 0xf8000000)
+ big = 1;
+ e1 = 10*e1 + n - 0x10;
+ }
+ if (esign)
+ e1 = -e1;
+ e += e1;
+ }
+ *sp = (char*)s;
+ if (!havedig)
+ *sp = (char*)s0 - 1;
+ if (zret)
+ return STRTOG_Zero;
+ if (big) {
+ if (esign) {
+ switch(fpi->rounding) {
+ case FPI_Round_up:
+ if (sign)
+ break;
+ goto ret_tiny;
+ case FPI_Round_down:
+ if (!sign)
+ break;
+ goto ret_tiny;
+ }
+ goto retz;
+ ret_tiny:
+ b = Balloc(0);
+ b->wds = 1;
+ b->x[0] = 1;
+ goto dret;
+ }
+ switch(fpi->rounding) {
+ case FPI_Round_near:
+ goto ovfl1;
+ case FPI_Round_up:
+ if (!sign)
+ goto ovfl1;
+ goto ret_big;
+ case FPI_Round_down:
+ if (sign)
+ goto ovfl1;
+ goto ret_big;
+ }
+ ret_big:
+ nbits = fpi->nbits;
+ n0 = n = nbits >> kshift;
+ if (nbits & kmask)
+ ++n;
+ for(j = n, k = 0; j >>= 1; ++k);
+ *bp = b = Balloc(k);
+ b->wds = n;
+ for(j = 0; j < n0; ++j)
+ b->x[j] = ALL_ON;
+ if (n > n0)
+ b->x[j] = ULbits >> (ULbits - (nbits & kmask));
+ *expo = fpi->emin;
+ return STRTOG_Normal | STRTOG_Inexlo;
+ }
+ n = s1 - s0 - 1;
+ for(k = 0; n > (1 << (kshift-2)) - 1; n >>= 1)
+ k++;
+ b = Balloc(k);
+ x = b->x;
+ n = 0;
+ L = 0;
+#ifdef USE_LOCALE
+ for(i = 0; decimalpoint[i+1]; ++i);
+#endif
+ while(s1 > s0) {
+#ifdef USE_LOCALE
+ if (*--s1 == decimalpoint[i]) {
+ s1 -= i;
+ continue;
+ }
+#else
+ if (*--s1 == '.')
+ continue;
+#endif
+ if (n == ULbits) {
+ *x++ = L;
+ L = 0;
+ n = 0;
+ }
+ L |= (hexdig[*s1] & 0x0f) << n;
+ n += 4;
+ }
+ *x++ = L;
+ b->wds = n = x - b->x;
+ n = ULbits*n - hi0bits(L);
+ nbits = fpi->nbits;
+ lostbits = 0;
+ x = b->x;
+ if (n > nbits) {
+ n -= nbits;
+ if (any_on(b,n)) {
+ lostbits = 1;
+ k = n - 1;
+ if (x[k>>kshift] & 1 << (k & kmask)) {
+ lostbits = 2;
+ if (k > 0 && any_on(b,k))
+ lostbits = 3;
+ }
+ }
+ rshift(b, n);
+ e += n;
+ }
+ else if (n < nbits) {
+ n = nbits - n;
+ b = lshift(b, n);
+ e -= n;
+ x = b->x;
+ }
+ if (e > fpi->emax) {
+ ovfl:
+ Bfree(b);
+ ovfl1:
+ SET_ERRNO(ERANGE);
+ return STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
+ }
+ irv = STRTOG_Normal;
+ if (e < fpi->emin) {
+ irv = STRTOG_Denormal;
+ n = fpi->emin - e;
+ if (n >= nbits) {
+ switch (fpi->rounding) {
+ case FPI_Round_near:
+ if (n == nbits && (n < 2 || any_on(b,n-1)))
+ goto one_bit;
+ break;
+ case FPI_Round_up:
+ if (!sign)
+ goto one_bit;
+ break;
+ case FPI_Round_down:
+ if (sign) {
+ one_bit:
+ x[0] = b->wds = 1;
+ dret:
+ *bp = b;
+ *expo = fpi->emin;
+ SET_ERRNO(ERANGE);
+ return STRTOG_Denormal | STRTOG_Inexhi
+ | STRTOG_Underflow;
+ }
+ }
+ Bfree(b);
+ retz:
+ SET_ERRNO(ERANGE);
+ return STRTOG_Zero | STRTOG_Inexlo | STRTOG_Underflow;
+ }
+ k = n - 1;
+ if (lostbits)
+ lostbits = 1;
+ else if (k > 0)
+ lostbits = any_on(b,k);
+ if (x[k>>kshift] & 1 << (k & kmask))
+ lostbits |= 2;
+ nbits -= n;
+ rshift(b,n);
+ e = fpi->emin;
+ }
+ if (lostbits) {
+ up = 0;
+ switch(fpi->rounding) {
+ case FPI_Round_zero:
+ break;
+ case FPI_Round_near:
+ if (lostbits & 2
+ && (lostbits | x[0]) & 1)
+ up = 1;
+ break;
+ case FPI_Round_up:
+ up = 1 - sign;
+ break;
+ case FPI_Round_down:
+ up = sign;
+ }
+ if (up) {
+ k = b->wds;
+ b = increment(b);
+ x = b->x;
+ if (irv == STRTOG_Denormal) {
+ if (nbits == fpi->nbits - 1
+ && x[nbits >> kshift] & 1 << (nbits & kmask))
+ irv = STRTOG_Normal;
+ }
+ else if (b->wds > k
+ || ((n = nbits & kmask) !=0
+ && hi0bits(x[k-1]) < 32-n)) {
+ rshift(b,1);
+ if (++e > fpi->emax)
+ goto ovfl;
+ }
+ irv |= STRTOG_Inexhi;
+ }
+ else
+ irv |= STRTOG_Inexlo;
+ }
+ *bp = b;
+ *expo = e;
+ return irv;
+}
diff --git a/src/lib/evil/gdtoa/gmisc.c b/src/lib/evil/gdtoa/gmisc.c
new file mode 100644
index 0000000000..157e872319
--- /dev/null
+++ b/src/lib/evil/gdtoa/gmisc.c
@@ -0,0 +1,76 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+void rshift (Bigint *b, int k)
+{
+ ULong *x, *x1, *xe, y;
+ int n;
+
+ x = x1 = b->x;
+ n = k >> kshift;
+ if (n < b->wds) {
+ xe = x + b->wds;
+ x += n;
+ if (k &= kmask) {
+ n = ULbits - k;
+ y = *x++ >> k;
+ while(x < xe) {
+ *x1++ = (y | (*x << n)) & ALL_ON;
+ y = *x++ >> k;
+ }
+ if ((*x1 = y) !=0)
+ x1++;
+ }
+ else
+ while(x < xe)
+ *x1++ = *x++;
+ }
+ if ((b->wds = x1 - b->x) == 0)
+ b->x[0] = 0;
+}
+
+int trailz (Bigint *b)
+{
+ ULong L, *x, *xe;
+ int n = 0;
+
+ x = b->x;
+ xe = x + b->wds;
+ for(n = 0; x < xe && !*x; x++)
+ n += ULbits;
+ if (x < xe) {
+ L = *x;
+ n += lo0bits(&L);
+ }
+ return n;
+}
diff --git a/src/lib/evil/gdtoa/hd_init.c b/src/lib/evil/gdtoa/hd_init.c
new file mode 100644
index 0000000000..5ee0caa73d
--- /dev/null
+++ b/src/lib/evil/gdtoa/hd_init.c
@@ -0,0 +1,49 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+unsigned char hexdig[256];
+
+static void htinit (unsigned char *h, unsigned char *s, int inc)
+{
+ int i, j;
+ for(i = 0; (j = s[i]) !=0; i++)
+ h[j] = i + inc;
+}
+
+void hexdig_init_D2A (void)
+{
+#define USC (unsigned char *)
+ htinit(hexdig, USC "0123456789", 0x10);
+ htinit(hexdig, USC "abcdef", 0x10 + 10);
+ htinit(hexdig, USC "ABCDEF", 0x10 + 10);
+}
diff --git a/src/lib/evil/gdtoa/hexnan.c b/src/lib/evil/gdtoa/hexnan.c
new file mode 100644
index 0000000000..4fa4c77458
--- /dev/null
+++ b/src/lib/evil/gdtoa/hexnan.c
@@ -0,0 +1,139 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+static void L_shift (ULong *x, ULong *x1, int i)
+{
+ int j;
+
+ i = 8 - i;
+ i <<= 2;
+ j = ULbits - i;
+ do {
+ *x |= x[1] << j;
+ x[1] >>= i;
+ } while(++x < x1);
+}
+
+int hexnan (const char **sp, FPI *fpi, ULong *x0)
+{
+ ULong c, h, *x, *x1, *xe;
+ const char *s;
+ int havedig, hd0, i, nbits;
+
+ if (!hexdig['0'])
+ hexdig_init_D2A();
+ nbits = fpi->nbits;
+ x = x0 + (nbits >> kshift);
+ if (nbits & kmask)
+ x++;
+ *--x = 0;
+ x1 = xe = x;
+ havedig = hd0 = i = 0;
+ s = *sp;
+ /* allow optional initial 0x or 0X */
+ while((c = *(const unsigned char*)(s+1)) && c <= ' ')
+ ++s;
+ if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')
+ && *(const unsigned char*)(s+3) > ' ')
+ s += 2;
+ while((c = *(const unsigned char*)++s)) {
+ if (!(h = hexdig[c])) {
+ if (c <= ' ') {
+ if (hd0 < havedig) {
+ if (x < x1 && i < 8)
+ L_shift(x, x1, i);
+ if (x <= x0) {
+ i = 8;
+ continue;
+ }
+ hd0 = havedig;
+ *--x = 0;
+ x1 = x;
+ i = 0;
+ }
+ while(*(const unsigned char*)(s+1) <= ' ')
+ ++s;
+ if (s[1] == '0' && (s[2] == 'x' || s[2] == 'X')
+ && *(const unsigned char*)(s+3) > ' ')
+ s += 2;
+ continue;
+ }
+ if (/*(*/ c == ')' && havedig) {
+ *sp = s + 1;
+ break;
+ }
+#ifndef GDTOA_NON_PEDANTIC_NANCHECK
+ do {
+ if (/*(*/ c == ')') {
+ *sp = s + 1;
+ break;
+ }
+ } while((c = *++s));
+#endif
+ return STRTOG_NaN;
+ }
+ havedig++;
+ if (++i > 8) {
+ if (x <= x0)
+ continue;
+ i = 1;
+ *--x = 0;
+ }
+ *x = (*x << 4) | (h & 0xf);
+ }
+ if (!havedig)
+ return STRTOG_NaN;
+ if (x < x1 && i < 8)
+ L_shift(x, x1, i);
+ if (x > x0) {
+ x1 = x0;
+ do *x1++ = *x++;
+ while(x <= xe);
+ do *x1++ = 0;
+ while(x1 <= xe);
+ }
+ else {
+ /* truncate high-order word if necessary */
+ if ( (i = nbits & (ULbits-1)) !=0)
+ *xe &= ((ULong)0xffffffff) >> (ULbits - i);
+ }
+ for(x1 = xe;; --x1) {
+ if (*x1 != 0)
+ break;
+ if (x1 == x0) {
+ *x1 = 1;
+ break;
+ }
+ }
+ return STRTOG_NaNbits;
+}
diff --git a/src/lib/evil/gdtoa/misc.c b/src/lib/evil/gdtoa/misc.c
new file mode 100644
index 0000000000..43f31cea55
--- /dev/null
+++ b/src/lib/evil/gdtoa/misc.c
@@ -0,0 +1,860 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+/* we have to include windows.h before gdtoa
+ headers, otherwise defines cause conflicts. */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+#include <windows.h>
+
+#define NLOCKS 2
+
+#ifdef USE_WIN32_SL
+/* Use spin locks. */
+static long dtoa_sl[NLOCKS];
+
+#define ACQUIRE_DTOA_LOCK(n) \
+ while (InterlockedCompareExchange (&dtoa_sl[n], 1, 0) != 0) \
+ Sleep (0);
+#define FREE_DTOA_LOCK(n) InterlockedExchange (&dtoa_sl[n], 0);
+
+#else /* USE_WIN32_SL */
+
+#include <stdlib.h>
+static CRITICAL_SECTION dtoa_CritSec[NLOCKS];
+static long dtoa_CS_init = 0;
+/*
+ 1 = initializing
+ 2 = initialized
+ 3 = deleted
+*/
+static void dtoa_lock_cleanup (void)
+{
+ long last_CS_init = InterlockedExchange (&dtoa_CS_init,3);
+ if (2 == last_CS_init) {
+ int i;
+ for (i = 0; i < NLOCKS; i++)
+ DeleteCriticalSection (&dtoa_CritSec[i]);
+ }
+}
+
+static void dtoa_lock (int n)
+{
+ if (2 == dtoa_CS_init) {
+ EnterCriticalSection (&dtoa_CritSec[n]);
+ return;
+ }
+ else if (0 == dtoa_CS_init) {
+ long last_CS_init = InterlockedExchange (&dtoa_CS_init, 1);
+ if (0 == last_CS_init) {
+ int i;
+ for (i = 0; i < NLOCKS; i++)
+ InitializeCriticalSection (&dtoa_CritSec[i]);
+ atexit (dtoa_lock_cleanup);
+ dtoa_CS_init = 2;
+ }
+ else if (2 == last_CS_init)
+ dtoa_CS_init = 2;
+ }
+ /* Another thread is initializing. Wait. */
+ while (1 == dtoa_CS_init)
+ Sleep (1);
+
+ /* It had better be initialized now. */
+ if (2 == dtoa_CS_init)
+ EnterCriticalSection(&dtoa_CritSec[n]);
+}
+
+static void dtoa_unlock (int n)
+{
+ if (2 == dtoa_CS_init)
+ LeaveCriticalSection (&dtoa_CritSec[n]);
+}
+
+#define ACQUIRE_DTOA_LOCK(n) dtoa_lock(n)
+#define FREE_DTOA_LOCK(n) dtoa_unlock(n)
+#endif /* USE_WIN32_SL */
+
+#endif /* __MINGW32__ / __MINGW64__ */
+
+#include "gdtoaimp.h"
+
+static Bigint *freelist[Kmax+1];
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+Bigint *Balloc (int k)
+{
+ int x;
+ Bigint *rv;
+#ifndef Omit_Private_Memory
+ unsigned int len;
+#endif
+
+ ACQUIRE_DTOA_LOCK(0);
+ /* The k > Kmax case does not need ACQUIRE_DTOA_LOCK(0), */
+ /* but this case seems very unlikely. */
+ if (k <= Kmax && (rv = freelist[k]) !=0) {
+ freelist[k] = rv->next;
+ }
+ else {
+ x = 1 << k;
+#ifdef Omit_Private_Memory
+ rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+ if (rv == NULL)
+ return NULL;
+#else
+ len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+ /sizeof(double);
+ if (k <= Kmax
+ && (size_t) (pmem_next - private_mem + len) <= PRIVATE_mem)
+ {
+ rv = (Bigint*)pmem_next;
+ pmem_next += len;
+ }
+ else
+ {
+ rv = (Bigint*)MALLOC(len*sizeof(double));
+ if (rv == NULL)
+ return NULL;
+ }
+#endif
+ rv->k = k;
+ rv->maxwds = x;
+ }
+ FREE_DTOA_LOCK(0);
+ rv->sign = rv->wds = 0;
+ return rv;
+}
+
+void Bfree (Bigint *v)
+{
+ if (v) {
+ if (v->k > Kmax)
+ free((void*)v);
+ else {
+ ACQUIRE_DTOA_LOCK(0);
+ v->next = freelist[v->k];
+ freelist[v->k] = v;
+ FREE_DTOA_LOCK(0);
+ }
+ }
+}
+
+/* lo0bits(): Shift y so lowest bit is 1 and return the
+ * number of bits y was shifted.
+ * With GCC, we use an inline wrapper for __builtin_clz()
+ */
+#ifndef __GNUC__
+int lo0bits (ULong *y)
+{
+ int k;
+ ULong x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x)
+ return 32;
+ }
+ *y = x;
+ return k;
+}
+#endif /* __GNUC__ */
+
+Bigint *multadd (Bigint *b, int m, int a) /* multiply by m and add a */
+{
+ int i, wds;
+#ifdef ULLong
+ ULong *x;
+ ULLong carry, y;
+#else
+ ULong carry, *x, y;
+#ifdef Pack_32
+ ULong xi, z;
+#endif
+#endif
+ Bigint *b1;
+
+ wds = b->wds;
+ x = b->x;
+ i = 0;
+ carry = a;
+ do {
+#ifdef ULLong
+ y = *x * (ULLong)m + carry;
+ carry = y >> 32;
+ *x++ = y & 0xffffffffUL;
+#else
+#ifdef Pack_32
+ xi = *x;
+ y = (xi & 0xffff) * m + carry;
+ z = (xi >> 16) * m + (y >> 16);
+ carry = z >> 16;
+ *x++ = (z << 16) + (y & 0xffff);
+#else
+ y = *x * m + carry;
+ carry = y >> 16;
+ *x++ = y & 0xffff;
+#endif
+#endif
+ } while(++i < wds);
+ if (carry) {
+ if (wds >= b->maxwds) {
+ b1 = Balloc(b->k+1);
+ if (b1 == NULL)
+ return NULL;
+ Bcopy(b1, b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[wds++] = carry;
+ b->wds = wds;
+ }
+ return b;
+}
+
+/* hi0bits();
+ * With GCC, we use an inline wrapper for __builtin_clz()
+ */
+#ifndef __GNUC__
+int hi0bits_D2A (ULong x)
+{
+ int k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+}
+#endif /* __GNUC__ */
+
+Bigint *i2b (int i)
+{
+ Bigint *b;
+
+ b = Balloc(1);
+ if (b == NULL)
+ return NULL;
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+}
+
+Bigint *mult (Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int k, wa, wb, wc;
+ ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+ ULong y;
+#ifdef ULLong
+ ULLong carry, z;
+#else
+ ULong carry, z;
+#ifdef Pack_32
+ ULong z2;
+#endif
+#endif
+
+ if (a->wds < b->wds) {
+ c = a;
+ a = b;
+ b = c;
+ }
+ k = a->k;
+ wa = a->wds;
+ wb = b->wds;
+ wc = wa + wb;
+ if (wc > a->maxwds)
+ k++;
+ c = Balloc(k);
+ if (c == NULL)
+ return NULL;
+ for(x = c->x, xa = x + wc; x < xa; x++)
+ *x = 0;
+ xa = a->x;
+ xae = xa + wa;
+ xb = b->x;
+ xbe = xb + wb;
+ xc0 = c->x;
+#ifdef ULLong
+ for(; xb < xbe; xc0++) {
+ if ( (y = *xb++) !=0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * (ULLong)y + *xc + carry;
+ carry = z >> 32;
+ *xc++ = z & 0xffffffffUL;
+ } while(x < xae);
+ *xc = carry;
+ }
+ }
+#else
+#ifdef Pack_32
+ for(; xb < xbe; xb++, xc0++) {
+ if ( (y = *xb & 0xffff) !=0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ Storeinc(xc, z2, z);
+ } while(x < xae);
+ *xc = carry;
+ }
+ if ( (y = *xb >> 16) !=0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ Storeinc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ } while(x < xae);
+ *xc = z2;
+ }
+ }
+#else
+ for(; xb < xbe; xc0++) {
+ if ( (y = *xb++) !=0) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * y + *xc + carry;
+ carry = z >> 16;
+ *xc++ = z & 0xffff;
+ } while(x < xae);
+ *xc = carry;
+ }
+ }
+#endif
+#endif
+ for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+ c->wds = wc;
+ return c;
+}
+
+static Bigint *p5s;
+
+Bigint *pow5mult (Bigint *b, int k)
+{
+ Bigint *b1, *p5, *p51;
+ int i;
+ static int p05[3] = { 5, 25, 125 };
+
+ if ( (i = k & 3) !=0)
+ {
+ b = multadd(b, p05[i-1], 0);
+ if (b == NULL)
+ return NULL;
+ }
+ if (!(k >>= 2))
+ return b;
+ if ((p5 = p5s) == 0) {
+ /* first time */
+#ifdef MULTIPLE_THREADS
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p5 = p5s)) {
+ p5 = p5s = i2b(625);
+ if (p5 == NULL)
+ return NULL;
+ p5->next = 0;
+ }
+ FREE_DTOA_LOCK(1);
+#else
+ p5 = p5s = i2b(625);
+ if (p5 == NULL)
+ return NULL;
+ p5->next = 0;
+#endif
+ }
+ for(;;) {
+ if (k & 1) {
+ b1 = mult(b, p5);
+ if (b1 == NULL)
+ return NULL;
+ Bfree(b);
+ b = b1;
+ }
+ if (!(k >>= 1))
+ break;
+ if ((p51 = p5->next) == 0) {
+#ifdef MULTIPLE_THREADS
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p51 = p5->next)) {
+ p51 = p5->next = mult(p5,p5);
+ if (p51 == NULL)
+ return NULL;
+ p51->next = 0;
+ }
+ FREE_DTOA_LOCK(1);
+#else
+ p51 = p5->next = mult(p5,p5);
+ if (p51 == NULL)
+ return NULL;
+ p51->next = 0;
+#endif
+ }
+ p5 = p51;
+ }
+ return b;
+}
+
+Bigint *lshift (Bigint *b, int k)
+{
+ int i, k1, n, n1;
+ Bigint *b1;
+ ULong *x, *x1, *xe, z;
+
+ n = k >> kshift;
+ k1 = b->k;
+ n1 = n + b->wds + 1;
+ for(i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ b1 = Balloc(k1);
+ if (b1 == NULL)
+ return NULL;
+ x1 = b1->x;
+ for(i = 0; i < n; i++)
+ *x1++ = 0;
+ x = b->x;
+ xe = x + b->wds;
+ if (k &= kmask) {
+#ifdef Pack_32
+ k1 = 32 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k | z;
+ z = *x++ >> k1;
+ } while(x < xe);
+ if ((*x1 = z) !=0)
+ ++n1;
+#else
+ k1 = 16 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k & 0xffff | z;
+ z = *x++ >> k1;
+ } while(x < xe);
+ if (*x1 = z)
+ ++n1;
+#endif
+ }
+ else do
+ *x1++ = *x++;
+ while(x < xe);
+ b1->wds = n1 - 1;
+ Bfree(b);
+ return b1;
+}
+
+int cmp (Bigint *a, Bigint *b)
+{
+ ULong *xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a->wds;
+ j = b->wds;
+#ifdef DEBUG
+ if (i > 1 && !a->x[i-1])
+ Bug("cmp called with a->x[a->wds-1] == 0");
+ if (j > 1 && !b->x[j-1])
+ Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+ if (i -= j)
+ return i;
+ xa0 = a->x;
+ xa = xa0 + j;
+ xb0 = b->x;
+ xb = xb0 + j;
+ for(;;) {
+ if (*--xa != *--xb)
+ return *xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+}
+
+Bigint *diff (Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ int i, wa, wb;
+ ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+ ULLong borrow, y;
+#else
+ ULong borrow, y;
+#ifdef Pack_32
+ ULong z;
+#endif
+#endif
+
+ i = cmp(a,b);
+ if (!i) {
+ c = Balloc(0);
+ if (c == NULL)
+ return NULL;
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+ if (i < 0) {
+ c = a;
+ a = b;
+ b = c;
+ i = 1;
+ }
+ else
+ i = 0;
+ c = Balloc(a->k);
+ if (c == NULL)
+ return NULL;
+ c->sign = i;
+ wa = a->wds;
+ xa = a->x;
+ xae = xa + wa;
+ wb = b->wds;
+ xb = b->x;
+ xbe = xb + wb;
+ xc = c->x;
+ borrow = 0;
+#ifdef ULLong
+ do {
+ y = (ULLong)*xa++ - *xb++ - borrow;
+ borrow = y >> 32 & 1UL;
+ *xc++ = y & 0xffffffffUL;
+ } while(xb < xbe);
+ while(xa < xae) {
+ y = *xa++ - borrow;
+ borrow = y >> 32 & 1UL;
+ *xc++ = y & 0xffffffffUL;
+ }
+#else
+#ifdef Pack_32
+ do {
+ y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ } while(xb < xbe);
+ while(xa < xae) {
+ y = (*xa & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+#else
+ do {
+ y = *xa++ - *xb++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ } while(xb < xbe);
+ while(xa < xae) {
+ y = *xa++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ }
+#endif
+#endif
+ while(!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+}
+
+double b2d (Bigint *a, int *e)
+{
+ ULong *xa, *xa0, w, y, z;
+ int k;
+ union _dbl_union d;
+#define d0 word0(&d)
+#define d1 word1(&d)
+
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+#ifdef DEBUG
+ if (!y) Bug("zero y in b2d");
+#endif
+ k = hi0bits(y);
+ *e = 32 - k;
+#ifdef Pack_32
+ if (k < Ebits) {
+ d0 = Exp_1 | y >> (Ebits - k);
+ w = xa > xa0 ? *--xa : 0;
+ d1 = y << ((32-Ebits) + k) | w >> (Ebits - k);
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ d0 = Exp_1 | y << k | z >> (32 - k);
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k | y >> (32 - k);
+ }
+ else {
+ d0 = Exp_1 | y;
+ d1 = z;
+ }
+#else
+ if (k < Ebits + 16) {
+ z = xa > xa0 ? *--xa : 0;
+ d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+ w = xa > xa0 ? *--xa : 0;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ w = xa > xa0 ? *--xa : 0;
+ k -= Ebits + 16;
+ d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+ return dval(&d);
+#undef d0
+#undef d1
+}
+
+Bigint *d2b (double dd, int *e, int *bits)
+{
+ Bigint *b;
+ union _dbl_union d;
+#ifndef Sudden_Underflow
+ int i;
+#endif
+ int de, k;
+ ULong *x, y, z;
+#define d0 word0(&d)
+#define d1 word1(&d)
+ d.d = dd;
+
+#ifdef Pack_32
+ b = Balloc(1);
+#else
+ b = Balloc(2);
+#endif
+ if (b == NULL)
+ return NULL;
+ x = b->x;
+
+ z = d0 & Frac_mask;
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+ de = (int)(d0 >> Exp_shift);
+ z |= Exp_msk11;
+#else
+ if ( (de = (int)(d0 >> Exp_shift)) !=0)
+ z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+ if ( (y = d1) !=0) {
+ if ( (k = lo0bits(&y)) !=0) {
+ x[0] = y | z << (32 - k);
+ z >>= k;
+ }
+ else
+ x[0] = y;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = (x[1] = z) !=0 ? 2 : 1;
+ }
+ else {
+ k = lo0bits(&z);
+ x[0] = z;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = 1;
+ k += 32;
+ }
+#else
+ if ( (y = d1) !=0) {
+ if ( (k = lo0bits(&y)) !=0)
+ if (k >= 16) {
+ x[0] = y | z << 32 - k & 0xffff;
+ x[1] = z >> k - 16 & 0xffff;
+ x[2] = z >> k;
+ i = 2;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16 | z << 16 - k & 0xffff;
+ x[2] = z >> k & 0xffff;
+ x[3] = z >> k+16;
+ i = 3;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16;
+ x[2] = z & 0xffff;
+ x[3] = z >> 16;
+ i = 3;
+ }
+ }
+ else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ if (k >= 16) {
+ x[0] = z;
+ i = 0;
+ }
+ else {
+ x[0] = z & 0xffff;
+ x[1] = z >> 16;
+ i = 1;
+ }
+ k += 32;
+ }
+ while(!x[i])
+ --i;
+ b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+ if (de) {
+#endif
+ *e = de - Bias - (P-1) + k;
+ *bits = P - k;
+#ifndef Sudden_Underflow
+ }
+ else {
+ *e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+ *bits = 32*i - hi0bits(x[i-1]);
+#else
+ *bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+ }
+#endif
+ return b;
+#undef d0
+#undef d1
+}
+
+const double
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+const double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
+
+const double
+tens[] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
+};
+
+char *strcp_D2A (char *a, const char *b)
+{
+ while((*a = *b++))
+ a++;
+ return a;
+}
+
+#ifdef NO_STRING_H
+void *memcpy_D2A (void *a1, void *b1, size_t len)
+{
+ char *a = (char*)a1, *ae = a + len;
+ char *b = (char*)b1, *a0 = a;
+ while(a < ae)
+ *a++ = *b++;
+ return a0;
+}
+#endif /* NO_STRING_H */
+
diff --git a/src/lib/evil/gdtoa/qnan.c b/src/lib/evil/gdtoa/qnan.c
new file mode 100644
index 0000000000..c6bc3fe49b
--- /dev/null
+++ b/src/lib/evil/gdtoa/qnan.c
@@ -0,0 +1,116 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 2005 by David M. Gay
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and its
+documentation for any purpose and without fee is hereby granted,
+provided that the above copyright notice appear in all copies and that
+both that the copyright notice and this permission notice and warranty
+disclaimer appear in supporting documentation, and that the name of
+the author or any of his current or former employers not be used in
+advertising or publicity pertaining to distribution of the software
+without specific, written prior permission.
+
+THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
+NO EVENT SHALL THE AUTHOR OR ANY OF HIS CURRENT OR FORMER EMPLOYERS BE
+LIABLE FOR ANY SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+/* Program to compute quiet NaNs of various precisions (float, */
+/* double, and perhaps long double) on the current system, */
+/* provided the system uses binary IEEE (P754) arithmetic. */
+/* Note that one system's quiet NaN may be a signaling NaN on */
+/* another system. The IEEE arithmetic standards (P754, P854) */
+/* do not specify how to distinguish signaling NaNs from quiet */
+/* ones, and this detail varies across systems. The computed */
+/* NaN values are encoded in #defines for values for an */
+/* unsigned 32-bit integer type, called Ulong below, and */
+/* (for long double) perhaps as unsigned short values. Once */
+/* upon a time, there were PC compilers for Intel CPUs that */
+/* had sizeof(long double) = 10. Are such compilers still */
+/* distributed? */
+
+#include <stdio.h>
+#include "gd_arith.h"
+
+#ifndef Long
+#define Long long
+#endif
+
+typedef unsigned Long Ulong;
+
+#undef HAVE_IEEE
+#ifdef IEEE_8087
+#define _0 1
+#define _1 0
+#define HAVE_IEEE
+#endif
+#ifdef IEEE_MC68k
+#define _0 0
+#define _1 1
+#define HAVE_IEEE
+#endif
+
+#define UL (unsigned long)
+
+#ifdef MINGW_BUILD_GEN
+ int
+main(void)
+{
+#ifdef HAVE_IEEE
+ typedef union {
+ float f;
+ double d;
+ Ulong L[4];
+#ifndef NO_LONG_LONG
+/* need u[8] instead of u[5] for 64 bit */
+ unsigned short u[8];
+ long double D;
+#endif
+ } U;
+ U a, b, c;
+ int i;
+ a.L[0]=a.L[1]=a.L[2]=a.L[3]=0;
+ b.L[0]=b.L[1]=b.L[2]=b.L[3]=0;
+ c.L[0]=c.L[1]=c.L[2]=c.L[3]=0;
+
+ a.L[0] = b.L[0] = 0x7f800000;
+ c.f = a.f - b.f;
+ printf("#define f_QNAN 0x%lx\n", UL c.L[0]);
+ a.L[_0] = b.L[_0] = 0x7ff00000;
+ a.L[_1] = b.L[_1] = 0;
+ c.d = a.d - b.d; /* quiet NaN */
+ printf("#define d_QNAN0 0x%lx\n", UL c.L[0]);
+ printf("#define d_QNAN1 0x%lx\n", UL c.L[1]);
+#ifdef NO_LONG_LONG
+ for(i = 0; i < 4; i++)
+ printf("#define ld_QNAN%d 0xffffffff\n", i);
+ for(i = 0; i < 5; i++)
+ printf("#define ldus_QNAN%d 0xffff\n", i);
+#else
+ b.D = c.D = a.d;
+ if (printf("") < 0)
+ c.D = 37; /* never executed; just defeat optimization */
+ a.L[2] = a.L[3] = 0;
+ a.D = b.D - c.D;
+ for(i = 0; i < 4; i++)
+ printf("#define ld_QNAN%d 0x%lx\n", i, UL a.L[i]);
+ for(i = 0; i < 5; i++)
+ printf("#define ldus_QNAN%d 0x%x\n", i, a.u[i]);
+#endif
+#endif /* HAVE_IEEE */
+ return 0;
+ }
+#endif
diff --git a/src/lib/evil/gdtoa/smisc.c b/src/lib/evil/gdtoa/smisc.c
new file mode 100644
index 0000000000..1d09b44ea1
--- /dev/null
+++ b/src/lib/evil/gdtoa/smisc.c
@@ -0,0 +1,149 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+Bigint *s2b (const char *s, int nd0, int nd, ULong y9, int dplen)
+{
+ Bigint *b;
+ int i, k;
+ Long x, y;
+
+ x = (nd + 8) / 9;
+ for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+ b = Balloc(k);
+ b->x[0] = y9;
+ b->wds = 1;
+#else
+ b = Balloc(k+1);
+ b->x[0] = y9 & 0xffff;
+ b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+ i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do b = multadd(b, 10, *s++ - '0');
+ while(++i < nd0);
+ s += dplen;
+ }
+ else
+ s += dplen + 9;
+ for(; i < nd; i++)
+ b = multadd(b, 10, *s++ - '0');
+ return b;
+}
+
+double ratio (Bigint *a, Bigint *b)
+{
+ union _dbl_union da, db;
+ int k, ka, kb;
+
+ dval(&da) = b2d(a, &ka);
+ dval(&db) = b2d(b, &kb);
+ k = ka - kb + ULbits*(a->wds - b->wds);
+ if (k > 0)
+ word0(&da) += k*Exp_msk1;
+ else {
+ k = -k;
+ word0(&db) += k*Exp_msk1;
+ }
+ return dval(&da) / dval(&db);
+}
+
+#ifdef INFNAN_CHECK
+
+int match (const char **sp, char *t)
+{
+ int c, d;
+ const char *s = *sp;
+
+ while( (d = *t++) !=0) {
+ if ((c = *++s) >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != d)
+ return 0;
+ }
+ *sp = s + 1;
+ return 1;
+}
+#endif /* INFNAN_CHECK */
+
+void copybits (ULong *c, int n, Bigint *b)
+{
+ ULong *ce, *x, *xe;
+#ifdef Pack_16
+ int nw, nw1;
+#endif
+
+ ce = c + ((n-1) >> kshift) + 1;
+ x = b->x;
+#ifdef Pack_32
+ xe = x + b->wds;
+ while(x < xe)
+ *c++ = *x++;
+#else
+ nw = b->wds;
+ nw1 = nw & 1;
+ for(xe = x + (nw - nw1); x < xe; x += 2)
+ Storeinc(c, x[1], x[0]);
+ if (nw1)
+ *c++ = *x;
+#endif
+ while(c < ce)
+ *c++ = 0;
+}
+
+ULong any_on (Bigint *b, int k)
+{
+ int n, nwds;
+ ULong *x, *x0, x1, x2;
+
+ x = b->x;
+ nwds = b->wds;
+ n = k >> kshift;
+ if (n > nwds)
+ n = nwds;
+ else if (n < nwds && (k &= kmask)) {
+ x1 = x2 = x[n];
+ x1 >>= k;
+ x1 <<= k;
+ if (x1 != x2)
+ return 1;
+ }
+ x0 = x;
+ x += n;
+ while(x > x0)
+ if (*--x)
+ return 1;
+ return 0;
+}
diff --git a/src/lib/evil/gdtoa/strtodg.c b/src/lib/evil/gdtoa/strtodg.c
new file mode 100644
index 0000000000..42ab9df3a2
--- /dev/null
+++ b/src/lib/evil/gdtoa/strtodg.c
@@ -0,0 +1,979 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998-2001 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+#ifdef USE_LOCALE
+#include "locale.h"
+#endif
+
+static const int
+fivesbits[] = { 0, 3, 5, 7, 10, 12, 14, 17, 19, 21,
+ 24, 26, 28, 31, 33, 35, 38, 40, 42, 45,
+ 47, 49, 52
+};
+
+Bigint *increment (Bigint *b)
+{
+ ULong *x, *xe;
+ Bigint *b1;
+#ifdef Pack_16
+ ULong carry = 1, y;
+#endif
+
+ x = b->x;
+ xe = x + b->wds;
+#ifdef Pack_32
+ do {
+ if (*x < (ULong)0xffffffffL) {
+ ++*x;
+ return b;
+ }
+ *x++ = 0;
+ } while(x < xe);
+#else
+ do {
+ y = *x + carry;
+ carry = y >> 16;
+ *x++ = y & 0xffff;
+ if (!carry)
+ return b;
+ } while(x < xe);
+ if (carry)
+#endif
+ {
+ if (b->wds >= b->maxwds) {
+ b1 = Balloc(b->k+1);
+ Bcopy(b1,b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[b->wds++] = 1;
+ }
+ return b;
+}
+
+void decrement (Bigint *b)
+{
+ ULong *x, *xe;
+#ifdef Pack_16
+ ULong borrow = 1, y;
+#endif
+
+ x = b->x;
+ xe = x + b->wds;
+#ifdef Pack_32
+ do {
+ if (*x) {
+ --*x;
+ break;
+ }
+ *x++ = 0xffffffffL;
+ } while(x < xe);
+#else
+ do {
+ y = *x - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *x++ = y & 0xffff;
+ } while(borrow && x < xe);
+#endif
+}
+
+static int all_on (Bigint *b, int n)
+{
+ ULong *x, *xe;
+
+ x = b->x;
+ xe = x + (n >> kshift);
+ while(x < xe)
+ if ((*x++ & ALL_ON) != ALL_ON)
+ return 0;
+ if (n &= kmask)
+ return ((*x | (ALL_ON << n)) & ALL_ON) == ALL_ON;
+ return 1;
+}
+
+Bigint *set_ones (Bigint *b, int n)
+{
+ int k;
+ ULong *x, *xe;
+
+ k = (n + ((1 << kshift) - 1)) >> kshift;
+ if (b->k < k) {
+ Bfree(b);
+ b = Balloc(k);
+ }
+ k = n >> kshift;
+ if (n &= kmask)
+ k++;
+ b->wds = k;
+ x = b->x;
+ xe = x + k;
+ while(x < xe)
+ *x++ = ALL_ON;
+ if (n)
+ x[-1] >>= ULbits - n;
+ return b;
+}
+
+static int rvOK (dbl_union *d, FPI *fpi, Long *expo, ULong *bits,
+ int exact, int rd, int *irv)
+{
+ Bigint *b;
+ ULong carry, inex, lostbits;
+ int bdif, e, j, k, k1, nb, rv;
+
+ carry = rv = 0;
+ b = d2b(dval(d), &e, &bdif);
+ bdif -= nb = fpi->nbits;
+ e += bdif;
+ if (bdif <= 0) {
+ if (exact)
+ goto trunc;
+ goto ret;
+ }
+ if (P == nb) {
+ if (
+#ifndef IMPRECISE_INEXACT
+ exact &&
+#endif
+ fpi->rounding ==
+#ifdef RND_PRODQUOT
+ FPI_Round_near
+#else
+ Flt_Rounds
+#endif
+ ) goto trunc;
+ goto ret;
+ }
+ switch(rd) {
+ case 1: /* round down (toward -Infinity) */
+ goto trunc;
+ case 2: /* round up (toward +Infinity) */
+ break;
+ default: /* round near */
+ k = bdif - 1;
+ if (k < 0)
+ goto trunc;
+ if (!k) {
+ if (!exact)
+ goto ret;
+ if (b->x[0] & 2)
+ break;
+ goto trunc;
+ }
+ if (b->x[k>>kshift] & ((ULong)1 << (k & kmask)))
+ break;
+ goto trunc;
+ }
+ /* "break" cases: round up 1 bit, then truncate; bdif > 0 */
+ carry = 1;
+ trunc:
+ inex = lostbits = 0;
+ if (bdif > 0) {
+ if ( (lostbits = any_on(b, bdif)) !=0)
+ inex = STRTOG_Inexlo;
+ rshift(b, bdif);
+ if (carry) {
+ inex = STRTOG_Inexhi;
+ b = increment(b);
+ if ( (j = nb & kmask) !=0)
+ j = ULbits - j;
+ if (hi0bits(b->x[b->wds - 1]) != j) {
+ if (!lostbits)
+ lostbits = b->x[0] & 1;
+ rshift(b, 1);
+ e++;
+ }
+ }
+ }
+ else if (bdif < 0)
+ b = lshift(b, -bdif);
+ if (e < fpi->emin) {
+ k = fpi->emin - e;
+ e = fpi->emin;
+ if (k > nb || fpi->sudden_underflow) {
+ b->wds = inex = 0;
+ *irv = STRTOG_Underflow | STRTOG_Inexlo;
+ }
+ else {
+ k1 = k - 1;
+ if (k1 > 0 && !lostbits)
+ lostbits = any_on(b, k1);
+ if (!lostbits && !exact)
+ goto ret;
+ lostbits |=
+ carry = b->x[k1>>kshift] & (1 << (k1 & kmask));
+ rshift(b, k);
+ *irv = STRTOG_Denormal;
+ if (carry) {
+ b = increment(b);
+ inex = STRTOG_Inexhi | STRTOG_Underflow;
+ }
+ else if (lostbits)
+ inex = STRTOG_Inexlo | STRTOG_Underflow;
+ }
+ }
+ else if (e > fpi->emax) {
+ e = fpi->emax + 1;
+ *irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
+ SET_ERRNO(ERANGE);
+ b->wds = inex = 0;
+ }
+ *expo = e;
+ copybits(bits, nb, b);
+ *irv |= inex;
+ rv = 1;
+ ret:
+ Bfree(b);
+ return rv;
+}
+
+static int mantbits (dbl_union *d)
+{
+ ULong L;
+ if ( (L = word1(d)) !=0)
+ return P - lo0bits(&L);
+ L = word0(d) | Exp_msk1;
+ return P - 32 - lo0bits(&L);
+}
+
+int __strtodg (const char *s00, char **se, FPI *fpi, Long *expo, ULong *bits)
+{
+ int abe, abits, asub;
+ int bb0, bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, decpt, denorm;
+ int dsign, e, e1, e2, emin, esign, finished, i, inex, irv;
+ int j, k, nbits, nd, nd0, nf, nz, nz0, rd, rvbits, rve, rve1, sign;
+ int sudden_underflow;
+ const char *s, *s0, *s1;
+ double adj0, tol;
+ Long L;
+ union _dbl_union adj, rv;
+ ULong *b, *be, y, z;
+ Bigint *ab, *bb, *bb1, *bd, *bd0, *bs, *delta, *rvb, *rvb0;
+#ifdef USE_LOCALE /*{{*/
+#ifdef NO_LOCALE_CACHE
+ char *decimalpoint = localeconv()->decimal_point;
+ int dplen = strlen(decimalpoint);
+#else
+ char *decimalpoint;
+ static char *decimalpoint_cache;
+ static int dplen;
+ if (!(s0 = decimalpoint_cache)) {
+ s0 = localeconv()->decimal_point;
+ if ((decimalpoint_cache = (char*)MALLOC(strlen(s0) + 1))) {
+ strcpy(decimalpoint_cache, s0);
+ s0 = decimalpoint_cache;
+ }
+ dplen = strlen(s0);
+ }
+ decimalpoint = (char*)s0;
+#endif /*NO_LOCALE_CACHE*/
+#else /*USE_LOCALE}{*/
+#define dplen 1
+#endif /*USE_LOCALE}}*/
+
+ irv = STRTOG_Zero;
+ denorm = sign = nz0 = nz = 0;
+ dval(&rv) = 0.;
+ rvb = 0;
+ nbits = fpi->nbits;
+ for(s = s00;;s++) switch(*s) {
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ if (*++s)
+ goto break2;
+ /* no break */
+ case 0:
+ sign = 0;
+ irv = STRTOG_NoNumber;
+ s = s00;
+ goto ret;
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ continue;
+ default:
+ goto break2;
+ }
+ break2:
+ if (*s == '0') {
+#ifndef NO_HEX_FP
+ switch(s[1]) {
+ case 'x':
+ case 'X':
+ irv = gethex(&s, fpi, expo, &rvb, sign);
+ if (irv == STRTOG_NoNumber) {
+ s = s00;
+ sign = 0;
+ }
+ goto ret;
+ }
+#endif
+ nz0 = 1;
+ while(*++s == '0') ;
+ if (!*s)
+ goto ret;
+ }
+ sudden_underflow = fpi->sudden_underflow;
+ s0 = s;
+ y = z = 0;
+ for(decpt = nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 9)
+ y = 10*y + c - '0';
+ else if (nd < 16)
+ z = 10*z + c - '0';
+ nd0 = nd;
+#ifdef USE_LOCALE
+ if (c == *decimalpoint) {
+ for(i = 1; decimalpoint[i]; ++i)
+ if (s[i] != decimalpoint[i])
+ goto dig_done;
+ s += i;
+ c = *s;
+#else
+ if (c == '.') {
+ c = *++s;
+#endif
+ decpt = 1;
+ if (!nd) {
+ for(; c == '0'; c = *++s)
+ nz++;
+ if (c > '0' && c <= '9') {
+ s0 = s;
+ nf += nz;
+ nz = 0;
+ goto have_dig;
+ }
+ goto dig_done;
+ }
+ for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+ nz++;
+ if (c -= '0') {
+ nf += nz;
+ for(i = 1; i < nz; i++)
+ if (nd++ < 9)
+ y *= 10;
+ else if (nd <= DBL_DIG + 1)
+ z *= 10;
+ if (nd++ < 9)
+ y = 10*y + c;
+ else if (nd <= DBL_DIG + 1)
+ z = 10*z + c;
+ nz = 0;
+ }
+ }
+ }/*}*/
+ dig_done:
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ if (!nd && !nz && !nz0) {
+ irv = STRTOG_NoNumber;
+ s = s00;
+ goto ret;
+ }
+ s00 = s;
+ esign = 0;
+ switch(c = *++s) {
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
+ }
+ if (c >= '0' && c <= '9') {
+ while(c == '0')
+ c = *++s;
+ if (c > '0' && c <= '9') {
+ L = c - '0';
+ s1 = s;
+ while((c = *++s) >= '0' && c <= '9')
+ L = 10*L + c - '0';
+ if (s - s1 > 8 || L > 19999)
+ /* Avoid confusion from exponents
+ * so large that e might overflow.
+ */
+ e = 19999; /* safe for 16 bit ints */
+ else
+ e = (int)L;
+ if (esign)
+ e = -e;
+ }
+ else
+ e = 0;
+ }
+ else
+ s = s00;
+ }
+ if (!nd) {
+ if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+ /* Check for Nan and Infinity */
+ if (!decpt)
+ switch(c) {
+ case 'i':
+ case 'I':
+ if (match(&s,"nf")) {
+ --s;
+ if (!match(&s,"inity"))
+ ++s;
+ irv = STRTOG_Infinite;
+ goto infnanexp;
+ }
+ break;
+ case 'n':
+ case 'N':
+ if (match(&s, "an")) {
+ irv = STRTOG_NaN;
+ *expo = fpi->emax + 1;
+#ifndef No_Hex_NaN
+ if (*s == '(') /*)*/
+ irv = hexnan(&s, fpi, bits);
+#endif
+ goto infnanexp;
+ }
+ }
+#endif /* INFNAN_CHECK */
+ irv = STRTOG_NoNumber;
+ s = s00;
+ }
+ goto ret;
+ }
+
+ irv = STRTOG_Normal;
+ e1 = e -= nf;
+ rd = 0;
+ switch(fpi->rounding & 3) {
+ case FPI_Round_up:
+ rd = 2 - sign;
+ break;
+ case FPI_Round_zero:
+ rd = 1;
+ break;
+ case FPI_Round_down:
+ rd = 1 + sign;
+ }
+
+ /* Now we have nd0 digits, starting at s0, followed by a
+ * decimal point, followed by nd-nd0 digits. The number we're
+ * after is the integer represented by those digits times
+ * 10**e */
+
+ if (!nd0)
+ nd0 = nd;
+ k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+ dval(&rv) = y;
+ if (k > 9)
+ dval(&rv) = tens[k - 9] * dval(&rv) + z;
+ bd0 = 0;
+ if (nbits <= P && nd <= DBL_DIG) {
+ if (!e) {
+ if (rvOK(&rv, fpi, expo, bits, 1, rd, &irv))
+ goto ret;
+ }
+ else if (e > 0) {
+ if (e <= Ten_pmax) {
+ i = fivesbits[e] + mantbits(&rv) <= P;
+ /* rv = */ rounded_product(dval(&rv), tens[e]);
+ if (rvOK(&rv, fpi, expo, bits, i, rd, &irv))
+ goto ret;
+ e1 -= e;
+ goto rv_notOK;
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+ e2 = e - i;
+ e1 -= i;
+ dval(&rv) *= tens[i];
+ /* rv = */ rounded_product(dval(&rv), tens[e2]);
+ if (rvOK(&rv, fpi, expo, bits, 0, rd, &irv))
+ goto ret;
+ e1 -= e2;
+ }
+ }
+#ifndef Inaccurate_Divide
+ else if (e >= -Ten_pmax) {
+ /* rv = */ rounded_quotient(dval(&rv), tens[-e]);
+ if (rvOK(&rv, fpi, expo, bits, 0, rd, &irv))
+ goto ret;
+ e1 -= e;
+ }
+#endif
+ }
+ rv_notOK:
+ e1 += nd - k;
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ e2 = 0;
+ if (e1 > 0) {
+ if ( (i = e1 & 15) !=0)
+ dval(&rv) *= tens[i];
+ if (e1 &= ~15) {
+ e1 >>= 4;
+ while(e1 >= (1 << (n_bigtens-1))) {
+ e2 += ((word0(&rv) & Exp_mask)
+ >> Exp_shift1) - Bias;
+ word0(&rv) &= ~Exp_mask;
+ word0(&rv) |= Bias << Exp_shift1;
+ dval(&rv) *= bigtens[n_bigtens-1];
+ e1 -= 1 << (n_bigtens-1);
+ }
+ e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias;
+ word0(&rv) &= ~Exp_mask;
+ word0(&rv) |= Bias << Exp_shift1;
+ for(j = 0; e1 > 0; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(&rv) *= bigtens[j];
+ }
+ }
+ else if (e1 < 0) {
+ e1 = -e1;
+ if ( (i = e1 & 15) !=0)
+ dval(&rv) /= tens[i];
+ if (e1 &= ~15) {
+ e1 >>= 4;
+ while(e1 >= (1 << (n_bigtens-1))) {
+ e2 += ((word0(&rv) & Exp_mask)
+ >> Exp_shift1) - Bias;
+ word0(&rv) &= ~Exp_mask;
+ word0(&rv) |= Bias << Exp_shift1;
+ dval(&rv) *= tinytens[n_bigtens-1];
+ e1 -= 1 << (n_bigtens-1);
+ }
+ e2 += ((word0(&rv) & Exp_mask) >> Exp_shift1) - Bias;
+ word0(&rv) &= ~Exp_mask;
+ word0(&rv) |= Bias << Exp_shift1;
+ for(j = 0; e1 > 0; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(&rv) *= tinytens[j];
+ }
+ }
+ rvb = d2b(dval(&rv), &rve, &rvbits); /* rv = rvb * 2^rve */
+ rve += e2;
+ if ((j = rvbits - nbits) > 0) {
+ rshift(rvb, j);
+ rvbits = nbits;
+ rve += j;
+ }
+ bb0 = 0; /* trailing zero bits in rvb */
+ e2 = rve + rvbits - nbits;
+ if (e2 > fpi->emax + 1)
+ goto huge;
+ rve1 = rve + rvbits - nbits;
+ if (e2 < (emin = fpi->emin)) {
+ denorm = 1;
+ j = rve - emin;
+ if (j > 0) {
+ rvb = lshift(rvb, j);
+ rvbits += j;
+ }
+ else if (j < 0) {
+ rvbits += j;
+ if (rvbits <= 0) {
+ if (rvbits < -1) {
+ ufl:
+ rvb->wds = 0;
+ rvb->x[0] = 0;
+ *expo = emin;
+ irv = STRTOG_Underflow | STRTOG_Inexlo;
+ goto ret;
+ }
+ rvb->x[0] = rvb->wds = rvbits = 1;
+ }
+ else
+ rshift(rvb, -j);
+ }
+ rve = rve1 = emin;
+ if (sudden_underflow && e2 + 1 < emin)
+ goto ufl;
+ }
+
+ /* Now the hard part -- adjusting rv to the correct value.*/
+
+ /* Put digits into bd: true value = bd * 10^e */
+
+ bd0 = s2b(s0, nd0, nd, y, dplen);
+
+ for(;;) {
+ bd = Balloc(bd0->k);
+ Bcopy(bd, bd0);
+ bb = Balloc(rvb->k);
+ Bcopy(bb, rvb);
+ bbbits = rvbits - bb0;
+ bbe = rve + bb0;
+ bs = i2b(1);
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ }
+ else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+ j = nbits + 1 - bbbits;
+ i = bbe + bbbits - nbits;
+ if (i < emin) /* denormal */
+ j += i - emin;
+ bb2 += j;
+ bd2 += j;
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+ if (bb5 > 0) {
+ bs = pow5mult(bs, bb5);
+ bb1 = mult(bs, bb);
+ Bfree(bb);
+ bb = bb1;
+ }
+ bb2 -= bb0;
+ if (bb2 > 0)
+ bb = lshift(bb, bb2);
+ else if (bb2 < 0)
+ rshift(bb, -bb2);
+ if (bd5 > 0)
+ bd = pow5mult(bd, bd5);
+ if (bd2 > 0)
+ bd = lshift(bd, bd2);
+ if (bs2 > 0)
+ bs = lshift(bs, bs2);
+ asub = 1;
+ inex = STRTOG_Inexhi;
+ delta = diff(bb, bd);
+ if (delta->wds <= 1 && !delta->x[0])
+ break;
+ dsign = delta->sign;
+ delta->sign = finished = 0;
+ L = 0;
+ i = cmp(delta, bs);
+ if (rd && i <= 0) {
+ irv = STRTOG_Normal;
+ if ( (finished = dsign ^ (rd&1)) !=0) {
+ if (dsign != 0) {
+ irv |= STRTOG_Inexhi;
+ goto adj1;
+ }
+ irv |= STRTOG_Inexlo;
+ if (rve1 == emin)
+ goto adj1;
+ for(i = 0, j = nbits; j >= ULbits;
+ i++, j -= ULbits) {
+ if (rvb->x[i] & ALL_ON)
+ goto adj1;
+ }
+ if (j > 1 && lo0bits(rvb->x + i) < j - 1)
+ goto adj1;
+ rve = rve1 - 1;
+ rvb = set_ones(rvb, rvbits = nbits);
+ break;
+ }
+ irv |= dsign ? STRTOG_Inexlo : STRTOG_Inexhi;
+ break;
+ }
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ irv = dsign
+ ? STRTOG_Normal | STRTOG_Inexlo
+ : STRTOG_Normal | STRTOG_Inexhi;
+ if (dsign || bbbits > 1 || denorm || rve1 == emin)
+ break;
+ delta = lshift(delta,1);
+ if (cmp(delta, bs) > 0) {
+ irv = STRTOG_Normal | STRTOG_Inexlo;
+ goto drop_down;
+ }
+ break;
+ }
+ if (i == 0) {
+ /* exactly half-way between */
+ if (dsign) {
+ if (denorm && all_on(rvb, rvbits)) {
+ /*boundary case -- increment exponent*/
+ rvb->wds = 1;
+ rvb->x[0] = 1;
+ rve = emin + nbits - (rvbits = 1);
+ irv = STRTOG_Normal | STRTOG_Inexhi;
+ denorm = 0;
+ break;
+ }
+ irv = STRTOG_Normal | STRTOG_Inexlo;
+ }
+ else if (bbbits == 1) {
+ irv = STRTOG_Normal;
+ drop_down:
+ /* boundary case -- decrement exponent */
+ if (rve1 == emin) {
+ irv = STRTOG_Normal | STRTOG_Inexhi;
+ if (rvb->wds == 1 && rvb->x[0] == 1)
+ sudden_underflow = 1;
+ break;
+ }
+ rve -= nbits;
+ rvb = set_ones(rvb, rvbits = nbits);
+ break;
+ }
+ else
+ irv = STRTOG_Normal | STRTOG_Inexhi;
+ if ((bbbits < nbits && !denorm) || !(rvb->x[0] & 1))
+ break;
+ if (dsign) {
+ rvb = increment(rvb);
+ j = kmask & (ULbits - (rvbits & kmask));
+ if (hi0bits(rvb->x[rvb->wds - 1]) != j)
+ rvbits++;
+ irv = STRTOG_Normal | STRTOG_Inexhi;
+ }
+ else {
+ if (bbbits == 1)
+ goto undfl;
+ decrement(rvb);
+ irv = STRTOG_Normal | STRTOG_Inexlo;
+ }
+ break;
+ }
+ if ((dval(&adj) = ratio(delta, bs)) <= 2.) {
+ adj1:
+ inex = STRTOG_Inexlo;
+ if (dsign) {
+ asub = 0;
+ inex = STRTOG_Inexhi;
+ }
+ else if (denorm && bbbits <= 1) {
+ undfl:
+ rvb->wds = 0;
+ rve = emin;
+ irv = STRTOG_Underflow | STRTOG_Inexlo;
+ break;
+ }
+ adj0 = dval(&adj) = 1.;
+ }
+ else {
+ adj0 = dval(&adj) *= 0.5;
+ if (dsign) {
+ asub = 0;
+ inex = STRTOG_Inexlo;
+ }
+ if (dval(&adj) < 2147483647.) {
+ L = adj0;
+ adj0 -= L;
+ switch(rd) {
+ case 0:
+ if (adj0 >= .5)
+ goto inc_L;
+ break;
+ case 1:
+ if (asub && adj0 > 0.)
+ goto inc_L;
+ break;
+ case 2:
+ if (!asub && adj0 > 0.) {
+ inc_L:
+ L++;
+ inex = STRTOG_Inexact - inex;
+ }
+ }
+ dval(&adj) = L;
+ }
+ }
+ y = rve + rvbits;
+
+ /* adj *= ulp(&rv); */
+ /* if (asub) rv -= adj; else rv += adj; */
+
+ if (!denorm && rvbits < nbits) {
+ rvb = lshift(rvb, j = nbits - rvbits);
+ rve -= j;
+ rvbits = nbits;
+ }
+ ab = d2b(dval(&adj), &abe, &abits);
+ if (abe < 0)
+ rshift(ab, -abe);
+ else if (abe > 0)
+ ab = lshift(ab, abe);
+ rvb0 = rvb;
+ if (asub) {
+ /* rv -= adj; */
+ j = hi0bits(rvb->x[rvb->wds-1]);
+ rvb = diff(rvb, ab);
+ k = rvb0->wds - 1;
+ if (denorm)
+ /* do nothing */;
+ else if (rvb->wds <= k
+ || hi0bits( rvb->x[k]) >
+ hi0bits(rvb0->x[k])) {
+ /* unlikely; can only have lost 1 high bit */
+ if (rve1 == emin) {
+ --rvbits;
+ denorm = 1;
+ }
+ else {
+ rvb = lshift(rvb, 1);
+ --rve;
+ --rve1;
+ L = finished = 0;
+ }
+ }
+ }
+ else {
+ rvb = sum(rvb, ab);
+ k = rvb->wds - 1;
+ if (k >= rvb0->wds
+ || hi0bits(rvb->x[k]) < hi0bits(rvb0->x[k])) {
+ if (denorm) {
+ if (++rvbits == nbits)
+ denorm = 0;
+ }
+ else {
+ rshift(rvb, 1);
+ rve++;
+ rve1++;
+ L = 0;
+ }
+ }
+ }
+ Bfree(ab);
+ Bfree(rvb0);
+ if (finished)
+ break;
+
+ z = rve + rvbits;
+ if (y == z && L) {
+ /* Can we stop now? */
+ tol = dval(&adj) * 5e-16; /* > max rel error */
+ dval(&adj) = adj0 - .5;
+ if (dval(&adj) < -tol) {
+ if (adj0 > tol) {
+ irv |= inex;
+ break;
+ }
+ }
+ else if (dval(&adj) > tol && adj0 < 1. - tol) {
+ irv |= inex;
+ break;
+ }
+ }
+ bb0 = denorm ? 0 : trailz(rvb);
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(delta);
+ }
+ if (!denorm && (j = nbits - rvbits)) {
+ if (j > 0)
+ rvb = lshift(rvb, j);
+ else
+ rshift(rvb, -j);
+ rve -= j;
+ }
+ *expo = rve;
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ if (rve > fpi->emax) {
+ switch(fpi->rounding & 3) {
+ case FPI_Round_near:
+ goto huge;
+ case FPI_Round_up:
+ if (!sign)
+ goto huge;
+ break;
+ case FPI_Round_down:
+ if (sign)
+ goto huge;
+ }
+ /* Round to largest representable magnitude */
+ Bfree(rvb);
+ rvb = 0;
+ irv = STRTOG_Normal | STRTOG_Inexlo;
+ *expo = fpi->emax;
+ b = bits;
+ be = b + ((fpi->nbits + 31) >> 5);
+ while(b < be)
+ *b++ = -1;
+ if ((j = fpi->nbits & 0x1f))
+ *--be >>= (32 - j);
+ goto ret;
+ huge:
+ rvb->wds = 0;
+ irv = STRTOG_Infinite | STRTOG_Overflow | STRTOG_Inexhi;
+ SET_ERRNO(ERANGE);
+ infnanexp:
+ *expo = fpi->emax + 1;
+ }
+ ret:
+ if (denorm) {
+ if (sudden_underflow) {
+ rvb->wds = 0;
+ irv = STRTOG_Underflow | STRTOG_Inexlo;
+ SET_ERRNO(ERANGE);
+ }
+ else {
+ irv = (irv & ~STRTOG_Retmask) |
+ (rvb->wds > 0 ? STRTOG_Denormal : STRTOG_Zero);
+ if (irv & STRTOG_Inexact) {
+ irv |= STRTOG_Underflow;
+ SET_ERRNO(ERANGE);
+ }
+ }
+ }
+ if (se)
+ *se = (char *)s;
+ if (sign)
+ irv |= STRTOG_Neg;
+ if (rvb) {
+ copybits(bits, nbits, rvb);
+ Bfree(rvb);
+ }
+ return irv;
+}
diff --git a/src/lib/evil/gdtoa/strtof.c b/src/lib/evil/gdtoa/strtof.c
new file mode 100644
index 0000000000..71be2225f5
--- /dev/null
+++ b/src/lib/evil/gdtoa/strtof.c
@@ -0,0 +1,77 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+float __evil_strtof (const char *s, char **sp)
+{
+ static FPI fpi0 = { 24, 1-127-24+1, 254-127-24+1, 1, SI, Int_max };
+ ULong bits[1];
+ Long expo;
+ int k;
+ union { ULong L[1]; float f; } u = { { 0 } };
+#ifdef Honor_FLT_ROUNDS
+#include "gdtoa_fltrnds.h"
+#else
+#define fpi &fpi0
+#endif
+
+ k = __strtodg(s, sp, fpi, &expo, bits);
+ switch(k & STRTOG_Retmask) {
+ case STRTOG_NoNumber:
+ case STRTOG_Zero:
+ u.L[0] = 0;
+ break;
+
+ case STRTOG_Normal:
+ case STRTOG_NaNbits:
+ u.L[0] = (bits[0] & 0x7fffff) | ((expo + 0x7f + 23) << 23);
+ break;
+
+ case STRTOG_Denormal:
+ u.L[0] = bits[0];
+ break;
+
+ case STRTOG_Infinite:
+ u.L[0] = 0x7f800000;
+ break;
+
+ case STRTOG_NaN:
+ u.L[0] = f_QNAN;
+ }
+ if (k & STRTOG_Neg)
+ u.L[0] |= 0x80000000L;
+ return u.f;
+}
+
+/* float __cdecl */
+/* __evil_strtof (const char * __restrict__ src, char ** __restrict__ endptr) */
+/* __attribute__((alias("__strtof"))); */
diff --git a/src/lib/evil/gdtoa/strtopx.c b/src/lib/evil/gdtoa/strtopx.c
new file mode 100644
index 0000000000..68b3ab3121
--- /dev/null
+++ b/src/lib/evil/gdtoa/strtopx.c
@@ -0,0 +1,119 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 2000 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+#undef _0
+#undef _1
+
+/* one or the other of IEEE_MC68k or IEEE_8087 should be #defined */
+
+#ifdef IEEE_MC68k
+#define _0 0
+#define _1 1
+#define _2 2
+#define _3 3
+#define _4 4
+#endif
+#ifdef IEEE_8087
+#define _0 4
+#define _1 3
+#define _2 2
+#define _3 1
+#define _4 0
+#endif
+
+typedef union lD {
+ UShort L[5];
+ long double D;
+} lD;
+
+static int __strtopx (const char *s, char **sp, lD *V)
+{
+ static FPI fpi0 = { 64, 1-16383-64+1, 32766 - 16383 - 64 + 1, 1, SI, Int_max };
+ ULong bits[2];
+ Long expo;
+ int k;
+ UShort *L = & (V->L[0]);
+#ifdef Honor_FLT_ROUNDS
+#include "gdtoa_fltrnds.h"
+#else
+#define fpi &fpi0
+#endif
+ V->D = 0.0L;
+
+ k = __strtodg(s, sp, fpi, &expo, bits);
+ switch(k & STRTOG_Retmask) {
+ case STRTOG_NoNumber:
+ case STRTOG_Zero:
+ L[0] = L[1] = L[2] = L[3] = L[4] = 0;
+ break;
+
+ case STRTOG_Denormal:
+ L[_0] = 0;
+ goto normal_bits;
+
+ case STRTOG_Normal:
+ case STRTOG_NaNbits:
+ L[_0] = expo + 0x3fff + 63;
+ normal_bits:
+ L[_4] = (UShort)bits[0];
+ L[_3] = (UShort)(bits[0] >> 16);
+ L[_2] = (UShort)bits[1];
+ L[_1] = (UShort)(bits[1] >> 16);
+ break;
+
+ case STRTOG_Infinite:
+ L[_0] = 0x7fff;
+ L[_1] = 0x8000;
+ L[_2] = L[_3] = L[_4] = 0;
+ break;
+
+ case STRTOG_NaN:
+ L[0] = ldus_QNAN0;
+ L[1] = ldus_QNAN1;
+ L[2] = ldus_QNAN2;
+ L[3] = ldus_QNAN3;
+ L[4] = ldus_QNAN4;
+ }
+ if (k & STRTOG_Neg)
+ L[_0] |= 0x8000;
+ return k;
+}
+
+long double __cdecl
+__evil_strtold (const char * __restrict__ src, char ** __restrict__ endptr)
+{
+ lD ret;
+ ret.D = 0.0L;
+ __strtopx(src, endptr, &ret);
+ return ret.D;
+}
diff --git a/src/lib/evil/gdtoa/sum.c b/src/lib/evil/gdtoa/sum.c
new file mode 100644
index 0000000000..8823541ea6
--- /dev/null
+++ b/src/lib/evil/gdtoa/sum.c
@@ -0,0 +1,91 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+Bigint *sum (Bigint *a, Bigint *b)
+{
+ Bigint *c;
+ ULong carry, *xc, *xa, *xb, *xe, y;
+#ifdef Pack_32
+ ULong z;
+#endif
+
+ if (a->wds < b->wds) {
+ c = b; b = a; a = c;
+ }
+ c = Balloc(a->k);
+ c->wds = a->wds;
+ carry = 0;
+ xa = a->x;
+ xb = b->x;
+ xc = c->x;
+ xe = xc + b->wds;
+#ifdef Pack_32
+ do {
+ y = (*xa & 0xffff) + (*xb & 0xffff) + carry;
+ carry = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) + (*xb++ >> 16) + carry;
+ carry = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ } while(xc < xe);
+ xe += a->wds - b->wds;
+ while(xc < xe) {
+ y = (*xa & 0xffff) + carry;
+ carry = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) + carry;
+ carry = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+#else
+ do {
+ y = *xa++ + *xb++ + carry;
+ carry = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ } while(xc < xe);
+ xe += a->wds - b->wds;
+ while(xc < xe) {
+ y = *xa++ + carry;
+ carry = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ }
+#endif
+ if (carry) {
+ if (c->wds == c->maxwds) {
+ b = Balloc(c->k + 1);
+ Bcopy(b, c);
+ Bfree(c);
+ c = b;
+ }
+ c->x[c->wds++] = 1;
+ }
+ return c;
+}
diff --git a/src/lib/evil/gdtoa/ulp.c b/src/lib/evil/gdtoa/ulp.c
new file mode 100644
index 0000000000..bfa9bdeeaf
--- /dev/null
+++ b/src/lib/evil/gdtoa/ulp.c
@@ -0,0 +1,61 @@
+/****************************************************************
+
+The author of this software is David M. Gay.
+
+Copyright (C) 1998, 1999 by Lucent Technologies
+All Rights Reserved
+
+Permission to use, copy, modify, and distribute this software and
+its documentation for any purpose and without fee is hereby
+granted, provided that the above copyright notice appear in all
+copies and that both that the copyright notice and this
+permission notice and warranty disclaimer appear in supporting
+documentation, and that the name of Lucent or any of its entities
+not be used in advertising or publicity pertaining to
+distribution of the software without specific, written prior
+permission.
+
+LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
+IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
+SPECIAL, 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.
+
+****************************************************************/
+
+/* Please send bug reports to David M. Gay (dmg at acm dot org,
+ * with " at " changed at "@" and " dot " changed to "."). */
+
+#include "gdtoaimp.h"
+
+double ulp (dbl_union *x)
+{
+ Long L;
+ union _dbl_union a;
+
+ L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Sudden_Underflow
+ if (L > 0) {
+#endif
+ word0(&a) = L;
+ word1(&a) = 0;
+#ifndef Sudden_Underflow
+ }
+ else {
+ L = -L >> Exp_shift;
+ if (L < Exp_shift) {
+ word0(&a) = 0x80000 >> L;
+ word1(&a) = 0;
+ }
+ else {
+ word0(&a) = 0;
+ L -= Exp_shift;
+ word1(&a) = L >= 31 ? 1 : 1 << (31 - L);
+ }
+ }
+#endif
+ return dval(&a);
+}
diff --git a/src/lib/evil/mingw32ce/errno.h b/src/lib/evil/mingw32ce/errno.h
new file mode 100644
index 0000000000..5e8f3d7cbd
--- /dev/null
+++ b/src/lib/evil/mingw32ce/errno.h
@@ -0,0 +1,111 @@
+#ifndef __EVIL_ERRNO_H__
+#define __EVIL_ERRNO_H__
+
+#ifdef EAPI
+# undef EAPI
+#endif /* EAPI */
+
+#ifdef _WIN32
+# ifdef EFL_EVIL_BUILD
+# ifdef DLL_EXPORT
+# define EAPI __declspec(dllexport)
+# else
+# define EAPI
+# endif /* ! DLL_EXPORT */
+# else
+# define EAPI __declspec(dllimport)
+# endif /* ! EFL_EVIL_BUILD */
+#endif /* _WIN32 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern EAPI int errno;
+
+/* Fake values */
+#define E2BIG 1
+#define EACCES 2
+#define EAGAIN 3
+#define EBADF 4
+#define EBADMSG 5
+#define EBUSY 6
+#define ECANCELED 7
+#define ECHILD 9
+#define EDEADLK 10
+#define EDOM 11
+#define EEXIST 12
+#define EFAULT 13
+#define EFBIG 14
+#define EINPROGRESS 15
+#define EINTR 16
+#define EINVAL 17
+#define EIO 18
+#define EISDIR 19
+#define EMFILE 20
+#define EMLINK 21
+#define EMSGSIZE 22
+#define ENAMETOOLONG 23
+#define ENFILE 24
+#define ENODEV 25
+#define ENOENT 26
+#define ENOEXEC 27
+#define ENOLCK 28
+#define ENOMEM 29
+#define ENOSPC 30
+#define ENOSYS 31
+#define ENOTDIR 32
+#define ENOTEMPTY 33
+#define ENOTSUP 34
+#define ENOTTY 35
+#define ENXIO 36
+#define EPERM 37
+#define EPIPE 38
+#define ERANGE 39
+#define EROFS 40
+#define ESPIPE 41
+#define ESRCH 42
+#define ETIMEDOUT 43
+#define EXDEV 44
+#define EADDRINUSE 45
+#define EADDRNOTAVAIL 46
+#define EAFNOSUPPORT 47
+#define EALREADY 48
+#define ECONNABORTED 49
+#define ECONNREFUSED 50
+#define ECONNRESET 51
+#define EDESTADDRREQ 52
+#define EDQUOT 53
+#define EHOSTUNREACH 54
+#define EIDRM 55
+#define EILSEQ 56
+#define EISCONN 57
+#define ELOOP 58
+#define EMULTIHOP 59
+#define ENETDOWN 60
+#define ENETRESET 61
+#define ENETUNREACH 62
+#define ENOBUFS 63
+#define ENODATA 64
+#define ENOLINK 65
+#define ENOMSG 66
+#define ENOPROTOOPT 67
+#define ENOSR 68
+#define ENOSTR 69
+#define ENOTCONN 70
+#define ENOTSOCK 71
+#define EOPNOTSUPP 72
+#define EOVERFLOW 73
+#define EPROTO 74
+#define EPROTONOSUPPORT 75
+#define EPROTOTYPE 76
+#define ESTALE 77
+#define ETIME 78
+#define ETXTBSY 79
+#define EWOULDBLOCK 80
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __EVIL_ERRNO_H__ */
diff --git a/src/lib/evil/pwd.h b/src/lib/evil/pwd.h
new file mode 100644
index 0000000000..e7907cacbd
--- /dev/null
+++ b/src/lib/evil/pwd.h
@@ -0,0 +1,71 @@
+#ifndef __EVIL_PWD_H__
+#define __EVIL_PWD_H__
+
+
+/**
+ * @file pwd.h
+ * @brief The file that provides functions ported from Unix in pwd.h.
+ * @defgroup Evil_Pwd_Group Pwd.h functions
+ *
+ * This header provides functions ported from Unix in dirent.h.
+ *
+ * @{
+ */
+
+
+#include <time.h>
+
+#include <Evil.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @struct passwd
+ * @brief A structure that describes a password.
+ */
+struct passwd {
+ char *pw_name; /**< user name */
+ char *pw_passwd; /**< encrypted password (always @c NULL) */
+ uid_t pw_uid; /**< user uid */
+ gid_t pw_gid; /**< user gid (always O) */
+ time_t pw_change; /**< password change time (always 0) */
+ char *pw_class; /**< user access class (always @c NULL) */
+ char *pw_gecos; /**< Honeywell login info */
+ char *pw_dir; /**< home directory */
+ char *pw_shell; /**< default shell */
+ time_t pw_expire; /**< account expiration (always O) */
+ int pw_fields; /**< internal: fields filled in (always O) */
+};
+
+/**
+ * @brief Return a passwd structure.
+ *
+ * @param uid The User ID
+ * @return A stacally allocated passwd structure.
+ *
+ * This function fills a static buffer @ref passwd with @p uid and the
+ * user name.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows XP, CE.
+ */
+EAPI struct passwd *getpwuid (uid_t uid);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __EVIL_PWD_H__ */
diff --git a/src/lib/evil/sys/mman.h b/src/lib/evil/sys/mman.h
new file mode 100644
index 0000000000..c53437f001
--- /dev/null
+++ b/src/lib/evil/sys/mman.h
@@ -0,0 +1,149 @@
+#ifndef __EVIL_SYS_MMAN_H__
+#define __EVIL_SYS_MMAN_H__
+
+#include <evil_macro.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * @def PROT_NONE
+ * Data can not be accessed.
+ */
+
+/**
+ * @def PROT_READ
+ * Data can be read.
+ */
+
+/**
+ * @def PROT_WRITE
+ * Data can be written.
+ */
+
+/**
+ * @def PROT_EXEC
+ * Data can be executed.
+ */
+
+#define PROT_NONE 0x00
+#define PROT_READ 0x01
+#define PROT_WRITE 0x02
+#define PROT_EXEC 0x04
+
+/**
+ * @def MAP_SHARED
+ * Changes are shared.
+ */
+
+/**
+ * @def MAP_PRIVATE
+ * Changes are private.
+ */
+
+/**
+ * @def MAP_FIXED
+ * Interpret the address (addr) exactly.
+ */
+
+/**
+ * @def MAP_FAILED
+ * Error return from mmap().
+ */
+
+#define MAP_SHARED 0x0001
+#define MAP_PRIVATE 0x0002
+#define MAP_FIXED 0x0010
+
+#define MAP_FAILED ((void *)-1)
+
+
+/**
+ * @file mman.h
+ * @brief The file that provides the memory map functions
+ * @defgroup Mman Functions that manage memory mappping.
+ *
+ * This header provides the meomry map functions mmap and munmap.
+ *
+ */
+
+/**
+ * Creates or opens a named or unnamed file mapping object for a
+ * specified file and maps a view of a file mapping into the
+ * address space of a calling process.
+ *
+ * @param addr Unused
+ * @param len Number of bytes to be mapped.
+ * @param prot Protections.
+ * @param flags Type of the mapped object.
+ * @param fd File descriptor that describes the object to map.
+ * @param offset Number of bytes from which to start the mapping.
+ * @return The starting address of the mapped view on success, -1 otherwise.
+ *
+ * Create or open an unnamed file mapping object for a specified
+ * file described by the file descriptor @p fd. The number of
+ * bytes that are mapped is given by @p len and start after
+ * @p offset bytes. The parameter @p addr is unused.
+ *
+ * The only type of the mapped object that is supported is
+ * @c MAP_SHARED. If another value if given, -1 is returned.
+ *
+ * @p prot specifies the protection of the mapped region. If
+ * PROT_EXEC is used, it set the execute access. If PROT_READ
+ * is used, it sets the read access. If PROT_WRITE is used, it
+ * sets the write access.
+ *
+ * If the map view of file can not be created, -1 is returned.
+ * If the mappping can not be done, -1 is returned.
+ *
+ * If no error occured, the starting address of the mapped view
+ * is returned.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows Vista, Windows XP or Windows 2000
+ * Professional.
+ *
+ * @ingroup Mman
+ */
+EAPI void *mmap(void *addr,
+ size_t len,
+ int prot,
+ int flags,
+ int fd,
+ off_t offset);
+
+/**
+ * Unmaps a mapped view of a file from the calling process's
+ * address space.
+ *
+ * @param addr Pointer to the base address.
+ * @param len Unused.
+ * @return 0 on success, -1 otherwise.
+ *
+ * Unmaps a mapped view of a file from the calling process's
+ * address space. @p addr is the pointer to the base address.
+ * This value must be identical to the value returned by a
+ * previous call to mmap(). The parameter @p len is unsed.
+ *
+ * Conformity: None.
+ *
+ * Supported OS: Windows Vista, Windows XP or Windows 2000
+ * Professional.
+ *
+ * @ingroup Mman
+ */
+EAPI int munmap(void *addr,
+ size_t len);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+#endif /* __EVIL_SYS_MMAN_H__ */
+