diff options
Diffstat (limited to 'apt-pkg/contrib')
-rw-r--r-- | apt-pkg/contrib/strutl.cc | 48 | ||||
-rw-r--r-- | apt-pkg/contrib/strutl.h | 2 |
2 files changed, 50 insertions, 0 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); } } |