Annotation of src/lib/libc/citrus/modules/citrus_utf7.c, Revision 1.5.48.1
1.5.48.1! tls 1: /* $NetBSD$ */
1.1 tnozaki 2:
3: /*-
4: * Copyright (c)2004, 2005 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(LIB_SCCS) && !defined(lint)
1.5.48.1! tls 32: __RCSID("$NetBSD$");
1.1 tnozaki 33: #endif /* LIB_SCCS and not lint */
34:
35: #include <assert.h>
36: #include <errno.h>
37: #include <string.h>
38: #include <stdio.h>
39: #include <stdint.h>
40: #include <stdlib.h>
41: #include <limits.h>
42: #include <wchar.h>
43:
44: #include "citrus_namespace.h"
45: #include "citrus_types.h"
46: #include "citrus_module.h"
47: #include "citrus_ctype.h"
48: #include "citrus_stdenc.h"
49: #include "citrus_utf7.h"
50:
51: /* ----------------------------------------------------------------------
52: * private stuffs used by templates
53: */
54:
55: typedef struct {
56: uint16_t cell[0x80];
57: #define EI_MASK UINT16_C(0xff)
58: #define EI_DIRECT UINT16_C(0x100)
59: #define EI_OPTION UINT16_C(0x200)
60: #define EI_SPACE UINT16_C(0x400)
61: } _UTF7EncodingInfo;
62:
63: typedef struct {
64: unsigned int
65: mode: 1, /* whether base64 mode */
66: bits: 4, /* need to hold 0 - 15 */
67: cache: 22, /* 22 = BASE64_BIT + UTF16_BIT */
1.2 tnozaki 68: surrogate: 1; /* whether surrogate pair or not */
69: int chlen;
1.1 tnozaki 70: char ch[4]; /* BASE64_IN, 3 * 6 = 18, most closed to UTF16_BIT */
71: } _UTF7State;
72:
73: typedef struct {
74: _UTF7EncodingInfo ei;
75: struct {
76: /* for future multi-locale facility */
77: _UTF7State s_mblen;
78: _UTF7State s_mbrlen;
79: _UTF7State s_mbrtowc;
80: _UTF7State s_mbtowc;
81: _UTF7State s_mbsrtowcs;
1.5.48.1! tls 82: _UTF7State s_mbsnrtowcs;
1.1 tnozaki 83: _UTF7State s_wcrtomb;
84: _UTF7State s_wcsrtombs;
1.5.48.1! tls 85: _UTF7State s_wcsnrtombs;
1.1 tnozaki 86: _UTF7State s_wctomb;
87: } states;
88: } _UTF7CTypeInfo;
89:
90: #define _CEI_TO_EI(_cei_) (&(_cei_)->ei)
91: #define _CEI_TO_STATE(_cei_, _func_) (_cei_)->states.s_##_func_
92:
93: #define _FUNCNAME(m) _citrus_UTF7_##m
94: #define _ENCODING_INFO _UTF7EncodingInfo
95: #define _CTYPE_INFO _UTF7CTypeInfo
96: #define _ENCODING_STATE _UTF7State
97: #define _ENCODING_MB_CUR_MAX(_ei_) 4
98: #define _ENCODING_IS_STATE_DEPENDENT 1
99: #define _STATE_NEEDS_EXPLICIT_INIT(_ps_) 0
100:
101: static __inline void
102: /*ARGSUSED*/
103: _citrus_UTF7_init_state(_UTF7EncodingInfo * __restrict ei,
104: _UTF7State * __restrict s)
105: {
106: /* ei appears to be unused */
107: _DIAGASSERT(s != NULL);
108:
109: memset((void *)s, 0, sizeof(*s));
110: }
111:
112: static __inline void
113: /*ARGSUSED*/
114: _citrus_UTF7_pack_state(_UTF7EncodingInfo * __restrict ei,
115: void *__restrict pspriv, const _UTF7State * __restrict s)
116: {
117: /* ei seem to be unused */
118: _DIAGASSERT(pspriv != NULL);
119: _DIAGASSERT(s != NULL);
120:
121: memcpy(pspriv, (const void *)s, sizeof(*s));
122: }
123:
124: static __inline void
125: /*ARGSUSED*/
126: _citrus_UTF7_unpack_state(_UTF7EncodingInfo * __restrict ei,
127: _UTF7State * __restrict s, const void * __restrict pspriv)
128: {
129: /* ei seem to be unused */
130: _DIAGASSERT(s != NULL);
131: _DIAGASSERT(pspriv != NULL);
132:
133: memcpy((void *)s, pspriv, sizeof(*s));
134: }
135:
136: static const char base64[] =
137: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
138: "abcdefghijklmnopqrstuvwxyz"
139: "0123456789+/";
140:
141: static const char direct[] =
142: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
143: "abcdefghijklmnopqrstuvwxyz"
144: "0123456789(),-./:?";
145:
146: static const char option[] = "!\"#$%&';<=>@[]^_`{|}";
147: static const char spaces[] = " \t\r\n";
148:
149: #define BASE64_BIT 6
150: #define UTF16_BIT 16
151:
152: #define BASE64_MAX 0x3f
153: #define UTF16_MAX UINT16_C(0xffff)
154: #define UTF32_MAX UINT32_C(0x10ffff)
155:
156: #define BASE64_IN '+'
157: #define BASE64_OUT '-'
158:
159: #define SHIFT7BIT(c) ((c) >> 7)
160: #define ISSPECIAL(c) ((c) == '\0' || (c) == BASE64_IN)
161:
162: #define FINDLEN(ei, c) \
163: (SHIFT7BIT((c)) ? -1 : (((ei)->cell[(c)] & EI_MASK) - 1))
164:
165: #define ISDIRECT(ei, c) (!SHIFT7BIT((c)) && (ISSPECIAL((c)) || \
166: ei->cell[(c)] & (EI_DIRECT | EI_OPTION | EI_SPACE)))
167:
168: #define ISSAFE(ei, c) (!SHIFT7BIT((c)) && (ISSPECIAL((c)) || \
1.4 christos 169: (c < 0x80 && ei->cell[(c)] & (EI_DIRECT | EI_SPACE))))
1.1 tnozaki 170:
171: /* surrogate pair */
172: #define SRG_BASE UINT32_C(0x10000)
173: #define HISRG_MIN UINT16_C(0xd800)
174: #define HISRG_MAX UINT16_C(0xdbff)
175: #define LOSRG_MIN UINT16_C(0xdc00)
176: #define LOSRG_MAX UINT16_C(0xdfff)
177:
178: static int
1.5 tnozaki 179: _citrus_UTF7_mbtoutf16(_UTF7EncodingInfo * __restrict ei,
1.1 tnozaki 180: uint16_t * __restrict u16, const char ** __restrict s, size_t n,
181: _UTF7State * __restrict psenc, size_t * __restrict nresult)
182: {
1.2 tnozaki 183: _UTF7State sv;
1.1 tnozaki 184: const char *s0;
185: int i, done, len;
186:
187: _DIAGASSERT(ei != NULL);
188: _DIAGASSERT(s != NULL && *s != NULL);
189: _DIAGASSERT(psenc != NULL);
190:
191: s0 = *s;
1.2 tnozaki 192: sv = *psenc;
1.1 tnozaki 193:
194: for (i = 0, done = 0; done == 0; i++) {
1.2 tnozaki 195: _DIAGASSERT(i <= psenc->chlen);
196: if (i == psenc->chlen) {
1.1 tnozaki 197: if (n-- < 1) {
198: *nresult = (size_t)-2;
199: *s = s0;
1.2 tnozaki 200: sv.chlen = psenc->chlen;
201: *psenc = sv;
1.5 tnozaki 202: return 0;
1.1 tnozaki 203: }
1.2 tnozaki 204: psenc->ch[psenc->chlen++] = *s0++;
1.1 tnozaki 205: }
206: if (SHIFT7BIT((int)psenc->ch[i]))
207: goto ilseq;
1.2 tnozaki 208: if (!psenc->mode) {
209: if (psenc->bits > 0 || psenc->cache > 0)
1.5 tnozaki 210: return EINVAL;
1.1 tnozaki 211: if (psenc->ch[i] == BASE64_IN) {
1.2 tnozaki 212: psenc->mode = 1;
1.1 tnozaki 213: } else {
214: if (!ISDIRECT(ei, (int)psenc->ch[i]))
215: goto ilseq;
216: *u16 = (uint16_t)psenc->ch[i];
217: done = 1;
218: continue;
219: }
220: } else {
1.2 tnozaki 221: if (psenc->ch[i] == BASE64_OUT && psenc->cache == 0) {
222: psenc->mode = 0;
1.1 tnozaki 223: *u16 = (uint16_t)BASE64_IN;
224: done = 1;
225: continue;
226: }
227: len = FINDLEN(ei, (int)psenc->ch[i]);
228: if (len < 0) {
1.2 tnozaki 229: if (psenc->bits >= BASE64_BIT)
1.5 tnozaki 230: return EINVAL;
1.2 tnozaki 231: psenc->mode = 0;
232: psenc->bits = psenc->cache = 0;
1.1 tnozaki 233: if (psenc->ch[i] != BASE64_OUT) {
234: if (!ISDIRECT(ei, (int)psenc->ch[i]))
235: goto ilseq;
236: *u16 = (uint16_t)psenc->ch[i];
237: done = 1;
238: }
239: } else {
1.5 tnozaki 240: psenc->cache =
241: (psenc->cache << BASE64_BIT) | len;
1.2 tnozaki 242: switch (psenc->bits) {
1.1 tnozaki 243: case 0: case 2: case 4: case 6: case 8:
1.2 tnozaki 244: psenc->bits += BASE64_BIT;
1.1 tnozaki 245: break;
246: case 10: case 12: case 14:
1.2 tnozaki 247: psenc->bits -= (UTF16_BIT - BASE64_BIT);
248: *u16 = (psenc->cache >> psenc->bits)
1.1 tnozaki 249: & UTF16_MAX;
250: done = 1;
251: break;
252: default:
1.5 tnozaki 253: return EINVAL;
1.1 tnozaki 254: }
255: }
256: }
257: }
258:
1.2 tnozaki 259: if (psenc->chlen > i)
1.5 tnozaki 260: return EINVAL;
1.2 tnozaki 261: psenc->chlen = 0;
1.1 tnozaki 262: *nresult = (size_t)((*u16 == 0) ? 0 : s0 - *s);
263: *s = s0;
264:
1.5 tnozaki 265: return 0;
1.1 tnozaki 266:
267: ilseq:
268: *nresult = (size_t)-1;
1.5 tnozaki 269: return EILSEQ;
1.1 tnozaki 270: }
271:
272: static int
273: _citrus_UTF7_mbrtowc_priv(_UTF7EncodingInfo * __restrict ei,
274: wchar_t * __restrict pwc, const char ** __restrict s, size_t n,
275: _UTF7State * __restrict psenc, size_t * __restrict nresult)
276: {
1.5 tnozaki 277: const char *s0;
1.1 tnozaki 278: uint32_t u32;
279: uint16_t hi, lo;
1.5 tnozaki 280: size_t siz, nr;
1.1 tnozaki 281: int err;
282:
283: _DIAGASSERT(ei != NULL);
284: /* pwc may be null */
285: _DIAGASSERT(s != NULL);
286: _DIAGASSERT(psenc != NULL);
287:
288: if (*s == NULL) {
289: _citrus_UTF7_init_state(ei, psenc);
290: *nresult = (size_t)_ENCODING_IS_STATE_DEPENDENT;
1.5 tnozaki 291: return 0;
1.1 tnozaki 292: }
1.5 tnozaki 293: s0 = *s;
1.2 tnozaki 294: if (psenc->surrogate) {
295: hi = (psenc->cache >> 2) & UTF16_MAX;
1.5 tnozaki 296: if (hi < HISRG_MIN || hi > HISRG_MAX)
297: return EINVAL;
1.1 tnozaki 298: siz = 0;
299: } else {
1.5 tnozaki 300: err = _citrus_UTF7_mbtoutf16(ei, &hi, &s0, n, psenc, &nr);
301: if (nr == (size_t)-1 || nr == (size_t)-2) {
302: *nresult = nr;
303: return err;
304: }
305: if (err != 0)
306: return err;
307: n -= nr;
308: siz = nr;
309: if (hi < HISRG_MIN || hi > HISRG_MAX) {
310: u32 = (uint32_t)hi;
311: goto done;
312: }
313: psenc->surrogate = 1;
1.1 tnozaki 314: }
1.5 tnozaki 315: err = _citrus_UTF7_mbtoutf16(ei, &lo, &s0, n, psenc, &nr);
316: if (nr == (size_t)-1 || nr == (size_t)-2) {
317: *nresult = nr;
318: return err;
1.1 tnozaki 319: }
1.5 tnozaki 320: if (err != 0)
321: return err;
322: hi -= HISRG_MIN;
323: lo -= LOSRG_MIN;
324: u32 = (hi << 10 | lo) + SRG_BASE;
325: siz += nr;
326: done:
327: *s = s0;
1.1 tnozaki 328: if (pwc != NULL)
329: *pwc = (wchar_t)u32;
1.5 tnozaki 330: if (u32 == (uint32_t)0) {
331: *nresult = (size_t)0;
332: _citrus_UTF7_init_state(ei, psenc);
333: } else {
334: *nresult = siz;
335: psenc->surrogate = 0;
336: }
337: return err;
1.1 tnozaki 338: }
339:
1.5 tnozaki 340: static int
341: _citrus_UTF7_utf16tomb(_UTF7EncodingInfo * __restrict ei,
342: char * __restrict s, size_t n, uint16_t u16,
343: _UTF7State * __restrict psenc, size_t * __restrict nresult)
1.1 tnozaki 344: {
345: int bits, i;
346:
347: _DIAGASSERT(ei != NULL);
348: _DIAGASSERT(psenc != NULL);
349:
1.2 tnozaki 350: if (psenc->chlen != 0 || psenc->bits > BASE64_BIT)
1.5 tnozaki 351: return EINVAL;
1.1 tnozaki 352:
353: if (ISSAFE(ei, u16)) {
1.2 tnozaki 354: if (psenc->mode) {
355: if (psenc->bits > 0) {
356: bits = BASE64_BIT - psenc->bits;
357: i = (psenc->cache << bits) & BASE64_MAX;
358: psenc->ch[psenc->chlen++] = base64[i];
359: psenc->bits = psenc->cache = 0;
1.1 tnozaki 360: }
361: if (u16 == BASE64_OUT || FINDLEN(ei, u16) >= 0)
1.2 tnozaki 362: psenc->ch[psenc->chlen++] = BASE64_OUT;
363: psenc->mode = 0;
1.1 tnozaki 364: }
1.2 tnozaki 365: if (psenc->bits != 0)
1.5 tnozaki 366: return EINVAL;
1.2 tnozaki 367: psenc->ch[psenc->chlen++] = (char)u16;
1.1 tnozaki 368: if (u16 == BASE64_IN)
1.2 tnozaki 369: psenc->ch[psenc->chlen++] = BASE64_OUT;
1.1 tnozaki 370: } else {
1.2 tnozaki 371: if (!psenc->mode) {
372: if (psenc->bits > 0)
1.5 tnozaki 373: return EINVAL;
1.2 tnozaki 374: psenc->ch[psenc->chlen++] = BASE64_IN;
375: psenc->mode = 1;
1.1 tnozaki 376: }
1.2 tnozaki 377: psenc->cache = (psenc->cache << UTF16_BIT) | u16;
378: bits = UTF16_BIT + psenc->bits;
379: psenc->bits = bits % BASE64_BIT;
1.1 tnozaki 380: while ((bits -= BASE64_BIT) >= 0) {
1.2 tnozaki 381: i = (psenc->cache >> bits) & BASE64_MAX;
382: psenc->ch[psenc->chlen++] = base64[i];
1.1 tnozaki 383: }
384: }
1.5 tnozaki 385: memcpy(s, psenc->ch, psenc->chlen);
386: *nresult = psenc->chlen;
387: psenc->chlen = 0;
1.1 tnozaki 388:
1.5 tnozaki 389: return 0;
1.1 tnozaki 390: }
391:
392: static int
393: _citrus_UTF7_wcrtomb_priv(_UTF7EncodingInfo * __restrict ei,
394: char * __restrict s, size_t n, wchar_t wchar,
395: _UTF7State * __restrict psenc, size_t * __restrict nresult)
396: {
397: uint32_t u32;
398: uint16_t u16[2];
399: int err, len, i;
1.5 tnozaki 400: size_t siz, nr;
1.1 tnozaki 401:
402: _DIAGASSERT(ei != NULL);
403: _DIAGASSERT(s != NULL);
404: _DIAGASSERT(psenc != NULL);
1.5 tnozaki 405: _DIAGASSERT(nresult != NULL);
1.1 tnozaki 406:
407: u32 = (uint32_t)wchar;
408: if (u32 <= UTF16_MAX) {
409: u16[0] = (uint16_t)u32;
410: len = 1;
411: } else if (u32 <= UTF32_MAX) {
412: u32 -= SRG_BASE;
413: u16[0] = (u32 >> 10) + HISRG_MIN;
414: u16[1] = ((uint16_t)(u32 & UINT32_C(0x3ff))) + LOSRG_MIN;
415: len = 2;
416: } else {
417: *nresult = (size_t)-1;
1.5 tnozaki 418: return EILSEQ;
1.1 tnozaki 419: }
1.5 tnozaki 420: siz = 0;
421: for (i = 0; i < len; ++i) {
422: err = _citrus_UTF7_utf16tomb(ei, s, n, u16[i], psenc, &nr);
423: if (err != 0)
424: return err; /* XXX: state has been modified */
425: s += nr;
426: n -= nr;
427: siz += nr;
1.1 tnozaki 428: }
1.5 tnozaki 429: *nresult = siz;
1.1 tnozaki 430:
1.5 tnozaki 431: return 0;
1.1 tnozaki 432: }
433:
434: static int
435: /* ARGSUSED */
436: _citrus_UTF7_put_state_reset(_UTF7EncodingInfo * __restrict ei,
437: char * __restrict s, size_t n, _UTF7State * __restrict psenc,
438: size_t * __restrict nresult)
439: {
440: int bits, pos;
441:
442: _DIAGASSERT(ei != NULL);
443: _DIAGASSERT(s != NULL);
444: _DIAGASSERT(psenc != NULL);
445: _DIAGASSERT(nresult != NULL);
446:
1.2 tnozaki 447: if (psenc->chlen != 0 || psenc->bits > BASE64_BIT || psenc->surrogate)
1.5 tnozaki 448: return EINVAL;
1.1 tnozaki 449:
1.2 tnozaki 450: if (psenc->mode) {
451: if (psenc->bits > 0) {
1.1 tnozaki 452: if (n-- < 1)
1.5 tnozaki 453: return E2BIG;
1.2 tnozaki 454: bits = BASE64_BIT - psenc->bits;
455: pos = (psenc->cache << bits) & BASE64_MAX;
456: psenc->ch[psenc->chlen++] = base64[pos];
457: psenc->ch[psenc->chlen++] = BASE64_OUT;
458: psenc->bits = psenc->cache = 0;
1.1 tnozaki 459: }
1.2 tnozaki 460: psenc->mode = 0;
1.1 tnozaki 461: }
1.2 tnozaki 462: if (psenc->bits != 0)
1.5 tnozaki 463: return EINVAL;
1.1 tnozaki 464: if (n-- < 1)
1.5 tnozaki 465: return E2BIG;
1.1 tnozaki 466:
1.2 tnozaki 467: _DIAGASSERT(n >= psenc->chlen);
468: *nresult = (size_t)psenc->chlen;
469: if (psenc->chlen > 0) {
470: memcpy(s, psenc->ch, psenc->chlen);
471: psenc->chlen = 0;
1.1 tnozaki 472: }
473:
1.5 tnozaki 474: return 0;
1.1 tnozaki 475: }
476:
477: static __inline int
478: /*ARGSUSED*/
479: _citrus_UTF7_stdenc_wctocs(_UTF7EncodingInfo * __restrict ei,
480: _csid_t * __restrict csid,
481: _index_t * __restrict idx, wchar_t wc)
482: {
483: /* ei seem to be unused */
484: _DIAGASSERT(csid != NULL);
485: _DIAGASSERT(idx != NULL);
486:
487: *csid = 0;
488: *idx = (_index_t)wc;
489:
1.5 tnozaki 490: return 0;
1.1 tnozaki 491: }
492:
493: static __inline int
494: /*ARGSUSED*/
495: _citrus_UTF7_stdenc_cstowc(_UTF7EncodingInfo * __restrict ei,
496: wchar_t * __restrict wc,
497: _csid_t csid, _index_t idx)
498: {
499: /* ei seem to be unused */
500: _DIAGASSERT(wc != NULL);
501:
502: if (csid != 0)
1.5 tnozaki 503: return EILSEQ;
1.1 tnozaki 504: *wc = (wchar_t)idx;
505:
1.5 tnozaki 506: return 0;
1.1 tnozaki 507: }
508:
1.3 tshiozak 509: static __inline int
510: /*ARGSUSED*/
511: _citrus_UTF7_stdenc_get_state_desc_generic(_UTF7EncodingInfo * __restrict ei,
512: _UTF7State * __restrict psenc,
513: int * __restrict rstate)
514: {
515:
516: if (psenc->chlen == 0)
517: *rstate = _STDENC_SDGEN_INITIAL;
518: else
519: *rstate = _STDENC_SDGEN_INCOMPLETE_CHAR;
520:
521: return 0;
522: }
523:
1.1 tnozaki 524: static void
525: /*ARGSUSED*/
526: _citrus_UTF7_encoding_module_uninit(_UTF7EncodingInfo *ei)
527: {
528: /* ei seems to be unused */
529: }
530:
531: static int
532: /*ARGSUSED*/
533: _citrus_UTF7_encoding_module_init(_UTF7EncodingInfo * __restrict ei,
534: const void * __restrict var, size_t lenvar)
535: {
536: const char *s;
537:
1.3 tshiozak 538: _DIAGASSERT(ei != NULL);
1.1 tnozaki 539: /* var may be null */
540:
541: memset(ei, 0, sizeof(*ei));
542:
543: #define FILL(str, flag) \
544: do { \
545: for (s = str; *s != '\0'; s++) \
546: ei->cell[*s & 0x7f] |= flag; \
547: } while (/*CONSTCOND*/0)
548:
549: FILL(base64, (s - base64) + 1);
550: FILL(direct, EI_DIRECT);
551: FILL(option, EI_OPTION);
552: FILL(spaces, EI_SPACE);
553:
1.5 tnozaki 554: return 0;
1.1 tnozaki 555: }
556:
557: /* ----------------------------------------------------------------------
558: * public interface for ctype
559: */
560:
561: _CITRUS_CTYPE_DECLS(UTF7);
562: _CITRUS_CTYPE_DEF_OPS(UTF7);
563:
564: #include "citrus_ctype_template.h"
565:
566: /* ----------------------------------------------------------------------
567: * public interface for stdenc
568: */
569:
570: _CITRUS_STDENC_DECLS(UTF7);
571: _CITRUS_STDENC_DEF_OPS(UTF7);
572:
573: #include "citrus_stdenc_template.h"
CVSweb <webmaster@jp.NetBSD.org>