--- /dev/null
+/*
+ * wchar utility functions.
+ *
+ * Copyright (c) 2012 Marko Kreen
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <usual/wchar.h>
+
+#include <string.h>
+
+wchar_t *mbstr_decode(const char *str, int str_len, int *wlen_p,
+ wchar_t *wbuf, int wbuf_len, bool allow_invalid)
+{
+ mbstate_t ps;
+ int clen, wcnt;
+ wchar_t *dst, *w, *wend;
+ const char *s;
+ const char *str_end;
+ int wmax;
+
+ if (str_len < 0)
+ str_len = strlen(str);
+ str_end = str + str_len;
+
+ /* max number of wchar_t that the output can take plus zero-terminator */
+ wmax = str_len + 1;
+ if (wbuf != NULL && wmax < wbuf_len) {
+ dst = wbuf;
+ } else {
+ dst = malloc(sizeof(wchar_t) * wmax);
+ if (!dst)
+ return NULL;
+ }
+
+ /* try full decode at once */
+ s = str;
+ memset(&ps, 0, sizeof(ps));
+ wcnt = mbsnrtowcs(dst, &s, str_len, wmax, &ps);
+ if (wcnt > 0 && s == NULL) {
+ if (wlen_p)
+ *wlen_p = wcnt;
+ return dst;
+ }
+
+ /* full decode failed, decode chars one-by-one */
+ s = str;
+ w = dst;
+ wend = dst + wmax - 1;
+ memset(&ps, 0, sizeof(ps));
+ while (s < str_end && w < wend) {
+ clen = mbrtowc(w, s, str_end - s, &ps);
+ if (clen > 0) {
+ w++;
+ s += clen;
+ } else if (allow_invalid) {
+ /* allow invalid encoding */
+ memset(&ps, 0, sizeof(ps));
+ *w++ = (unsigned char)*s++;
+ } else {
+ goto fail;
+ }
+ }
+
+ if (s != str_end)
+ goto fail;
+
+ *w = 0;
+ if (wlen_p != NULL)
+ *wlen_p = w - dst;
+ return dst;
+
+fail:
+ if (dst != wbuf)
+ free(dst);
+ errno = EILSEQ;
+ return NULL;
+}
+
+wctype_t wctype_wcsn(const wchar_t *name, unsigned int namelen)
+{
+ char buf[10];
+ unsigned int i;
+
+ if (namelen >= sizeof(buf))
+ return (wctype_t)0;
+ for (i = 0; i < namelen; i++) {
+ wchar_t c = name[i];
+ if (c < 0x20 || c > 127)
+ return (wctype_t)0;
+ buf[i] = c;
+ }
+ buf[i] = 0;
+ return wctype(buf);
+}
+
--- /dev/null
+/*
+ * wchar.h - wchar_t utilities.
+ *
+ * Copyright (c) 2012 Marko Kreen
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _USUAL_WCHAR_H_
+#define _USUAL_WCHAR_H_
+
+#include <usual/base.h>
+
+#include <wchar.h>
+#include <wctype.h>
+
+wchar_t *mbstr_decode(const char *str, int str_len, int *wlen_p, wchar_t *wbuf, int wbuf_len, bool allow_invalid);
+
+wctype_t wctype_wcsn(const wchar_t *name, unsigned int namelen);
+
+#endif