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