Add CJK codecs support as discussed on python-dev. (SF #873597)

Several style fixes are suggested by Martin v. Loewis and
Marc-Andre Lemburg. Thanks!
diff --git a/Modules/cjkcodecs/codecentry.h b/Modules/cjkcodecs/codecentry.h
new file mode 100644
index 0000000..a8bc04c
--- /dev/null
+++ b/Modules/cjkcodecs/codecentry.h
@@ -0,0 +1,177 @@
+/*
+ * codecentry.h: Common Codec Entry Routines
+ *
+ * Written by Hye-Shik Chang <perky@FreeBSD.org>
+ * $CJKCodecs: codecentry.h,v 1.5 2004/01/17 11:26:10 perky Exp $
+ */
+
+#ifdef HAVE_ENCODER_INIT
+#define ENCODER_INIT_FUNC(encoding)     encoding##_encode_init
+#else
+#define ENCODER_INIT_FUNC(encoding)     NULL
+#endif
+
+#ifdef HAVE_ENCODER_RESET
+#define ENCODER_RESET_FUNC(encoding)    encoding##_encode_reset
+#else
+#define ENCODER_RESET_FUNC(encoding)    NULL
+#endif
+
+#ifdef HAVE_DECODER_INIT
+#define DECODER_INIT_FUNC(encoding)     encoding##_decode_init
+#else
+#define DECODER_INIT_FUNC(encoding)     NULL
+#endif
+
+#ifdef HAVE_DECODER_RESET
+#define DECODER_RESET_FUNC(encoding)    encoding##_decode_reset
+#else
+#define DECODER_RESET_FUNC(encoding)    NULL
+#endif
+
+#ifdef STRICT_BUILD
+#define BEGIN_CODEC_REGISTRY(encoding)                      \
+    __BEGIN_CODEC_REGISTRY(encoding, init_codecs_##encoding##_strict)
+#else
+#define BEGIN_CODEC_REGISTRY(encoding)                      \
+    __BEGIN_CODEC_REGISTRY(encoding, init_codecs_##encoding)
+#endif
+
+#define __BEGIN_CODEC_REGISTRY(encoding, initname)          \
+    static MultibyteCodec __codec = {                       \
+        #encoding STRICT_SUFX,                              \
+        encoding##_encode,                                  \
+        ENCODER_INIT_FUNC(encoding),                        \
+        ENCODER_RESET_FUNC(encoding),                       \
+        encoding##_decode,                                  \
+        DECODER_INIT_FUNC(encoding),                        \
+        DECODER_RESET_FUNC(encoding),                       \
+    };                                                      \
+                                                            \
+    static struct PyMethodDef __methods[] = {               \
+        {NULL, NULL},                                       \
+    };                                                      \
+                                                            \
+    void                                                    \
+    initname(void)                                          \
+    {                                                       \
+        PyObject    *codec;                                 \
+        PyObject    *m = NULL, *mod = NULL, *o = NULL;      \
+                                                            \
+        m = Py_InitModule("_codecs_" #encoding STRICT_SUFX, __methods);
+
+#define MAPOPEN(locale)                                     \
+    mod = PyImport_ImportModule("_codecs_mapdata_" #locale);\
+    if (mod == NULL) goto errorexit;                        \
+    if (
+#define IMPORTMAP_ENCDEC(charset)                           \
+    importmap(mod, "__map_" #charset, &charset##encmap,     \
+        &charset##decmap) ||
+#define IMPORTMAP_ENC(charset)                              \
+    importmap(mod, "__map_" #charset, &charset##encmap,     \
+        NULL) ||
+#define IMPORTMAP_DEC(charset)                              \
+    importmap(mod, "__map_" #charset, NULL,                 \
+        &charset##decmap) ||
+#define MAPCLOSE()                                          \
+    0) goto errorexit;                                      \
+    Py_DECREF(mod);
+
+#define END_CODEC_REGISTRY(encoding)                        \
+    mod = PyImport_ImportModule("_multibytecodec");         \
+    if (mod == NULL) goto errorexit;                        \
+    o = PyObject_GetAttrString(mod, "__create_codec");      \
+    if (o == NULL || !PyCallable_Check(o))                  \
+        goto errorexit;                                     \
+                                                            \
+    codec = createcodec(o, &__codec);                       \
+    if (codec == NULL)                                      \
+        goto errorexit;                                     \
+    PyModule_AddObject(m, "codec", codec);                  \
+    Py_DECREF(o); Py_DECREF(mod);                           \
+                                                            \
+    if (PyErr_Occurred())                                   \
+        Py_FatalError("can't initialize the _" #encoding    \
+            STRICT_SUFX " module");                         \
+                                                            \
+    return;                                                 \
+                                                            \
+errorexit:                                                  \
+    Py_XDECREF(m);                                          \
+    Py_XDECREF(mod);                                        \
+    Py_XDECREF(o);                                          \
+}
+
+#define CODEC_REGISTRY(encoding)                            \
+    BEGIN_CODEC_REGISTRY(encoding)                          \
+    END_CODEC_REGISTRY(encoding)
+
+#ifdef USING_BINARY_PAIR_SEARCH
+static DBCHAR
+find_pairencmap(ucs2_t body, ucs2_t modifier,
+                struct pair_encodemap *haystack, int haystacksize)
+{
+    int      pos, min, max;
+    ucs4_t   value = body << 16 | modifier;
+
+    min = 0;
+    max = haystacksize;
+
+    for (pos = haystacksize >> 1; min != max; pos = (min + max) >> 1)
+        if (value < haystack[pos].uniseq) {
+            if (max == pos) break;
+            else max = pos;
+        } else if (value > haystack[pos].uniseq) {
+            if (min == pos) break;
+            else min = pos;
+        } else
+            break;
+
+    if (value == haystack[pos].uniseq)
+        return haystack[pos].code;
+    else
+        return DBCINV;
+}
+#endif
+
+#ifndef CODEC_WITHOUT_MAPS
+static int
+importmap(PyObject *mod, const char *symbol,
+          const struct unim_index **encmap, const struct dbcs_index **decmap)
+{
+    PyObject    *o;
+
+    o = PyObject_GetAttrString(mod, (char*)symbol);
+    if (o == NULL)
+        return -1;
+    else if (!PyCObject_Check(o)) {
+        PyErr_SetString(PyExc_ValueError, "map data must be a CObject.");
+        return -1;
+    } else {
+        struct dbcs_map *map;
+        map = PyCObject_AsVoidPtr(o);
+        if (encmap != NULL)
+            *encmap = map->encmap;
+        if (decmap != NULL)
+            *decmap = map->decmap;
+        Py_DECREF(o);
+    }
+
+    return 0;
+}
+#endif
+
+static PyObject *
+createcodec(PyObject *cofunc, MultibyteCodec *codec)
+{
+    PyObject    *args, *r;
+
+    args = PyTuple_New(1);
+    if (args == NULL) return NULL;
+    PyTuple_SET_ITEM(args, 0, PyCObject_FromVoidPtr(codec, NULL));
+
+    r = PyObject_CallObject(cofunc, args);
+    Py_DECREF(args);
+
+    return r;
+}