+
+ bufpos = buf + MAX_PUTBACK;
+ bufend = dst;
+}
+
+typedef void (*decoder_t)(void);
+
+static decoder_t decoder = decode_utf8;
+
+typedef struct named_decoder_t {
+ char const *name;
+ decoder_t decoder;
+} named_decoder_t;
+
+static named_decoder_t const decoders[] = {
+ { "CP819", decode_iso_8859_1 }, // offical alias
+ { "IBM819", decode_iso_8859_1 }, // offical alias
+ { "ISO-8859-1", decode_iso_8859_1 }, // offical alias
+ { "ISO-8859-15", decode_iso_8859_15 }, // offical name
+ { "ISO8859-1", decode_iso_8859_1 },
+ { "ISO8859-15", decode_iso_8859_15 },
+ { "ISO_8859-1", decode_iso_8859_1 }, // offical alias
+ { "ISO_8859-15", decode_iso_8859_15 }, // offical alias
+ { "ISO_8859-1:1987", decode_iso_8859_1 }, // offical name
+ { "Latin-9", decode_iso_8859_15 }, // offical alias
+ { "UTF-8", decode_utf8 }, // offical name
+ { "csISOLatin1", decode_iso_8859_1 }, // offical alias
+ { "cp1252", decode_windows_1252 },
+ { "iso-ir-100", decode_iso_8859_1 }, // offical alias
+ { "l1", decode_iso_8859_1 }, // offical alias
+ { "latin1", decode_iso_8859_1 }, // offical alias
+ { "windows-1252", decode_windows_1252 }, // official name
+
+ { NULL, NULL }
+};
+
+/** strcasecmp is not part of C99 so we need our own implementation here */
+static int my_strcasecmp(const char *s1, const char *s2)
+{
+ for ( ; *s1 != 0; ++s1, ++s2) {
+ if (tolower(*s1) != tolower(*s2))
+ break;
+ }
+ return (unsigned char)*s1 - (unsigned char)*s2;
+}
+
+void select_input_encoding(char const* const encoding)
+{
+ for (named_decoder_t const *i = decoders; i->name != NULL; ++i) {
+ if (my_strcasecmp(encoding, i->name) != 0)
+ continue;
+ decoder = i->decoder;
+ return;
+ }
+ fprintf(stderr, "error: input encoding \"%s\" not supported\n", encoding);
+}
+
+static inline void next_real_char(void)
+{
+ assert(bufpos <= bufend);
+ if (bufpos >= bufend) {
+ if (input == NULL) {
+ c = EOF;
+ return;
+ }
+ decoder();
+ }
+ c = *bufpos++;