diff options
author | Karel Zak | 2014-01-29 14:09:54 +0100 |
---|---|---|
committer | Karel Zak | 2014-03-11 11:35:13 +0100 |
commit | 1b1f66e477f229fe9f3d4b5f9d8484ca50db02f2 (patch) | |
tree | 64cd6a69f582b00d3e2e92283e64df880e81eaab /lib/mbsalign.c | |
parent | fdisk: fix 'p'rint error on empty PT (diff) | |
download | kernel-qcow2-util-linux-1b1f66e477f229fe9f3d4b5f9d8484ca50db02f2.tar.gz kernel-qcow2-util-linux-1b1f66e477f229fe9f3d4b5f9d8484ca50db02f2.tar.xz kernel-qcow2-util-linux-1b1f66e477f229fe9f3d4b5f9d8484ca50db02f2.zip |
lib/mbalign: add mbs_safe_width() from tt.c
Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'lib/mbsalign.c')
-rw-r--r-- | lib/mbsalign.c | 137 |
1 files changed, 136 insertions, 1 deletions
diff --git a/lib/mbsalign.c b/lib/mbsalign.c index 89ef03298..5933f1863 100644 --- a/lib/mbsalign.c +++ b/lib/mbsalign.c @@ -23,17 +23,152 @@ #include <stdio.h> #include <stdbool.h> #include <limits.h> +#include <ctype.h> #include "c.h" #include "mbsalign.h" #include "widechar.h" - #ifdef HAVE_WIDECHAR /* Replace non printable chars. Note \t and \n etc. are non printable. Return 1 if replacement made, 0 otherwise. */ +/* + * Counts number of cells in multibyte string. For all control and + * non-printable chars is the result width enlarged to store \x?? hex + * sequence. See mbs_safe_encode(). + */ +size_t mbs_safe_width(const char *s) +{ + mbstate_t st; + const char *p = s; + size_t width = 0; + + memset(&st, 0, sizeof(st)); + + while (p && *p) { + if (iscntrl((unsigned char) *p)) { + width += 4; /* *p encoded to \x?? */ + p++; + } +#ifdef HAVE_WIDECHAR + else { + wchar_t wc; + size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); + + if (len == 0) + break; + + if (len == (size_t) -1 || len == (size_t) -2) { + len = 1; + width += (isprint((unsigned char) *p) ? 1 : 4); + + } if (!iswprint(wc)) + width += len * 4; /* hex encode whole sequence */ + else + width += wcwidth(wc); /* number of cells */ + p += len; + } +#else + else if (!isprint((unsigned char) *p)) { + width += 4; /* *p encoded to \x?? */ + p++; + } else { + width++; + p++; + } +#endif + } + + return width; +} + +/* + * Returns allocated string where all control and non-printable chars are + * replaced with \x?? hex sequence. + */ +char *mbs_safe_encode(const char *s, size_t *width) +{ + mbstate_t st; + const char *p = s; + char *res, *r; + size_t sz = s ? strlen(s) : 0; + + + if (!sz) + return NULL; + + memset(&st, 0, sizeof(st)); + + res = malloc((sz * 4) + 1); + if (!res) + return NULL; + + r = res; + *width = 0; + + while (p && *p) { + if (iscntrl((unsigned char) *p)) { + sprintf(r, "\\x%02x", (unsigned char) *p); + r += 4; + *width += 4; + p++; + } +#ifdef HAVE_WIDECHAR + else { + wchar_t wc; + size_t len = mbrtowc(&wc, p, MB_CUR_MAX, &st); + + if (len == 0) + break; /* end of string */ + + if (len == (size_t) -1 || len == (size_t) -2) { + len = 1; + /* + * Not valid multibyte sequence -- maybe it's + * printable char according to the current locales. + */ + if (!isprint((unsigned char) *p)) { + sprintf(r, "\\x%02x", (unsigned char) *p); + r += 4; + *width += 4; + } else { + width++; + *r++ = *p; + } + } else if (!iswprint(wc)) { + size_t i; + for (i = 0; i < len; i++) { + sprintf(r, "\\x%02x", (unsigned char) *p); + r += 4; + *width += 4; + } + } else { + memcpy(r, p, len); + r += len; + *width += wcwidth(wc); + } + p += len; + } +#else + else if (!isprint((unsigned char) *p)) { + sprintf(r, "\\x%02x", (unsigned char) *p); + p++; + r += 4; + *width += 4; + } else { + *r++ = *p++; + *width++; + } +#endif + } + + *r = '\0'; + + return res; +} + static bool wc_ensure_printable (wchar_t *wchars) { |