~ubuntu-branches/ubuntu/hardy/sigscheme/hardy-proposed

« back to all changes in this revision

Viewing changes to encoding.c

  • Committer: Bazaar Package Importer
  • Author(s): NIIBE Yutaka
  • Date: 2006-05-23 21:46:41 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20060523214641-6ix4gz34wpiehub8
Tags: 0.5.0-2
* debian/control (Build-Depends): Added ruby.
  Thanks to Frederik Schueler.  Closes: #368571
* debian/rules (clean): invoke 'distclean' instead of 'clean'.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*===========================================================================
2
 
 *  FileName : encoding.c
3
 
 *  About    : handling encoding
4
 
 *
5
 
 *  Copyright (C) 2005      by Kazuki Ohta (mover@hct.zaq.ne.jp)
6
 
 *
7
 
 *  All rights reserved.
8
 
 *
9
 
 *  Redistribution and use in source and binary forms, with or without
10
 
 *  modification, are permitted provided that the following conditions
11
 
 *  are met:
12
 
 *
13
 
 *  1. Redistributions of source code must retain the above copyright
14
 
 *     notice, this list of conditions and the following disclaimer.
15
 
 *  2. Redistributions in binary form must reproduce the above copyright
16
 
 *     notice, this list of conditions and the following disclaimer in the
17
 
 *     documentation and/or other materials provided with the distribution.
18
 
 *  3. Neither the name of authors nor the names of its contributors
19
 
 *     may be used to endorse or promote products derived from this software
20
 
 *     without specific prior written permission.
21
 
 *
22
 
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
23
 
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 
 *  ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
26
 
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27
 
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
28
 
 *  GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 
 *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 
 *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 
 *  SUCH DAMAGE.
33
 
===========================================================================*/
34
 
 
35
 
/* Acknowledgement: much information was gained from the
36
 
 * i18n-introduction of the debian project.  Many thanks to its
37
 
 * authors, Tomohiro KUBOTA, et al. */
38
 
 
39
 
 
40
 
/*=======================================
41
 
  System Include
42
 
=======================================*/
43
 
 
44
 
/*=======================================
45
 
  Local Include
46
 
=======================================*/
47
 
#include "sigscheme.h"
48
 
#include "sigschemeinternal.h"
49
 
 
50
 
/*=======================================
51
 
  File Local Functions
52
 
=======================================*/
53
 
#if SCM_USE_EUCJP
54
 
static ScmMultibyteCharInfo eucjp_scan_char(ScmMultibyteString mbs);
55
 
#endif
56
 
 
57
 
#if SCM_USE_ISO2022KR
58
 
static ScmMultibyteCharInfo iso2022kr_scan_char(ScmMultibyteString mbs);
59
 
static ScmMultibyteCharInfo iso2022kr_scan_input_char(ScmMultibyteString mbs);
60
 
#endif
61
 
 
62
 
#if SCM_USE_ISO2022JP
63
 
static ScmMultibyteCharInfo iso2022jp_scan_char(ScmMultibyteString mbs);
64
 
static ScmMultibyteCharInfo iso2022jp_scan_input_char(ScmMultibyteString mbs);
65
 
#endif
66
 
 
67
 
#if SCM_USE_SJIS
68
 
static ScmMultibyteCharInfo sjis_scan_char(ScmMultibyteString mbs);
69
 
#endif
70
 
 
71
 
#if SCM_USE_EUCCN
72
 
static ScmMultibyteCharInfo euccn_scan_char(ScmMultibyteString mbs);
73
 
#endif
74
 
 
75
 
#if SCM_USE_EUCKR
76
 
static ScmMultibyteCharInfo euckr_scan_char(ScmMultibyteString mbs);
77
 
#endif
78
 
 
79
 
#if SCM_USE_UTF8
80
 
static ScmMultibyteCharInfo utf8_scan_char(ScmMultibyteString mbs);
81
 
#endif
82
 
 
83
 
static ScmMultibyteCharInfo unibyte_scan_char(ScmMultibyteString mbs);
84
 
 
85
 
typedef unsigned char uchar;
86
 
 
87
 
