2 * Copyright © 2023 Nick Bowler
4 * Helper function to output the copyright symbol in a specified encoding.
6 * License WTFPL2: Do What The Fuck You Want To Public License, version 2.
7 * This is free software: you are free to do what the fuck you want to.
8 * There is NO WARRANTY, to the extent permitted by law.
21 #define ARRAYSIZE(x) (sizeof (x) / sizeof (x)[0])
23 static int compar_5arr(const void *key, const void *elem_)
25 const char (*elem)[5] = (void *)elem_;
27 return strncmp(key, *elem, sizeof *elem);
31 * Return, as a multibyte string, the copyright symbol for the
32 * given character encoding, which is one of the strings returned
33 * by Gnulib's locale_charset function. In particular, we are
34 * looking for one of the strings:
67 * All of these are ASCII supersets. EBCDIC code pages like CP1122 are
68 * presently handled by returning (C), even if the character set does
69 * include the copyright symbol.
71 * To simplify the implementation, we allow some slop in the matching,
72 * as long as the result is valid for any actual encoding names.
74 * If NLS support is disabled, or if the character set does not
75 * include the copyright symbol, then the string (C) is returned
76 * in the C execution character set.
78 const char *copyright_symbol(const char *charset)
80 /* All known encodings of the copyright symbol */
81 static const char codes[] =
88 "\x81\x30\x84\x38" "\0"
92 * We need the list below to be in lexicographic order in
93 * the C execution character encoding.
95 #if 'B'>'E' || 'C'>'E' || 'E'>'G' || 'G'>'I' || 'K'>'P' || 'P'>'U'
96 # error this character encoding is unsupported, please report a bug.
100 * For character sets that include the copyright symbol,
101 * the first 5 characters suffices to distinguish amongst
102 * all the different possible encodings.
104 static const char t1[][5] = {
123 * Each nibble in the results value contains the offset in the
124 * codes array for the corresponding index in t1, except that
125 * ISO-8859 matches the special value '2' (handled below).
127 uint_least64_t results = 0x001921fb13777511;
128 const char (*m1)[sizeof *t1];
134 m1 = bsearch(charset, t1, ARRAYSIZE(t1), sizeof *t1, compar_5arr);
140 cindex = (results >> (x << 2)) & 0xf;
143 * We now need to identify encodings that match one of the 5-character
144 * prefixes above but don't actually have the copyright symbol in their
145 * character set. Specifically, these are:
147 * CP1122 (does have it, but EBCDIC)
158 if ((x == 0) != (*charset == '9')) {
159 /* CP112x, x != '9', no copyright symbol. */
161 } else if (cindex == 2) {
163 * ISO-8859 special case. Simply find and look at the final
164 * two digits. The set bits in the 'accept' value indicate
165 * which encodings have the copyright symbol.
167 uint_least32_t accept = 0x00380383;
168 uint_least32_t collect = 0;
171 while ((c = *charset++)) {
178 cindex = (accept >> (collect & 0x1f)) & 1;
183 return &codes[cindex];