+ 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_nbytes;
+
+ 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_nbytes);
+ } else {
+ utf8char *ucs = va_arg(va, utf8char*);
+ size_t ucs_nbytes = strlen(ucs);
+ ret = utf8_to_mbs(ucs, ucs_nbytes,
+ &mbs, &mbs_nbytes);
+ }
+ if (ret) {
+ ret = fprintf(fp, "??????");
+ } else {
+ ret = fprintf(fp, "%s", mbs);
+ FREE(mbs);
+ }
+ if (ret < 0)
+ return -1;
+ else
+ n += ret;
+ p++;
+ } 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;
+}
+
+#if defined(ENABLE_ERROR_MESSAGES) || defined(ENABLE_DEBUG)
+static void
+wimlib_vmsg(const char *tag, const char *format,
+ va_list va, bool perror)
+{
+#ifndef DEBUG