Coverage Report

Created: 2026-05-16 06:37

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