kernel: scheduling fix for ARM
[minix.git] / lib / libc / citrus / modules / citrus_hz.c
blobcaebd2f50ba3ab0d8925e85a6197a4dbe794015f
1 /* $NetBSD: citrus_hz.c,v 1.2 2008/06/14 16:01:07 tnozaki Exp $ */
3 /*-
4 * Copyright (c)2004, 2006 Citrus Project,
5 * All rights reserved.
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.
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.
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 */
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>
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"
53 #include "citrus_hz.h"
54 #include "citrus_prop.h"
57 * wchar_t mapping:
59 * CTRL/ASCII 00000000 00000000 00000000 gxxxxxxx
60 * GB2312 00000000 00000000 0xxxxxxx gxxxxxxx
61 * 94/96*n (~M) 0mmmmmmm 0xxxxxxx 0xxxxxxx gxxxxxxx
64 #define ESCAPE_CHAR '~'
66 typedef enum {
67 CTRL = 0, ASCII = 1, GB2312 = 2, CS94 = 3, CS96 = 4
68 } charset_t;
70 typedef struct {
71 int start, end, width;
72 } range_t;
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
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;
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;
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)))
106 static __inline escape_t *
107 find_escape(escape_list *set, int ch)
109 escape_t *escape;
111 _DIAGASSERT(set != NULL);
113 TAILQ_FOREACH(escape, set, entry) {
114 if (ESC(escape) == ch)
115 break;
118 return escape;
121 typedef struct {
122 escape_list e0, e1;
123 graphic_t *ascii, *gb2312;
124 } _HZEncodingInfo;
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)))
131 typedef struct {
132 int chlen;
133 char ch[ROWCOL_MAX];
134 escape_t *inuse;
135 } _HZState;
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;
152 #define _CEI_TO_EI(_cei_) (&(_cei_)->ei)
153 #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_
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)
163 static __inline void
164 _citrus_HZ_init_state(_HZEncodingInfo * __restrict ei,
165 _HZState * __restrict psenc)
167 _DIAGASSERT(ei != NULL);
168 _DIAGASSERT(psenc != NULL);
170 psenc->chlen = 0;
171 psenc->inuse = INIT0(ei);
174 static __inline void
175 /*ARGSUSED*/
176 _citrus_HZ_pack_state(_HZEncodingInfo * __restrict ei,
177 void *__restrict pspriv, const _HZState * __restrict psenc)
179 /* ei may be unused */
180 _DIAGASSERT(pspriv != NULL);
181 _DIAGASSERT(psenc != NULL);
183 memcpy(pspriv, (const void *)psenc, sizeof(*psenc));
186 static __inline void
187 /*ARGSUSED*/
188 _citrus_HZ_unpack_state(_HZEncodingInfo * __restrict ei,
189 _HZState * __restrict psenc, const void * __restrict pspriv)
191 /* ei may be unused */
192 _DIAGASSERT(psenc != NULL);
193 _DIAGASSERT(pspriv != NULL);
195 memcpy((void *)psenc, pspriv, sizeof(*psenc));
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)
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;
210 _DIAGASSERT(ei != NULL);
211 /* pwc may be null */
212 _DIAGASSERT(s != NULL);
213 _DIAGASSERT(psenc != NULL);
214 _DIAGASSERT(nresult != NULL);
216 if (*s == NULL) {
217 _citrus_HZ_init_state(ei, psenc);
218 *nresult = 1;
219 return 0;
221 s0 = *s;
222 if (psenc->chlen < 0 || psenc->inuse == NULL)
223 return EINVAL;
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;
235 psenc->ch[psenc->chlen++] = *s0++;
236 ++len;
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;
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;
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;
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;
289 psenc->inuse = candidate;
290 tail = psenc->chlen = 0;
291 continue;
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;
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;
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;
325 return 0;
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)
333 int bit, ch;
334 escape_t *candidate, *init;
335 graphic_t *graphic;
336 size_t len;
337 const range_t *range;
339 _DIAGASSERT(ei != NULL);
340 _DIAGASSERT(s != NULL);
341 _DIAGASSERT(psenc != NULL);
342 _DIAGASSERT(nresult != NULL);
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;
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;
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;
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;
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);
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;
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;
421 memcpy(s, psenc->ch, psenc->chlen);
422 *nresult = psenc->chlen;
423 psenc->chlen = 0;
425 return 0;
427 ilseq:
428 *nresult = (size_t)-1;
429 return EILSEQ;
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)
437 escape_t *candidate;
439 _DIAGASSERT(ei != NULL);
440 _DIAGASSERT(s != NULL);
441 _DIAGASSERT(psenc != NULL);
442 _DIAGASSERT(nresult != NULL);
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);
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);
461 return 0;
464 static __inline int
465 _citrus_HZ_stdenc_get_state_desc_generic(_HZEncodingInfo * __restrict ei,
466 _HZState * __restrict psenc, int * __restrict rstate)
468 _DIAGASSERT(ei != NULL);
469 _DIAGASSERT(psenc != NULL);
470 _DIAGASSERT(rstate != NULL);
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);
482 return 0;
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)
490 int bit;
492 _DIAGASSERT(csid != NULL);
493 _DIAGASSERT(idx != NULL);
495 if (wc & 0x80) {
496 bit = 0x80;
497 wc &= ~0x80;
498 } else {
499 bit = 0x0;
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);
512 return 0;
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)
520 _DIAGASSERT(ei != NULL);
521 _DIAGASSERT(wc != NULL);
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;
536 return 0;
539 static void
540 _citrus_HZ_encoding_module_uninit(_HZEncodingInfo *ei)
542 escape_t *escape;
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);
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);
559 static int
560 _citrus_HZ_parse_char(void **context, const char *name, const char *s)
562 void **p;
563 escape_t *escape;
565 _DIAGASSERT(context != NULL && *context != NULL);
566 _DIAGASSERT(name != NULL);
567 _DIAGASSERT(s != NULL);
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;
577 return 0;
580 static int
581 _citrus_HZ_parse_graphic(void **context, const char *name, const char *s)
583 void **p;
584 _HZEncodingInfo *ei;
585 escape_t *escape;
586 graphic_t *graphic;
588 _DIAGASSERT(context != NULL && *context != NULL);
589 _DIAGASSERT(name != NULL);
590 _DIAGASSERT(s != NULL);
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;
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;
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;
644 return 0;
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
654 static int
655 _citrus_HZ_parse_escape(void **context, const char *name, const char *s)
657 _HZEncodingInfo *ei;
658 escape_t *escape;
659 void *p[2];
661 _DIAGASSERT(context != NULL);
662 _DIAGASSERT(name != NULL);
663 _DIAGASSERT(s != NULL);
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;
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));
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
692 static int
693 _citrus_HZ_encoding_module_init(_HZEncodingInfo * __restrict ei,
694 const void * __restrict var, size_t lenvar)
696 int errnum;
698 _DIAGASSERT(ei != NULL);
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;
710 /* ----------------------------------------------------------------------
711 * public interface for ctype
714 _CITRUS_CTYPE_DECLS(HZ);
715 _CITRUS_CTYPE_DEF_OPS(HZ);
717 #include "citrus_ctype_template.h"
719 /* ----------------------------------------------------------------------
720 * public interface for stdenc
723 _CITRUS_STDENC_DECLS(HZ);
724 _CITRUS_STDENC_DEF_OPS(HZ);
726 #include "citrus_stdenc_template.h"