develooper Front page | perl.i18n | Postings from July 2008

Printing non-ascii on the Win32 console

Bjoern Hoehrmann
July 1, 2008 14:47
Printing non-ascii on the Win32 console
Message ID:

  Writing an example script for Win32::MultiLanguage that simply lists
all supported code pages in the user's default language, I naturally got
all the umlauts in the german output messed up in the console. Wondering
how to fix that I thought there should be a simple way to say, e.g.,

  binmode STDOUT => ':encoding(:terminal)' if -t STDOUT;

I only found the :locale sub-pragma in and and it
seems it does not work with binmode at all and would also fail on Win32
systems due to not setting the relevant environment variables. So I've
implemented a crude and simple solution like this:

  use Encode;
  use Encode::Alias;

  sub terminal_encoding {
    my $encoding;

    if ($^O eq 'MSWin32') {
     eval {
        require Win32::API;
        $encoding = "cp" . Win32::API->new('kernel32',
          'UINT GetConsoleOutputCP()')->Call();
    } else {
      require encoding;
      $encoding = encoding::_get_locale_encoding();

    return $encoding;

  define_alias(qr/^:terminal$/ =>
    __PACKAGE__ . '->terminal_encoding()');

I then wondered about putting this into a module, but there seem too
many problems with this at the moment, one obvious thing is calling the
supposedly private _get_locale_encoding function to provide a fallback
on non-Win32 systems, then there are some codepages that might be used
as default somewhere that Encode supports but does not support the cp
alias for it (I could not find a list of those in use, presumably only
the three digit pages are default oem code pages and Encode supports the
cp alias for the encodings it support it seems), needing a C compiler on
Windows is kind of annoying (it would be nice if a Core module would ex-
pose GetConsoleOutputCP), and error handling seems tricky.

For example, it seems not possible to control the Encode fallback beha-
vior only for the one file handle in question, falling back to "no
encoding" if the terminal encoding is unsupported is not possible either
(unless someone makes a 'raw' encoding I suppose), the encoding finder
code cannot croak as it's running in a string eval, and I am not sure
there is a good way to generate a warning if and only if the code doing
the binmode has warnings turned on. So while this seemed elegant at
first, I've ditched the idea. Perhaps someone else is going to take this

Björn Höhrmann · ·
Weinh. Str. 22 · Telefon: +49(0)621/4309674 ·
68309 Mannheim · PGP Pub. KeyID: 0xA4357E78 · Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About