/*=======================================
88
 
  Global Variables
89
 
=======================================*/
90
 
/* TODO: add some mechanism to dynamically switch between encodings. */
91
 
ScmMultibyteCharInfo (*Scm_mb_scan_char)(ScmMultibyteString mbs)
92
 
    = utf8_scan_char;
93
 
 
94
 
/*=======================================
95
 
  Public API
96
 
=======================================*/
97
 
 
98
 
int Scm_mb_strlen(ScmMultibyteString mbs)
99
 
{
100
 
    int len = 0;
101
 
    ScmMultibyteCharInfo c;
102
 
 
103
 
    CDBG((SCM_DBG_ENCODING, "mb_strlen: size = %d; str = %s;",
104
 
          SCM_MBS_GET_SIZE(mbs), SCM_MBS_GET_STR(mbs)));
105
 
 
106
 
    while (SCM_MBS_GET_SIZE(mbs)) {
107
 
        c = Scm_mb_scan_char(mbs);
108
 
        CDBG((SCM_DBG_ENCODING, "%d, %d;", SCM_MBCINFO_GET_SIZE(c), c.flag));
109
 
        SCM_MBS_SKIP_CHAR(mbs, c);
110
 
        len++;
111
 
    }
112
 
 
113
 
    CDBG((SCM_DBG_ENCODING, "len=%d\n", len));
114
 
    return len;
115
 
}
116
 
 
117
 
/* FIXME: pick a better name. */
118
 
int Scm_mb_bare_c_strlen(const char *s)
119
 
{
120
 
    ScmMultibyteString mbs;
121
 
    SCM_MBS_INIT(mbs);
122
 
    SCM_MBS_SET_STR(mbs, s);
123
 
    SCM_MBS_SET_SIZE(mbs, strlen(s));
124
 
    return Scm_mb_strlen(mbs);
125
 
}
126
 
 
127
 
ScmMultibyteString Scm_mb_substring(ScmMultibyteString mbs, int i, int len)
128
 
{
129
 
    ScmMultibyteString ret;
130
 
    ScmMultibyteString end;
131
 
    ScmMultibyteCharInfo c;
132
 
 
133
 
    ret = mbs;
134
 
 
135
 
    while (i--) {
136
 
        c = Scm_mb_scan_char(ret);
137
 
        SCM_MBS_SKIP_CHAR(ret, c);
138
 
    }
139
 
 
140
 
    end = ret;
141
 
 
142
 
    while (len--) {
143
 
        c = Scm_mb_scan_char(end);
144
 
        SCM_MBS_SKIP_CHAR(end, c);
145
 
    }
146
 
 
147
 
    SCM_MBS_SET_SIZE(ret, SCM_MBS_GET_STR(end) - SCM_MBS_GET_STR(ret));
148
 
    return ret;
149
 
}
150
 
 
151
 
 
152
 
/*=======================================
153
 
  Encoding-specific functions
154
 
=======================================*/
155
 
 
156
 
/* Every encoding implements the <encoding name>_scan_char()
157
 
 * primitive.  Its job is to determine the length of the first
158
 
 * character in the given string.  Stateful encodings should save
159
 
 * their state *at exit*, that is, the state right after reading the
160
 
 * first character (so don't omit it).  */
161
 
 
162
 
/* Convenience macros.  Start with ENTER and return with RETURN*.
163
 
 * EXPECT_SIZE() declares the expected length of the character.  We'll
164
 
 * use it to return information on how many octets are missing.  It
165
 
 * also serves as documentation.  */
166
 
#define ENTER   ScmMultibyteCharInfo _ret;  SCM_MBCINFO_INIT(_ret)
167
 
#define RETURN(n)  do { SCM_MBCINFO_SET_SIZE(_ret, n); return _ret; } while (0)
168
 
#define RETURN_ERROR() do { SCM_MBCINFO_SET_ERROR(_ret); RETURN(1); } while (0)
169
 
#define RETURN_INCOMPLETE(n) do { SCM_MBCINFO_SET_INCOMPLETE(_ret); RETURN(n); } while (0)
170
 
#define SAVE_STATE(stat) (SCM_MBCINFO_SET_STATE(_ret, (stat)))
171
 
