Include a stripped-down version of FLTK in tree and add a USE_INCLUDED_FLTK option to build against it.


git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@4603 3789f03b-4d11-0410-bbf8-ca57d06f2519
diff --git a/common/fltk/src/fl_utf8.cxx b/common/fltk/src/fl_utf8.cxx
new file mode 100644
index 0000000..5533532
--- /dev/null
+++ b/common/fltk/src/fl_utf8.cxx
@@ -0,0 +1,850 @@
+//
+// "$Id: fl_utf8.cxx 7975 2010-12-08 12:15:48Z AlbrechtS $"
+//
+// Unicode to UTF-8 conversion functions.
+//
+// Author: Jean-Marc Lienher ( http://oksid.ch )
+// Copyright 2000-2010 by O'ksi'D.
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+// USA.
+//
+// Please report all bugs and problems on the following page:
+//
+//     http://www.fltk.org/str.php
+
+
+#include <config.h>
+#include <FL/filename.H>
+#include <stdarg.h>
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+# include <ctype.h>
+# include <io.h>
+# include <windows.h>
+# include <winbase.h>
+# include <process.h>
+#ifdef __CYGWIN__
+#include  <wchar.h>
+#else
+#include  <direct.h>
+#endif
+extern "C" {
+  int XUtf8Tolower(int ucs);
+  unsigned short XUtf8IsNonSpacing(unsigned int ucs);
+};
+
+#elif defined(__APPLE__)
+# include <stdio.h>
+# include <time.h>
+//# include <unix.h>
+# include <fcntl.h>
+# include <unistd.h>
+# include <wchar.h>
+# include <stdlib.h>
+#   include <sys/types.h>
+# include <sys/stat.h>
+
+extern "C" {
+  int XUtf8Tolower(int ucs);
+  unsigned short XUtf8IsNonSpacing(unsigned int ucs);
+}
+
+#else // X-windows platform
+
+# include <FL/Xutf8.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# include <fcntl.h>
+# include <unistd.h>
+#endif // WIN32
+
+#include <FL/fl_utf8.h>
+#include <string.h>
+#include <stdlib.h>
+
+#undef fl_open
+
+/** \addtogroup fl_unicode
+    @{
+*/
+
+/*** NOTE : all functions are LIMITED to 24 bits Unicode values !!! ***/
+/***        but only 16 bits are really used under Linux and win32  ***/
+
+
+#define NBC 0xFFFF + 1
+
+static int
+Toupper(
+	int ucs)
+{
+	long i;
+	static unsigned short *table = NULL;
+
+	if (!table) {
+		table = (unsigned short*) malloc(
+			sizeof(unsigned short) * (NBC));
+		for (i = 0; i < NBC; i++) {
+			table[i] = (unsigned short) i;
+		}
+		for (i = 0; i < NBC; i++) {
+			int l;
+			l = XUtf8Tolower(i);
+			if (l != i) table[l] = (unsigned short) i;
+		}
+
+	}
+	if (ucs >= NBC || ucs < 0) return ucs;
+	return table[ucs];
+}
+
+/**
+ return the byte length of the UTF-8 sequence with first byte \p c,
+ or -1 if \p c is not valid.
+ This function is helpful for finding faulty UTF8 sequences.
+ \see fl_utf8len1
+ */
+int fl_utf8len(char c)
+{
+  if (!(c & 0x80)) return 1;
+  if (c & 0x40) {
+    if (c & 0x20) {
+      if (c & 0x10) {
+        if (c & 0x08) {
+          if (c & 0x04) {
+            return 6;
+          }
+          return 5;
+        }
+        return 4;
+      }
+      return 3;
+    }
+    return 2;
+  }
+  return -1;
+} // fl_utf8len
+
+
+/**
+ Return the byte length of the UTF-8 sequence with first byte \p c,
+ or 1 if \p c is not valid. 
+ This function can be used to scan faulty UTF8 sequence, albeit ignoring invalid
+ codes.
+ \see fl_utf8len
+ */
+int fl_utf8len1(char c)
+{
+  if (!(c & 0x80)) return 1;
+  if (c & 0x40) {
+    if (c & 0x20) {
+      if (c & 0x10) {
+        if (c & 0x08) {
+          if (c & 0x04) {
+            return 6;
+          }
+          return 5;
+        }
+        return 4;
+      }
+      return 3;
+    }
+    return 2;
+  }
+  return 1;
+} // fl_utf8len1
+
+
+/**
+  returns the number of Unicode chars in the UTF-8 string
+  */
+int
+fl_utf_nb_char(
+	const unsigned char 	*buf,
+	int 			len)
+{
+	int i = 0;
+	int nbc = 0;
+	while (i < len) {
+		int cl = fl_utf8len((buf+i)[0]);//fl_utflen(buf + i, len - i);
+		if (cl < 1) cl = 1;
+		nbc++;
+		i += cl;
+	}
+	return nbc;
+}
+
+/*
+ * compare only the first n bytes
+ * return 0 if the strings are equal;
+ * return 1 if s1 is greater than s2
+ * return -1 if s1 is less than s2
+ */
+/**
+  UTF-8 aware strncasecmp - converts to lower case Unicode and tests.
+
+  \todo Correct the incorrect logic where length of strings tested
+  \todo Clarify whether n means number of bytes, or characters.
+  */
+int fl_utf_strncasecmp(const char *s1, const char *s2, int n)
+{
+        int i;
+        int s1_l;
+        int s2_l;
+        char *e1, *e2; // string end pointers
+
+        s1_l = 0;
+        while (s1_l < n && s1[s1_l]) s1_l++;
+        s2_l = 0;
+        while (s2_l < n && s2[s2_l]) s2_l++;
+
+        if (s1_l < s2_l) {
+                return -1;
+        } else if (s1_l > s2_l) {
+                return 1;
+        }
+		e1 = (char *)&s1[s1_l]; // last char to test
+		e2 = (char *)&s2[s2_l];
+        for (i = 0; i < n;) {
+                int l1, l2;
+                unsigned int u1, u2;
+                int res;
+
+//              l1 = fl_utf2ucs((unsigned char*)s1 + i, n - i, &u1);
+                u1 = fl_utf8decode(s1 + i, e1, &l1);
+//              l2 = fl_utf2ucs((unsigned char*)s2 + i, n - i, &u2);
+                u2 = fl_utf8decode(s2 + i, e2, &l2);
+                if (l1 - l2 != 0) return l1 - l2;
+                res = XUtf8Tolower(u1) - XUtf8Tolower(u2);
+                if (res != 0) return res;
+                if (l1 < 1) {
+                        i += 1;
+                } else {
+                        i += l1;
+                }
+        }
+        return 0;
+}
+
+/*
+ * return 0 if the strings are equal;
+ * return 1 if s1 is greater than s2
+ * return -1 if s1 is less than s2
+ */
+/**
+  UTF-8 aware strcasecmp - converts to Unicode and tests.
+
+  \todo Correct the incorrect logic where length of strings tested
+  */
+int fl_utf_strcasecmp(const char *s1, const char *s2)
+{
+	int s1_l = strlen(s1);
+	int s2_l = strlen(s2);
+
+        if (s1_l < s2_l) {
+                return -1;
+        } else if (s1_l > s2_l) {
+                return 1;
+	}
+	return fl_utf_strncasecmp(s1, s2, s1_l);
+}
+
+/**
+  return the Unicode lower case value of \p ucs
+  */
+int fl_tolower(unsigned int ucs)
+{
+	return XUtf8Tolower(ucs);
+}
+
+/**
+  return the Unicode upper case value of \p ucs
+  */
+int fl_toupper(unsigned int ucs)
+{
+	return Toupper(ucs);
+}
+
+/**
+  converts the str string to the lower case equivalent into buf.
+  Warning: to be safe buf length must be at least 3 * len [for 16-bit Unicode]
+  */
+int fl_utf_tolower(const unsigned char *str, int len, char *buf)
+{
+	int i;
+	int l = 0;
+	char *end = (char *)&str[len];
+        for (i = 0; i < len;) {
+                int l1, l2;
+                unsigned int u1;
+
+//              l1 = fl_utf2ucs((unsigned char*)str + i, len - i, &u1);
+                u1 = fl_utf8decode((const char*)(str + i), end, &l1);
+                l2 = fl_utf8encode((unsigned int) XUtf8Tolower(u1), buf + l);
+                if (l1 < 1) {
+                        i += 1;
+                } else {
+                        i += l1;
+		}
+                if (l2 < 1) {
+                        l += 1;
+                } else {
+                        l += l2;
+		}
+
+	}
+	return l;
+}
+
+/**
+  converts the str string to the upper case equivalent into buf.
+  Warning: to be safe buf length must be at least 3 * len [for 16-bit Unicode]
+  */
+int fl_utf_toupper(const unsigned char *str, int len, char *buf)
+{
+	int i;
+	int l = 0;
+	char *end = (char *)&str[len];
+        for (i = 0; i < len;) {
+                int l1, l2;
+                unsigned int u1;
+
+//              l1 = fl_utf2ucs((unsigned char*)str + i, len - i, &u1);
+                u1 = fl_utf8decode((const char*)(str + i), end, &l1);
+                l2 = fl_utf8encode((unsigned int) Toupper(u1), buf + l);
+                if (l1 < 1) {
+                        i += 1;
+                } else {
+                        i += l1;
+		}
+                if (l2 < 1) {
+                        l += 1;
+                } else {
+                        l += l2;
+		}
+	}
+	return l;
+}
+
+#if 0 // deprecated in favour of FLTK2's fl_utf8toa
+/*
+ * convert UTF-8 str to latin1
+ * Warning: buf must be at least len long
+ */
+int fl_utf2latin1(const unsigned char *str, int len, char *buf)
+{
+	int i;
+	int l = 0;
+	char *end = (char *)&str[len];
+        for (i = 0; i < len;) {
+                unsigned int u1;
+		int l1;
+
+//              l1 = fl_utf2ucs((unsigned char*)str + i, len - i, &u1);
+                u1 = fl_utf8decode((const char*)(str + i), end, &l1);
+		if (u1 > 0xFF) u1 = '?';
+		buf[l] = (char) u1;
+                if (l1 < 1) {
+                        i += 1;
+                } else {
+                        i += l1;
+		}
+		l++;
+
+	}
+	return l;
+}
+#endif
+
+#if 0 // deprecated in favour of FLTK2's fl_utf8froma
+/*
+ * convert latin1 str to UTF-8
+ * Warning: buf must be at least 2 * len long
+ */
+int fl_latin12utf(const unsigned char *str, int len, char *buf)
+{
+	int i;
+	int l = 0;
+	int l1 = 0;
+        for (i = 0; i < len; i++) {
+		unsigned int n = (unsigned int) str[i];
+		l1 = fl_utf8encode(n, buf + l);
+                if (l1 < 1) {
+                        l = l + 1;
+                } else {
+                        l = l + l1;
+		}
+
+	}
+	return l;
+}
+#endif
+
+/**
+  returns true if the character is non-spacing.
+  \todo explain what non-spacing means.
+  */
+unsigned int fl_nonspacing(unsigned int ucs)
+{
+#ifdef __APPLE__
+  return (ucs==0x20); // FIXME: what does this really do?
+#else
+  return (unsigned int) XUtf8IsNonSpacing(ucs);
+#endif
+}
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+static xchar *mbwbuf = NULL;
+#endif
+
+#ifdef WIN32
+unsigned int fl_codepage = 0;
+#endif
+
+#if defined (WIN32) && !defined(__CYGWIN__)
+
+static char *buf = NULL;
+static int buf_len = 0;
+static unsigned short *wbufa = NULL;
+
+// FIXME: This should *maybe* return 'const char *' instead of 'char *'
+char *fl_utf8_to_locale(const char *s, int len, UINT codepage)
+{
+	if (!s) return (char *)"";
+	int l = 0;
+//	if (buf_len < len * 2 + 1) {
+//		buf_len = len * 2 + 1;
+//		buf = (char*) realloc(buf, buf_len);
+//		wbufa = (unsigned short*) realloc(wbufa, buf_len * sizeof(short));
+//	}
+	unsigned wn = fl_utf8toUtf16(s, len, NULL, 0); // Query length
+	wn = wn * 2 + 1;
+	if (wn >= (unsigned)buf_len) {
+		buf_len = wn;
+		buf = (char*) realloc(buf, buf_len);
+		wbufa = (unsigned short*) realloc(wbufa, buf_len * sizeof(short));
+	}
+	if (codepage < 1) codepage = fl_codepage;
+//	l = fl_utf2unicode((const unsigned char *)s, len, (xchar*) wbufa);
+	l = fl_utf8toUtf16(s, len, wbufa, wn); // Convert string
+	wbufa[l] = 0;
+	buf[l] = 0;
+	l = WideCharToMultiByte(codepage, 0, (WCHAR*)wbufa, l, buf, buf_len, NULL, NULL);
+	if (l < 0) l = 0;
+	buf[l] = 0;
+	return buf;
+}
+
+// FIXME: This should maybe return 'const char *' instead of 'char *'
+char *fl_locale_to_utf8(const char *s, int len, UINT codepage)
+{
+	if (!s) return (char *)"";
+	int l = 0;
+	if (buf_len < len * 5 + 1) {
+		buf_len = len * 5 + 1;
+		buf = (char*) realloc(buf, buf_len);
+		wbufa = (unsigned short*) realloc(wbufa, buf_len * sizeof(short));
+	}
+	if (codepage < 1) codepage = fl_codepage;
+	buf[l] = 0;
+
+	l = MultiByteToWideChar(codepage, 0, s, len, (WCHAR*)wbufa, buf_len);
+	if (l < 0) l = 0;
+	wbufa[l] = 0;
+//	l = fl_unicode2utf((xchar*)wbufa, l, buf);
+	l = fl_utf8fromwc(buf, buf_len, (xchar*)wbufa, l);
+	buf[l] = 0;
+	return buf;
+}
+#endif
+
+/**
+  converts UTF8 to a local multi-byte character string.
+  */
+char * fl_utf2mbcs(const char *s)
+{
+	if (!s) return NULL;
+#if defined(WIN32) && !defined(__CYGWIN__)
+	int l = strlen(s);
+	static char *buf = NULL;
+
+//	mbwbuf = (xchar*)realloc(mbwbuf, (l+6) * sizeof(xchar));
+//	l = fl_utf2unicode((unsigned char*)s, l, mbwbuf);
+//	mbwbuf[l] = 0;
+	unsigned wn = fl_utf8toUtf16(s, l, NULL, 0) + 7; // Query length
+	mbwbuf = (xchar*)realloc(mbwbuf, sizeof(xchar)*wn);
+	l = fl_utf8toUtf16(s, l, (unsigned short *)mbwbuf, wn); // Convert string
+	mbwbuf[l] = 0;
+
+	buf = (char*)realloc(buf, l * 6 + 1);
+	l = wcstombs(buf, mbwbuf, l * 6);
+	buf[l] = 0;
+	return buf;
+#else
+	return (char*) s;
+#endif
+}
+
+
+#if 0 // deprecated in favour of FLTK2's fl_utf8from_mb
+char * fl_mbcs2utf(const char *s)
+{
+	if (!s) return NULL;
+#if defined(WIN32)
+	int l = strlen(s);
+	unsigned dstlen;
+	static char *buf = NULL;
+
+	mbwbuf = (xchar*)realloc(mbwbuf,(l * 6 + 6) * sizeof(xchar));
+	l = mbstowcs(mbwbuf, s, l);
+	dstlen = l * 6 + 1;
+	buf = (char*)realloc(buf, dstlen);
+//	l = fl_unicode2utf(mbwbuf, l, buf);
+	l = fl_utf8fromwc(buf, dstlen, mbwbuf, l);
+	buf[l] = 0;
+	return buf;
+#else
+	return (char*) s;
+#endif
+} // fl_mbcs2utf
+#endif
+
+#if defined(WIN32)  && !defined(__CYGWIN__)
+static xchar *wbuf = NULL;
+static xchar *wbuf1 = NULL;
+#endif
+
+
+char *fl_getenv(const char* v)
+{
+#if defined (WIN32) && !defined(__CYGWIN__)
+	int l = strlen(v);
+//	static xchar* wbuf = NULL;
+//	wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//	wbuf[fl_utf2unicode((const unsigned char*)v, l, wbuf)] = 0;
+	unsigned wn = fl_utf8toUtf16(v, l, NULL, 0) + 1; // Query length
+	wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+	wn = fl_utf8toUtf16(v, l, (unsigned short *)wbuf, wn); // Convert string
+	wbuf[wn] = 0;
+	xchar *ret = _wgetenv(wbuf);
+	static char *buf = NULL;
+	if (ret) {
+		l = wcslen(ret);
+		wn = fl_utf8fromwc(NULL, 0, ret, l) + 1; // query length
+		buf = (char*) realloc(buf, wn);
+//		buf[fl_unicode2utf(ret, l, buf)] = 0;
+		wn = fl_utf8fromwc(buf, wn, ret, l); // convert string
+		buf[wn] = 0;
+		return buf;
+	} else {
+		return NULL;
+	}
+#else
+	return getenv(v);
+#endif
+}
+
+int fl_open(const char* f, int oflags, ...)
+{
+	int pmode;
+	va_list ap;
+	va_start(ap, oflags);
+	pmode = va_arg (ap, int);
+	va_end(ap);
+#if defined (WIN32) && !defined(__CYGWIN__)
+		int l = strlen(f);
+//		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)f, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		if (pmode == -1) return _wopen(wbuf, oflags);
+		else return _wopen(wbuf, oflags, pmode);
+#else
+	if (pmode == -1) return open(f, oflags);
+	else return open(f, oflags, pmode);
+#endif
+}
+
+FILE *fl_fopen(const char* f, const char *mode)
+{
+#if  defined (WIN32) && !defined(__CYGWIN__)
+		int l = strlen(f);
+//		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)f, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		l = strlen(mode);
+//		wbuf1 = (xchar*)realloc(wbuf1, sizeof(xchar) * (l+1));
+//		wbuf1[fl_utf2unicode((const unsigned char*)mode, l, wbuf1)] = 0;
+		wn = fl_utf8toUtf16(mode, l, NULL, 0) + 1; // Query length
+		wbuf1 = (xchar*)realloc(wbuf1, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(mode, l, (unsigned short *)wbuf1, wn); // Convert string
+		wbuf1[wn] = 0;
+		return _wfopen(wbuf, wbuf1);
+#else
+	return fopen(f, mode);
+#endif
+}
+
+int fl_system(const char* f)
+{
+#if  defined (WIN32) && !defined(__CYGWIN__)
+#  ifdef __MINGW32__
+	return system(fl_utf2mbcs(f));
+#  else
+		int l = strlen(f);
+//		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)f, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		return _wsystem(wbuf);
+#  endif
+#else
+	return system(f);
+#endif
+}
+
+int fl_execvp(const char *file, char *const *argv)
+{
+#if  defined (WIN32) && !defined(__CYGWIN__)
+#ifdef __MINGW32__
+	return _execvp(fl_utf2mbcs(file), argv);
+#else
+		int l = strlen(file);
+		int i, n, ret;
+		xchar **ar;
+//		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)file, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(file, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(file, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+
+		i = 0; n = 0;
+		while (argv[i]) {i++; n++;}
+		ar = (xchar**) malloc(sizeof(xchar*) * (n + 1));
+		i = 0;
+		while (i <= n) {
+			unsigned wn;
+			l = strlen(argv[i]);
+//			ar[i] = (xchar *)malloc(sizeof(xchar) * (l+1));
+//			ar[i][fl_utf2unicode((const unsigned char*)argv[i], l, ar[i])] = 0;
+			wn = fl_utf8toUtf16(argv[i], l, NULL, 0) + 1; // Query length
+			ar[i] = (xchar *)malloc(sizeof(xchar)*wn);
+			wn = fl_utf8toUtf16(argv[i], l, (unsigned short *)ar[i], wn); // Convert string
+			ar[i][wn] = 0;
+			i++;
+		}
+		ar[n] = NULL;
+		ret = _wexecvp(wbuf, ar);
+		i = 0;
+		while (i <= n) {
+			free(ar[i]);
+			i++;
+		}
+		free(ar);
+		return ret;
+#endif
+#else
+	return execvp(file, argv);
+#endif
+}
+
+
+
+int fl_chmod(const char* f, int mode)
+{
+#if  defined (WIN32) && !defined(__CYGWIN__)
+		int l = strlen(f);
+//		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)f, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		return _wchmod(wbuf, mode);
+#else
+	return chmod(f, mode);
+#endif
+}
+
+int fl_access(const char* f, int mode)
+{
+#if defined (WIN32) && !defined(__CYGWIN__)
+		int l = strlen(f);
+//		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)f, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		return _waccess(wbuf, mode);
+#else
+	return access(f, mode);
+#endif
+}
+
+
+int fl_stat(const char* f, struct stat *b)
+{
+#if defined(WIN32) && !defined(__CYGWIN__)
+		int l = strlen(f);
+//		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)f, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		return _wstat(wbuf, (struct _stat*)b);
+#else
+	return stat(f, b);
+#endif
+}
+
+char *fl_getcwd(char* b, int l)
+{
+	if (b == NULL) {
+		b = (char*) malloc(l+1);
+	}
+#if defined(WIN32) && !defined(__CYGWIN__)
+		static xchar *wbuf = NULL;
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		xchar *ret = _wgetcwd(wbuf, l / 5);
+		xchar *ret = _wgetcwd(wbuf, l);
+		if (ret) {
+			unsigned dstlen = l;
+			l = wcslen(wbuf);
+//			b[fl_unicode2utf(wbuf, l, b)] = 0;
+			dstlen = fl_utf8fromwc(b, dstlen, wbuf, l);
+			b[dstlen] = 0;
+			return b;
+		} else {
+			return NULL;
+		}
+#else
+	return getcwd(b, l);
+#endif
+}
+
+
+int fl_unlink(const char* f)
+{
+#if defined(WIN32) && !defined(__CYGWIN__)
+		int l = strlen(f);
+//		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)f, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		return _wunlink(wbuf);
+#else
+	return unlink(f);
+#endif
+}
+
+int fl_mkdir(const char* f, int mode)
+{
+#if defined(WIN32) && !defined(__CYGWIN__)
+		int l = strlen(f);
+//		wbuf = (xchar*)realloc(wbuf, sizeof(short) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)f, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		return _wmkdir(wbuf);
+#else
+	return mkdir(f, mode);
+#endif
+}
+
+
+int fl_rmdir(const char* f)
+{
+#if defined (WIN32) && !defined(__CYGWIN__)
+		int l = strlen(f);
+//		wbuf = (xchar*)realloc(wbuf, sizeof(xchar) * (l+1));
+//		wbuf[fl_utf2unicode((const unsigned char*)f, l, wbuf)] = 0;
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		return _wrmdir(wbuf);
+#else
+	return rmdir(f);
+#endif
+}
+
+int fl_rename(const char* f, const char *n)
+{
+#if defined (WIN32) && !defined(__CYGWIN__)
+		int l = strlen(f);
+		unsigned wn = fl_utf8toUtf16(f, l, NULL, 0) + 1; // Query length
+		wbuf = (xchar*)realloc(wbuf, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(f, l, (unsigned short *)wbuf, wn); // Convert string
+		wbuf[wn] = 0;
+		l = strlen(n);
+		wn = fl_utf8toUtf16(n, l, NULL, 0) + 1; // Query length
+		wbuf1 = (xchar*)realloc(wbuf1, sizeof(xchar)*wn);
+		wn = fl_utf8toUtf16(n, l, (unsigned short *)wbuf1, wn); // Convert string
+		wbuf1[wn] = 0;
+		return _wrename(wbuf, wbuf1);
+#else
+	return rename(f, n);
+#endif
+}
+
+// recursively create a path in the file system
+char fl_make_path( const char *path ) {
+  if (fl_access(path, 0)) {
+    const char *s = strrchr( path, '/' );
+    if ( !s ) return 0;
+    int len = s-path;
+    char *p = (char*)malloc( len+1 );
+    memcpy( p, path, len );
+    p[len] = 0;
+    fl_make_path( p );
+    free( p );
+    fl_mkdir(path, 0700);
+  }
+  return 1;
+}
+
+// strip the filename and create a path
+void fl_make_path_for_file( const char *path )
+{
+  const char *s = strrchr( path, '/' );
+  if ( !s ) return;
+  int len = s-path;
+  char *p = (char*)malloc( len+1 );
+  memcpy( p, path, len );
+  p[len] = 0;
+  fl_make_path( p );
+  free( p );
+}
+
+/** @} */
+
+//
+// End of "$Id: fl_utf8.cxx 7975 2010-12-08 12:15:48Z AlbrechtS $".
+//