1/*	$NetBSD: citrus_ctype_template.h,v 1.40 2022/05/28 22:16:43 andvar Exp $	*/
2
3/*-
4 * Copyright (c)2002 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 * Copyright (c) 1993
31 *	The Regents of the University of California.  All rights reserved.
32 *
33 * This code is derived from software contributed to Berkeley by
34 * Paul Borman at Krystal Technologies.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 * 1. Redistributions of source code must retain the above copyright
40 *    notice, this list of conditions and the following disclaimer.
41 * 2. Redistributions in binary form must reproduce the above copyright
42 *    notice, this list of conditions and the following disclaimer in the
43 *    documentation and/or other materials provided with the distribution.
44 * 3. Neither the name of the University nor the names of its contributors
45 *    may be used to endorse or promote products derived from this software
46 *    without specific prior written permission.
47 *
48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 * SUCH DAMAGE.
59 */
60
61
62/*
63 * CAUTION: THIS IS NOT STANDALONE FILE
64 *
65 * function templates of ctype encoding handler for each encodings.
66 *
67 * you need to define the macros below:
68 *
69 *   _FUNCNAME(method) :
70 *     It should convine the real function name for the method.
71 *      e.g. _FUNCNAME(mbrtowc) should be expanded to
72 *             _EUC_ctype_mbrtowc
73 *           for EUC locale.
74 *
75 *   _CEI_TO_STATE(cei, method) :
76 *     It should be expanded to the pointer of the method-internal state
77 *     structures.
78 *     e.g. _CEI_TO_STATE(cei, mbrtowc) might be expanded to
79 *             (cei)->states.s_mbrtowc
80 *     This structure may use if the function is called as
81 *           mbrtowc(&wc, s, n, NULL);
82 *     Such individual structures are needed by:
83 *           mblen
84 *           mbrlen
85 *           mbrtowc
86 *           mbtowc
87 *           mbsrtowcs
88 *           mbsnrtowcs
89 *           wcrtomb
90 *           wcsrtombs
91 *           wcsnrtombs
92 *           wctomb
93 *     These need to be kept in the ctype encoding information structure,
94 *     pointed by "cei".
95 *
96 *   _ENCODING_INFO :
97 *     It should be expanded to the name of the encoding information structure.
98 *     e.g. For EUC encoding, this macro is expanded to _EUCInfo.
99 *     Encoding information structure need to contain the common informations
100 *     for the codeset.
101 *
102 *   _ENCODING_STATE :
103 *     It should be expanded to the name of the encoding state structure.
104 *     e.g. For EUC encoding, this macro is expanded to _EUCState.
105 *     Encoding state structure need to contain the context-dependent states,
106 *     which are "unpacked-form" of mbstate_t type and kept during sequent
107 *     calls of mb/wc functions,
108 *
109 *   _ENCODING_IS_STATE_DEPENDENT :
110 *     If the encoding is state dependent, this should be expanded to
111 *     non-zero integral value.  Otherwise, 0.
112 *
113 *   _STATE_NEEDS_EXPLICIT_INIT(ps) :
114 *     some encodings, states needs some explicit initialization.
115 *     (ie. initialization with memset isn't enough.)
116 *     If the encoding state pointed by "ps" needs to be initialized
117 *     explicitly, return non-zero. Otherwize, 0.
118 *
119 */
120
121#include <stdalign.h>
122
123/* prototypes */
124
125__BEGIN_DECLS
126static void _FUNCNAME(init_state)(_ENCODING_INFO * __restrict,
127				  _ENCODING_STATE * __restrict);
128static void _FUNCNAME(pack_state)(_ENCODING_INFO * __restrict,
129				  void * __restrict,
130				  const _ENCODING_STATE * __restrict);
131static void _FUNCNAME(unpack_state)(_ENCODING_INFO * __restrict,
132				    _ENCODING_STATE * __restrict,
133				    const void * __restrict);
134#if _ENCODING_IS_STATE_DEPENDENT
135static int _FUNCNAME(put_state_reset)(_ENCODING_INFO * __restrict,
136				      char * __restrict, size_t,
137				      _ENCODING_STATE * __restrict,
138				      size_t * __restrict);
139#endif
140
141/*
142 * standard form of mbrtowc_priv.
143 *
144 * note (differences from real mbrtowc):
145 *   - 3rd parameter is not "const char *s" but "const char **s".
146 *     after the call of the function, *s will point the first byte of
147 *     the next character.
148 *   - additional 4th parameter is the size of src buffer.
149 *   - 5th parameter is unpacked encoding-dependent state structure.
150 *   - additional 6th parameter is the storage to be stored
151 *     the return value in the real mbrtowc context.
152 *   - return value means "errno" in the real mbrtowc context.
153 */
154
155static int _FUNCNAME(mbrtowc_priv)(_ENCODING_INFO * __restrict,
156				   wchar_t * __restrict,
157				   const char ** __restrict,
158				   size_t, _ENCODING_STATE * __restrict,
159				   size_t * __restrict);
160
161/*
162 * standard form of wcrtomb_priv.
163 *
164 * note (differences from real wcrtomb):
165 *   - additional 3th parameter is the size of src buffer.
166 *   - 5th parameter is unpacked encoding-dependent state structure.
167 *   - additional 6th parameter is the storage to be stored
168 *     the return value in the real mbrtowc context.
169 *   - return value means "errno" in the real wcrtomb context.
170 *   - caller should ensure that 2nd parameter isn't NULL.
171 *     (XXX inconsist with mbrtowc_priv)
172 */
173
174static int _FUNCNAME(wcrtomb_priv)(_ENCODING_INFO * __restrict,
175				   char * __restrict, size_t, wchar_t,
176				   _ENCODING_STATE * __restrict,
177				   size_t * __restrict);
178__END_DECLS
179
180
181/*
182 * macros
183 */
184
185#define _TO_CEI(_cl_)	((_CTYPE_INFO*)(_cl_))
186
187
188/*
189 * templates
190 */
191
192/* internal routines */
193
194static __inline int
195_FUNCNAME(mbtowc_priv)(_ENCODING_INFO * __restrict ei,
196		       wchar_t * __restrict pwc,  const char * __restrict s,
197		       size_t n, _ENCODING_STATE * __restrict psenc,
198		       int * __restrict nresult)
199{
200	_ENCODING_STATE state;
201	size_t nr;
202	int err = 0;
203
204	_DIAGASSERT(ei != NULL);
205	_DIAGASSERT(psenc != NULL);
206
207	if (s == NULL) {
208		_FUNCNAME(init_state)(ei, psenc);
209		*nresult = _ENCODING_IS_STATE_DEPENDENT;
210		return (0);
211	}
212
213	state = *psenc;
214	err = _FUNCNAME(mbrtowc_priv)(ei, pwc, (const char **)&s, n, psenc, &nr);
215	if (nr == (size_t)-2)
216		err = EILSEQ;
217	if (err) {
218		/* In error case, we should restore the state. */
219		*psenc = state;
220		*nresult = -1;
221		return (err);
222	}
223
224	*nresult = (int)nr;
225
226	return (0);
227}
228
229static int
230_FUNCNAME(mbsrtowcs_priv)(_ENCODING_INFO * __restrict ei,
231			  wchar_t * __restrict pwcs,
232			  const char ** __restrict s,
233			  size_t n, _ENCODING_STATE * __restrict psenc,
234			  size_t * __restrict nresult)
235{
236	int err, cnt;
237	size_t siz;
238	const char *s0;
239	size_t mbcurmax;
240
241	_DIAGASSERT(nresult != 0);
242	_DIAGASSERT(ei != NULL);
243	_DIAGASSERT(psenc != NULL);
244	_DIAGASSERT(s != NULL);
245	_DIAGASSERT(*s != NULL);
246
247	/* if pwcs is NULL, ignore n */
248	if (pwcs == NULL)
249		n = 1; /* arbitrary >0 value */
250
251	err = cnt = 0;
252	s0 = *s; /* to keep *s unchanged for now, use copy instead. */
253	mbcurmax = _ENCODING_MB_CUR_MAX(ei);
254	while (n > 0) {
255		err = _FUNCNAME(mbrtowc_priv)(ei, pwcs, &s0, mbcurmax,
256					      psenc, &siz);
257		if (siz == (size_t)-2)
258			err = EILSEQ;
259		if (err) {
260			cnt = -1;
261			goto bye;
262		}
263		switch (siz) {
264		case 0:
265			if (pwcs) {
266				_FUNCNAME(init_state)(ei, psenc);
267			}
268			s0 = 0;
269			goto bye;
270		default:
271			if (pwcs) {
272				pwcs++;
273				n--;
274			}
275			cnt++;
276			break;
277		}
278	}
279bye:
280	if (pwcs)
281		*s = s0;
282
283	*nresult = (size_t)cnt;
284
285	return err;
286}
287
288static int
289_FUNCNAME(mbsnrtowcs_priv)(_ENCODING_INFO * __restrict ei,
290			  wchar_t * __restrict pwcs,
291			  const char ** __restrict s, size_t in,
292			  size_t n, _ENCODING_STATE * __restrict psenc,
293			  size_t * __restrict nresult)
294{
295	int err;
296	size_t cnt, siz;
297	const char *s0, *se;
298
299	_DIAGASSERT(nresult != 0);
300	_DIAGASSERT(ei != NULL);
301	_DIAGASSERT(psenc != NULL);
302	_DIAGASSERT(s != NULL);
303	_DIAGASSERT(*s != NULL);
304
305	/* if pwcs is NULL, ignore n */
306	if (pwcs == NULL)
307		n = 1; /* arbitrary >0 value */
308
309	err = 0;
310	cnt = 0;
311	se = *s + in;
312	s0 = *s; /* to keep *s unchanged for now, use copy instead. */
313	while (s0 < se && n > 0) {
314		err = _FUNCNAME(mbrtowc_priv)(ei, pwcs, &s0, se - s0,
315					      psenc, &siz);
316		if (err) {
317			cnt = (size_t)-1;
318			goto bye;
319		}
320		if (siz == (size_t)-2) {
321			s0 = se;
322			goto bye;
323		}
324		switch (siz) {
325		case 0:
326			if (pwcs) {
327				_FUNCNAME(init_state)(ei, psenc);
328			}
329			s0 = 0;
330			goto bye;
331		default:
332			if (pwcs) {
333				pwcs++;
334				n--;
335			}
336			cnt++;
337			break;
338		}
339	}
340bye:
341	if (pwcs)
342		*s = s0;
343
344	*nresult = cnt;
345
346	return err;
347}
348
349static int
350_FUNCNAME(wcsrtombs_priv)(_ENCODING_INFO * __restrict ei, char * __restrict s,
351			  const wchar_t ** __restrict pwcs,
352			  size_t n, _ENCODING_STATE * __restrict psenc,
353			  size_t * __restrict nresult)
354{
355	int err;
356	char buf[MB_LEN_MAX];
357	size_t cnt, siz;
358	const wchar_t* pwcs0;
359#if _ENCODING_IS_STATE_DEPENDENT
360	_ENCODING_STATE state;
361#endif
362
363	pwcs0 = *pwcs;
364
365	cnt = 0;
366	if (!s)
367		n = 1;
368
369	while (n > 0) {
370#if _ENCODING_IS_STATE_DEPENDENT
371		state = *psenc;
372#endif
373		err = _FUNCNAME(wcrtomb_priv)(ei, buf, sizeof(buf),
374					      *pwcs0, psenc, &siz);
375		if (siz == (size_t)-1) {
376			*pwcs = pwcs0;
377			*nresult = siz;
378			return (err);
379		}
380
381		if (s) {
382			if (n < siz) {
383#if _ENCODING_IS_STATE_DEPENDENT
384				*psenc = state;
385#endif
386				break;
387			}
388			memcpy(s, buf, siz);
389			s += siz;
390			n -= siz;
391		}
392		cnt += siz;
393		if (!*pwcs0) {
394			if (s) {
395				_FUNCNAME(init_state)(ei, psenc);
396			}
397			pwcs0 = 0;
398			cnt--; /* don't include terminating null */
399			break;
400		}
401		pwcs0++;
402	}
403	if (s)
404		*pwcs = pwcs0;
405
406	*nresult = cnt;
407	return (0);
408}
409
410static int
411_FUNCNAME(wcsnrtombs_priv)(_ENCODING_INFO * __restrict ei, char * __restrict s,
412			  const wchar_t ** __restrict pwcs, size_t in,
413			  size_t n, _ENCODING_STATE * __restrict psenc,
414			  size_t * __restrict nresult)
415{
416	int cnt = 0, err;
417	char buf[MB_LEN_MAX];
418	size_t siz;
419	const wchar_t* pwcs0;
420#if _ENCODING_IS_STATE_DEPENDENT
421	_ENCODING_STATE state;
422#endif
423
424	pwcs0 = *pwcs;
425
426	if (!s)
427		n = 1;
428
429	while (in > 0 && n > 0) {
430#if _ENCODING_IS_STATE_DEPENDENT
431		state = *psenc;
432#endif
433		err = _FUNCNAME(wcrtomb_priv)(ei, buf, sizeof(buf),
434					      *pwcs0, psenc, &siz);
435		if (siz == (size_t)-1) {
436			*nresult = siz;
437			return (err);
438		}
439
440		if (s) {
441			if (n < siz) {
442#if _ENCODING_IS_STATE_DEPENDENT
443				*psenc = state;
444#endif
445				break;
446			}
447			memcpy(s, buf, siz);
448			s += siz;
449			n -= siz;
450		}
451		cnt += siz;
452		if (!*pwcs0) {
453			if (s) {
454				_FUNCNAME(init_state)(ei, psenc);
455			}
456			pwcs0 = 0;
457			cnt--; /* don't include terminating null */
458			break;
459		}
460		pwcs0++;
461		--in;
462	}
463	if (s)
464		*pwcs = pwcs0;
465
466	*nresult = (size_t)cnt;
467	return (0);
468}
469
470
471/* ----------------------------------------------------------------------
472 * templates for public functions
473 */
474
475#define _RESTART_BEGIN(_func_, _cei_, _pspriv_, _pse_)			\
476do {									\
477	_ENCODING_STATE _state;						\
478	do {								\
479		if (_pspriv_ == NULL) {					\
480			_pse_ = &_CEI_TO_STATE(_cei_, _func_);		\
481			if (_STATE_NEEDS_EXPLICIT_INIT(_pse_))		\
482			    _FUNCNAME(init_state)(_CEI_TO_EI(_cei_),	\
483							(_pse_));	\
484		} else {						\
485			_pse_ = &_state;				\
486			_FUNCNAME(unpack_state)(_CEI_TO_EI(_cei_),	\
487						_pse_, _pspriv_);	\
488		}							\
489	} while (0)
490
491#define _RESTART_END(_func_, _cei_, _pspriv_, _pse_)			\
492	if (_pspriv_ != NULL) {						\
493		_FUNCNAME(pack_state)(_CEI_TO_EI(_cei_), _pspriv_,	\
494				      _pse_);				\
495	}								\
496} while (0)
497
498int
499_FUNCNAME(ctype_getops)(_citrus_ctype_ops_rec_t *ops, size_t lenops,
500			uint32_t expected_version)
501{
502	if (expected_version<_CITRUS_CTYPE_ABI_VERSION || lenops<sizeof(*ops))
503		return (EINVAL);
504
505	memcpy(ops, &_FUNCNAME(ctype_ops), sizeof(_FUNCNAME(ctype_ops)));
506
507	return (0);
508}
509
510/* Ensure alignment matches guarantees from locale/multibyte.h */
511__CTASSERT(alignof(_ENCODING_STATE) <= alignof(int) ||
512           alignof(_ENCODING_STATE) <= alignof(void *));
513
514static int
515_FUNCNAME(ctype_init)(void ** __restrict cl,
516		      void * __restrict var, size_t lenvar, size_t lenps)
517{
518	_CTYPE_INFO *cei;
519
520	_DIAGASSERT(cl != NULL);
521
522	/* sanity check to avoid overruns */
523	if (sizeof(_ENCODING_STATE) > lenps)
524		return (EINVAL);
525
526	cei = calloc(1, sizeof(_CTYPE_INFO));
527	if (cei == NULL)
528		return (ENOMEM);
529
530	*cl = (void *)cei;
531
532	return _FUNCNAME(encoding_module_init)(_CEI_TO_EI(cei), var, lenvar);
533}
534
535static void
536_FUNCNAME(ctype_uninit)(void *cl)
537{
538	if (cl) {
539		_FUNCNAME(encoding_module_uninit)(_CEI_TO_EI(_TO_CEI(cl)));
540		free(cl);
541	}
542}
543
544static unsigned
545/*ARGSUSED*/
546_FUNCNAME(ctype_get_mb_cur_max)(void *cl)
547{
548	return _ENCODING_MB_CUR_MAX(_CEI_TO_EI(_TO_CEI(cl)));
549}
550
551static int
552_FUNCNAME(ctype_mblen)(void * __restrict cl,
553		       const char * __restrict s, size_t n,
554		       int * __restrict nresult)
555{
556	_ENCODING_STATE *psenc;
557	_ENCODING_INFO *ei;
558
559	_DIAGASSERT(cl != NULL);
560
561	psenc = &_CEI_TO_STATE(_TO_CEI(cl), mblen);
562	ei = _CEI_TO_EI(_TO_CEI(cl));
563	if (_STATE_NEEDS_EXPLICIT_INIT(psenc))
564		_FUNCNAME(init_state)(ei, psenc);
565	return _FUNCNAME(mbtowc_priv)(ei, NULL, s, n, psenc, nresult);
566}
567
568static int
569_FUNCNAME(ctype_mbrlen)(void * __restrict cl, const char * __restrict s,
570			size_t n, void * __restrict pspriv,
571			size_t * __restrict nresult)
572{
573	_ENCODING_STATE *psenc;
574	_ENCODING_INFO *ei;
575	int err = 0;
576
577	_DIAGASSERT(cl != NULL);
578
579	ei = _CEI_TO_EI(_TO_CEI(cl));
580	_RESTART_BEGIN(mbrlen, _TO_CEI(cl), pspriv, psenc);
581	if (s == NULL) {
582		_FUNCNAME(init_state)(ei, psenc);
583		*nresult = 0;
584	} else {
585		err = _FUNCNAME(mbrtowc_priv)(ei, NULL, (const char **)&s, n,
586		    (void *)psenc, nresult);
587	}
588	_RESTART_END(mbrlen, _TO_CEI(cl), pspriv, psenc);
589
590	return (err);
591}
592
593static int
594_FUNCNAME(ctype_mbrtowc)(void * __restrict cl, wchar_t * __restrict pwc,
595			 const char * __restrict s, size_t n,
596			 void * __restrict pspriv, size_t * __restrict nresult)
597{
598	_ENCODING_STATE *psenc;
599	_ENCODING_INFO *ei;
600	int err = 0;
601
602	_DIAGASSERT(cl != NULL);
603
604	ei = _CEI_TO_EI(_TO_CEI(cl));
605	_RESTART_BEGIN(mbrtowc, _TO_CEI(cl), pspriv, psenc);
606	if (s == NULL) {
607		_FUNCNAME(init_state)(ei, psenc);
608		*nresult = 0;
609	} else {
610		err = _FUNCNAME(mbrtowc_priv)(ei, pwc, (const char **)&s, n,
611		    (void *)psenc, nresult);
612	}
613	_RESTART_END(mbrtowc, _TO_CEI(cl), pspriv, psenc);
614
615	return (err);
616}
617
618static int
619/*ARGSUSED*/
620_FUNCNAME(ctype_mbsinit)(void * __restrict cl, const void * __restrict pspriv,
621			 int * __restrict nresult)
622{
623	_ENCODING_STATE state;
624
625	if (pspriv == NULL) {
626		*nresult = 1;
627		return (0);
628	}
629
630	_FUNCNAME(unpack_state)(_CEI_TO_EI(_TO_CEI(cl)), &state, pspriv);
631
632	*nresult = (state.chlen == 0); /* XXX: FIXME */
633
634	return (0);
635}
636
637static int
638_FUNCNAME(ctype_mbsrtowcs)(void * __restrict cl, wchar_t * __restrict pwcs,
639			   const char ** __restrict s, size_t n,
640			   void * __restrict pspriv,
641			   size_t * __restrict nresult)
642{
643	_ENCODING_STATE *psenc;
644	_ENCODING_INFO *ei;
645	int err = 0;
646
647	_DIAGASSERT(cl != NULL);
648
649	ei = _CEI_TO_EI(_TO_CEI(cl));
650	_RESTART_BEGIN(mbsrtowcs, _TO_CEI(cl), pspriv, psenc);
651	err = _FUNCNAME(mbsrtowcs_priv)(ei, pwcs, s, n, psenc, nresult);
652	_RESTART_END(mbsrtowcs, _TO_CEI(cl), pspriv, psenc);
653
654	return (err);
655}
656
657static int __used
658_FUNCNAME(ctype_mbsnrtowcs)(_citrus_ctype_rec_t * __restrict cc, wchar_t * __restrict pwcs,
659			   const char ** __restrict s, size_t in, size_t n,
660			   void * __restrict pspriv,
661			   size_t * __restrict nresult)
662{
663	void *cl = cc->cc_closure;
664	_ENCODING_STATE *psenc;
665	_ENCODING_INFO *ei;
666	int err = 0;
667
668	_DIAGASSERT(cl != NULL);
669
670	ei = _CEI_TO_EI(_TO_CEI(cl));
671	_RESTART_BEGIN(mbsnrtowcs, _TO_CEI(cl), pspriv, psenc);
672	err = _FUNCNAME(mbsnrtowcs_priv)(ei, pwcs, s, in, n, psenc, nresult);
673	_RESTART_END(mbsnrtowcs, _TO_CEI(cl), pspriv, psenc);
674
675	return (err);
676}
677
678static int
679_FUNCNAME(ctype_mbstowcs)(void * __restrict cl, wchar_t * __restrict pwcs,
680			  const char * __restrict s, size_t n,
681			  size_t * __restrict nresult)
682{
683	int err;
684	_ENCODING_STATE state;
685	_ENCODING_INFO *ei;
686
687	_DIAGASSERT(cl != NULL);
688
689	ei = _CEI_TO_EI(_TO_CEI(cl));
690	_FUNCNAME(init_state)(ei, &state);
691	err = _FUNCNAME(mbsrtowcs_priv)(ei, pwcs, (const char **)&s, n,
692					&state, nresult);
693	if (*nresult == (size_t)-2) {
694		err = EILSEQ;
695		*nresult = (size_t)-1;
696	}
697
698	return (err);
699}
700
701static int
702_FUNCNAME(ctype_mbtowc)(void * __restrict cl, wchar_t * __restrict pwc,
703			const char * __restrict s, size_t n,
704			int * __restrict nresult)
705{
706	_ENCODING_STATE *psenc;
707	_ENCODING_INFO *ei;
708
709	_DIAGASSERT(cl != NULL);
710
711	psenc = &_CEI_TO_STATE(_TO_CEI(cl), mbtowc);
712	ei = _CEI_TO_EI(_TO_CEI(cl));
713	if (_STATE_NEEDS_EXPLICIT_INIT(psenc))
714		_FUNCNAME(init_state)(ei, psenc);
715	return _FUNCNAME(mbtowc_priv)(ei, pwc, s, n, psenc, nresult);
716}
717
718static int
719_FUNCNAME(ctype_wcrtomb)(void * __restrict cl, char * __restrict s, wchar_t wc,
720			 void * __restrict pspriv, size_t * __restrict nresult)
721{
722	_ENCODING_STATE *psenc;
723	char buf[MB_LEN_MAX];
724	int err = 0;
725	size_t sz;
726#if _ENCODING_IS_STATE_DEPENDENT
727	size_t rsz = 0;
728#endif
729
730	_DIAGASSERT(cl != NULL);
731
732	if (s == NULL) {
733		/*
734		 * use internal buffer.
735		 */
736		s = buf;
737		wc = L'\0'; /* SUSv3 */
738	}
739
740	_RESTART_BEGIN(wcrtomb, _TO_CEI(cl), pspriv, psenc);
741	sz = _ENCODING_MB_CUR_MAX(_CEI_TO_EI(_TO_CEI(cl)));
742#if _ENCODING_IS_STATE_DEPENDENT
743	if (wc == L'\0') {
744		/* reset state */
745		err = _FUNCNAME(put_state_reset)(_CEI_TO_EI(_TO_CEI(cl)), s,
746						 sz, psenc, &rsz);
747		if (err) {
748			*nresult = -1;
749			goto quit;
750		}
751		s += rsz;
752		sz -= rsz;
753	}
754#endif
755	err = _FUNCNAME(wcrtomb_priv)(_CEI_TO_EI(_TO_CEI(cl)), s, sz,
756				      wc, psenc, nresult);
757#if _ENCODING_IS_STATE_DEPENDENT
758	if (err == 0)
759		*nresult += rsz;
760quit:
761#endif
762	if (err == E2BIG)
763		err = EINVAL;
764	_RESTART_END(wcrtomb, _TO_CEI(cl), pspriv, psenc);
765
766	return err;
767}
768
769static int
770/*ARGSUSED*/
771_FUNCNAME(ctype_wcsrtombs)(void * __restrict cl, char * __restrict s,
772			   const wchar_t ** __restrict pwcs, size_t n,
773			   void * __restrict pspriv,
774			   size_t * __restrict nresult)
775{
776	_ENCODING_STATE *psenc;
777	_ENCODING_INFO *ei;
778	int err = 0;
779
780	_DIAGASSERT(cl != NULL);
781
782	ei = _CEI_TO_EI(_TO_CEI(cl));
783	_RESTART_BEGIN(wcsrtombs, _TO_CEI(cl), pspriv, psenc);
784	err = _FUNCNAME(wcsrtombs_priv)(ei, s, pwcs, n, psenc, nresult);
785	_RESTART_END(wcsrtombs, _TO_CEI(cl), pspriv, psenc);
786
787	return err;
788}
789
790static int __used
791/*ARGSUSED*/
792_FUNCNAME(ctype_wcsnrtombs)(_citrus_ctype_rec_t * __restrict cc,
793			   char * __restrict s,
794			   const wchar_t ** __restrict pwcs, size_t in,
795			   size_t n, void * __restrict pspriv,
796			   size_t * __restrict nresult)
797{
798	void *cl = cc->cc_closure;
799	_ENCODING_STATE *psenc;
800	_ENCODING_INFO *ei;
801	int err = 0;
802
803	_DIAGASSERT(cl != NULL);
804
805	ei = _CEI_TO_EI(_TO_CEI(cl));
806	_RESTART_BEGIN(wcsnrtombs, _TO_CEI(cl), pspriv, psenc);
807	err = _FUNCNAME(wcsnrtombs_priv)(ei, s, pwcs, in, n, psenc, nresult);
808	_RESTART_END(wcsnrtombs, _TO_CEI(cl), pspriv, psenc);
809
810	return err;
811}
812
813static int
814/*ARGSUSED*/
815_FUNCNAME(ctype_wcstombs)(void * __restrict cl, char * __restrict s,
816			  const wchar_t * __restrict pwcs, size_t n,
817			  size_t * __restrict nresult)
818{
819	_ENCODING_STATE state;
820	_ENCODING_INFO *ei;
821	int err;
822
823	_DIAGASSERT(cl != NULL);
824
825	ei = _CEI_TO_EI(_TO_CEI(cl));
826	_FUNCNAME(init_state)(ei, &state);
827	err = _FUNCNAME(wcsrtombs_priv)(ei, s, (const wchar_t **)&pwcs, n,
828					&state, nresult);
829
830	return err;
831}
832
833static int
834_FUNCNAME(ctype_wctomb)(void * __restrict cl, char * __restrict s, wchar_t wc,
835			int * __restrict nresult)
836{
837	_ENCODING_STATE *psenc;
838	_ENCODING_INFO *ei;
839	size_t nr, sz;
840#if _ENCODING_IS_STATE_DEPENDENT
841	size_t rsz = 0;
842#endif
843	int err = 0;
844
845	_DIAGASSERT(cl != NULL);
846
847	ei = _CEI_TO_EI(_TO_CEI(cl));
848	psenc = &_CEI_TO_STATE(_TO_CEI(cl), wctomb);
849	if (_STATE_NEEDS_EXPLICIT_INIT(psenc))
850		_FUNCNAME(init_state)(ei, psenc);
851	if (s == NULL) {
852		_FUNCNAME(init_state)(ei, psenc);
853		*nresult = _ENCODING_IS_STATE_DEPENDENT;
854		return 0;
855	}
856	sz = _ENCODING_MB_CUR_MAX(_CEI_TO_EI(_TO_CEI(cl)));
857#if _ENCODING_IS_STATE_DEPENDENT
858	if (wc == L'\0') {
859		/* reset state */
860		err = _FUNCNAME(put_state_reset)(_CEI_TO_EI(_TO_CEI(cl)), s,
861						 sz, psenc, &rsz);
862		if (err) {
863			*nresult = -1; /* XXX */
864			return 0;
865		}
866		s += rsz;
867		sz -= rsz;
868	}
869#endif
870	err = _FUNCNAME(wcrtomb_priv)(ei, s, sz, wc, psenc, &nr);
871#if _ENCODING_IS_STATE_DEPENDENT
872	if (err == 0)
873		*nresult = (int)(nr + rsz);
874	else
875#endif
876	*nresult = (int)nr;
877
878	return 0;
879}
880
881static int
882/*ARGSUSED*/
883_FUNCNAME(ctype_btowc)(_citrus_ctype_rec_t * __restrict cc,
884		       int c, wint_t * __restrict wcresult)
885{
886	_ENCODING_STATE state;
887	_ENCODING_INFO *ei;
888	char mb;
889	char const *s;
890	wchar_t wc;
891	size_t nr;
892	int err;
893
894	_DIAGASSERT(cc != NULL && cc->cc_closure != NULL);
895
896	if (c == EOF) {
897		*wcresult = WEOF;
898		return 0;
899	}
900	ei = _CEI_TO_EI(_TO_CEI(cc->cc_closure));
901	_FUNCNAME(init_state)(ei, &state);
902	mb = (char)(unsigned)c;
903	s = &mb;
904	err = _FUNCNAME(mbrtowc_priv)(ei, &wc, &s, 1, &state, &nr);
905	if (!err && (nr == 0 || nr == 1))
906		*wcresult = (wint_t)wc;
907	else
908		*wcresult = WEOF;
909
910	return 0;
911}
912
913static int
914/*ARGSUSED*/
915_FUNCNAME(ctype_wctob)(_citrus_ctype_rec_t * __restrict cc,
916		       wint_t wc, int * __restrict cresult)
917{
918	_ENCODING_STATE state;
919	_ENCODING_INFO *ei;
920	char buf[MB_LEN_MAX];
921	size_t nr;
922	int err;
923
924	_DIAGASSERT(cc != NULL && cc->cc_closure != NULL);
925
926	if (wc == WEOF) {
927		*cresult = EOF;
928		return 0;
929	}
930	ei = _CEI_TO_EI(_TO_CEI(cc->cc_closure));
931	_FUNCNAME(init_state)(ei, &state);
932	err = _FUNCNAME(wcrtomb_priv)(ei, buf, _ENCODING_MB_CUR_MAX(ei),
933				      (wchar_t)wc, &state, &nr);
934	if (!err && nr == 1)
935		*cresult = buf[0];
936	else
937		*cresult = EOF;
938
939	return 0;
940}
941