#define EXPECT_SIZE(size) /* Currently ignored. */
172
 
 
173
 
/* Encodings based on ISO/IEC 2022. */
174
 
 
175
 
/* Control regions. */
176
 
#define IN_CL(c)   ((uchar)(c) < 0x20)
177
 
#define IN_CR(c)   (0x80 <= (uchar)(c) && (uchar)(c) <= 0x9F)
178
 
 
179
 
/* General purpose regions. */
180
 
#define IN_GL94(c) (0x21 <= (uchar)(c) && (uchar)(c) <= 0x7E)
181
 
#define IN_GL96(c) (0x20 <= (uchar)(c) && (uchar)(c) <= 0x7F)
182
 
#define IN_GR94(c) (0xA1 <= (uchar)(c) && (uchar)(c) <= 0xFE)
183
 
#define IN_GR96(c) (0xA0 <= (uchar)(c) && (uchar)(c) <= 0xFF)
184
 
 
185
 
#define IS_ASCII(c) ((uchar)(c) <= 0x7F)
186
 
#define IS_GR_SPC_OR_DEL(c)  ((uchar)(c) == 0xA0 || (uchar)(c) == 0xFF)
187
 
 
188
 
#define ESC 0x1B
189
 
#define SO  0x0E
190
 
#define SI  0x0F
191
 
#define SS2 0x8E
192
 
#define SS3 0x8F
193
 
 
194
 
 
195
 
#if SCM_USE_EUCJP
196
 
/* G0 <- (96) ASCII (or was it JIS X 0201 Roman?)
197
 
 * G1 <- (94x94) JIS X 0208 kanji/kana
198
 
 * G2 <- (94) JIS X 0201 Katakana ("half-width katakana")
199
 
 * G3 <- (94x94) JIS X 0212 kanji, or JIS X 0213 kanji plane 2
200
 
 *
201
 
 * GL <- G0 (ASCII)
202
 
 * GR <- G1 (JIS X 0208)
203
 
 * CL <- JIS X 0211 C0
204
 
 * CR <- JIS X 0211 C1 */
205
 
static ScmMultibyteCharInfo eucjp_scan_char(ScmMultibyteString mbs)
206
 
{
207
 
    const char *str = SCM_MBS_GET_STR(mbs);
208
 
    const int size  = SCM_MBS_GET_SIZE(mbs);
209
 
    ENTER;
210
 
 
211
 
    if (!size)
212
 
        RETURN(0);
213
 
 
214
 
    if (IN_CL(str[0]) || IN_GL96(str[0]))
215
 
        RETURN(1);
216
 
    else if (IN_GR94(str[0]) || (uchar)str[0] == SS2) {
217
 
        EXPECT_SIZE(2);
218
 
        if (size < 2)         RETURN_INCOMPLETE(1);
219
 
#if SCM_STRICT_ENCODING_CHECK
220
 
        if (!IN_GR96(str[1])) RETURN_ERROR();
221
 
#endif
222
 
        RETURN(2);
223
 
    } else if ((uchar)str[0] == SS3) {
224
 
        EXPECT_SIZE(3);
225
 
#if SCM_STRICT_ENCODING_CHECK
226
 
        if (size < 2)         RETURN_INCOMPLETE(size);
227
 
        if (IS_GR_SPC_OR_DEL(str[1]))
228
 
            RETURN(2);
229
 
        if (!IN_GR94(str[1])) RETURN_ERROR();
230
 
        if (size < 3)         RETURN_INCOMPLETE(size);
231
 
        if (!IN_GR94(str[2])) RETURN_ERROR();
232
 
        RETURN(3);
233
 
#else  /* not SCM_STRICT_ENCODING_CHECK */
234
 
        if (size < 3)
235
 
            RETURN_INCOMPLETE(size);
236
 
        RETURN(3);
237
 
#endif /* not SCM_STRICT_ENCODING_CHECK */
238
 
    }
239
 
 
240
 
    RETURN_ERROR();
241
 
}
242
 
#endif /* SCM_USE_EUCJP */
243
 
 
244
 
