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