← Back to davo.co
summaryrefslogtreecommitdiffstats
path: root/mbstrings-main.c
diff options
context:
space:
mode:
Diffstat (limited to 'mbstrings-main.c')
-rw-r--r--mbstrings-main.c206
1 files changed, 206 insertions, 0 deletions
diff --git a/mbstrings-main.c b/mbstrings-main.c
new file mode 100644
index 0000000..56a3838
--- /dev/null
+++ b/mbstrings-main.c
@@ -0,0 +1,206 @@
+#include <errno.h>
+#include <limits.h>
+#include <locale.h>
+#include <stdbool.h>
+#include <stdio.h>
+
+#include "mbstrings.h"
+
+enum {
+ g_l = 1,
+ g_r = 2,
+ g_u = 4,
+ g_d = 8,
+};
+
+#define MONTH(X) \
+ (char const*[]){ \
+ [1] = "Jan", \
+ [2] = "Feb", \
+ [3] = "Mar", \
+ [4] = "Apr", \
+ [5] = "Mai", \
+ [6] = "Jun", \
+ [7] = "Jul", \
+ [8] = "Aug", \
+ [9] = "Sep", \
+ [10] = "Oct", \
+ [11] = "Nov", \
+ [12] = "Dec", \
+ }[(X)%100]
+
+#define STRINGIFY_(X) #X
+#define STRINGIFY(X) STRINGIFY_(X)
+
+#define YEAR(X) \
+(char const[5]){ \
+ STRINGIFY(X)[0], \
+ STRINGIFY(X)[1], \
+ STRINGIFY(X)[2], \
+ STRINGIFY(X)[3], \
+ }
+
+#define VBAR "\u2502" /**< a vertical bar character */
+#define HBAR "\u2500" /**< a horizontal bar character */
+#define TOPLEFT "\u250c" /**< topleft corner character */
+#define TOPRIGHT "\u2510" /**< topright corner character */
+
+/**
+ ** @brief Draw multibyte strings @a start and @a end separated
+ ** by a horizontal line.
+ **/
+void draw_sep(char const start[static 1],
+ char const end[static 1]) {
+ fputs(start, stdout);
+ size_t slen = mbsrlen(start, 0);
+ size_t elen = 90 - mbsrlen(end, 0);
+ for (size_t i = slen; i < elen; ++i) fputs(HBAR, stdout);
+ fputs(end, stdout);
+ fputc('\n', stdout);
+}
+
+char const* g_table[] = {
+ [0] = " ",
+ [g_l] = "\u2574",
+ [g_r] = "\u2576",
+ [g_l|g_r] = "\u2500",
+ [g_u] = "\u2575",
+ [g_l|g_u] = "\u2518",
+ [g_r|g_u] = "\u2514",
+ [g_l|g_r|g_u] = "\u2534",
+ [g_d] = "\u2577",
+ [g_l|g_d] = "\u2510",
+ [g_r|g_d] = "\u250c",
+ [g_l|g_r|g_d] = "\u252c",
+ [g_u|g_d] = "\u2502",
+ [g_l|g_u|g_d] = "\u2524",
+ [g_r|g_u|g_d] = "\u251c",
+ [g_l|g_r|g_u|g_d] = "\u253c",
+};
+
+int main(void) {
+ /* The first action of the executable should be locale switch. */
+ char const* locC_ = setlocale(LC_CTYPE, 0);
+ char locC[strlen(locC_)+1];
+ strcpy(locC, locC_);
+
+ setlocale(LC_ALL, "");
+ /* Multibyte character printing only works after the locale
+ has been switched. */
+ draw_sep(TOPLEFT " © 2014 jɛnz ˈgʊzˌtɛt ", TOPRIGHT);
+
+ char const* locLoc_ = setlocale(LC_CTYPE, 0);
+ char locLoc[strlen(locLoc_)+1];
+ strcpy(locLoc, locLoc_);
+ char const strhello[] = "Hä\u0131łłö";
+ char const u8hello[] = u8"Hä\u0131łłö";
+ wchar_t const wcshello[] = L"Hä\u0131łłö";
+ char const strvowel[] = "aeiouäëïöüáéíóúàèìòùæœ\u0131";
+ char const u8vowel[] = u8"aeiouäëïöüáéíóúàèìòùæœ\u0131";
+ wchar_t const wcsvowel[] = L"aeiouäëïöüáéíóúàèìòùæœ\u0131";
+ char16_t c16butterfly[] = u"\U000272CA";
+ char32_t c32butterfly[] = U"\U000272CA";
+ wchar_t wbutterfly[] = L"\U000272CA";
+ char u8butterfly[] = u8"\U000272CA";
+ bool mbs_u8 = (sizeof strvowel != sizeof u8vowel)
+ ? false :
+ (!strcmp(strvowel, u8vowel))
+ && (!strcmp("\U000272CA", (char const*)u8"\U000272CA"));
+ printf(VBAR "%ls world: switched \"%s\" \u21E8 \"%s\", multibyte strings are%s utf8, state%s\n",
+ wcshello, locC, locLoc,
+ mbs_u8 ? "" : " not",
+ mblen(nullptr, 0) ? "full" : "less");
+ printf(VBAR "wchar_t (%ssigned) is %zu bit, wint_t (%ssigned) is %zu bit, WEOF is ",
+ (WCHAR_MIN ? "" : "un"), sizeof(wchar_t)*CHAR_BIT,
+ (WINT_MIN ? "" : "un"), sizeof(wint_t)*CHAR_BIT);
+ if (WINT_MIN) printf("%lld\n", (long long)WEOF);
+ else printf("%#llx\n", (unsigned long long)WEOF);
+ printf(VBAR "wchar_t are Unicode code points as of %s %s, ",
+# ifdef __STDC_ISO_10646__
+ MONTH(__STDC_ISO_10646__),
+ YEAR(__STDC_ISO_10646__)
+# else
+ "<unknown>",
+ "<unknown>"
+# endif
+ );
+# ifdef __STDC_MB_MIGHT_NEQ_WC__
+ fputs("the basic character set is not extended to wchar_t\n", stdout);
+# else
+ fputs("wchar_t extends the basic character set\n", stdout);
+# endif
+#ifdef __STDC_UTF_16__
+ fputs(VBAR "char16_t is UTF-16, ", stdout);
+#else
+ fputs("char16_t is not UTF-16, ", stdout);
+#endif
+#ifdef __STDC_UTF_32__
+ fputs("char32_t is UTF-32\n", stdout);
+#else
+ fputs(VBAR "char32_t is not UTF-32\n", stdout);
+#endif
+ draw_sep(g_table[g_u|g_d|g_r], g_table[g_l|g_u|g_d]);
+ printf(VBAR "testing character %ls, codepoint U+%lX, utf8 %hhx %hhx %hhx %hhx %hhx:\n",
+ wbutterfly, 0x272CALU,
+ u8butterfly[0], u8butterfly[1], u8butterfly[2], u8butterfly[3], u8butterfly[4]);
+ printf(VBAR "\twchar_t,\tlength %zu,\t%s\n",
+ (sizeof(wbutterfly)/sizeof(wbutterfly[0])) - 1,
+ (sizeof(wbutterfly)/sizeof(wbutterfly[0])) == 2
+ ? "one word encoding" : "surrogate encoding");
+ printf(VBAR "\tchar32_t,\tlength %zu,\t%s\n",
+ (sizeof(c32butterfly)/sizeof(c32butterfly[0])) - 1,
+ (sizeof(c32butterfly)/sizeof(c32butterfly[0])) == 2
+ ? "one word encoding" : "surrogate encoding");
+ printf(VBAR "\tchar16_t,\tlength %zu,\t%s\n",
+ (sizeof(c16butterfly)/sizeof(c16butterfly[0])) - 1,
+ (sizeof(c16butterfly)/sizeof(c16butterfly[0])) == 2
+ ? "one word encoding" : "surrogate encoding");
+ if (sizeof(wchar_t) == sizeof(char32_t))
+ printf(VBAR "\twchar_t and char32_t encoding %s\n",
+ (sizeof(c32butterfly) == sizeof(wbutterfly)
+ && c32butterfly[0] == wbutterfly[0]
+ && c32butterfly[1] == wbutterfly[1]) ? "are equal" : "differ");
+ else if (sizeof(wchar_t) == sizeof(char16_t))
+ printf(VBAR "\twchar_t and char16_t encoding %s\n",
+ (sizeof(c16butterfly) == sizeof(wbutterfly)
+ && c16butterfly[0] == wbutterfly[0]
+ && c16butterfly[1] == wbutterfly[1]) ? "are equal" : "differ");
+ else
+ printf(VBAR "\twchar_t, char32_t and char16_t types and encodings all differ\n");
+ char const mbs0[] = u8"ł";
+ char const* pos0 = mbsrmb(u8hello, nullptr, mbs0, 0);
+ draw_sep(g_table[g_u|g_d|g_r], g_table[g_l|g_u|g_d]);
+ printf(VBAR "search first:\tfound \"%s\",\tposition %td, %s\n", mbs0, pos0-u8hello, pos0);
+ pos0 = mbsrmb(u8hello, nullptr, mbs0, 1);
+ printf(VBAR "search second:\tfound \"%s\",\tposition %td, %s\n", mbs0, pos0-u8hello, pos0);
+ char const mbs1[] = u8"ł";
+ char const* pos1 = mbsrrmb(u8hello, nullptr, mbs1);
+ printf(VBAR "search last:\tfound \"%s\",\tposition %td, %s\n", mbs1, pos1-u8hello, pos1);
+ char const mbs2[] = u8"łö";
+ char const* pos2 = mbsrmbs(u8hello, nullptr, mbs2);
+ printf(VBAR "search needle:\tfound \"%s\",\tposition %td, %s\n", mbs2, pos2-u8hello, pos2);
+ char const mbs3[] = u8" \u2003\u2002—";
+ size_t pos3 = mbsspn_class(mbs3, iswspace);
+ printf(VBAR "skip space:\tfound \"%s\",\tposition %zu, %s\n", mbs3, pos3, mbs3+pos3);
+ draw_sep(g_table[g_u|g_d|g_r], g_table[g_l|g_u|g_d]);
+ printf(VBAR "floats (locale):\t%g (C with .)\t%g (C with ,)\t%g (with .)\t%g (with ,)\n",
+ strtod("9.3", nullptr), strtod("9,3", nullptr),
+ mbsrtod("\u20039.3", nullptr, nullptr), mbsrtod("\u20039,3", nullptr, nullptr));
+ draw_sep(g_table[g_u|g_d|g_r], g_table[g_l|g_u|g_d]);
+ printf(VBAR "vowels\t%ls\n", wcsvowel);
+ char u8vowel2[MB_LEN_MAX + sizeof u8vowel];
+ char* partial = mbsrncpy(sizeof u8vowel-2, u8vowel2, nullptr, u8vowel, nullptr);
+ if (partial[0]) partial[0] = 0;
+ printf(VBAR "partial\t%s\n", u8vowel2);
+ for (char const* s = strhello; s && s[0];) {
+ s += mbscspn(s, strvowel);
+ int vowels = mbsspn(s, strvowel);
+ if (!vowels) {
+ printf("bizarre, no vowels in remaining string %s", s);
+ break;
+ }
+ printf(VBAR "%d bytes for vowel(s) %.*s\n", vowels, vowels, s);
+ s += vowels;
+ }
+ draw_sep(g_table[g_u|g_r], g_table[g_l|g_u]);
+}