Home | History | Annotate | Line # | Download | only in citrus
      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
    126 static void _FUNCNAME(init_state)(_ENCODING_INFO * __restrict,
    127 				  _ENCODING_STATE * __restrict);
    128 static void _FUNCNAME(pack_state)(_ENCODING_INFO * __restrict,
    129 				  void * __restrict,
    130 				  const _ENCODING_STATE * __restrict);
    131 static void _FUNCNAME(unpack_state)(_ENCODING_INFO * __restrict,
    132 				    _ENCODING_STATE * __restrict,
    133 				    const void * __restrict);
    134 #if _ENCODING_IS_STATE_DEPENDENT
    135 static 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 
    155 static 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 
    174 static 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 
    194 static __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 
    229 static 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 	}
    279 bye:
    280 	if (pwcs)
    281 		*s = s0;
    282 
    283 	*nresult = (size_t)cnt;
    284 
    285 	return err;
    286 }
    287 
    288 static 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 	}
    340 bye:
    341 	if (pwcs)
    342 		*s = s0;
    343 
    344 	*nresult = cnt;
    345 
    346 	return err;
    347 }
    348 
    349 static 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 
    410 static 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_)			\
    476 do {									\
    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 
    498 int
    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 
    514 static 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 
    535 static 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 
    544 static 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 
    551 static 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 
    568 static 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 
    593 static 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 
    618 static 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 
    637 static 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 
    657 static 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 
    678 static 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 
    701 static 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 
    718 static 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;
    760 quit:
    761 #endif
    762 	if (err == E2BIG)
    763 		err = EINVAL;
    764 	_RESTART_END(wcrtomb, _TO_CEI(cl), pspriv, psenc);
    765 
    766 	return err;
    767 }
    768 
    769 static 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 
    790 static 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 
    813 static 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 
    833 static 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 
    881 static 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 
    913 static 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