~ubuntu-branches/ubuntu/hardy/uim/hardy

« back to all changes in this revision

Viewing changes to sigscheme/src/encoding.c

  • Committer: Bazaar Package Importer
  • Author(s): Masahito Omote
  • Date: 2007-04-21 03:46:09 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: james.westby@ubuntu.com-20070421034609-gpcurkutp8vaysqj
Tags: 1:1.4.1-3
* Switch to dh_gtkmodules for the gtk 2.10 transition (Closes:
  #419318)
  - debian/control: Add ${misc:Depends} and remove libgtk2.0-bin on
    uim-gtk2.0.
  - debian/uim-gtk2.0.post{inst,rm}: Removed.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*===========================================================================
 
2
 *  Filename : encoding.c
 
3
 *  About    : Character encoding handling
 
4
 *
 
5
 *  Copyright (C) 2005      Kazuki Ohta <mover AT hct.zaq.ne.jp>
 
6
 *  Copyright (C) 2005      Jun Inoue <jun.lambda AT gmail.com>
 
7
 *  Copyright (C) 2005-2006 YAMAMOTO Kengo <yamaken AT bp.iij4u.or.jp>
 
8
 *  Copyright (c) 2007 SigScheme Project <uim AT freedesktop.org>
 
9
 *
 
10
 *  All rights reserved.
 
11
 *
 
12
 *  Redistribution and use in source and binary forms, with or without
 
13
 *  modification, are permitted provided that the following conditions
 
14
 *  are met:
 
15
 *
 
16
 *  1. Redistributions of source code must retain the above copyright
 
17
 *     notice, this list of conditions and the following disclaimer.
 
18
 *  2. Redistributions in binary form must reproduce the above copyright
 
19
 *     notice, this list of conditions and the following disclaimer in the
 
20
 *     documentation and/or other materials provided with the distribution.
 
21
 *  3. Neither the name of authors nor the names of its contributors
 
22
 *     may be used to endorse or promote products derived from this software
 
23
 *     without specific prior written permission.
 
24
 *
 
25
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
 
26
 *  IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 
27
 *  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 
28
 *  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
 
29
 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 
30
 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 
31
 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 
32
 *  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 
33
 *  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 
34
 *  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 
35
 *  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
36
===========================================================================*/
 
37
 
 
38
/* Acknowledgement: much information was gained from the
 
39
 * i18n-introduction of the debian project.  Many thanks to its
 
40
 * authors, Tomohiro KUBOTA, et al. */
 
41
 
 
42
/*
 
43
 * This file is intended to be portable. Don't depend on SigScheme and don't
 
44
 * merge into another file.
 
45
 */
 
46
 
 
47
#include <config.h>
 
48
 
 
49
#include <stdlib.h>
 
50
#include <string.h>
 
51
 
 
52
#include "scmint.h"
 
53
#include "encoding-config.h"
 
54
#include "encoding.h"
 
55
 
 
56
/*=======================================
 
57
  File Local Macro Definitions
 
58
=======================================*/
 
59
 
 
60
/*=======================================
 
61
  File Local Type Definitions
 
62
=======================================*/
 
63
typedef unsigned char uchar;
 
64
 
 
65
/*=======================================
 
66
  File Local Functions
 
67
=======================================*/
 
68
static scm_bool pred_always_true(void) SCM_UNUSED;
 
69
static scm_bool pred_always_false(void) SCM_UNUSED;
 
70
 
 
71
#if SCM_USE_EUCJP
 
72
static const char *eucjp_encoding(void);
 
73
static enum ScmCodedCharSet eucjp_ccs(void);
 
74
static int eucjp_char_len(scm_ichar_t ch);
 
75
static ScmMultibyteCharInfo eucjp_scan_char(ScmMultibyteString mbs);
 
76
static scm_ichar_t eucjp_str2int(const uchar *src, size_t len,
 
77
                                 ScmMultibyteState state);
 
78
static uchar *eucjp_int2str(uchar *dst, scm_ichar_t ch,
 
79
                            ScmMultibyteState state);
 
80
#endif
 
81
 
 
82
#if SCM_USE_ISO2022KR
 
83
static ScmMultibyteCharInfo iso2022kr_scan_char(ScmMultibyteString mbs);
 
84
static ScmMultibyteCharInfo iso2022kr_scan_input_char(ScmMultibyteString mbs);
 
85
#endif
 
86
 
 
87
#if SCM_USE_ISO2022JP
 
88
static ScmMultibyteCharInfo iso2022jp_scan_char(ScmMultibyteString mbs);
 
89
static ScmMultibyteCharInfo iso2022jp_scan_input_char(ScmMultibyteString mbs);
 
90
#endif
 
91
 
 
92
#if SCM_USE_SJIS
 
93
static const char *sjis_encoding(void);
 
94
static enum ScmCodedCharSet sjis_ccs(void);
 
95
static int sjis_char_len(scm_ichar_t ch);
 
96
static ScmMultibyteCharInfo sjis_scan_char(ScmMultibyteString mbs);
 
97
static uchar *sjis_int2str(uchar *dst, scm_ichar_t ch,
 
98
                           ScmMultibyteState state);
 
99
#endif
 
100
 
 
101
#if (SCM_USE_EUCCN || SCM_USE_EUCKR || SCM_USE_SJIS)
 
102
/* generic double-byte char */
 
103
static scm_ichar_t dbc_str2int(const uchar *src, size_t len,
 
104
                               ScmMultibyteState state);
 
105
#endif
 
106
 
 
107
#if (SCM_USE_EUCCN || SCM_USE_EUCKR)
 
108
/* shared by EUCCN and EUCKR */
 
109
static int euc_char_len(scm_ichar_t ch);
 
110
static uchar *euc_int2str(uchar *dst, scm_ichar_t ch, ScmMultibyteState state);
 
111
#endif
 
112
 
 
113
#if SCM_USE_EUCCN
 
114
static const char *euccn_encoding(void);
 
115
static enum ScmCodedCharSet euccn_ccs(void);
 
116
static ScmMultibyteCharInfo euccn_scan_char(ScmMultibyteString mbs);
 
117
#endif
 
118
 
 
119
#if SCM_USE_EUCKR
 
120
static const char *euckr_encoding(void);
 
121
static enum ScmCodedCharSet euckr_ccs(void);
 
122
static ScmMultibyteCharInfo euckr_scan_char(ScmMultibyteString mbs);
 
123
#endif
 
124
 
 
125
#if SCM_USE_UTF8
 
126
static const char *utf8_encoding(void);
 
127
static enum ScmCodedCharSet utf8_ccs(void);
 
128
static int utf8_char_len(scm_ichar_t ch);
 
129
static ScmMultibyteCharInfo utf8_scan_char(ScmMultibyteString mbs);
 
130
static scm_ichar_t utf8_str2int(const uchar *src, size_t len,
 
131
                                ScmMultibyteState state);
 
132
static uchar *utf8_int2str(uchar *dst, scm_ichar_t ch,
 
133
                           ScmMultibyteState state);
 
134
#endif
 
135
 
 
136
static const char *unibyte_encoding(void);
 
137
static enum ScmCodedCharSet unibyte_ccs(void);
 
138
static int unibyte_char_len(scm_ichar_t ch);
 
139
static ScmMultibyteCharInfo unibyte_scan_char(ScmMultibyteString mbs);
 
140
static scm_ichar_t unibyte_str2int(const uchar *src, size_t len,
 
141
                                   ScmMultibyteState state);
 
142
static uchar *unibyte_int2str(uchar *dst, scm_ichar_t ch,
 
143
                              ScmMultibyteState state);
 
144
 
 
145
/*=======================================
 
146
  Local Variables
 
147
=======================================*/
 
148
#if SCM_USE_UTF8
 
149
static const ScmCharCodecVTbl utf8_codec_vtbl = {
 
150
    &pred_always_false,
 
151
    &utf8_encoding,
 
152
    &utf8_ccs,
 
153
    &utf8_char_len,
 
154
    &utf8_scan_char,
 
155
    (ScmCharCodecMethod_str2int)&utf8_str2int,
 
156
    (ScmCharCodecMethod_int2str)&utf8_int2str
 
157
};
 
158
#define utf8_codec (&utf8_codec_vtbl)
 
159
#endif
 
160
 
 
161
#if SCM_USE_EUCCN
 
162
static const ScmCharCodecVTbl euccn_codec_vtbl = {
 
163
    &pred_always_false,
 
164
    &euccn_encoding,
 
165
    &euccn_ccs,
 
166
    &euc_char_len,
 
167
    &euccn_scan_char,
 
168
    (ScmCharCodecMethod_str2int)&dbc_str2int,
 
169
    (ScmCharCodecMethod_int2str)&euc_int2str
 
170
};
 
171
#define euccn_codec (&euccn_codec_vtbl)
 
172
#endif
 
173
 
 
174
#if SCM_USE_EUCJP
 
175
static const ScmCharCodecVTbl eucjp_codec_vtbl = {
 
176
    &pred_always_false,
 
177
    &eucjp_encoding,
 
178
    &eucjp_ccs,
 
179
    &eucjp_char_len,
 
180
    &eucjp_scan_char,
 
181
    (ScmCharCodecMethod_str2int)&eucjp_str2int,
 
182
    (ScmCharCodecMethod_int2str)&eucjp_int2str
 
183
};
 
184
#define eucjp_codec (&eucjp_codec_vtbl)
 
185
#endif
 
186
 
 
187
#if SCM_USE_EUCKR
 
188
static const ScmCharCodecVTbl euckr_codec_vtbl = {
 
189
    &pred_always_false,
 
190
    &euckr_encoding,
 
191
    &euckr_ccs,
 
192
    &euc_char_len,
 
193
    &euckr_scan_char,
 
194
    (ScmCharCodecMethod_str2int)&dbc_str2int,
 
195
    (ScmCharCodecMethod_int2str)&euc_int2str
 
196
};
 
197
#define euckr_codec (&euckr_codec_vtbl)
 
198
#endif
 
199
 
 
200
#if SCM_USE_SJIS
 
201
static const ScmCharCodecVTbl sjis_codec_vtbl = {
 
202
    &pred_always_false,
 
203
    &sjis_encoding,
 
204
    &sjis_ccs,
 
205
    &sjis_char_len,
 
206
    &sjis_scan_char,
 
207
    (ScmCharCodecMethod_str2int)&dbc_str2int,
 
208
    (ScmCharCodecMethod_int2str)&sjis_int2str
 
209
};
 
210
#define sjis_codec (&sjis_codec_vtbl)
 
211
#endif
 
212
 
 
213
static const ScmCharCodecVTbl unibyte_codec_vtbl = {
 
214
    &pred_always_false,
 
215
    &unibyte_encoding,
 
216
    &unibyte_ccs,
 
217
    &unibyte_char_len,
 
218
    &unibyte_scan_char,
 
219
    (ScmCharCodecMethod_str2int)&unibyte_str2int,
 
220
    (ScmCharCodecMethod_int2str)&unibyte_int2str
 
221
};
 
222
#define unibyte_codec (&unibyte_codec_vtbl)
 
223
 
 
224
static ScmCharCodec *const available_codecs[] = {
 
225
#if SCM_USE_UTF8
 
226
    utf8_codec,
 
227
#endif
 
228
#if SCM_USE_EUCJP
 
229
    eucjp_codec,
 
230
#endif
 
231
#if SCM_USE_EUCCN
 
232
    euccn_codec,
 
233
#endif
 
234
#if SCM_USE_EUCKR
 
235
    euckr_codec,
 
236
#endif
 
237
#if SCM_USE_SJIS
 
238
    sjis_codec,
 
239
#endif
 
240
    unibyte_codec,
 
241
    NULL
 
242
};
 
243
 
 
244
/*=======================================
 
245
  Global Variables
 
246
=======================================*/
 
247
SCM_DEFINE_EXPORTED_VARS(encoding);
 
248
 
 
249
/*=======================================
 
250
  Public API
 
251
=======================================*/
 
252
SCM_EXPORT void
 
253
scm_encoding_init(void)
 
254
{
 
255
    SCM_GLOBAL_VARS_INIT(encoding);
 
256
 
 
257
    /* To allow re-initialization of the interpreter, this variables must be
 
258
     * initialized by assignment. Initialized .data section does not work for
 
259
     * such situation.  -- YamaKen 2006-03-31 */
 
260
 
 
261
    /* temporary solution */
 
262
    scm_current_char_codec
 
263
#if SCM_USE_UTF8_AS_DEFAULT
 
264
        = utf8_codec;
 
265
#elif SCM_USE_EUCJP_AS_DEFAULT
 
266
        = eucjp_codec;
 
267
#elif SCM_USE_EUCCN_AS_DEFAULT
 
268
        = euccn_codec;
 
269
#elif SCM_USE_EUCKR_AS_DEFAULT
 
270
        = euckr_codec;
 
271
#elif SCM_USE_SJIS_AS_DEFAULT
 
272
        = sjis_codec;
 
273
#else
 
274
        = unibyte_codec;
 
275
#endif
 
276
}
 
277
 
 
278
SCM_EXPORT size_t
 
279
scm_mb_strlen(ScmCharCodec *codec, ScmMultibyteString mbs)
 
280
{
 
281
    size_t len;
 
282
    ScmMultibyteCharInfo c;
 
283
 
 
284
    SCM_ENCODING_CDBG((SCM_DBG_ENCODING, "mb_strlen: size = ~ZU; str = ~S;",
 
285
                       SCM_MBS_GET_SIZE(mbs), SCM_MBS_GET_STR(mbs)));
 
286
 
 
287
    for (len = 0; SCM_MBS_GET_SIZE(mbs); len++) {
 
288
        c = SCM_CHARCODEC_SCAN_CHAR(codec, mbs);
 
289
        SCM_ENCODING_CDBG((SCM_DBG_ENCODING, "~ZU, ~D;",
 
290
                           SCM_MBCINFO_GET_SIZE(c), c.flag));
 
291
        SCM_MBS_SKIP_CHAR(mbs, c);
 
292
    }
 
293
 
 
294
    SCM_ENCODING_CDBG((SCM_DBG_ENCODING, "len=~ZU\n", len));
 
295
    return len;
 
296
}
 
297
 
 
298
/* FIXME: pick a better name. */
 
299
SCM_EXPORT size_t
 
300
scm_mb_bare_c_strlen(ScmCharCodec *codec, const char *s)
 
301
{
 
302
    ScmMultibyteString mbs;
 
303
 
 
304
    SCM_MBS_INIT2(mbs, s, strlen(s));
 
305
    return scm_mb_strlen(codec, mbs);
 
306
}
 
307
 
 
308
SCM_EXPORT ScmMultibyteString
 
309
scm_mb_substring(ScmCharCodec *codec,
 
310
                 ScmMultibyteString mbs, size_t i, size_t len)
 
311
{
 
312
    ScmMultibyteString ret, end;
 
313
    ScmMultibyteCharInfo c;
 
314
 
 
315
    ret = mbs;
 
316
 
 
317
    while (i--) {
 
318
        c = SCM_CHARCODEC_SCAN_CHAR(codec, ret);
 
319
        SCM_MBS_SKIP_CHAR(ret, c);
 
320
    }
 
321
 
 
322
    end = ret;
 
323
 
 
324
    while (len--) {
 
325
        c = SCM_CHARCODEC_SCAN_CHAR(codec, end);
 
326
        SCM_MBS_SKIP_CHAR(end, c);
 
327
    }
 
328
 
 
329
    SCM_MBS_SET_SIZE(ret, SCM_MBS_GET_STR(end) - SCM_MBS_GET_STR(ret));
 
330
    return ret;
 
331
}
 
332
 
 
333
/* TODO: support encoding name canonicalization */
 
334
SCM_EXPORT ScmCharCodec *
 
335
scm_mb_find_codec(const char *encoding)
 
336
{
 
337
    ScmCharCodec *const *codecp;
 
338
 
 
339
    for (codecp = &available_codecs[0]; *codecp; codecp++) {
 
340
        if (strcmp(SCM_CHARCODEC_ENCODING(*codecp), encoding) == 0)
 
341
            return *codecp;
 
342
    }
 
343
 
 
344
    return NULL;
 
345
}
 
346
 
 
347
SCM_EXPORT scm_ichar_t
 
348
scm_charcodec_read_char(ScmCharCodec *codec, ScmMultibyteString *mbs,
 
349
                        const char *caller)
 
350
{
 
351
    ScmMultibyteCharInfo mbc;
 
352
    ScmMultibyteState state;
 
353
    scm_ichar_t ch;
 
354
 
 
355
    SCM_ENCODING_ASSERT(SCM_MBS_GET_SIZE(*mbs));
 
356
 
 
357
    state = SCM_MBS_GET_STATE(*mbs);
 
358
    mbc = SCM_CHARCODEC_SCAN_CHAR(codec, *mbs);
 
359
    if (SCM_MBCINFO_ERRORP(mbc) || SCM_MBCINFO_INCOMPLETEP(mbc))
 
360
        SCM_ENCODING_ERROR("scm_charcodec_read_char: invalid char sequence");
 
361
    ch = SCM_CHARCODEC_STR2INT(codec,
 
362
                               SCM_MBS_GET_STR(*mbs),
 
363
                               SCM_MBCINFO_GET_SIZE(mbc),
 
364
                               state);
 
365
    if (ch == SCM_ICHAR_EOF)
 
366
        SCM_ENCODING_ERROR("scm_charcodec_read_char: invalid char sequence");
 
367
 
 
368
    SCM_MBS_SKIP_CHAR(*mbs, mbc);
 
369
 
 
370
    return ch;
 
371
}
 
372
 
 
373
/*=======================================
 
374
  Encoding-specific functions
 
375
=======================================*/
 
376
 
 
377
static scm_bool
 
378
pred_always_true(void)
 
379
{
 
380
    return scm_true;
 
381
}
 
382
 
 
383
static scm_bool
 
384
pred_always_false(void)
 
385
{
 
386
    return scm_false;
 
387
}
 
388
 
 
389
/* Every encoding implements the <encoding name>_scan_char()
 
390
 * primitive.  Its job is to determine the length of the first
 
391
 * character in the given string.  Stateful encodings should save
 
392
 * their state *at exit*, that is, the state right after reading the
 
393
 * first character (so don't omit it).  */
 
394
 
 
395
/* Convenience macros.  Start with ENTER and return with RETURN*.
 
396
 * EXPECT_SIZE() declares the expected length of the character.  We'll
 
397
 * use it to return information on how many octets are missing.  It
 
398
 * also serves as documentation.  */
 
399
#define ENTER   ScmMultibyteCharInfo _ret;  SCM_MBCINFO_INIT(_ret)
 
400
#define RETURN(n)                                                            \
 
401
    do {                                                                     \
 
402
        SCM_MBCINFO_SET_SIZE(_ret, n);                                       \
 
403
        return _ret;                                                         \
 
404
    } while (/* CONSTCOND */ 0)
 
405
#define RETURN_ERROR()                                                       \
 
406
    do {                                                                     \
 
407
        SCM_MBCINFO_SET_ERROR(_ret);                                         \
 
408
        RETURN(1);                                                           \
 
409
    } while (/* CONSTCOND */ 0)
 
410
#define RETURN_INCOMPLETE(n)                                                 \
 
411
    do {                                                                     \
 
412
        SCM_MBCINFO_SET_INCOMPLETE(_ret);                                    \
 
413
        RETURN(n);                                                           \
 
414
    } while (/* CONSTCOND */ 0)
 
415
#define SAVE_STATE(stat) SCM_MBCINFO_SET_STATE(_ret, (stat))
 
416
#define EXPECT_SIZE(size) SCM_EMPTY_EXPR /* Currently ignored. */
 
417
 
 
418
/* Encodings based on ISO/IEC 2022. */
 
419
 
 
420
/* Control regions. */
 
421
#define IN_CL(c)   ((uchar)(c) < 0x20)
 
422
#define IN_CR(c)   (0x80 <= (uchar)(c) && (uchar)(c) <= 0x9F)
 
423
 
 
424
/* General purpose regions. */
 
425
#define IN_GL94(c) (0x21 <= (uchar)(c) && (uchar)(c) <= 0x7E)
 
426
#define IN_GL96(c) (0x20 <= (uchar)(c) && (uchar)(c) <= 0x7F)
 
427
#define IN_GR94(c) (0xA1 <= (uchar)(c) && (uchar)(c) <= 0xFE)
 
428
#define IN_GR96(c) (0xA0 <= (uchar)(c) /* && (uchar)(c) <= 0xFF */)
 
429
 
 
430
#define IS_ASCII(c) ((scm_ichar_t)(c) <= 0x7F)
 
431
#define IS_GR_SPC_OR_DEL(c)  ((uchar)(c) == 0xA0 || (uchar)(c) == 0xFF)
 
432
 
 
433
#define CHAR_BITS    8
 
434
#define BYTE_MASK    0xFF
 
435
#define IS_1BYTE(e)  ((scm_ichar_t)(e) <= 0x7F)
 
436
#define IS_2BYTES(e) ((scm_ichar_t)(e) <= 0xFFFF)
 
437
#define IS_3BYTES(e) ((scm_ichar_t)(e) <= ((SS3 << CHAR_BITS * 2) | 0xFFFF))
 
438
 
 
439
#define ESC 0x1B
 
440
#define SO  0x0E
 
441
#define SI  0x0F
 
442
#define SS2 0x8E
 
443
#define SS3 0x8F
 
444
 
 
445
#if SCM_USE_EUCJP
 
446
static const char *
 
447
eucjp_encoding(void)
 
448
{
 
449
    return "EUC-JP";
 
450
}
 
451
 
 
452
static enum ScmCodedCharSet
 
453
eucjp_ccs(void)
 
454
{
 
455
    return SCM_CCS_JIS;
 
456
}
 
457
 
 
458
/* FIXME: Optimize */
 
459
static int
 
460
eucjp_char_len(scm_ichar_t ch)
 
461
{
 
462
    uchar *end;
 
463
    uchar buf[SCM_MB_CHAR_BUF_SIZE];
 
464
 
 
465
    end = eucjp_int2str(buf, ch, SCM_MB_STATELESS);
 
466
 
 
467
    return (end) ? end - buf : 0;
 
468
}
 
469
 
 
470
/* G0 <- (96) ASCII (or was it JIS X 0201 Roman?)
 
471
 * G1 <- (94x94) JIS X 0208 kanji/kana
 
472
 * G2 <- (94) JIS X 0201 Katakana ("half-width katakana")
 
473
 * G3 <- (94x94) JIS X 0212 kanji, or JIS X 0213 kanji plane 2
 
474
 *
 
475
 * GL <- G0 (ASCII)
 
476
 * GR <- G1 (JIS X 0208)
 
477
 * CL <- JIS X 0211 C0
 
478
 * CR <- JIS X 0211 C1 */
 
479
static ScmMultibyteCharInfo
 
480
eucjp_scan_char(ScmMultibyteString mbs)
 
481
{
 
482
    const uchar *str = (const uchar *)SCM_MBS_GET_STR(mbs);
 
483
    const size_t size = SCM_MBS_GET_SIZE(mbs);
 
484
    ENTER;
 
485
 
 
486
    if (!size)
 
487
        RETURN(0);
 
488
 
 
489
    if (IN_CL(str[0]) || IN_GL96(str[0]))
 
490
        RETURN(1);
 
491
    else if (IN_GR94(str[0]) || (uchar)str[0] == SS2) {
 
492
        EXPECT_SIZE(2);
 
493
        if (size < 2)         RETURN_INCOMPLETE(1);
 
494
#if SCM_STRICT_ENCODING_CHECK
 
495
        if (!IN_GR96(str[1])) RETURN_ERROR();
 
496
#endif
 
497
        RETURN(2);
 
498
    } else if ((uchar)str[0] == SS3) {
 
499
        EXPECT_SIZE(3);
 
500
#if SCM_STRICT_ENCODING_CHECK
 
501
        if (size < 2)         RETURN_INCOMPLETE(size);
 
502
        if (IS_GR_SPC_OR_DEL(str[1]))
 
503
            RETURN(2);
 
504
        if (!IN_GR94(str[1])) RETURN_ERROR();
 
505
        if (size < 3)         RETURN_INCOMPLETE(size);
 
506
        if (!IN_GR94(str[2])) RETURN_ERROR();
 
507
        RETURN(3);
 
508
#else  /* not SCM_STRICT_ENCODING_CHECK */
 
509
        if (size < 3)
 
510
            RETURN_INCOMPLETE(size);
 
511
        RETURN(3);
 
512
#endif /* not SCM_STRICT_ENCODING_CHECK */
 
513
    }
 
514
 
 
515
    RETURN_ERROR();
 
516
}
 
517
 
 
518
static scm_ichar_t
 
519
eucjp_str2int(const uchar *src, size_t len, ScmMultibyteState state)
 
520
{
 
521
    scm_ichar_t ch;
 
522
 
 
523
    switch (len) {
 
524
    case 1:
 
525
        ch = src[0];
 
526
        break;
 
527
 
 
528
    case 2:
 
529
        ch  = src[0] << CHAR_BITS;
 
530
        ch |= src[1];
 
531
        break;
 
532
 
 
533
    case 3:
 
534
        ch  = src[0] << CHAR_BITS * 2;
 
535
        ch |= src[1] << CHAR_BITS;
 
536
        ch |= src[2];
 
537
        break;
 
538
 
 
539
    default:
 
540
        return SCM_ICHAR_EOF;
 
541
    }
 
542
 
 
543
    return ch;
 
544
}
 
545
 
 
546
/* TODO: migrate to a canonical form shared with ISO-2022 variants that contain
 
547
   absolute character set identifier instead of raw encoding-dependent
 
548
   shifts */
 
549
static uchar *
 
550
eucjp_int2str(uchar *dst, scm_ichar_t ch, ScmMultibyteState state)
 
551
{
 
552
#if SCM_STRICT_ENCODING_CHECK
 
553
    uchar seq[3];
 
554
#endif
 
555
 
 
556
    if (IS_1BYTE(ch)) {
 
557
        *dst++ = ch;
 
558
    } else if (IS_2BYTES(ch)) {
 
559
#if SCM_STRICT_ENCODING_CHECK
 
560
        seq[0] = ch >> CHAR_BITS;
 
561
        seq[1] = ch & BYTE_MASK;
 
562
        if ((!IN_GR94(seq[0]) && seq[0] != SS2)
 
563
            || !IN_GR96(seq[1]))
 
564
            return NULL;
 
565
#endif
 
566
        *dst++ = ch >> CHAR_BITS;
 
567
        *dst++ = ch & BYTE_MASK;
 
568
    } else if (IS_3BYTES(ch)) {
 
569
#if SCM_STRICT_ENCODING_CHECK
 
570
        seq[0] = ch >> CHAR_BITS * 2;
 
571
        seq[1] = (ch >> CHAR_BITS) & BYTE_MASK;
 
572
        seq[2] = ch & BYTE_MASK;
 
573
        if (seq[0] != SS3 || !IN_GR94(seq[1]) || !IN_GR94(seq[2]))
 
574
            return NULL;
 
575
#endif
 
576
        *dst++ = ch >> CHAR_BITS * 2;
 
577
        *dst++ = (ch >> CHAR_BITS) & BYTE_MASK;
 
578
        *dst++ = ch & BYTE_MASK;
 
579
    } else {
 
580
        return NULL;
 
581
    }
 
582
    *dst = '\0';
 
583
 
 
584
    return dst;
 
585
}
 
586
#endif /* SCM_USE_EUCJP */
 
587
 
 
588
#if (SCM_USE_EUCCN || SCM_USE_EUCKR || SCM_USE_SJIS)
 
589
/* generic double-byte char */
 
590
static scm_ichar_t
 
591
dbc_str2int(const uchar *src, size_t len, ScmMultibyteState state)
 
592
{
 
593
    scm_ichar_t ch;
 
594
 
 
595
    switch (len) {
 
596
    case 1:
 
597
        ch = src[0];
 
598
        break;
 
599
 
 
600
    case 2:
 
601
        ch  = src[0] << CHAR_BITS;
 
602
        ch |= src[1];
 
603
        break;
 
604
 
 
605
    default:
 
606
        return SCM_ICHAR_EOF;
 
607
    }
 
608
 
 
609
    return ch;
 
610
}
 
611
#endif /* (SCM_USE_EUCCN || SCM_USE_EUCKR || SCM_USE_SJIS) */
 
612
 
 
613
#if (SCM_USE_EUCCN || SCM_USE_EUCKR)
 
614
/* FIXME: Optimize */
 
615
static int
 
616
euc_char_len(scm_ichar_t ch)
 
617
{
 
618
    uchar *end;
 
619
    uchar buf[SCM_MB_CHAR_BUF_SIZE];
 
620
 
 
621
    end = euc_int2str(buf, ch, SCM_MB_STATELESS);
 
622
 
 
623
    return (end) ? end - buf : 0;
 
624
}
 
625
 
 
626
static uchar *
 
627
euc_int2str(uchar *dst, scm_ichar_t ch, ScmMultibyteState state)
 
628
{
 
629
#if SCM_STRICT_ENCODING_CHECK
 
630
    uchar seq[2];
 
631
#endif
 
632
 
 
633
    if (IS_1BYTE(ch)) {
 
634
        *dst++ = ch;
 
635
    } else if (IS_2BYTES(ch)) {
 
636
#if SCM_STRICT_ENCODING_CHECK
 
637
        seq[0] = ch >> CHAR_BITS;
 
638
        seq[1] = ch & BYTE_MASK;
 
639
        if (!IN_GR94(seq[0]) || !IN_GR96(seq[1]))
 
640
            return NULL;
 
641
#endif
 
642
        *dst++ = ch >> CHAR_BITS;
 
643
        *dst++ = ch & BYTE_MASK;
 
644
    } else {
 
645
        return NULL;
 
646
    }
 
647
    *dst = '\0';
 
648
 
 
649
    return dst;
 
650
}
 
651
#endif /* (SCM_USE_EUCCN || SCM_USE_EUCKR) */
 
652
 
 
653
#if SCM_USE_EUCCN
 
654
static const char *
 
655
euccn_encoding(void)
 
656
{
 
657
    return "EUC-CN";
 
658
}
 
659
 
 
660
static enum ScmCodedCharSet
 
661
euccn_ccs(void)
 
662
{
 
663
    return SCM_CCS_UNKNOWN;
 
664
}
 
665
 
 
666
/* FIXME: NOT TESTED!
 
667
 *
 
668
 * G0 <- ASCII (or GB 1988?)
 
669
 * G1 <- GB2312
 
670
 *
 
671
 * GL <- G0 (ASCII)
 
672
 * GR <- G1 (GB2312) */
 
673
static ScmMultibyteCharInfo
 
674
euccn_scan_char(ScmMultibyteString mbs)
 
675
{
 
676
    /* TODO: maybe we can make this an alias of eucjp_scan_char()? */
 
677
    const uchar *str = (const uchar *)SCM_MBS_GET_STR(mbs);
 
678
    const size_t size = SCM_MBS_GET_SIZE(mbs);
 
679
    ENTER;
 
680
 
 
681
    if (!size)
 
682
        RETURN(0);
 
683
    if (IS_ASCII(str[0]))
 
684
        RETURN(1);
 
685
    if (IN_GR94(str[0])) {
 
686
        EXPECT_SIZE(2);
 
687
        if (size < 2)
 
688
            RETURN_INCOMPLETE(size);
 
689
#if SCM_STRICT_ENCODING_CHECK
 
690
        if (!IN_GR96(str[1]))
 
691
            RETURN_ERROR();
 
692
#endif
 
693
        RETURN(2);
 
694
    }
 
695
    RETURN_ERROR();
 
696
}
 
697
#endif
 
698
 
 
699
#if SCM_USE_EUCKR
 
700
static enum ScmCodedCharSet
 
701
euckr_ccs(void)
 
702
{
 
703
    return SCM_CCS_UNKNOWN;
 
704
}
 
705
 
 
706
static const char *
 
707
euckr_encoding(void)
 
708
{
 
709
    return "EUC-KR";
 
710
}
 
711
 
 
712
/* FIXME: NOT TESTED!  I'm not sure about this encoding.  There's also
 
713
 * a Microsoft variant called CP949, which is not supported (yet).
 
714
 * RFC 1557 says KS X 1001 is 94x94.
 
715
 *
 
716
 * G0 <- ASCII
 
717
 * G1 <- KS X 1001 (aka KSC 5601)
 
718
 *
 
719
 * GL <- G0
 
720
 * GR <- G1 */
 
721
static ScmMultibyteCharInfo
 
722
euckr_scan_char(ScmMultibyteString mbs)
 
723
{
 
724
    const uchar *str = (const uchar *)SCM_MBS_GET_STR(mbs);
 
725
    const size_t size = SCM_MBS_GET_SIZE(mbs);
 
726
    ENTER;
 
727
 
 
728
    if (!size)
 
729
        RETURN(0);
 
730
    if (IS_ASCII(str[0]))
 
731
        RETURN(1);
 
732
    if (IN_GR94(str[0])) {
 
733
        EXPECT_SIZE(2);
 
734
        if (size < 2)
 
735
            RETURN_INCOMPLETE(size);
 
736
#if SCM_STRICT_ENCODING_CHECK
 
737
        if (!IN_GR96(str[1]))
 
738
            RETURN_ERROR();
 
739
#endif
 
740
        RETURN(2);
 
741
    }
 
742
    RETURN_ERROR();
 
743
}
 
744
#endif /* SCM_USE_EUCKR */
 
745
 
 
746
/*==== Encodings for Unicode ====*/
 
747
#define IN_OCT_BMP(u)  ((scm_ichar_t)(u) <= 0x7ff)
 
748
#define IN_BMP(u)      ((scm_ichar_t)(u) <= 0xffff)
 
749
#define IN_SMP(u)      ((scm_ichar_t)(u) <= 0x10ffff && !IN_BMP(u))
 
750
 
 
751
#if SCM_USE_UTF8
 
752
/* RFC 3629 */
 
753
#define MASK(n)        ((LEN_CODE(n) >> 1) | 0x80)
 
754
#define LEN_CODE(n)    (((1 << (n))-1) << (8-n))
 
755
#define IS_LEN(c, n)   ((MASK(n) & (c)) == LEN_CODE(n))
 
756
#define IS_TRAILING(c) (IS_LEN((c), 1))
 
757
 
 
758
#define LEN_CODE_BITS(n)    (n + 1)
 
759
#define TRAILING_CODE_BITS  LEN_CODE_BITS(1)
 
760
#define TRAILING_VAL_BITS   (CHAR_BITS - TRAILING_CODE_BITS)
 
761
#define LEADING_VAL_BITS(n) (CHAR_BITS - LEN_CODE_BITS(n))
 
762
#define LEADING_VAL(u, n)   ((u) >> TRAILING_VAL_BITS * ((n) - 1))
 
763
#define TRAILING_VAL(u, i)  (~MASK(1) & ((u) >> TRAILING_VAL_BITS * (i)))
 
764
 
 
765
static const char *
 
766
utf8_encoding(void)
 
767
{
 
768
    return "UTF-8";
 
769
}
 
770
 
 
771
static enum ScmCodedCharSet
 
772
utf8_ccs(void)
 
773
{
 
774
    return SCM_CCS_UCS4;
 
775
}
 
776
 
 
777
/* FIXME: Optimize */
 
778
static int
 
779
utf8_char_len(scm_ichar_t ch)
 
780
{
 
781
    uchar *end;
 
782
    uchar buf[SCM_MB_CHAR_BUF_SIZE];
 
783
 
 
784
    end = utf8_int2str(buf, ch, SCM_MB_STATELESS);
 
785
 
 
786
    return (end) ? end - buf : 0;
 
787
}
 
788
 
 
789
static ScmMultibyteCharInfo
 
790
utf8_scan_char(ScmMultibyteString mbs)
 
791
{
 
792
    const uchar *str = (const uchar *)SCM_MBS_GET_STR(mbs);
 
793
    const size_t size = SCM_MBS_GET_SIZE(mbs);
 
794
    size_t len;
 
795
    ENTER;
 
796
 
 
797
    if (!size)
 
798
        RETURN(0);
 
799
    if (IS_ASCII(str[0]))
 
800
        RETURN(1);
 
801
 
 
802
    if (IS_LEN(str[0], 2))       len = 2;
 
803
    else if (IS_LEN(str[0], 3))  len = 3;
 
804
    else if (IS_LEN(str[0], 4))  len = 4;
 
805
    else                         RETURN_ERROR();
 
806
 
 
807
#if SCM_STRICT_ENCODING_CHECK
 
808
    {
 
809
        size_t i;
 
810
        for (i = 1; i < len; i++) {
 
811
            if (size <= i)
 
812
                RETURN_INCOMPLETE(size);
 
813
            if (!IS_TRAILING(str[i]))
 
814
                RETURN_ERROR();
 
815
        }
 
816
    }
 
817
#else  /* not SCM_STRICT_ENCODING_CHECK */
 
818
    if (size < len)
 
819
        RETURN_INCOMPLETE(size);
 
820
#endif /* not SCM_STRICT_ENCODING_CHECK */
 
821
 
 
822
    RETURN(len);
 
823
 
 
824
}
 
825
 
 
826
static scm_ichar_t
 
827
utf8_str2int(const uchar *src, size_t len, ScmMultibyteState state)
 
828
{
 
829
    scm_ichar_t ch;
 
830
 
 
831
    switch (len) {
 
832
    case 1:
 
833
        ch = src[0];
 
834
        break;
 
835
 
 
836
    case 2:
 
837
        ch  = (~MASK(2) & src[0]) << TRAILING_VAL_BITS;
 
838
        ch |= (~MASK(1) & src[1]);
 
839
        break;
 
840
 
 
841
    case 3:
 
842
        ch  = (~MASK(3) & src[0]) << TRAILING_VAL_BITS * 2;
 
843
        ch |= (~MASK(1) & src[1]) << TRAILING_VAL_BITS;
 
844
        ch |= (~MASK(1) & src[2]);
 
845
        break;
 
846
 
 
847
    case 4:
 
848
        ch  = (~MASK(4) & src[0]) << TRAILING_VAL_BITS * 3;
 
849
        ch |= (~MASK(1) & src[1]) << TRAILING_VAL_BITS * 2;
 
850
        ch |= (~MASK(1) & src[2]) << TRAILING_VAL_BITS;
 
851
        ch |= (~MASK(1) & src[3]);
 
852
        break;
 
853
 
 
854
    default:
 
855
        return SCM_ICHAR_EOF;
 
856
    }
 
857
 
 
858
    return ch;
 
859
}
 
860
 
 
861
static uchar *
 
862
utf8_int2str(uchar *dst, scm_ichar_t ch, ScmMultibyteState state)
 
863
{
 
864
    if (IS_ASCII(ch)) {
 
865
        *dst++ = ch;
 
866
    } else if (IN_OCT_BMP(ch)) {
 
867
        *dst++ = LEN_CODE(2) | LEADING_VAL(ch, 2);
 
868
        *dst++ = LEN_CODE(1) | TRAILING_VAL(ch, 0);
 
869
    } else if (IN_BMP(ch)) {
 
870
        *dst++ = LEN_CODE(3) | LEADING_VAL(ch, 3);
 
871
        *dst++ = LEN_CODE(1) | TRAILING_VAL(ch, 1);
 
872
        *dst++ = LEN_CODE(1) | TRAILING_VAL(ch, 0);
 
873
    } else if (IN_SMP(ch)) {
 
874
        *dst++ = LEN_CODE(4) | LEADING_VAL(ch, 4);
 
875
        *dst++ = LEN_CODE(1) | TRAILING_VAL(ch, 2);
 
876
        *dst++ = LEN_CODE(1) | TRAILING_VAL(ch, 1);
 
877
        *dst++ = LEN_CODE(1) | TRAILING_VAL(ch, 0);
 
878
    } else {
 
879
        return NULL;
 
880
    }
 
881
    *dst = '\0';
 
882
 
 
883
    return dst;
 
884
}
 
885
#undef MASK
 
886
#undef LEN_CODE
 
887
#undef IS_LEN
 
888
#undef IS_TRAILING
 
889
#undef LEN_CODE_BITS
 
890
#undef TRAILING_CODE_BITS
 
891
#undef TRAILING_VAL_BITS
 
892
#undef LEADING_VAL_BITS
 
893
#undef LEADING_VAL
 
894
#undef TRAILING_VAL
 
895
#endif /* SCM_USE_UTF8 */
 
896
 
 
897
/*==== Other encodings ====*/
 
898
 
 
899
#if SCM_USE_SJIS
 
900
/* The cwazy Japanese encoding.  This function implements the JIS X
 
901
 * 0213 variant.
 
902
 *
 
903
 * 0 .. 0x7F: ASCII
 
904
 * 0x80: undefined
 
905
 * 0x81 .. 0x9F: lead byte of 2-byte char
 
906
 * 0xA0: undefined
 
907
 * 0xA1 .. 0xDF: JIS X 0201 katakana (1 byte)
 
908
 * 0xE0 .. 0xEF: lead byte of 2-byte char
 
909
 * 0xF0 .. 0xFC: lead byte of 2-byte char if JIS X 0213 is used
 
910
 * 0xFD .. 0xFF: undefined
 
911
 *
 
912
 * 0x40 .. 0x7E: trailing byte of 2-byte char
 
913
 * 0x80 .. 0xFC: trailing byte of 2-byte char
 
914
 */
 
915
#define IS_KANA(c) (0xA1 <= (uchar)(c) && (uchar)(c) <= 0xDF)
 
916
#define IS_LEAD(c)        \
 
917
    (0x81 <= (uchar)(c)   \
 
918
    && !IS_KANA(c)        \
 
919
    && (uchar)(c) <= 0xFC \
 
920
    && (uchar)(c) != 0xA0)
 
921
#define IS_TRAIL(c) (0x40 <= (uchar)(c) && (uchar)(c) <= 0xFC && (c) != 0x7E)
 
922
 
 
923
static const char *
 
924
sjis_encoding(void)
 
925
{
 
926
    return "SHIFT_JIS";
 
927
}
 
928
 
 
929
static enum ScmCodedCharSet
 
930
sjis_ccs(void)
 
931
{
 
932
    return SCM_CCS_UNKNOWN;
 
933
}
 
934
 
 
935
/* FIXME: Optimize */
 
936
static int
 
937
sjis_char_len(scm_ichar_t ch)
 
938
{
 
939
    uchar *end;
 
940
    uchar buf[SCM_MB_CHAR_BUF_SIZE];
 
941
 
 
942
    end = sjis_int2str(buf, ch, SCM_MB_STATELESS);
 
943
 
 
944
    return (end) ? end - buf : 0;
 
945
}
 
946
 
 
947
static ScmMultibyteCharInfo
 
948
sjis_scan_char(ScmMultibyteString mbs)
 
949
{
 
950
    const uchar *str = (const uchar *)SCM_MBS_GET_STR(mbs);
 
951
    const size_t size = SCM_MBS_GET_SIZE(mbs);
 
952
    ENTER;
 
953
 
 
954
    if (!size)
 
955
        RETURN(0);
 
956
    if (IS_LEAD(str[0])) {
 
957
        EXPECT_SIZE(2);
 
958
        if (size < 2)
 
959
            RETURN_INCOMPLETE(size);
 
960
#if SCM_STRICT_ENCODING_CHECK
 
961
        if (!IS_TRAIL(str[1]))
 
962
            RETURN_ERROR();
 
963
#endif
 
964
        RETURN(2);
 
965
    }
 
966
    RETURN(1);
 
967
}
 
968
 
 
969
static uchar *
 
970
sjis_int2str(uchar *dst, scm_ichar_t ch, ScmMultibyteState state)
 
971
{
 
972
    uchar high, low;
 
973
 
 
974
#if SCM_STRICT_ENCODING_CHECK
 
975
    if (ch >> CHAR_BITS * 2)
 
976
        return NULL;
 
977
#endif
 
978
    high = ch >> CHAR_BITS;
 
979
    low  = ch & BYTE_MASK;
 
980
 
 
981
    if (IS_LEAD(high)) {
 
982
#if SCM_STRICT_ENCODING_CHECK
 
983
        if (!IS_TRAIL(high))
 
984
            return NULL;
 
985
#endif
 
986
        *dst++ = high;
 
987
    }
 
988
    *dst++ = low;
 
989
    *dst = '\0';
 
990
 
 
991
    return dst;
 
992
}
 
993
#undef IS_KANA
 
994
#undef IS_LEAD
 
995
#undef IS_TRAIL
 
996
#endif /* SCM_USE_SJIS */
 
997
 
 
998
/* Single-byte encodings.  Please add any that you know are missing.
 
999
 * Sorted alphabetically.
 
1000
 *
 
1001
 * ASCII
 
1002
 * ISO 646
 
1003
 * ISO-8859-*
 
1004
 * VISCII
 
1005
 */
 
1006
static const char *
 
1007
unibyte_encoding(void)
 
1008
{
 
1009
    /* conventional assumption */
 
1010
    return "ISO-8859-1";
 
1011
}
 
1012
 
 
1013
static enum ScmCodedCharSet
 
1014
unibyte_ccs(void)
 
1015
{
 
1016
    /* conventional assumption */
 
1017
    return SCM_CCS_ISO8859_1;
 
1018
}
 
1019
 
 
1020
static int
 
1021
unibyte_char_len(scm_ichar_t ch)
 
1022
{
 
1023
    return (0 < ch && ch <= 0xff) ? 1 : 0;
 
1024
}
 
1025
 
 
1026
static ScmMultibyteCharInfo
 
1027
unibyte_scan_char(ScmMultibyteString mbs)
 
1028
{
 
1029
    ENTER;
 
1030
 
 
1031
    if (SCM_MBS_GET_SIZE(mbs))
 
1032
        RETURN(1);
 
1033
    RETURN(0);
 
1034
}
 
1035
 
 
1036
static scm_ichar_t
 
1037
unibyte_str2int(const uchar *src, size_t len, ScmMultibyteState state)
 
1038
{
 
1039
#if SCM_STRICT_ENCODING_CHECK
 
1040
    if (len != 1)
 
1041
        return SCM_ICHAR_EOF;
 
1042
#endif
 
1043
    return src[0];
 
1044
}
 
1045
 
 
1046
static uchar *
 
1047
unibyte_int2str(uchar *dst, scm_ichar_t ch, ScmMultibyteState state)
 
1048
{
 
1049
#if SCM_STRICT_ENCODING_CHECK
 
1050
    if (ch & ~BYTE_MASK)
 
1051
        return NULL;
 
1052
#endif
 
1053
    *dst++ = ch;
 
1054
    return dst;
 
1055
}