1 1.4 spz /* $NetBSD: citrus_hz.c,v 1.4 2014/06/24 22:24:18 spz Exp $ */ 2 1.1 tnozaki 3 1.1 tnozaki /*- 4 1.1 tnozaki * Copyright (c)2004, 2006 Citrus Project, 5 1.1 tnozaki * All rights reserved. 6 1.1 tnozaki * 7 1.1 tnozaki * Redistribution and use in source and binary forms, with or without 8 1.1 tnozaki * modification, are permitted provided that the following conditions 9 1.1 tnozaki * are met: 10 1.1 tnozaki * 1. Redistributions of source code must retain the above copyright 11 1.1 tnozaki * notice, this list of conditions and the following disclaimer. 12 1.1 tnozaki * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 tnozaki * notice, this list of conditions and the following disclaimer in the 14 1.1 tnozaki * documentation and/or other materials provided with the distribution. 15 1.1 tnozaki * 16 1.1 tnozaki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 1.1 tnozaki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 1.1 tnozaki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 1.1 tnozaki * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 1.1 tnozaki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 1.1 tnozaki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 1.1 tnozaki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 1.1 tnozaki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 1.1 tnozaki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 tnozaki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 tnozaki * SUCH DAMAGE. 27 1.1 tnozaki * 28 1.1 tnozaki */ 29 1.1 tnozaki 30 1.1 tnozaki #include <sys/cdefs.h> 31 1.1 tnozaki #if defined(LIBC_SCCS) && !defined(lint) 32 1.4 spz __RCSID("$NetBSD: citrus_hz.c,v 1.4 2014/06/24 22:24:18 spz Exp $"); 33 1.1 tnozaki #endif /* LIBC_SCCS and not lint */ 34 1.1 tnozaki 35 1.1 tnozaki #include <sys/queue.h> 36 1.1 tnozaki #include <sys/types.h> 37 1.1 tnozaki #include <assert.h> 38 1.1 tnozaki #include <errno.h> 39 1.1 tnozaki #include <string.h> 40 1.1 tnozaki #include <stdint.h> 41 1.1 tnozaki #include <stdlib.h> 42 1.1 tnozaki #include <stddef.h> 43 1.1 tnozaki #include <limits.h> 44 1.1 tnozaki #include <wchar.h> 45 1.1 tnozaki 46 1.1 tnozaki #include "citrus_namespace.h" 47 1.1 tnozaki #include "citrus_types.h" 48 1.1 tnozaki #include "citrus_bcs.h" 49 1.1 tnozaki #include "citrus_module.h" 50 1.1 tnozaki #include "citrus_ctype.h" 51 1.1 tnozaki #include "citrus_stdenc.h" 52 1.1 tnozaki 53 1.1 tnozaki #include "citrus_hz.h" 54 1.1 tnozaki #include "citrus_prop.h" 55 1.1 tnozaki 56 1.1 tnozaki /* 57 1.1 tnozaki * wchar_t mapping: 58 1.1 tnozaki * 59 1.1 tnozaki * CTRL/ASCII 00000000 00000000 00000000 gxxxxxxx 60 1.1 tnozaki * GB2312 00000000 00000000 0xxxxxxx gxxxxxxx 61 1.1 tnozaki * 94/96*n (~M) 0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx 62 1.1 tnozaki */ 63 1.1 tnozaki 64 1.1 tnozaki #define ESCAPE_CHAR '~' 65 1.1 tnozaki 66 1.1 tnozaki typedef enum { 67 1.1 tnozaki CTRL = 0, ASCII = 1, GB2312 = 2, CS94 = 3, CS96 = 4 68 1.1 tnozaki } charset_t; 69 1.1 tnozaki 70 1.1 tnozaki typedef struct { 71 1.1 tnozaki int start, end, width; 72 1.1 tnozaki } range_t; 73 1.1 tnozaki 74 1.1 tnozaki static const range_t ranges[] = { 75 1.1 tnozaki #define RANGE(start, end) { start, end, (end - start) + 1 } 76 1.1 tnozaki /* CTRL */ RANGE(0x00, 0x1F), 77 1.1 tnozaki /* ASCII */ RANGE(0x20, 0x7F), 78 1.1 tnozaki /* GB2312 */ RANGE(0x21, 0x7E), 79 1.1 tnozaki /* CS94 */ RANGE(0x21, 0x7E), 80 1.1 tnozaki /* CS96 */ RANGE(0x20, 0x7F), 81 1.1 tnozaki #undef RANGE 82 1.1 tnozaki }; 83 1.1 tnozaki 84 1.1 tnozaki typedef struct escape_t escape_t; 85 1.1 tnozaki typedef struct { 86 1.1 tnozaki charset_t charset; 87 1.1 tnozaki size_t length; 88 1.1 tnozaki #define ROWCOL_MAX 3 89 1.1 tnozaki escape_t *escape; 90 1.1 tnozaki } graphic_t; 91 1.1 tnozaki 92 1.1 tnozaki typedef TAILQ_HEAD(escape_list, escape_t) escape_list; 93 1.1 tnozaki struct escape_t { 94 1.1 tnozaki TAILQ_ENTRY(escape_t) entry; 95 1.1 tnozaki int ch; 96 1.1 tnozaki graphic_t *left, *right; 97 1.1 tnozaki escape_list *set; 98 1.1 tnozaki }; 99 1.1 tnozaki 100 1.1 tnozaki #define GL(escape) ((escape)->left) 101 1.1 tnozaki #define GR(escape) ((escape)->right) 102 1.1 tnozaki #define SET(escape) ((escape)->set) 103 1.1 tnozaki #define ESC(escape) ((escape)->ch) 104 1.1 tnozaki #define INIT(escape) (TAILQ_FIRST(SET(escape))) 105 1.1 tnozaki 106 1.1 tnozaki static __inline escape_t * 107 1.1 tnozaki find_escape(escape_list *set, int ch) 108 1.1 tnozaki { 109 1.1 tnozaki escape_t *escape; 110 1.1 tnozaki 111 1.1 tnozaki _DIAGASSERT(set != NULL); 112 1.1 tnozaki 113 1.1 tnozaki TAILQ_FOREACH(escape, set, entry) { 114 1.1 tnozaki if (ESC(escape) == ch) 115 1.1 tnozaki break; 116 1.1 tnozaki } 117 1.1 tnozaki 118 1.1 tnozaki return escape; 119 1.1 tnozaki } 120 1.1 tnozaki 121 1.1 tnozaki typedef struct { 122 1.1 tnozaki escape_list e0, e1; 123 1.1 tnozaki graphic_t *ascii, *gb2312; 124 1.1 tnozaki } _HZEncodingInfo; 125 1.1 tnozaki 126 1.1 tnozaki #define E0SET(ei) (&(ei)->e0) 127 1.1 tnozaki #define E1SET(ei) (&(ei)->e1) 128 1.1 tnozaki #define INIT0(ei) (TAILQ_FIRST(E0SET(ei))) 129 1.1 tnozaki #define INIT1(ei) (TAILQ_FIRST(E1SET(ei))) 130 1.1 tnozaki 131 1.1 tnozaki typedef struct { 132 1.1 tnozaki int chlen; 133 1.1 tnozaki char ch[ROWCOL_MAX]; 134 1.1 tnozaki escape_t *inuse; 135 1.1 tnozaki } _HZState; 136 1.1 tnozaki 137 1.1 tnozaki typedef struct { 138 1.1 tnozaki _HZEncodingInfo ei; 139 1.1 tnozaki struct { 140 1.1 tnozaki /* for future multi-locale facility */ 141 1.1 tnozaki _HZState s_mblen; 142 1.1 tnozaki _HZState s_mbrlen; 143 1.1 tnozaki _HZState s_mbrtowc; 144 1.1 tnozaki _HZState s_mbtowc; 145 1.1 tnozaki _HZState s_mbsrtowcs; 146 1.3 joerg _HZState s_mbsnrtowcs; 147 1.1 tnozaki _HZState s_wcrtomb; 148 1.1 tnozaki _HZState s_wcsrtombs; 149 1.3 joerg _HZState s_wcsnrtombs; 150 1.1 tnozaki _HZState s_wctomb; 151 1.1 tnozaki } states; 152 1.1 tnozaki } _HZCTypeInfo; 153 1.1 tnozaki 154 1.1 tnozaki #define _CEI_TO_EI(_cei_) (&(_cei_)->ei) 155 1.1 tnozaki #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_ 156 1.1 tnozaki 157 1.1 tnozaki #define _FUNCNAME(m) _citrus_HZ_##m 158 1.1 tnozaki #define _ENCODING_INFO _HZEncodingInfo 159 1.1 tnozaki #define _CTYPE_INFO _HZCTypeInfo 160 1.1 tnozaki #define _ENCODING_STATE _HZState 161 1.1 tnozaki #define _ENCODING_MB_CUR_MAX(_ei_) MB_LEN_MAX 162 1.1 tnozaki #define _ENCODING_IS_STATE_DEPENDENT 1 163 1.1 tnozaki #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) ((_ps_)->inuse == NULL) 164 1.1 tnozaki 165 1.1 tnozaki static __inline void 166 1.1 tnozaki _citrus_HZ_init_state(_HZEncodingInfo * __restrict ei, 167 1.1 tnozaki _HZState * __restrict psenc) 168 1.1 tnozaki { 169 1.1 tnozaki _DIAGASSERT(ei != NULL); 170 1.1 tnozaki _DIAGASSERT(psenc != NULL); 171 1.1 tnozaki 172 1.1 tnozaki psenc->chlen = 0; 173 1.1 tnozaki psenc->inuse = INIT0(ei); 174 1.1 tnozaki } 175 1.1 tnozaki 176 1.1 tnozaki static __inline void 177 1.1 tnozaki /*ARGSUSED*/ 178 1.1 tnozaki _citrus_HZ_pack_state(_HZEncodingInfo * __restrict ei, 179 1.1 tnozaki void *__restrict pspriv, const _HZState * __restrict psenc) 180 1.1 tnozaki { 181 1.1 tnozaki /* ei may be unused */ 182 1.1 tnozaki _DIAGASSERT(pspriv != NULL); 183 1.1 tnozaki _DIAGASSERT(psenc != NULL); 184 1.1 tnozaki 185 1.1 tnozaki memcpy(pspriv, (const void *)psenc, sizeof(*psenc)); 186 1.1 tnozaki } 187 1.1 tnozaki 188 1.1 tnozaki static __inline void 189 1.1 tnozaki /*ARGSUSED*/ 190 1.1 tnozaki _citrus_HZ_unpack_state(_HZEncodingInfo * __restrict ei, 191 1.1 tnozaki _HZState * __restrict psenc, const void * __restrict pspriv) 192 1.1 tnozaki { 193 1.1 tnozaki /* ei may be unused */ 194 1.1 tnozaki _DIAGASSERT(psenc != NULL); 195 1.1 tnozaki _DIAGASSERT(pspriv != NULL); 196 1.1 tnozaki 197 1.1 tnozaki memcpy((void *)psenc, pspriv, sizeof(*psenc)); 198 1.1 tnozaki } 199 1.1 tnozaki 200 1.1 tnozaki static int 201 1.1 tnozaki _citrus_HZ_mbrtowc_priv(_HZEncodingInfo * __restrict ei, 202 1.1 tnozaki wchar_t * __restrict pwc, const char ** __restrict s, size_t n, 203 1.1 tnozaki _HZState * __restrict psenc, size_t * __restrict nresult) 204 1.1 tnozaki { 205 1.1 tnozaki const char *s0; 206 1.1 tnozaki wchar_t wc; 207 1.1 tnozaki int bit, head, tail, len, ch; 208 1.1 tnozaki graphic_t *graphic; 209 1.1 tnozaki escape_t *candidate, *init; 210 1.1 tnozaki const range_t *range; 211 1.1 tnozaki 212 1.1 tnozaki _DIAGASSERT(ei != NULL); 213 1.1 tnozaki /* pwc may be null */ 214 1.1 tnozaki _DIAGASSERT(s != NULL); 215 1.1 tnozaki _DIAGASSERT(psenc != NULL); 216 1.1 tnozaki _DIAGASSERT(nresult != NULL); 217 1.1 tnozaki 218 1.1 tnozaki if (*s == NULL) { 219 1.1 tnozaki _citrus_HZ_init_state(ei, psenc); 220 1.1 tnozaki *nresult = 1; 221 1.1 tnozaki return 0; 222 1.1 tnozaki } 223 1.1 tnozaki s0 = *s; 224 1.1 tnozaki if (psenc->chlen < 0 || psenc->inuse == NULL) 225 1.1 tnozaki return EINVAL; 226 1.1 tnozaki 227 1.1 tnozaki wc = (wchar_t)0; 228 1.1 tnozaki bit = head = tail = 0; 229 1.1 tnozaki graphic = NULL; 230 1.1 tnozaki for (len = 0; len <= MB_LEN_MAX; /**/) { 231 1.1 tnozaki if (psenc->chlen == tail) { 232 1.1 tnozaki if (n-- < 1) { 233 1.1 tnozaki *s = s0; 234 1.1 tnozaki *nresult = (size_t)-2; 235 1.1 tnozaki return 0; 236 1.1 tnozaki } 237 1.1 tnozaki psenc->ch[psenc->chlen++] = *s0++; 238 1.1 tnozaki ++len; 239 1.1 tnozaki } 240 1.1 tnozaki ch = (unsigned char)psenc->ch[tail++]; 241 1.1 tnozaki if (tail == 1) { 242 1.1 tnozaki if ((ch & ~0x80) <= 0x1F) { 243 1.1 tnozaki if (psenc->inuse != INIT0(ei)) 244 1.1 tnozaki break; 245 1.1 tnozaki wc = (wchar_t)ch; 246 1.1 tnozaki goto done; 247 1.1 tnozaki } 248 1.1 tnozaki if (ch & 0x80) { 249 1.1 tnozaki graphic = GR(psenc->inuse); 250 1.1 tnozaki bit = 0x80; 251 1.1 tnozaki ch &= ~0x80; 252 1.1 tnozaki } else { 253 1.1 tnozaki graphic = GL(psenc->inuse); 254 1.1 tnozaki if (ch == ESCAPE_CHAR) 255 1.1 tnozaki continue; 256 1.1 tnozaki bit = 0x0; 257 1.1 tnozaki } 258 1.1 tnozaki if (graphic == NULL) 259 1.1 tnozaki break; 260 1.1 tnozaki } else if (tail == 2 && psenc->ch[0] == ESCAPE_CHAR) { 261 1.1 tnozaki if (tail < psenc->chlen) 262 1.1 tnozaki return EINVAL; 263 1.1 tnozaki if (ch == ESCAPE_CHAR) { 264 1.1 tnozaki ++head; 265 1.1 tnozaki } else if (ch == '\n') { 266 1.1 tnozaki if (psenc->inuse != INIT0(ei)) 267 1.1 tnozaki break; 268 1.1 tnozaki tail = psenc->chlen = 0; 269 1.1 tnozaki continue; 270 1.1 tnozaki } else { 271 1.1 tnozaki candidate = NULL; 272 1.1 tnozaki init = INIT0(ei); 273 1.1 tnozaki _DIAGASSERT(init != NULL); 274 1.1 tnozaki if (psenc->inuse == init) { 275 1.1 tnozaki init = INIT1(ei); 276 1.1 tnozaki } else if (INIT(psenc->inuse) == init) { 277 1.1 tnozaki if (ESC(init) != ch) 278 1.1 tnozaki break; 279 1.1 tnozaki candidate = init; 280 1.1 tnozaki } 281 1.1 tnozaki if (candidate == NULL) { 282 1.1 tnozaki candidate = find_escape( 283 1.1 tnozaki SET(psenc->inuse), ch); 284 1.1 tnozaki if (candidate == NULL) { 285 1.1 tnozaki if (init == NULL || 286 1.1 tnozaki ESC(init) != ch) 287 1.1 tnozaki break; 288 1.1 tnozaki candidate = init; 289 1.1 tnozaki } 290 1.1 tnozaki } 291 1.1 tnozaki psenc->inuse = candidate; 292 1.1 tnozaki tail = psenc->chlen = 0; 293 1.1 tnozaki continue; 294 1.1 tnozaki } 295 1.1 tnozaki } else if (ch & 0x80) { 296 1.1 tnozaki if (graphic != GR(psenc->inuse)) 297 1.1 tnozaki break; 298 1.1 tnozaki ch &= ~0x80; 299 1.1 tnozaki } else { 300 1.1 tnozaki if (graphic != GL(psenc->inuse)) 301 1.1 tnozaki break; 302 1.1 tnozaki } 303 1.1 tnozaki _DIAGASSERT(graphic != NULL); 304 1.1 tnozaki range = &ranges[(size_t)graphic->charset]; 305 1.1 tnozaki if (range->start > ch || range->end < ch) 306 1.1 tnozaki break; 307 1.1 tnozaki wc <<= 8; 308 1.1 tnozaki wc |= ch; 309 1.1 tnozaki if (graphic->length == (tail - head)) { 310 1.1 tnozaki if (graphic->charset > GB2312) 311 1.1 tnozaki bit |= ESC(psenc->inuse) << 24; 312 1.1 tnozaki wc |= bit; 313 1.1 tnozaki goto done; 314 1.1 tnozaki } 315 1.1 tnozaki } 316 1.1 tnozaki *nresult = (size_t)-1; 317 1.1 tnozaki return EILSEQ; 318 1.1 tnozaki done: 319 1.1 tnozaki if (tail < psenc->chlen) 320 1.1 tnozaki return EINVAL; 321 1.1 tnozaki *s = s0; 322 1.1 tnozaki if (pwc != NULL) 323 1.1 tnozaki *pwc = wc; 324 1.1 tnozaki psenc->chlen = 0; 325 1.1 tnozaki *nresult = (wc == 0) ? 0 : len; 326 1.1 tnozaki 327 1.1 tnozaki return 0; 328 1.1 tnozaki } 329 1.1 tnozaki 330 1.1 tnozaki static int 331 1.1 tnozaki _citrus_HZ_wcrtomb_priv(_HZEncodingInfo * __restrict ei, 332 1.1 tnozaki char * __restrict s, size_t n, wchar_t wc, 333 1.1 tnozaki _HZState * __restrict psenc, size_t * __restrict nresult) 334 1.1 tnozaki { 335 1.1 tnozaki int bit, ch; 336 1.1 tnozaki escape_t *candidate, *init; 337 1.1 tnozaki graphic_t *graphic; 338 1.1 tnozaki size_t len; 339 1.1 tnozaki const range_t *range; 340 1.1 tnozaki 341 1.1 tnozaki _DIAGASSERT(ei != NULL); 342 1.1 tnozaki _DIAGASSERT(s != NULL); 343 1.1 tnozaki _DIAGASSERT(psenc != NULL); 344 1.1 tnozaki _DIAGASSERT(nresult != NULL); 345 1.1 tnozaki 346 1.1 tnozaki if (psenc->chlen != 0 || psenc->inuse == NULL) 347 1.1 tnozaki return EINVAL; 348 1.1 tnozaki if (wc & 0x80) { 349 1.1 tnozaki bit = 0x80; 350 1.1 tnozaki wc &= ~0x80; 351 1.1 tnozaki } else { 352 1.1 tnozaki bit = 0x0; 353 1.1 tnozaki } 354 1.1 tnozaki if ((uint32_t)wc <= 0x1F) { 355 1.1 tnozaki candidate = INIT0(ei); 356 1.1 tnozaki graphic = (bit == 0) 357 1.1 tnozaki ? candidate->left : candidate->right; 358 1.1 tnozaki if (graphic == NULL) 359 1.1 tnozaki goto ilseq; 360 1.1 tnozaki range = &ranges[(size_t)CTRL]; 361 1.1 tnozaki len = 1; 362 1.1 tnozaki } else if ((uint32_t)wc <= 0x7F) { 363 1.1 tnozaki graphic = ei->ascii; 364 1.1 tnozaki if (graphic == NULL) 365 1.1 tnozaki goto ilseq; 366 1.1 tnozaki candidate = graphic->escape; 367 1.1 tnozaki range = &ranges[(size_t)graphic->charset]; 368 1.1 tnozaki len = graphic->length; 369 1.1 tnozaki } else if ((uint32_t)wc <= 0x7F7F) { 370 1.1 tnozaki graphic = ei->gb2312; 371 1.1 tnozaki if (graphic == NULL) 372 1.1 tnozaki goto ilseq; 373 1.1 tnozaki candidate = graphic->escape; 374 1.1 tnozaki range = &ranges[(size_t)graphic->charset]; 375 1.1 tnozaki len = graphic->length; 376 1.1 tnozaki } else { 377 1.1 tnozaki ch = (wc >> 24) & 0xFF; 378 1.1 tnozaki candidate = find_escape(E0SET(ei), ch); 379 1.1 tnozaki if (candidate == NULL) { 380 1.1 tnozaki candidate = find_escape(E1SET(ei), ch); 381 1.1 tnozaki if (candidate == NULL) 382 1.1 tnozaki goto ilseq; 383 1.1 tnozaki } 384 1.1 tnozaki wc &= ~0xFF000000; 385 1.1 tnozaki graphic = (bit == 0) 386 1.1 tnozaki ? candidate->left : candidate->right; 387 1.1 tnozaki if (graphic == NULL) 388 1.1 tnozaki goto ilseq; 389 1.1 tnozaki range = &ranges[(size_t)graphic->charset]; 390 1.1 tnozaki len = graphic->length; 391 1.1 tnozaki } 392 1.1 tnozaki if (psenc->inuse != candidate) { 393 1.1 tnozaki init = INIT0(ei); 394 1.1 tnozaki if (SET(psenc->inuse) == SET(candidate)) { 395 1.1 tnozaki if (INIT(psenc->inuse) != init || 396 1.1 tnozaki psenc->inuse == init || candidate == init) 397 1.1 tnozaki init = NULL; 398 1.1 tnozaki } else if (candidate == (init = INIT(candidate))) { 399 1.1 tnozaki init = NULL; 400 1.1 tnozaki } 401 1.1 tnozaki if (init != NULL) { 402 1.1 tnozaki if (n < 2) 403 1.1 tnozaki return E2BIG; 404 1.1 tnozaki n -= 2; 405 1.1 tnozaki psenc->ch[psenc->chlen++] = ESCAPE_CHAR; 406 1.1 tnozaki psenc->ch[psenc->chlen++] = ESC(init); 407 1.1 tnozaki } 408 1.1 tnozaki if (n < 2) 409 1.1 tnozaki return E2BIG; 410 1.1 tnozaki n -= 2; 411 1.1 tnozaki psenc->ch[psenc->chlen++] = ESCAPE_CHAR; 412 1.1 tnozaki psenc->ch[psenc->chlen++] = ESC(candidate); 413 1.1 tnozaki psenc->inuse = candidate; 414 1.1 tnozaki } 415 1.1 tnozaki if (n < len) 416 1.1 tnozaki return E2BIG; 417 1.1 tnozaki while (len-- > 0) { 418 1.1 tnozaki ch = (wc >> (len * 8)) & 0xFF; 419 1.1 tnozaki if (range->start > ch || range->end < ch) 420 1.1 tnozaki goto ilseq; 421 1.1 tnozaki psenc->ch[psenc->chlen++] = ch | bit; 422 1.1 tnozaki } 423 1.1 tnozaki memcpy(s, psenc->ch, psenc->chlen); 424 1.1 tnozaki *nresult = psenc->chlen; 425 1.1 tnozaki psenc->chlen = 0; 426 1.1 tnozaki 427 1.1 tnozaki return 0; 428 1.1 tnozaki 429 1.1 tnozaki ilseq: 430 1.1 tnozaki *nresult = (size_t)-1; 431 1.1 tnozaki return EILSEQ; 432 1.1 tnozaki } 433 1.1 tnozaki 434 1.1 tnozaki static __inline int 435 1.1 tnozaki _citrus_HZ_put_state_reset(_HZEncodingInfo * __restrict ei, 436 1.1 tnozaki char * __restrict s, size_t n, _HZState * __restrict psenc, 437 1.1 tnozaki size_t * __restrict nresult) 438 1.1 tnozaki { 439 1.1 tnozaki escape_t *candidate; 440 1.1 tnozaki 441 1.1 tnozaki _DIAGASSERT(ei != NULL); 442 1.1 tnozaki _DIAGASSERT(s != NULL); 443 1.1 tnozaki _DIAGASSERT(psenc != NULL); 444 1.1 tnozaki _DIAGASSERT(nresult != NULL); 445 1.1 tnozaki 446 1.1 tnozaki if (psenc->chlen != 0 || psenc->inuse == NULL) 447 1.1 tnozaki return EINVAL; 448 1.1 tnozaki candidate = INIT0(ei); 449 1.1 tnozaki if (psenc->inuse != candidate) { 450 1.1 tnozaki if (n < 2) 451 1.1 tnozaki return E2BIG; 452 1.1 tnozaki n -= 2; 453 1.1 tnozaki psenc->ch[psenc->chlen++] = ESCAPE_CHAR; 454 1.1 tnozaki psenc->ch[psenc->chlen++] = ESC(candidate); 455 1.1 tnozaki } 456 1.1 tnozaki if (n < 1) 457 1.1 tnozaki return E2BIG; 458 1.1 tnozaki if (psenc->chlen > 0) 459 1.1 tnozaki memcpy(s, psenc->ch, psenc->chlen); 460 1.1 tnozaki *nresult = psenc->chlen; 461 1.1 tnozaki _citrus_HZ_init_state(ei, psenc); 462 1.1 tnozaki 463 1.1 tnozaki return 0; 464 1.1 tnozaki } 465 1.1 tnozaki 466 1.1 tnozaki static __inline int 467 1.1 tnozaki _citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei, 468 1.1 tnozaki _HZState * __restrict psenc, int * __restrict rstate) 469 1.1 tnozaki { 470 1.1 tnozaki _DIAGASSERT(ei != NULL); 471 1.1 tnozaki _DIAGASSERT(psenc != NULL); 472 1.1 tnozaki _DIAGASSERT(rstate != NULL); 473 1.1 tnozaki 474 1.1 tnozaki if (psenc->chlen < 0 || psenc->inuse == NULL) 475 1.1 tnozaki return EINVAL; 476 1.1 tnozaki *rstate = (psenc->chlen == 0) 477 1.1 tnozaki ? ((psenc->inuse == INIT0(ei)) 478 1.1 tnozaki ? _STDENC_SDGEN_INITIAL 479 1.1 tnozaki : _STDENC_SDGEN_STABLE) 480 1.1 tnozaki : ((psenc->ch[0] == ESCAPE_CHAR) 481 1.1 tnozaki ? _STDENC_SDGEN_INCOMPLETE_SHIFT 482 1.1 tnozaki : _STDENC_SDGEN_INCOMPLETE_CHAR); 483 1.1 tnozaki 484 1.1 tnozaki return 0; 485 1.1 tnozaki } 486 1.1 tnozaki 487 1.1 tnozaki static __inline int 488 1.1 tnozaki /*ARGSUSED*/ 489 1.1 tnozaki _citrus_HZ_stdenc_wctocs(_HZEncodingInfo * __restrict ei, 490 1.1 tnozaki _csid_t * __restrict csid, _index_t * __restrict idx, wchar_t wc) 491 1.1 tnozaki { 492 1.1 tnozaki int bit; 493 1.1 tnozaki 494 1.1 tnozaki _DIAGASSERT(csid != NULL); 495 1.1 tnozaki _DIAGASSERT(idx != NULL); 496 1.1 tnozaki 497 1.1 tnozaki if (wc & 0x80) { 498 1.1 tnozaki bit = 0x80; 499 1.1 tnozaki wc &= ~0x80; 500 1.1 tnozaki } else { 501 1.1 tnozaki bit = 0x0; 502 1.1 tnozaki } 503 1.1 tnozaki if ((uint32_t)wc <= 0x7F) { 504 1.1 tnozaki *csid = (_csid_t)bit; 505 1.1 tnozaki *idx = (_index_t)wc; 506 1.1 tnozaki } else if ((uint32_t)wc <= 0x7F7F) { 507 1.1 tnozaki *csid = (_csid_t)(bit | 0x8000); 508 1.1 tnozaki *idx = (_index_t)wc; 509 1.1 tnozaki } else { 510 1.1 tnozaki *csid = (_index_t)(wc & ~0x00FFFF7F); 511 1.1 tnozaki *idx = (_csid_t)(wc & 0x00FFFF7F); 512 1.1 tnozaki } 513 1.1 tnozaki 514 1.1 tnozaki return 0; 515 1.1 tnozaki } 516 1.1 tnozaki 517 1.1 tnozaki static __inline int 518 1.1 tnozaki /*ARGSUSED*/ 519 1.1 tnozaki _citrus_HZ_stdenc_cstowc(_HZEncodingInfo * __restrict ei, 520 1.1 tnozaki wchar_t * __restrict wc, _csid_t csid, _index_t idx) 521 1.1 tnozaki { 522 1.1 tnozaki _DIAGASSERT(ei != NULL); 523 1.1 tnozaki _DIAGASSERT(wc != NULL); 524 1.1 tnozaki 525 1.1 tnozaki *wc = (wchar_t)idx; 526 1.1 tnozaki switch (csid) { 527 1.1 tnozaki case 0x80: 528 1.1 tnozaki case 0x8080: 529 1.1 tnozaki *wc |= (wchar_t)0x80; 530 1.1 tnozaki /*FALLTHROUGH*/ 531 1.1 tnozaki case 0x0: 532 1.1 tnozaki case 0x8000: 533 1.1 tnozaki break; 534 1.1 tnozaki default: 535 1.1 tnozaki *wc |= (wchar_t)csid; 536 1.1 tnozaki } 537 1.1 tnozaki 538 1.1 tnozaki return 0; 539 1.1 tnozaki } 540 1.1 tnozaki 541 1.1 tnozaki static void 542 1.1 tnozaki _citrus_HZ_encoding_module_uninit(_HZEncodingInfo *ei) 543 1.1 tnozaki { 544 1.1 tnozaki escape_t *escape; 545 1.1 tnozaki 546 1.1 tnozaki _DIAGASSERT(ei != NULL); 547 1.1 tnozaki while ((escape = TAILQ_FIRST(E0SET(ei))) != NULL) { 548 1.1 tnozaki TAILQ_REMOVE(E0SET(ei), escape, entry); 549 1.1 tnozaki free(GL(escape)); 550 1.1 tnozaki free(GR(escape)); 551 1.1 tnozaki free(escape); 552 1.1 tnozaki } 553 1.1 tnozaki while ((escape = TAILQ_FIRST(E1SET(ei))) != NULL) { 554 1.1 tnozaki TAILQ_REMOVE(E1SET(ei), escape, entry); 555 1.1 tnozaki free(GL(escape)); 556 1.1 tnozaki free(GR(escape)); 557 1.1 tnozaki free(escape); 558 1.1 tnozaki } 559 1.1 tnozaki } 560 1.1 tnozaki 561 1.1 tnozaki static int 562 1.4 spz _citrus_HZ_parse_char(void *context, const char *name, const char *s) 563 1.1 tnozaki { 564 1.1 tnozaki void **p; 565 1.1 tnozaki escape_t *escape; 566 1.1 tnozaki 567 1.1 tnozaki _DIAGASSERT(context != NULL && *context != NULL); 568 1.1 tnozaki _DIAGASSERT(name != NULL); 569 1.1 tnozaki _DIAGASSERT(s != NULL); 570 1.1 tnozaki 571 1.4 spz p = (void **)context; 572 1.1 tnozaki escape = (escape_t *)p[0]; 573 1.1 tnozaki if (escape->ch != '\0') 574 1.1 tnozaki return EINVAL; 575 1.1 tnozaki escape->ch = *s++; 576 1.1 tnozaki if (escape->ch == ESCAPE_CHAR || *s != '\0') 577 1.1 tnozaki return EINVAL; 578 1.1 tnozaki 579 1.1 tnozaki return 0; 580 1.1 tnozaki } 581 1.1 tnozaki 582 1.1 tnozaki static int 583 1.4 spz _citrus_HZ_parse_graphic(void *context, const char *name, const char *s) 584 1.1 tnozaki { 585 1.1 tnozaki void **p; 586 1.1 tnozaki _HZEncodingInfo *ei; 587 1.1 tnozaki escape_t *escape; 588 1.1 tnozaki graphic_t *graphic; 589 1.1 tnozaki 590 1.1 tnozaki _DIAGASSERT(context != NULL && *context != NULL); 591 1.1 tnozaki _DIAGASSERT(name != NULL); 592 1.1 tnozaki _DIAGASSERT(s != NULL); 593 1.1 tnozaki 594 1.4 spz p = (void **)context; 595 1.1 tnozaki escape = (escape_t *)p[0]; 596 1.1 tnozaki ei = (_HZEncodingInfo *)p[1]; 597 1.1 tnozaki graphic = malloc(sizeof(*graphic)); 598 1.1 tnozaki if (graphic == NULL) 599 1.1 tnozaki return ENOMEM; 600 1.1 tnozaki memset(graphic, 0, sizeof(*graphic)); 601 1.1 tnozaki if (strcmp("GL", name) == 0) { 602 1.1 tnozaki if (GL(escape) != NULL) 603 1.1 tnozaki goto release; 604 1.1 tnozaki GL(escape) = graphic; 605 1.1 tnozaki } else if (strcmp("GR", name) == 0) { 606 1.1 tnozaki if (GR(escape) != NULL) 607 1.1 tnozaki goto release; 608 1.1 tnozaki GR(escape) = graphic; 609 1.1 tnozaki } else { 610 1.1 tnozaki release: 611 1.1 tnozaki free(graphic); 612 1.1 tnozaki return EINVAL; 613 1.1 tnozaki } 614 1.1 tnozaki graphic->escape = escape; 615 1.1 tnozaki if (_bcs_strncasecmp("ASCII", s, 5) == 0) { 616 1.1 tnozaki if (s[5] != '\0') 617 1.1 tnozaki return EINVAL; 618 1.1 tnozaki graphic->charset = ASCII; 619 1.1 tnozaki graphic->length = 1; 620 1.1 tnozaki ei->ascii = graphic; 621 1.1 tnozaki return 0; 622 1.1 tnozaki } else if (_bcs_strncasecmp("GB2312", s, 6) == 0) { 623 1.1 tnozaki if (s[6] != '\0') 624 1.1 tnozaki return EINVAL; 625 1.1 tnozaki graphic->charset = GB2312; 626 1.1 tnozaki graphic->length = 2; 627 1.1 tnozaki ei->gb2312 = graphic; 628 1.1 tnozaki return 0; 629 1.1 tnozaki } else if (strncmp("94*", s, 3) == 0) { 630 1.1 tnozaki graphic->charset = CS94; 631 1.1 tnozaki } else if (strncmp("96*", s, 3) == 0) { 632 1.1 tnozaki graphic->charset = CS96; 633 1.1 tnozaki } else { 634 1.1 tnozaki return EINVAL; 635 1.1 tnozaki } 636 1.1 tnozaki s += 3; 637 1.1 tnozaki switch(*s) { 638 1.1 tnozaki case '1': case '2': case '3': 639 1.1 tnozaki graphic->length = (size_t)(*s - '0'); 640 1.1 tnozaki if (*++s == '\0') 641 1.1 tnozaki break; 642 1.1 tnozaki /*FALLTHROUGH*/ 643 1.1 tnozaki default: 644 1.1 tnozaki return EINVAL; 645 1.1 tnozaki } 646 1.1 tnozaki return 0; 647 1.1 tnozaki } 648 1.1 tnozaki 649 1.1 tnozaki static const _citrus_prop_hint_t escape_hints[] = { 650 1.1 tnozaki _CITRUS_PROP_HINT_STR("CH", &_citrus_HZ_parse_char), 651 1.1 tnozaki _CITRUS_PROP_HINT_STR("GL", &_citrus_HZ_parse_graphic), 652 1.1 tnozaki _CITRUS_PROP_HINT_STR("GR", &_citrus_HZ_parse_graphic), 653 1.1 tnozaki _CITRUS_PROP_HINT_END 654 1.1 tnozaki }; 655 1.1 tnozaki 656 1.1 tnozaki static int 657 1.4 spz _citrus_HZ_parse_escape(void *context, const char *name, const char *s) 658 1.1 tnozaki { 659 1.1 tnozaki _HZEncodingInfo *ei; 660 1.1 tnozaki escape_t *escape; 661 1.1 tnozaki void *p[2]; 662 1.1 tnozaki 663 1.1 tnozaki _DIAGASSERT(context != NULL); 664 1.1 tnozaki _DIAGASSERT(name != NULL); 665 1.1 tnozaki _DIAGASSERT(s != NULL); 666 1.1 tnozaki 667 1.4 spz ei = (_HZEncodingInfo *)context; 668 1.1 tnozaki escape = malloc(sizeof(*escape)); 669 1.1 tnozaki if (escape == NULL) 670 1.1 tnozaki return EINVAL; 671 1.1 tnozaki memset(escape, 0, sizeof(*escape)); 672 1.1 tnozaki if (strcmp("0", name) == 0) { 673 1.1 tnozaki escape->set = E0SET(ei); 674 1.1 tnozaki TAILQ_INSERT_TAIL(E0SET(ei), escape, entry); 675 1.1 tnozaki } else if (strcmp("1", name) == 0) { 676 1.1 tnozaki escape->set = E1SET(ei); 677 1.1 tnozaki TAILQ_INSERT_TAIL(E1SET(ei), escape, entry); 678 1.1 tnozaki } else { 679 1.1 tnozaki free(escape); 680 1.1 tnozaki return EINVAL; 681 1.1 tnozaki } 682 1.1 tnozaki p[0] = (void *)escape; 683 1.1 tnozaki p[1] = (void *)ei; 684 1.1 tnozaki return _citrus_prop_parse_variable( 685 1.1 tnozaki escape_hints, (void *)&p[0], s, strlen(s)); 686 1.1 tnozaki } 687 1.1 tnozaki 688 1.1 tnozaki static const _citrus_prop_hint_t root_hints[] = { 689 1.1 tnozaki _CITRUS_PROP_HINT_STR("0", &_citrus_HZ_parse_escape), 690 1.1 tnozaki _CITRUS_PROP_HINT_STR("1", &_citrus_HZ_parse_escape), 691 1.1 tnozaki _CITRUS_PROP_HINT_END 692 1.1 tnozaki }; 693 1.1 tnozaki 694 1.1 tnozaki static int 695 1.1 tnozaki _citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei, 696 1.1 tnozaki const void * __restrict var, size_t lenvar) 697 1.1 tnozaki { 698 1.1 tnozaki int errnum; 699 1.1 tnozaki 700 1.1 tnozaki _DIAGASSERT(ei != NULL); 701 1.1 tnozaki 702 1.1 tnozaki memset(ei, 0, sizeof(*ei)); 703 1.1 tnozaki TAILQ_INIT(E0SET(ei)); 704 1.1 tnozaki TAILQ_INIT(E1SET(ei)); 705 1.1 tnozaki errnum = _citrus_prop_parse_variable( 706 1.1 tnozaki root_hints, (void *)ei, var, lenvar); 707 1.1 tnozaki if (errnum != 0) 708 1.1 tnozaki _citrus_HZ_encoding_module_uninit(ei); 709 1.1 tnozaki return errnum; 710 1.1 tnozaki } 711 1.1 tnozaki 712 1.1 tnozaki /* ---------------------------------------------------------------------- 713 1.1 tnozaki * public interface for ctype 714 1.1 tnozaki */ 715 1.1 tnozaki 716 1.1 tnozaki _CITRUS_CTYPE_DECLS(HZ); 717 1.1 tnozaki _CITRUS_CTYPE_DEF_OPS(HZ); 718 1.1 tnozaki 719 1.1 tnozaki #include "citrus_ctype_template.h" 720 1.1 tnozaki 721 1.1 tnozaki /* ---------------------------------------------------------------------- 722 1.1 tnozaki * public interface for stdenc 723 1.1 tnozaki */ 724 1.1 tnozaki 725 1.1 tnozaki _CITRUS_STDENC_DECLS(HZ); 726 1.1 tnozaki _CITRUS_STDENC_DEF_OPS(HZ); 727 1.1 tnozaki 728 1.1 tnozaki #include "citrus_stdenc_template.h" 729