summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Lambers <marlam@marlam.de>2011-04-18 20:42:58 +0200
committerMartin Lambers <marlam@marlam.de>2011-04-18 20:42:58 +0200
commit66993854b13c0039d98ce3e7b3e2ec8856236c98 (patch)
tree64e3cceeac9b75658b9921f7d7a9f98e6196431b
parentb40f31c9bbd0137598afbebbb52400115d7fa423 (diff)
downloadbino-66993854b13c0039d98ce3e7b3e2ec8856236c98.tar.gz
Fix formatted output from msg::*_txt for non-ASCII locales.
-rw-r--r--configure.ac2
-rw-r--r--src/base/msg.cpp90
2 files changed, 69 insertions, 23 deletions
diff --git a/configure.ac b/configure.ac
index b93f793..4b37c17 100644
--- a/configure.ac
+++ b/configure.ac
@@ -71,7 +71,7 @@ dnl Feature checks needed by the base module
AC_CHECK_DECLS([optreset], [#include <getopt.h>])
AC_SEARCH_LIBS([clock_gettime], [rt])
AC_SEARCH_LIBS([pthread_create], [pthread])
-AC_CHECK_FUNCS([backtrace clock_gettime sigaction vasprintf])
+AC_CHECK_FUNCS([backtrace clock_gettime sigaction vasprintf wcwidth])
dnl Gettext
AM_GNU_GETTEXT([external])
diff --git a/src/base/msg.cpp b/src/base/msg.cpp
index ebe38c4..e31ab0b 100644
--- a/src/base/msg.cpp
+++ b/src/base/msg.cpp
@@ -20,9 +20,12 @@
#include "config.h"
+#include <limits>
#include <cstdlib>
#include <cstdio>
+#include <cwchar>
+#include "dbg.h"
#include "str.h"
#include "msg.h"
@@ -151,6 +154,49 @@ namespace msg
msg(indent, level, s);
}
+ static std::wstring str_to_wstr(const std::string &in)
+ {
+ std::wstring out;
+ size_t l = std::mbstowcs(NULL, in.c_str(), 0);
+ if (l == static_cast<size_t>(-1) || l > static_cast<size_t>(std::numeric_limits<int>::max() - 1))
+ {
+ // This should never happen. We don't want to handle this case, and we don't want to throw
+ // an exception from a msg function, so inform the user and abort.
+ msg::err("Failure in msg::str_to_wstr().");
+ dbg::crash();
+ }
+ out.resize(l);
+ std::mbstowcs(&(out[0]), in.c_str(), l);
+ return out;
+ }
+
+ static int display_width(const std::wstring &ws)
+ {
+#ifdef HAVE_WCWIDTH
+ return std::max(0, ::wcswidth(ws.c_str(), ws.length()));
+#else
+ return ws.size() - 1;
+#endif
+ }
+
+ static int display_width(const wchar_t *ws, size_t n)
+ {
+#ifdef HAVE_WCWIDTH
+ return std::max(0, ::wcswidth(ws, n));
+#else
+ return n;
+#endif
+ }
+
+ static int display_width(wchar_t w)
+ {
+#ifdef HAVE_WCWIDTH
+ return std::max(0, ::wcwidth(w));
+#else
+ return 1;
+#endif
+ }
+
void msg_txt(int indent, level_t level, const std::string &s)
{
if (level < _level)
@@ -158,38 +204,38 @@ namespace msg
return;
}
- std::string pfx = prefix(level) + std::string(indent, ' ');
- int pfx_len = pfx.length();
- std::string text(s);
+ std::wstring pfx = str_to_wstr(prefix(level) + std::string(indent, ' '));
+ int pfx_dw = display_width(pfx);
+ std::wstring text = str_to_wstr(s);
- std::string out;
- int line_len = 0;
+ std::wstring out;
+ int line_dw = 0;
int first_unprinted = 0;
int last_blank = -1;
bool end_of_text = false;
for (int text_index = 0; !end_of_text; text_index++)
{
- if (text[text_index] == '\0')
+ if (text[text_index] == L'\0')
{
- text[text_index] = '\n';
+ text[text_index] = L'\n';
end_of_text = true;
}
- if (text[text_index] == '\n')
+ if (text[text_index] == L'\n')
{
// output from first_unprinted to text_index
out += pfx;
- out += std::string(text.c_str() + first_unprinted, text_index - first_unprinted + 1);
+ out += std::wstring(text.c_str() + first_unprinted, text_index - first_unprinted + 1);
first_unprinted = text_index + 1;
last_blank = -1;
- line_len = 0;
+ line_dw = 0;
}
else
{
- if (text[text_index] == ' ' || text[text_index] == '\t')
+ if (text[text_index] == L' ' || text[text_index] == L'\t')
{
last_blank = text_index;
}
- if (line_len >= _columns - pfx_len)
+ if (line_dw >= _columns - pfx_dw)
{
// output from first_unprinted to last_blank (which is replaced
// by '\n'), then update first_unprinted.
@@ -200,30 +246,30 @@ namespace msg
{
text_index++;
}
- while (text[text_index] != ' '
- && text[text_index] != '\t'
- && text[text_index] != '\n'
- && text[text_index] != '\0');
- if (text[text_index] == '\0')
+ while (text[text_index] != L' '
+ && text[text_index] != L'\t'
+ && text[text_index] != L'\n'
+ && text[text_index] != L'\0');
+ if (text[text_index] == L'\0')
{
end_of_text = true;
}
last_blank = text_index;
}
- text[last_blank] = '\n';
+ text[last_blank] = L'\n';
out += pfx;
- out += std::string(text.c_str() + first_unprinted, last_blank - first_unprinted + 1);
+ out += std::wstring(text.c_str() + first_unprinted, last_blank - first_unprinted + 1);
first_unprinted = last_blank + 1;
last_blank = -1;
- line_len = text_index - first_unprinted + 1;
+ line_dw = display_width(text.c_str() + first_unprinted, text_index - first_unprinted + 1);
}
else
{
- line_len++;
+ line_dw += display_width(text[text_index]);
}
}
}
- std::fputs(out.c_str(), _file);
+ std::fprintf(_file, "%ls", &(out[0]));
}
void msg_txt(int indent, level_t level, const char *format, ...)