#if SCM_USE_EUCCN
245
 
/* FIXME: NOT TESTED!
246
 
 * 
247
 
 * G0 <- ASCII (or GB 1988?)
248
 
 * G1 <- GB2312
249
 
 *
250
 
 * GL <- G0 (ASCII)
251
 
 * GR <- G1 (GB2312) */
252
 
static ScmMultibyteCharInfo euccn_scan_char(ScmMultibyteString mbs)
253
 
{
254
 
    /* TODO: maybe we can make this an alias of eucjp_scan_char()? */
255
 
    const char *str = SCM_MBS_GET_STR(mbs);
256
 
    const int size  = SCM_MBS_GET_SIZE(mbs);
257
 
    ENTER;
258
 
 
259
 
    if (!size)
260
 
        RETURN(0);
261
 
    if (IS_ASCII(str[0]))
262
 
        RETURN(1);
263
 
    if (IN_GR94(str[0])) {
264
 
        EXPECT_SIZE(2);
265
 
        if (size < 2)
266
 
            RETURN_INCOMPLETE(size);
267
 
#if SCM_STRICT_ENCODING_CHECK
268
 
        if (!IN_GR96(str[1]))
269
 
            RETURN_ERROR();
270
 
#endif
271
 
        RETURN(2);
272
 
    }
273
 
    RETURN_ERROR();
274
 
}
275
 
#endif
276
 
 
277
 
#if SCM_USE_EUCKR
278
 
/* FIXME: NOT TESTED!  I'm not sure about this encoding.  There's also
279
 
 * a Microsoft variant called CP949, which is not supported (yet).
280
 
 * RFC 1557 says KS X 1001 is 94x94.
281
 
 *
282
 
 * G0 <- ASCII
283
 
 * G1 <- KS X 1001 (aka KSC 5601)
284
 
 *
285
 
 * GL <- G0
286
 
 * GR <- G1 */
287
 
static ScmMultibyteCharInfo euckr_scan_char(ScmMultibyteString mbs)
288
 
{
289
 
    const char *str = SCM_MBS_GET_STR(mbs);
290
 
    const int size  = SCM_MBS_GET_SIZE(mbs);
291
 
    ENTER;
292
 
 
293
 
    if (!size)
294
 
        RETURN(0);
295
 
    if (IS_ASCII(str[0]))
296
 
        RETURN(1);
297
 
    if (IN_GR94(str[0])) {
298
 
        EXPECT_SIZE(2);
299
 
        if (size < 2)
300
 
            RETURN_INCOMPLETE(size);
301
 
#if SCM_STRICT_ENCODING_CHECK
302
 
        if (!IN_GR96(str[1]))
303
 
            RETURN_ERROR();
304
 
#endif
305
 
        RETURN(2);
306
 
    }
307
 
    RETURN_ERROR();
308
 
}
309
 
#endif /* SCM_USE_EUCKR */
310
 
 
311
 
/*==== Encodings for Unicode ====*/
312
 
#if SCM_USE_UTF8
313
 
/* RFC 3629 */
314
 
#define MASK(n)        ((LEN_CODE(n) >> 1) | 0x80)
315
 
#define LEN_CODE(n)    (((1 << (n))-1) << (8-n))
316
 
#define IS_LEN(c, n)   ((MASK(n) & (c)) == LEN_CODE(n))
317
 
#define IS_TRAILING(c) (IS_LEN((c), 1))
318
 
 
319
 
static ScmMultibyteCharInfo utf8_scan_char(ScmMultibyteString mbs)
320
 
