+static size_t utf16le_strlen(const utf16lechar *s)
+{
+ const utf16lechar *p = s;
+ while (p)
+ p++;
+ return (p - s) / sizeof(utf16lechar);
+}
+
+/* Handle %W for UTF16-LE printing and %U for UTF-8 printing.
+ *
+ * WARNING: this is not yet done properly--- it's assumed that if the format
+ * string contains %W and/or %U, then it contains no other format specifiers.
+ */
+static int
+wimlib_vfprintf(FILE *fp, const char *format, va_list va)
+{
+ const char *p;
+
+ for (p = format; *p; p++)
+ if (*p == '%' && ((*p + 1) == 'W' || *(p + 1) == 'U'))
+ goto special;
+ return vfprintf(fp, format, va);
+special:
+ ;
+ int n = 0;
+ for (p = format; *p; p++) {
+ if (*p == '%' && ((*p + 1) == 'W' || *(p + 1) == 'U')) {
+ int ret;
+ mbchar *mbs;
+ size_t mbs_len;
+
+ if (*(p + 1) == 'W') {
+ utf16lechar *ucs = va_arg(va, utf16lechar*);
+ size_t ucs_nbytes = utf16le_strlen(ucs);
+ ret = utf16le_to_mbs(ucs, ucs_nbytes,
+ &mbs, &mbs_len);
+ } else {
+ utf8char *ucs = va_arg(va, utf8char*);
+ size_t ucs_nbytes = strlen(ucs);
+ ret = utf8_to_mbs(ucs, ucs_nbytes,
+ &mbs, &mbs_len);
+ }
+ if (ret) {
+ ret = fprintf(fp, "???");
+ } else {
+ ret = fprintf(fp, "%s", mbs);
+ FREE(mbs);
+ }
+ if (ret < 0)
+ return -1;
+ else
+ n += ret;
+ } else {
+ if (putc(*p, fp) == EOF)
+ return -1;
+ n++;
+ }
+ }
+ return n;
+}
+
+int
+wimlib_printf(const char *format, ...)
+{
+ int ret;
+ va_list va;
+
+ va_start(va, format);
+ ret = wimlib_vfprintf(stdout, format, va);
+ va_end(va);
+ return ret;
+}
+
+int
+wimlib_fprintf(FILE *fp, const char *format, ...)
+{
+ int ret;
+ va_list va;
+
+ va_start(va, format);
+ ret = wimlib_vfprintf(fp, format, va);
+ va_end(va);
+ return ret;
+}
+