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