xref: /netbsd/lib/libc/citrus/modules/citrus_hz.c (revision 6550d01e)
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