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.
22 static int compar_5arr(const void *key, const void *elem_)
24 const char (*elem)[5] = elem_;
26 return strncmp(key, *elem, sizeof *elem);
30 * Return, as a multibyte string, the copyright symbol for the
31 * given character encoding, which is one of the strings returned
32 * by Gnulib's locale_charset function. In particular, we are
33 * looking for one of the strings:
66 * All of these are ASCII supersets. EBCDIC code pages like CP1122 are
67 * presently handled by returning (C), even if the character set does
68 * include the copyright symbol.
70 * To simplify the implementation, we allow some slop in the matching,
71 * as long as the result is valid for any actual encoding names.
73 * If NLS support is disabled, or if the character set does not
74 * include the copyright symbol, then the string (C) is returned
75 * in the C execution character set.
77 const char *copyright_symbol(const char *charset)
79 /* All known encodings of the copyright symbol */
80 static const char codes[] =
87 "\x81\x30\x84\x38" "\0"
91 * We need the list below to be in lexicographic order in
92 * the C execution character encoding.
94 #if 'B'>'E' || 'C'>'E' || 'E'>'G' || 'G'>'I' || 'K'>'P' || 'P'>'U'
95 # error this character encoding is unsupported, please report a bug.
99 * For character sets that include the copyright symbol,
100 * the first 5 characters suffices to distinguish amongst
101 * all the different possible encodings.
103 static const char t1[][5] = {
122 * Each nibble in the results value contains the offset in the
123 * codes array for the corresponding index in t1, except that
124 * ISO-8859 matches the special value '2' (handled below).
126 uint_least64_t results = 0x001921fb13777511;
127 const char (*m1)[sizeof *t1];
133 m1 = bsearch(charset, t1, XTRA_ARRAYSIZE(t1), sizeof *t1, compar_5arr);
139 cindex = (results >> (x << 2)) & 0xf;
142 * We now need to identify encodings that match one of the 5-character
143 * prefixes above but don't actually have the copyright symbol in their
144 * character set. Specifically, these are:
146 * CP1122 (does have it, but EBCDIC)
157 if ((x == 0) != (*charset == '9')) {
158 /* CP112x, x != '9', no copyright symbol. */
160 } else if (cindex == 2) {
162 * ISO-8859 special case. Simply find and look at the final
163 * two digits. The set bits in the 'accept' value indicate
164 * which encodings have the copyright symbol.
166 uint_least32_t accept = 0x00380383;
167 uint_least32_t collect = 0;
170 while ((c = *charset++)) {
177 cindex = (accept >> (collect & 0x1f)) & 1;
182 return &codes[cindex];