A set of windows utf8 patches fromJanne Hyvärinen <cse@sci.fi>.
authorErik de Castro Lopo <erikd@mega-nerd.com>
Sun, 21 Apr 2013 06:16:44 +0000 (16:16 +1000)
committerErik de Castro Lopo <erikd@mega-nerd.com>
Sun, 21 Apr 2013 06:50:24 +0000 (16:50 +1000)
src/flac/decode.c
src/flac/encode.c
src/flac/utils.c
src/flac/utils.h
src/metaflac/utils.c
src/share/win_utf8_io/win_utf8_io.c

index 5f89253..3984eb9 100644 (file)
@@ -172,6 +172,7 @@ int flac__decode_file(const char *infilename, const char *outfilename, FLAC__boo
        )
                return 1;
 
+       stats_new_file();
        if(!DecoderSession_init_decoder(&decoder_session, infilename))
                return DecoderSession_finish_error(&decoder_session);
 
@@ -433,19 +434,23 @@ int DecoderSession_finish_ok(DecoderSession *d)
        if(d->analysis_mode)
                flac__analyze_finish(d->aopts);
        if(md5_failure) {
-               flac__utils_printf(stderr, 1, "\r%s: ERROR, MD5 signature mismatch\n", d->inbasefilename);
+               stats_print_name(1, d->inbasefilename);
+               flac__utils_printf(stderr, 1, "ERROR, MD5 signature mismatch\n");
                ok = d->continue_through_decode_errors;
        }
        else {
                if(!d->got_stream_info) {
-                       flac__utils_printf(stderr, 1, "\r%s: WARNING, cannot check MD5 signature since there was no STREAMINFO\n", d->inbasefilename);
+                       stats_print_name(1, d->inbasefilename);
+                       flac__utils_printf(stderr, 1, "WARNING, cannot check MD5 signature since there was no STREAMINFO\n");
                        ok = !d->treat_warnings_as_errors;
                }
                else if(!d->has_md5sum) {
-                       flac__utils_printf(stderr, 1, "\r%s: WARNING, cannot check MD5 signature since it was unset in the STREAMINFO\n", d->inbasefilename);
+                       stats_print_name(1, d->inbasefilename);
+                       flac__utils_printf(stderr, 1, "WARNING, cannot check MD5 signature since it was unset in the STREAMINFO\n");
                        ok = !d->treat_warnings_as_errors;
                }
-               flac__utils_printf(stderr, 2, "\r%s: %s         \n", d->inbasefilename, d->test_only? "ok           ":d->analysis_mode?"done           ":"done");
+               stats_print_name(2, d->inbasefilename);
+               flac__utils_printf(stderr, 2, "%s         \n", d->test_only? "ok           ":d->analysis_mode?"done           ":"done");
        }
        DecoderSession_destroy(d, /*error_occurred=*/!ok);
        if(!d->analysis_mode && !d->test_only && d->format != FORMAT_RAW) {
@@ -1348,7 +1353,8 @@ void error_callback(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderError
        DecoderSession *decoder_session = (DecoderSession*)client_data;
        (void)decoder;
        if(!decoder_session->error_callback_suppress_messages)
-               flac__utils_printf(stderr, 1, "%s: *** Got error code %d:%s\n", decoder_session->inbasefilename, status, FLAC__StreamDecoderErrorStatusString[status]);
+               stats_print_name(1, decoder_session->inbasefilename);
+               flac__utils_printf(stderr, 1, "*** Got error code %d:%s\n", status, FLAC__StreamDecoderErrorStatusString[status]);
        if(!decoder_session->continue_through_decode_errors) {
                /* if we got a sync error while looking for metadata, either it's not a FLAC file (more likely) or the file is corrupted */
                if(
@@ -1414,7 +1420,6 @@ void print_error_with_state(const DecoderSession *d, const char *message)
 
 void print_stats(const DecoderSession *decoder_session)
 {
-       static int count = 0;
        if(flac__utils_verbosity_ >= 2) {
 #if defined _MSC_VER || defined __MINGW32__
                /* with MSVC you have to spoon feed it the casting */
@@ -1422,24 +1427,22 @@ void print_stats(const DecoderSession *decoder_session)
 #else
                const double progress = (double)decoder_session->samples_processed / (double)decoder_session->total_samples * 100.0;
 #endif
-               if(decoder_session->total_samples > 0) {
-                       while (count > 0 && count--)
-                               fprintf(stderr, "\b");
 
+               if(decoder_session->total_samples > 0) {
                        if ((unsigned)floor(progress + 0.5) == 100)
                                return;
 
-                       count = flac_fprintf(stderr, "%s: %s%u%% complete",
-                               decoder_session->inbasefilename,
+                       stats_print_name(2, decoder_session->inbasefilename);
+                       stats_print_info(2, "%s%u%% complete",
                                decoder_session->test_only? "testing, " : decoder_session->analysis_mode? "analyzing, " : "",
                                (unsigned)floor(progress + 0.5)
                        );
                }
                else {
-                       flac_fprintf(stderr, "\r%s: %s %u samples",
-                               decoder_session->inbasefilename,
+                       stats_print_name(2, decoder_session->inbasefilename);
+                       stats_print_info(2, "%s %" PRIu64 " samples",
                                decoder_session->test_only? "tested" : decoder_session->analysis_mode? "analyzed" : "wrote",
-                               (unsigned)decoder_session->samples_processed
+                               decoder_session->samples_processed
                        );
                }
        }
index 8769f60..fe104cb 100644 (file)
@@ -1180,6 +1180,7 @@ int flac__encode_file(FILE *infile, FLAC__off_t infilesize, const char *infilena
                if(options.format == FORMAT_FLAC || options.format == FORMAT_OGGFLAC)
                        encoder_session.fmt.flac.client_data.samples_left_to_process = encoder_session.total_samples_to_encode;
 
+               stats_new_file();
                /* init the encoder */
                if(!EncoderSession_init_encoder(&encoder_session, options))
                        return EncoderSession_finish_error(&encoder_session);
@@ -2543,7 +2544,8 @@ void flac_decoder_error_callback(const FLAC__StreamDecoder *decoder, FLAC__Strea
     FLACDecoderData *data = &e->fmt.flac.client_data;
        (void)decoder;
 
-       flac__utils_printf(stderr, 1, "%s: ERROR got %s while decoding FLAC input\n", e->inbasefilename, FLAC__StreamDecoderErrorStatusString[status]);
+       stats_print_name(1, e->inbasefilename);
+       flac__utils_printf(stderr, 1, "ERROR got %s while decoding FLAC input\n", FLAC__StreamDecoderErrorStatusString[status]);
        if(!e->continue_through_decode_errors)
                data->fatal_error = true;
 }
@@ -2594,33 +2596,36 @@ FLAC__bool parse_cuesheet(FLAC__StreamMetadata **cuesheet, const char *cuesheet_
 
 void print_stats(const EncoderSession *encoder_session)
 {
-       const FLAC__uint64 samples_written = min(encoder_session->total_samples_to_encode, encoder_session->samples_written);
-       const FLAC__uint64 uesize = encoder_session->unencoded_size;
+       if(flac__utils_verbosity_ >= 2) {
+               const FLAC__uint64 samples_written = min(encoder_session->total_samples_to_encode, encoder_session->samples_written);
+               const FLAC__uint64 uesize = encoder_session->unencoded_size;
 #if defined _MSC_VER || defined __MINGW32__
-       /* with MSVC you have to spoon feed it the casting */
-       const double progress = (double)(FLAC__int64)samples_written / (double)(FLAC__int64)encoder_session->total_samples_to_encode;
-       const double ratio = (double)(FLAC__int64)encoder_session->bytes_written / ((double)(FLAC__int64)(uesize? uesize:1) * min(1.0, progress));
+               /* with MSVC you have to spoon feed it the casting */
+               const double progress = (double)(FLAC__int64)samples_written / (double)(FLAC__int64)encoder_session->total_samples_to_encode;
+               const double ratio = (double)(FLAC__int64)encoder_session->bytes_written / ((double)(FLAC__int64)(uesize? uesize:1) * min(1.0, progress));
 #else
-       const double progress = (double)samples_written / (double)encoder_session->total_samples_to_encode;
-       const double ratio = (double)encoder_session->bytes_written / ((double)(uesize? uesize:1) * min(1.0, progress));
+               const double progress = (double)samples_written / (double)encoder_session->total_samples_to_encode;
+               const double ratio = (double)encoder_session->bytes_written / ((double)(uesize? uesize:1) * min(1.0, progress));
 #endif
+               char ratiostr[16];
 
-       FLAC__ASSERT(encoder_session->total_samples_to_encode > 0);
+               FLAC__ASSERT(encoder_session->total_samples_to_encode > 0);
 
-       if(samples_written == encoder_session->total_samples_to_encode) {
-               flac__utils_printf(stderr, 2, "\r%s:%s wrote %" PRIu64 " bytes, ratio=",
-                       encoder_session->inbasefilename,
-                       encoder_session->verify? " Verify OK," : "",
-                       encoder_session->bytes_written
-               );
-       }
-       else {
-               flac__utils_printf(stderr, 2, "\r%s: %u%% complete, ratio=", encoder_session->inbasefilename, (unsigned)floor(progress * 100.0 + 0.5));
+               if (uesize)     sprintf(ratiostr, "%0.3f", ratio); else sprintf(ratiostr, "N/A");
+
+               if(samples_written == encoder_session->total_samples_to_encode) {
+                       stats_print_name(2, encoder_session->inbasefilename);
+                       stats_print_info(2, "%swrote %" PRIu64 " bytes, ratio=%s",
+                               encoder_session->verify? "Verify OK, " : "",
+                               encoder_session->bytes_written,
+                               ratiostr
+                       );
+               }
+               else {
+                       stats_print_name(2, encoder_session->inbasefilename);
+                       stats_print_info(2, "%u%% complete, ratio=%s", (unsigned)floor(progress * 100.0 + 0.5), ratiostr);
+               }
        }
-       if(uesize)
-               flac__utils_printf(stderr, 2, "%0.3f", ratio);
-       else
-               flac__utils_printf(stderr, 2, "N/A");
 }
 
 void print_error_with_init_status(const EncoderSession *e, const char *message, FLAC__StreamEncoderInitStatus init_status)
index 91a7f9e..965ab59 100644 (file)
 #include "FLAC/assert.h"
 #include "FLAC/metadata.h"
 #include "share/compat.h"
+#ifndef _WIN32
+#include <wchar.h>
+#include <sys/ioctl.h>
+#endif
 
 const char *CHANNEL_MASK_TAG = "WAVEFORMATEXTENSIBLE_CHANNEL_MASK";
 
@@ -158,6 +162,95 @@ void flac__utils_printf(FILE *stream, int level, const char *format, ...)
        }
 }
 
+/* variables and functions for console status output */
+static FLAC__bool is_name_printed;
+static int stats_char_count = 0;
+static int console_width;
+static int console_chars_left;
+
+int get_console_width()
+{
+       int width = 80;
+#ifdef _WIN32
+       width = win_get_console_width();
+#else
+       struct winsize w;
+       if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != -1) width = w.ws_col;
+#endif
+       return width;
+}
+
+size_t strlen_console(const char *text)
+{
+#ifdef _WIN32
+       return strlen_utf8(text);
+#else
+       size_t len;
+       wchar_t *wtmp;
+
+       len = strlen(text)+1;
+       wtmp = (wchar_t *)malloc(len*sizeof(wchar_t));
+       if (wtmp == NULL) return len-1;
+       mbstowcs(wtmp, text, len);
+       len = wcswidth(wtmp, len);
+       free(wtmp);
+
+       return len;
+#endif
+}
+
+void stats_new_file()
+{
+       is_name_printed = false;
+}
+
+void stats_clear()
+{
+       while (stats_char_count > 0 && stats_char_count--)
+               fprintf(stderr, "\b");
+}
+
+void stats_print_name(int level, const char *name)
+{
+       int len;
+
+       if (flac__utils_verbosity_ >= level) {
+               stats_clear();
+               if(is_name_printed) return;
+
+               console_width = get_console_width();
+               len = strlen_console(name)+2;
+               console_chars_left = console_width  - (len % console_width);
+               flac_fprintf(stderr, "%s: ", name);
+               is_name_printed = true;
+       }
+}
+
+void stats_print_info(int level, const char *format, ...)
+{
+       char tmp[80];
+       int len, cleared_len;
+
+       if (flac__utils_verbosity_ >= level) {
+               va_list args;
+               va_start(args, format);
+               len = vsnprintf(tmp, sizeof(tmp), format, args);
+               va_end(args);
+               if (len < 0 || len == sizeof(tmp)) {
+                       tmp[sizeof(tmp)-1] = '\0';
+                       len = sizeof(tmp)-1;
+               }
+               cleared_len = stats_char_count;
+               stats_clear();
+               if (len >= console_chars_left) {
+                       while (cleared_len > 0 && cleared_len--) fprintf(stderr, " ");
+                       fprintf(stderr, "\n");
+                       console_chars_left = console_width;
+               }
+               stats_char_count = fprintf(stderr, "%s", tmp);
+       }
+}
+
 #ifdef FLAC__VALGRIND_TESTING
 size_t flac__utils_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream)
 {
index 41a0f91..b5ce839 100644 (file)
@@ -53,6 +53,13 @@ size_t flac__utils_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stre
 extern int flac__utils_verbosity_;
 void flac__utils_printf(FILE *stream, int level, const char *format, ...);
 
+int get_console_width();
+size_t strlen_console(const char *text);
+void stats_new_file();
+void stats_clear();
+void stats_print_name(int level, const char *name);
+void stats_print_info(int level, const char *format, ...);
+
 FLAC__bool flac__utils_parse_skip_until_specification(const char *s, utils__SkipUntilSpecification *spec);
 void flac__utils_canonicalize_skip_until_specification(utils__SkipUntilSpecification *spec, unsigned sample_rate);
 
index 934cfcf..af17d5b 100644 (file)
@@ -136,7 +136,7 @@ void print_error_with_chain_status(FLAC__Metadata_Chain *chain, const char *form
 
        va_start(args, format);
 
-       (void) vfprintf(stderr, format, args);
+       (void) flac_vfprintf(stderr, format, args);
 
        va_end(args);
 
index d7d1dbd..fae78a8 100644 (file)
@@ -91,8 +91,47 @@ int get_utf8_argv(int *argc, char ***argv)
        return ret;
 }
 
+/* return number of characters in the UTF-8 string */
+size_t strlen_utf8(const char *str)
+{
+       size_t len;
+       if ((len = MultiByteToWideChar(win_utf8_io_codepage, 0, str, -1, NULL, 0)) == 0)
+               len = strlen(str);
+       return len;
+}
+
+/* get the console width in characters */
+int win_get_console_width()
+{
+       int width = 80;
+       CONSOLE_SCREEN_BUFFER_INFO csbi;
+       HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+       if (GetConsoleScreenBufferInfo(hOut, &csbi) != 0) width = csbi.dwSize.X;
+       return width;
+}
+
 /* print functions */
 
+int print_console(FILE *stream, const wchar_t *text, DWORD len)
+{
+       static HANDLE hOut;
+       static HANDLE hErr;
+       DWORD out;
+       hOut = GetStdHandle(STD_OUTPUT_HANDLE);
+       hErr = GetStdHandle(STD_ERROR_HANDLE);
+       if (stream == stdout && hOut != INVALID_HANDLE_VALUE && GetFileType(hOut) == FILE_TYPE_CHAR) {
+               if (WriteConsoleW(hOut, text, len, &out, NULL) == 0) return -1;
+               return out;
+       } else if (stream == stderr && hErr != INVALID_HANDLE_VALUE && GetFileType(hErr) == FILE_TYPE_CHAR) {
+               if (WriteConsoleW(hErr, text, len, &out, NULL) == 0) return -1;
+               return out;
+       } else {
+               int ret = fwprintf(stream, L"%s", text);
+               if (ret < 0) return ret;
+               return len;
+       }
+}
+
 int printf_utf8(const char *format, ...)
 {
        char *utmp = NULL;
@@ -110,7 +149,7 @@ int printf_utf8(const char *format, ...)
                        ret = -1;
                        break;
                }
-               ret = wprintf(L"%s", wout);
+               ret = print_console(stdout, wout, wcslen(wout));
                break;
        }
        if (utmp) free(utmp);
@@ -136,7 +175,7 @@ int fprintf_utf8(FILE *stream, const char *format, ...)
                        ret = -1;
                        break;
                }
-               ret = fwprintf(stream, L"%s", wout);
+               ret = print_console(stream, wout, wcslen(wout));
                break;
        }
        if (utmp) free(utmp);
@@ -158,7 +197,7 @@ int vfprintf_utf8(FILE *stream, const char *format, va_list argptr)
                        ret = -1;
                        break;
                }
-               ret = fwprintf(stream, L"%s", wout);
+               ret = print_console(stream, wout, wcslen(wout));
                break;
        }
        if (utmp) free(utmp);