+static void
+getwidth(const char *string)
+{
+ wchar_t c;
+ int charlen, charleft = strlen(string);
+ int length = 0;
+
+ /*
+ * In theory we should be able to use wcswidth(), but since we're
+ * testing out how the format libraries behave we'll do it a character
+ * at a time.
+ */
+
+ if (mbtowc(NULL, NULL, 0)) {}
+
+ while (charleft > 0) {
+ int clen;
+
+ charlen = mbtowc(&c, string, charleft);
+
+ if (charlen == 0)
+ break;
+
+ if (charlen < 0) {
+ fprintf(stderr, "Unable to convert string \"%s\"\n",
+ string);
+ return;
+ }
+
+ if ((clen = wcwidth(c)) < 0) {
+ fprintf(stderr, "U+%04lX non-printable\n",
+ (unsigned long int) c);
+ return;
+ }
+
+ length += clen;
+ string += charlen;
+ charleft -= charlen;
+ }
+
+ printf("%d\n", length);
+}
+
+typedef struct {
+ wchar_t min, max;
+} unicode_range;
+
+static unicode_range range[] = {
+ /* https://en.wikipedia.org/wiki/Unicode#Code_point_planes_and_blocks */
+ { L'\x0000', L'\xff' },
+#if WCHAR_MAX >= 0xffff
+ { L'\x0100', L'\xffff' },
+#if WCHAR_MAX >= 0xfffff
+ { L'\x10000', L'\x14fff' },
+ { L'\x16000', L'\x18fff' },
+ { L'\x1b000', L'\x1bfff' },
+ { L'\x1d000', L'\x1ffff' },
+ { L'\x20000', L'\x2ffff' },
+ { L'\xe0000', L'\xe0fff' },
+#endif
+#endif
+ { L'\0', L'\0' }, /* Terminates list. */
+};
+