summaryrefslogtreecommitdiffstats
path: root/lib/mbsalign.c
diff options
context:
space:
mode:
authorKarel Zak2014-01-29 14:09:54 +0100
committerKarel Zak2014-03-11 11:35:13 +0100
commit1b1f66e477f229fe9f3d4b5f9d8484ca50db02f2 (patch)
tree64cd6a69f582b00d3e2e92283e64df880e81eaab /lib/mbsalign.c
parentfdisk: fix 'p'rint error on empty PT (diff)
downloadkernel-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.c137
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)
{