[BACK]Return to gettext_iconv.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / lib / libintl

Annotation of src/lib/libintl/gettext_iconv.c, Revision 1.8

1.8     ! yamt        1: /*     $NetBSD: gettext_iconv.c,v 1.7 2004/08/02 13:38:21 tshiozak Exp $       */
1.1       yamt        2:
                      3: /*-
                      4:  * Copyright (c) 2004 Citrus Project,
                      5:  * All rights reserved.
                      6:  *
                      7:  * Redistribution and use in source and binary forms, with or without
                      8:  * modification, are permitted provided that the following conditions
                      9:  * are met:
                     10:  * 1. Redistributions of source code must retain the above copyright
                     11:  *    notice, this list of conditions and the following disclaimer.
                     12:  * 2. Redistributions in binary form must reproduce the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer in the
                     14:  *    documentation and/or other materials provided with the distribution.
                     15:  *
                     16:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
                     17:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     18:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     19:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
                     20:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     21:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     22:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     23:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     24:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     25:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     26:  * SUCH DAMAGE.
                     27:  *
                     28:  * $Citrus$
                     29:  */
                     30:
                     31:
                     32: #include <sys/types.h>
                     33: #include <sys/param.h>
                     34:
                     35: #include <errno.h>
                     36: #include <iconv.h>
                     37: #include <libintl.h>
                     38: #include <langinfo.h>
                     39: #include <search.h>
                     40: #include <stdlib.h>
                     41: #include <string.h>
                     42:
                     43: #include "libintl_local.h"
                     44:
                     45: struct cache {
                     46:        const char *c_origmsg;
                     47:        const char *c_resultmsg;
                     48: };
                     49:
                     50: static const struct cache *cache_find(const char *, struct domainbinding *);
                     51: static int cache_enter(const char *, const char *);
                     52: static int cache_cmp(const void *, const void *);
                     53:
                     54: static void *cacheroot;
                     55:
1.3       yamt       56: /* ARGSUSED1 */
1.1       yamt       57: static const struct cache *
                     58: cache_find(const char *msg, struct domainbinding *db)
                     59: {
                     60:        struct cache key;
                     61:        struct cache **c;
                     62:
                     63:        key.c_origmsg = msg;
                     64:        c = tfind(&key, &cacheroot, cache_cmp);
                     65:
                     66:        return c ? *c : NULL;
                     67: }
                     68:
                     69: static int
                     70: cache_enter(const char *origmsg, const char *resultmsg)
                     71: {
                     72:        struct cache *c;
                     73:
                     74:        c = malloc(sizeof(*c));
                     75:        if (c == NULL)
                     76:                return -1;
                     77:
                     78:        c->c_origmsg = origmsg;
                     79:        c->c_resultmsg = resultmsg;
                     80:
                     81:        if (tsearch(c, &cacheroot, cache_cmp) == NULL) {
                     82:                free(c);
                     83:                return -1;
                     84:        }
                     85:
                     86:        return 0;
                     87: }
                     88:
                     89: static int
                     90: cache_cmp(const void *va, const void *vb)
                     91: {
                     92:        const struct cache *a = va;
                     93:        const struct cache *b = vb;
                     94:        int result;
                     95:
1.8     ! yamt       96:        if (a->c_origmsg > b->c_origmsg) {
        !            97:                result = 1;
        !            98:        } else if (a->c_origmsg < b->c_origmsg) {
        !            99:                result = -1;
        !           100:        } else {
        !           101:                result = 0;
        !           102:        }
1.1       yamt      103:
                    104:        return result;
                    105: }
                    106:
