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