diff options
author | Julian Andres Klode <jak@debian.org> | 2019-11-25 20:11:19 +0000 |
---|---|---|
committer | Julian Andres Klode <jak@debian.org> | 2019-11-25 20:11:19 +0000 |
commit | 6e2500016c7a07725a05f70d084fd572cd628575 (patch) | |
tree | 3d8f6ece94bf89c4ed7aa57352fe98a9d4eb3ffb | |
parent | 83f2732b10498c4a3abdfbc072da63803557ce9b (diff) | |
parent | 2497198e9599a6a8d4d0ad08627bcfc7ea49c644 (diff) | |
download | apt-6e2500016c7a07725a05f70d084fd572cd628575.tar.gz |
Merge branch 'fix-progressbar-size' into 'master'
Fix progress bar width for multibyte charsets
See merge request apt-team/apt!81
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 48 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.h | 2 | ||||
-rw-r--r-- | apt-pkg/install-progress.cc | 2 |
3 files changed, 51 insertions, 1 deletions
diff --git a/apt-pkg/contrib/strutl.cc b/apt-pkg/contrib/strutl.cc index 860e3fe47..70befdc48 100644 --- a/apt-pkg/contrib/strutl.cc +++ b/apt-pkg/contrib/strutl.cc @@ -40,6 +40,7 @@ #include <string.h> #include <time.h> #include <unistd.h> +#include <wchar.h> #include <apti18n.h> /*}}}*/ @@ -96,6 +97,53 @@ std::string Join(std::vector<std::string> list, const std::string &sep) return oss.str(); } +// Returns string display length honoring multi-byte characters +size_t DisplayLength(StringView str) +{ + size_t len = 0; + + const char *p = str.data(); + const char *const end = str.end(); + + mbstate_t state{}; + while (p < end) + { + wchar_t wch; + size_t res = mbrtowc(&wch, p, end - p, &state); + switch (res) + { + case 0: + // Null wide character (i.e. L'\0') - stop + p = end; + break; + + case static_cast<size_t>(-1): + // Byte sequence is invalid. Assume that it's + // a single-byte single-width character. + len += 1; + p += 1; + + // state is undefined in this case - reset it + state = {}; + + break; + + case static_cast<size_t>(-2): + // Byte sequence is too short. Assume that it's + // an incomplete single-width character and stop. + len += 1; + p = end; + break; + + default: + len += wcwidth(wch); + p += res; + } + } + + return len; +} + } } /*}}}*/ diff --git a/apt-pkg/contrib/strutl.h b/apt-pkg/contrib/strutl.h index fc02357a8..738480402 100644 --- a/apt-pkg/contrib/strutl.h +++ b/apt-pkg/contrib/strutl.h @@ -33,6 +33,8 @@ namespace APT { bool Endswith(const std::string &s, const std::string &ending); bool Startswith(const std::string &s, const std::string &starting); std::string Join(std::vector<std::string> list, const std::string &sep); + // Returns string display length honoring multi-byte characters + size_t DisplayLength(StringView str); } } diff --git a/apt-pkg/install-progress.cc b/apt-pkg/install-progress.cc index 2e8fac236..aadd28e51 100644 --- a/apt-pkg/install-progress.cc +++ b/apt-pkg/install-progress.cc @@ -382,7 +382,7 @@ bool PackageManagerFancy::DrawStatusLine() if (_config->FindB("Dpkg::Progress-Fancy::Progress-Bar", true)) { int padding = 4; - auto const progressbar_size = size.columns - padding - progress_str.size(); + auto const progressbar_size = size.columns - padding - String::DisplayLength(progress_str); auto const current_percent = percentage / 100.0f; std::cout << " " << GetTextProgressStr(current_percent, progressbar_size) |