1.5       uebayasi  107: #define        GETTEXT_ICONV_MALLOC_CHUNK      (16 * 1024)
1.1       yamt      108:
                    109: const char *
                    110: __gettext_iconv(const char *origmsg, struct domainbinding *db)
                    111: {
                    112:        const char *tocode;
                    113:        const char *fromcode = db->mohandle.mo.mo_charset;
                    114:        const struct cache *cache;
                    115:        const char *result;
                    116:        iconv_t cd;
                    117:        const char *src;
                    118:        char *dst;
                    119:        size_t origlen;
                    120:        size_t srclen;
                    121:        size_t dstlen;
                    122:        size_t nvalid;
                    123:        int savederrno = errno;
                    124:
1.2       yamt      125:        /*
                    126:         * static buffer for converted texts.
                    127:         *
                    128:         * note:
                    129:         * we never free buffers once returned to callers.
                    130:         * because of interface design of gettext, we can't know
                    131:         * the lifetime of them.
                    132:         */
1.1       yamt      133:        static char *buffer;
                    134:        static size_t bufferlen;
                    135:
1.5       uebayasi  136:        /*
                    137:         * don't convert message if *.mo doesn't specify codeset.
                    138:         */
                    139:        if (fromcode == NULL)
                    140:                return origmsg;
                    141:
1.1       yamt      142:        tocode = db->codeset;
                    143:        if (tocode == NULL) {
                    144:                /*
1.2       yamt      145:                 * codeset isn't specified explicitly by
                    146:                 * bind_textdomain_codeset().
1.4       yamt      147:                 * use current locale(LC_CTYPE)'s codeset.
1.1       yamt      148:                 *
                    149:                 * XXX maybe wrong; it can mismatch with
                    150:                 * environment variable setting.
                    151:                 */
                    152:                tocode = nl_langinfo(CODESET);
                    153:        }
                    154:
                    155:        /*
                    156:         * shortcut if possible.
                    157:         * XXX should handle aliases
                    158:         */
                    159:        if (!strcasecmp(tocode, fromcode))
                    160:                return origmsg;
                    161:
                    162:        /* XXX LOCK */
                    163:
                    164:        /* XXX should detect change of tocode and purge caches? */
                    165:
                    166:        /*
                    167:         * see if we have already converted this message.
                    168:         */
                    169:        cache = cache_find(origmsg, db);
                    170:        if (cache) {
                    171:                result = cache->c_resultmsg;
                    172:                goto out;
                    173:        }
                    174:
                    175:        origlen = strlen(origmsg) + 1;
                    176: again:
                    177:        cd = iconv_open(tocode, fromcode);
                    178:        if (cd == (iconv_t)-1) {
                    179:                result = origmsg;
                    180:                goto out;
                    181:        }
                    182:
                    183:        src = origmsg;
                    184:        srclen = origlen;
                    185:        dst = buffer;
                    186:        dstlen = bufferlen;
1.7       tshiozak  187:        nvalid = iconv(cd, &src, &srclen, &dst, &dstlen);
1.1       yamt      188:        iconv_close(cd);
                    189:
                    190:        if (nvalid == (size_t)-1) {
                    191:                /*
                    192:                 * try to allocate a new buffer.
                    193:                 *
                    194:                 * just give up if GETTEXT_ICONV_MALLOC_CHUNK was not enough.
                    195:                 */
                    196:                if (errno == E2BIG &&
                    197:                    bufferlen != GETTEXT_ICONV_MALLOC_CHUNK) {
                    198:                        buffer = malloc(GETTEXT_ICONV_MALLOC_CHUNK);
                    199:                        if (buffer) {
                    200:                                bufferlen = GETTEXT_ICONV_MALLOC_CHUNK;
                    201:                                goto again;
                    202:                        }
                    203:                }
                    204:
                    205:                result = origmsg;
                    206:        } else if (cache_enter(origmsg, buffer)) {
                    207:                /*
                    208:                 * failed to enter cache.  give up.
                    209:                 */
                    210:                result = origmsg;
                    211:        } else {
                    212:                size_t resultlen = dst - buffer;
                    213:
                    214:                result = buffer;
                    215:                bufferlen -= resultlen;
                    216:                buffer += resultlen;
                    217:        }
                    218:
                    219: out:
                    220:        /* XXX UNLOCK */
                    221:        errno = savederrno;
                    222:
                    223:        return result;
                    224: }

CVSweb <webmaster@jp.NetBSD.org>