{
321
 
    const char *str = SCM_MBS_GET_STR(mbs);
322
 
    const int size  = SCM_MBS_GET_SIZE(mbs);
323
 
    int len;
324
 
    ENTER;
325
 
 
326
 
    if (!size)
327
 
        RETURN(0);
328
 
    if (IS_ASCII(str[0]))
329
 
        RETURN(1);
330
 
 
331
 
    if (IS_LEN(str[0], 2))       len = 2;
332
 
    else if (IS_LEN(str[0], 3))  len = 3;
333
 
    else if (IS_LEN(str[0], 4))  len = 4;
334
 
    else                         RETURN_ERROR();
335
 
 
336
 
#if SCM_STRICT_ENCODING_CHECK
337
 
    {
338
 
        int i;
339
 
        for (i=1; i < len; i++) {
340
 
            if (size <= i)
341
 
                RETURN_INCOMPLETE(size);
342
 
            if (!IS_TRAILING(str[i]))
343
 
                RETURN_ERROR();
344
 
        }
345
 
    }
346
 
#else  /* not SCM_STRICT_ENCODING_CHECK */
347
 
    if (size < len)
348
 
        RETURN_INCOMPLETE(size);
349
 
#endif /* not SCM_STRICT_ENCODING_CHECK */
350
 
 
351
 
    RETURN(len);
352
 
 
353
 
}
354
 
 
355
 
#undef MASK
356
 
#undef LEN_CODE
357
 
#undef IS_LEN
358
 
#undef IS_TRAILING
359
 
#endif /* SCM_USE_UTF8 */
360
 
 
361
 
/*==== Other encodings ====*/
362
 
 
363
 
#if SCM_USE_SJIS
364
 
/* The cwazy Japanese encoding.  This function implements the JIS X
365
 
 * 0213 variant.
366
 
 *
367
 
 * 0 .. 0x7F: ASCII
368
 
 * 0x80: undefined
369
 
 * 0x81 .. 0x9F: lead byte of 2-byte char
370
 
 * 0xA0: undefined
371
 
 * 0xA1 .. 0xDF: JIS X 0201 katakana (1 byte)
372
 
 * 0xE0 .. 0xEF: lead byte of 2-byte char
373
 
 * 0xF0 .. 0xFC: lead byte of 2-byte char if JIS X 0213 is used
374
 
 * 0xFD .. 0xFF: undefined
375
 
 * 
376
 
 * 0x40 .. 0x7E: trailing byte of 2-byte char
377
 
 * 0x80 .. 0xFC: trailing byte of 2-byte char
378
 
 */
379
 
static ScmMultibyteCharInfo sjis_scan_char(ScmMultibyteString mbs)
380
 
{
381
 
#define IS_KANA(c) (0xA1 <= (uchar)(c) && (uchar)(c) <= 0xDF)
382
 
#define IS_LEAD(c)        \
383
 
    (0x81 <= (uchar)(c)   \
384
 
    && !IS_KANA(c)        \
385
 
    && (uchar)(c) <= 0xFC \
386
 
    && (uchar)(c) != 0xA0)
387
 
#define IS_TRAIL(c) (0x40 <= (uchar)(c) && (uchar)(c) <= 0xFC && (c) != 0x7E)
388
 
 
389
 
    const char *str = SCM_MBS_GET_STR(mbs);
390
 
    const int  size = SCM_MBS_GET_SIZE(mbs);
391
 
    ENTER;
392
 
    if (!size)
393
 
        RETURN(0);
394
 
    if (IS_LEAD(str[0])) {
395
 
        EXPECT_SIZE(2);
396
 
        if (size < 2)
397
 
            RETURN_INCOMPLETE(size);
398
 
#if SCM_STRICT_ENCODING_CHECK
399
 
        if (!IS_TRAIL(str[1]))
400
 
            RETURN_ERROR();
401
 
#endif
402
 
        RETURN(2);
403
 
    }
404
 
    RETURN(1);
405
 
 
406
 
#undef IS_KANA
407
 
#undef IS_LEAD
408
 
#undef IS_TRAIL
409
 
}
410
 
#endif /* SCM_USE_SJIS */
411
 
 
412
 
/* Single-byte encodings.  Please add any that you know are missing.
413
 
 * Sorted alphabetically.
414
 
 * 
415
 
 * ASCII
416
 
 * ISO 646
417
 
 * ISO-8859-*
418
 
 * VISCII
419
 
 */
420
 
static ScmMultibyteCharInfo unibyte_scan_char(ScmMultibyteString mbs)
421
 
{
422
 
    ENTER;
423
 
    if (SCM_MBS_GET_SIZE(mbs))
424
 
        RETURN(1);
425
 
    RETURN(0);
426
 
}