xref: /titanic_52/usr/src/lib/libbc/libc/gen/common/iso.multibyte.c (revision 263f549e5da8b32c4922f586afb365b8ae388a6c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 1988 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <sys/types.h>
30 #include "codeset.h"
31 #include "mbextern.h"
32 #include "iso2022.h"
33 
34 #define TO_MULTI	2
35 #define TO_SINGLE	1
36 
37 #define BIT7ENV		7	/* 7bit enviornment */
38 #define BIT8ENV		8	/* 8bit environment */
39 #define NUM_OF_STATES	4	/* G0, G1, G2, G3 */
40 #define BIT8(_ch)	(_ch & 0x80)
41 #define MAXSIZE		100	/* ESC LOCK upper lower */
42 
43 #define USE_STATE	0	/* use the actual _state info */
44 #define USE_CONTROL	1	/* use C0 or C1 */
45 #define USE_SS2		2	/* use Single shift 2 */
46 #define USE_SS3		3	/* use Single shift 3 */
47 
48 #define G0MASK	0x0000
49 #define G1MASK	0x0080
50 #define G2MASK	0x8000
51 #define G3MASK	0x8080
52 #define FINAL	0x33		/* Temporary final character */
53 
54 #define MMB_CUR_MAX 128
55 
56 /*
57  * Keep state informations
58  */
59 struct state {
60 	char width;	/* 1 or 2 */
61 	char final;	/* final character */
62 };
63 
64 static char _my_env = BIT7ENV;	/* default 7bits environment */
65 static struct state Invoked_G0, Invoked_G1;
66 static char _currentG0 = G0;
67 static char _currentG1 = G1;
68 static struct state _des_states[NUM_OF_STATES] = {
69 	{-1, 0}, {-1, 0}, {-1, 0}, {01, 0}
70 };
71 
72 void _savestates(void);	/* save states */
73 void _restorestates(void);	/* restore states */
74 void _initializestates(void);/* Initialize states */
75 
76 
77 /*
78  * Variables for wc*tomb*()
79  */
80 static char _currentOUT = G0; /* G0, G1, G2 or G3 */
81 static int	prevcsize = 1;
82 
83 /*
84  * mbtowc - subroutine for most iso codeset sequences
85  */
86 int
87 _mbtowc_iso(wchar_t *pwc, char *s, size_t n)
88 {
89 	unsigned char ch;
90 	unsigned char tch;	/* temporary use */
91 	unsigned char *us = (unsigned char *)s;
92 	int gen_wide_state = USE_STATE; /* used in gen_wide: */
93 	int length = 0;
94 	int len = 0;
95 	wchar_t wide;
96 	int mask;
97 	int i;
98 
99 	isowidth_t * isoinfo = (isowidth_t *) _code_set_info.code_info;
100 
101 	/*
102 	 * initialize _g0_stuff
103 	 */
104 	if (_des_states[G0].width == -1) {
105 		_des_states[G0].width = isoinfo->g0_len;
106 		_des_states[G1].width = isoinfo->g1_len;
107 		_des_states[G2].width = isoinfo->g2_len;
108 		_des_states[G3].width = isoinfo->g3_len;
109 		_my_env = isoinfo->bit_env;
110 
111 		Invoked_G0 = _des_states[G0];
112 		Invoked_G1 = _des_states[G1];
113 	}
114 
115 	/*
116 	 * get character and proceed
117 	 */
118 loop:
119 	ch = *us++;
120 	if (++length > n) return (-1);		/* too long */
121 	switch (ch) {	/* get a character */
122 	/* escape sequence or locking shifts */
123 	case ESC:	/* escape sequence */
124 		gen_wide_state = USE_STATE; /* used in gen_wide: */
125 		ch = *us++;
126 		if (++length > n) return (-1);	/* too long */
127 		switch (ch) {
128 		/* DESIGNATE */
129 		case 0x24:		/* designate */
130 			ch = *us++;
131 			if (++length > n) return (-1);	/* too long */
132 			switch (ch) {
133 			case 0x28:	case 0x29:
134 			case 0x2A:	case 0x2B:
135 			case 0x2D:	case 0x2E:
136 			case 0x2F:
137 				tch = ch;	/* save this to decide _des_state */
138 				/* Skip intermidiates */
139 				do {
140 					ch = *us++;
141 					if (++length > n) return (-1);	/* too long */
142 				} while (ch >= 0x20 && ch <= 0x2F);
143 				if (ch < 0x30)		/* ch should be a final character */
144 					return (-1);	/* error */
145 				if (tch == 0x28)
146 					i = G0;
147 				else if (tch == 0x29 || tch == 0x2D)
148 					i = G1;
149 				else if (tch == 0x2A || tch == 0x2E)
150 					i = G2;
151 				else /* (tch == 0x2B || tch == 0x2F) */
152 					i = G3;
153 				/* updates state info */
154 				_des_states[i].width = TO_MULTI;
155 				_des_states[i].final = ch;
156 
157 				goto loop;
158 				break;
159 			default:
160 				/* This is an illegal sequence */
161 				return (-1);
162 				break;
163 			}
164 			break;
165 		case 0x28:		/* designate */
166 		case 0x29: case 0x2A: case 0x2B:
167 		case 0x2D: case 0x2E: case 0x2F:
168 			tch = ch;	/* save this to decide _des_state */
169 			/* Skip intermidiates */
170 			do {
171 				ch = *us++;
172 				if (++length > n) return (-1);	/* too long */
173 			} while (ch >= 0x20 && ch <= 0x2F);
174 			if (ch < 0x30)		/* ch should be a final character */
175 				return (-1);	/* error */
176 			if (tch == 0x28)
177 				i = G0;
178 			else if (tch == 0x29 || tch == 0x2D)
179 				i = G1;
180 			else if (tch == 0x2A || tch == 0x2E)
181 				i = G2;
182 			else /* (tch == 0x2B || tch == 0x2F) */
183 				i = G3;
184 			/* updates state info */
185 			_des_states[i].width = TO_SINGLE;
186 			_des_states[i].final = ch;
187 
188 			goto loop;
189 			break;
190 
191 		/* LOCKING SHIFTS */
192 		case LS1R:		/* locking shift LS1R */;
193 			Invoked_G1 = _des_states[G1];
194 			_currentG1 = G1;
195 			goto loop;
196 			break;
197 		case LS2:		/* locking shift LS2 */
198 			Invoked_G0 = _des_states[G2];
199 			_currentG0 = G2;
200 			goto loop;
201 			break;
202 		case LS2R:		/* locking shift LS2R */
203 			Invoked_G1 = _des_states[G2];
204 			_currentG1 = G2;
205 			goto loop;
206 			break;
207 		case LS3:		/* locking shift LS3 */
208 			Invoked_G0 = _des_states[G3];
209 			_currentG0 = G3;
210 			goto loop;
211 			break;
212 		case LS3R:		/* locking shift LS3R */
213 			Invoked_G1 = _des_states[G3];
214 			_currentG1 = G3;
215 			goto loop;
216 			break;
217 
218 		/* CONTROL FUNCTIONS */
219 		case 0x21:		/* C0 sets */
220 		case 0x22:		/* C1 sets */
221 			do {
222 				ch = *us++;
223 				if (++length > n) return (-1);	/* too long */
224 			} while (ch >= 0x20 && ch <= 0x2F);
225 			if (ch < 0x30)		/* ch should be a final character */
226 				return (-1);	/* error */
227 			goto loop;
228 			break;
229 
230 		/* SINGLE SHIFT for 7bit environment */
231 		case SS2_7B:		/* Single shift SS2 for 7bits */
232 		case SS3_7B:		/* Single shoft SS3 for 7bits */
233 			if (ch == SS2_7B)
234 				gen_wide_state = USE_SS2;
235 			else
236 				gen_wide_state = USE_SS3;
237 			goto loop;
238 			break;
239 
240 		default:		/* should be an error */
241 			return (-1);
242 			break;
243 		}
244 	/* locking shifts */
245 	case LS0:
246 		gen_wide_state = USE_STATE; /* used in gen_wide: */
247 		Invoked_G0 = _des_states[G0];
248 		_currentG0 = G0;
249 		goto loop;
250 		break;
251 
252 	case LS1:
253 		gen_wide_state = USE_STATE; /* used in gen_wide: */
254 		Invoked_G0 = _des_states[G1];
255 		_currentG0 = G1;
256 		goto loop;
257 		break;
258 
259 	/* Single shift SS3 and SS2 for 8bits */
260 	case SS2_8B:
261 	case SS3_8B:
262 		if (ch == SS2_8B)
263 			gen_wide_state = USE_SS2;
264 		else
265 			gen_wide_state = USE_SS3;
266 		goto loop;
267 		break;
268 
269 	/* This character is not any special character/
270 	 * It does not change any state.
271 	 * Goto where it generates wide character.
272 	 */
273 	default:
274 		/*
275 		 * Use this ch to generate pwc.
276 		 */
277 		if (ch == 0) {	/* end of string or 0 */
278 			wide = 0;
279 			mask = 0;
280 			goto gen_wide;
281 		}
282 		break;
283 	}
284 
285 
286 	/*
287 	 * Generate pwc here.
288 	 * The information here is
289 	 * 	current state and length. If the length is two, you need to
290 	 *      read one more character.
291 	 */
292 	switch (gen_wide_state) {
293 	case USE_STATE:
294 		if (BIT8(ch)) {	/* 8bit environment ? */
295 			/* current mode is G1 mode */
296 			if (Invoked_G1.width == 2) {
297 				tch = *us++;
298 				if (++length > n) return (-1);
299 				wide = ch;
300 				wide = (wide << 8 | tch);
301 			}
302 			else {
303 				wide = ch;
304 			}
305 			if (_currentG1 == G0)	mask = G0MASK;
306 			else if (_currentG1 == G1) mask = G1MASK;
307 			else if (_currentG1 == G2) mask = G2MASK;
308 			else mask = G3MASK;
309 		}
310 		else {
311 			/* current mode is G0 mode */
312 			if (Invoked_G0.width == 2) {
313 				tch = *us++;
314 				if (++length > n) return (-1);
315 				wide = ch;
316 				wide = (wide << 8 | tch);
317 			}
318 			else {
319 				wide = ch;
320 			}
321 			if (_currentG0 == G0)	mask = G0MASK;
322 			else if (_currentG0 == G1) mask = G1MASK;
323 			else if (_currentG0 == G2) mask = G2MASK;
324 			else mask = G3MASK;
325 		}
326 		break;
327 	case USE_SS2:
328 		if (_des_states[G2].width == 2) {
329 			tch = *us++;
330 			if (++length > n) return (-1);
331 			wide = ch;
332 			wide = (wide << 8 | tch);
333 		}
334 		else {
335 			wide = ch;
336 		}
337 		mask = G2MASK;
338 		break;
339 	case USE_SS3:
340 		if (_des_states[G3].width == 2) {
341 			tch = *us++;
342 			if (++length > n) return (-1);
343 			wide = ch;
344 			wide = (wide << 8 | tch);
345 		}
346 		else {
347 			wide = ch;
348 		}
349 		mask = G3MASK;
350 		break;
351 	default:
352 		/* shoult be internal error */
353 		return (-1);
354 		break;
355 	}
356 gen_wide:
357 	wide &= 0x7F7F;			/* strip off the top bit */
358 	wide = wide | mask;
359 	if (pwc != NULL)
360 		*pwc = wide;
361 	return (length);
362 }
363 
364 
365 #define MAXMBSIZE	128
366 /*
367  *  mbstowcs()
368  */
369 size_t
370 _mbstowcs_iso(wchar_t *pwcs, unsigned char *s, size_t n)
371 {
372 	int ret1;
373 	int accsum = 0;
374 	wchar_t pwc;
375 
376 	/*
377 	 * If pwcs == 0, do nothing.
378 	 */
379 	if (pwcs == 0)
380 		return (0);
381 	/*
382 	 * States things
383 	 */
384 	 _savestates(); _initializestates();
385 	 while (accsum < n) {
386 		ret1 = _mbtowc_iso (&pwc, (char *)s, MAXMBSIZE);
387 		if (ret1 < 0)
388 			return (-1);	/* error */
389 		if (ret1 == 0 || pwc == 0) {
390 			if (pwcs == 0)
391 				*pwcs = 0;
392 			/*
393 			 * Restore states
394 			 */
395 			_restorestates();
396 			return (accsum);
397 		}
398 		s = s + ret1;		/* increment the pointer */
399 		*pwcs++ = pwc;
400 		++accsum;
401 	}
402 	/*
403 	 * Restore states
404 	 */
405 	_restorestates();
406 	return (accsum);
407 }
408 
409 /*
410  * wctomb -
411  */
412 int
413 _wctomb_iso(unsigned char *s, wchar_t pwc)
414 {
415 	unsigned char ch;
416 	unsigned char tch;	/* temporary use */
417 	unsigned char *us = (unsigned char *)s;
418 	int gen_wide_state = USE_STATE; /* used in gen_wide: */
419 	int length = 0;
420 	int len = 0;
421 	wchar_t wide;
422 	unsigned short mode;
423 	unsigned char buf[MAXSIZE];
424 	unsigned char *bp;
425 	int csize, i;
426 	int n = MMB_CUR_MAX;
427 
428 	isowidth_t * isoinfo = (isowidth_t *) _code_set_info.code_info;
429 
430 	/*
431 	 * If pwc is 0, do this first.
432 	 */
433 	if (pwc  == 0) {
434 		if (s != 0) {
435 			*s = 0;
436 			return (1);
437 		}
438 		else {
439 			return (0);
440 		}
441 	}
442 
443 	mode = pwc & G3MASK;	/* The mode of this character */
444 	if (((pwc >> 8) & 0x007f) == 0)
445 		csize = 1;
446 	else
447 		csize = 2;
448 	bp = buf;
449 	length = 0;
450 #ifdef DDDebug
451 	if (_my_env == BIT7ENV)
452 		printf ("7b ");
453 	else
454 		printf ("8b ");
455 	printf ("csize = %d, prevcsize = %d, (%x,%x) ",csize, prevcsize, (pwc>>8)&0x00ff, pwc&0x00ff);
456 	switch (mode) {
457 	case G0MASK:
458 		printf ("G0"); break;
459 	case G1MASK:
460 		printf ("G1"); break;
461 	case G2MASK:
462 		printf ("G2"); break;
463 	case G3MASK:
464 		printf ("G3"); break;
465 	default:
466 		printf ("XXXX"); break;
467 	}
468 #endif
469 
470 	switch (_my_env) {
471 	case BIT7ENV:	/* 7 bit environment */
472 		switch (mode) {
473 		case G0MASK:
474 			if (_currentOUT != G0 || prevcsize != csize) {
475 				 _currentOUT = G0;
476 				if (csize == 2) {
477 					/*
478 					 * Emit escape sequences
479 					 */
480 					 *bp++ = ESC;
481 					 *bp++ = 0x24;
482 					 *bp++ = 0x28;
483 					 *bp++ = FINAL;
484 					 length += 4;
485 				}
486 				else {
487 					/*
488 					 * Emit escape sequences
489 					 */
490 					 *bp++ = ESC;
491 					 *bp++ = 0x28;
492 					 *bp++ = FINAL;
493 					 length += 3;
494 				}
495 				*bp++ = SI;
496 				++length;
497 			}
498 			if (csize == 1) {
499 				*bp++ = pwc & 0x007f;
500 				++length;
501 			}
502 			else {
503 				*bp++ = (pwc & 0x7f00) >> 8;
504 				++length;
505 				*bp++ = pwc & 0x007f;
506 				++length;
507 			}
508 			break;
509 		case G1MASK:
510 			if (_currentOUT != G1 || prevcsize != csize) {
511 				 _currentOUT = G1;
512 				if (csize == 2) {
513 					/*
514 					 * Emit escape sequences
515 					 */
516 					 *bp++ = ESC;
517 					 *bp++ = 0x24;
518 					 *bp++ = 0x29;
519 					 *bp++ = FINAL;
520 					 length += 4;
521 				}
522 				else {
523 					/*
524 					 * Emit escape sequences
525 					 */
526 					 *bp++ = ESC;
527 					 *bp++ = 0x29;
528 					 *bp++ = FINAL;
529 					 length += 3;
530 				}
531 				*bp++ = SO;
532 				++length;
533 			}
534 			if (csize == 1) {
535 				*bp++ = pwc & 0x007f;
536 				++length;
537 			}
538 			else {
539 				*bp++ = (pwc & 0x7f00) >> 8;
540 				++length;
541 				*bp++ = pwc & 0x007f;
542 				++length;
543 			}
544 			break;
545 		case G2MASK:
546 			if (_currentOUT != G2 || prevcsize != csize) {
547 				 _currentOUT = G2;
548 				if (csize == 2) {
549 					/*
550 					 * Emit escape sequences
551 					 */
552 					 *bp++ = ESC;
553 					 *bp++ = 0x24;
554 					 *bp++ = 0x2A;
555 					 *bp++ = FINAL;
556 					 length += 4;
557 				}
558 				else {
559 					/*
560 					 * Emit escape sequences
561 					 */
562 					 *bp++ = ESC;
563 					 *bp++ = 0x2A;
564 					 *bp++ = FINAL;
565 					 length += 3;
566 				}
567 				*bp++ = ESC; *bp++ = LS2;
568 				length += 2;
569 			}
570 			if (csize == 1) {
571 				*bp++ = pwc & 0x007f;
572 				++length;
573 			}
574 			else {
575 				*bp++ = (pwc & 0x7f00) >> 8;
576 				++length;
577 				*bp++ = pwc & 0x007f;
578 				++length;
579 			}
580 			break;
581 		case G3MASK:
582 			if (_currentOUT != G3 || prevcsize != csize) {
583 				 _currentOUT = G3;
584 				if (csize == 2) {
585 					/*
586 					 * Emit escape sequences
587 					 */
588 					 *bp++ = ESC;
589 					 *bp++ = 0x24;
590 					 *bp++ = 0x2B;
591 					 *bp++ = FINAL;
592 					 length += 4;
593 				}
594 				else {
595 					/*
596 					 * Emit escape sequences
597 					 */
598 					 *bp++ = ESC;
599 					 *bp++ = 0x2B;
600 					 *bp++ = FINAL;
601 					 length += 3;
602 				}
603 				*bp++ = ESC; *bp++ = LS3;
604 				length += 2;
605 			}
606 			if (csize == 1) {
607 				*bp++ = pwc & 0x007f;
608 				++length;
609 			}
610 			else {
611 				*bp++ = (pwc & 0x7f00) >> 8;
612 				++length;
613 				*bp++ = pwc & 0x007f;
614 				++length;
615 			}
616 			break;
617 		}
618 		break;
619 	case BIT8ENV:	/* 8 bit environment */
620 		switch (mode) {
621 		case G0MASK:
622 			if (_currentOUT != G0 || prevcsize != csize) {
623 				_currentOUT = G0;
624 				if (csize == 2) {
625 					/*
626 					 * Emit escape sequences
627 					 */
628 					 *bp++ = ESC;
629 					 *bp++ = 0x24;
630 					 *bp++ = 0x28;
631 					 *bp++ = FINAL;
632 					 length += 4;
633 				}
634 				else {
635 					/*
636 					 * Emit escape sequences
637 					 */
638 					 *bp++ = ESC;
639 					 *bp++ = 0x28;
640 					 *bp++ = FINAL;
641 					 length += 3;
642 				}
643 				*bp++ = LS0;
644 				++length;
645 			}
646 			if (csize == 1) {
647 				*bp++ = pwc & 0x007f;
648 				++length;
649 			}
650 			else {
651 				*bp++ = (pwc & 0x7f00) >> 8;
652 				++length;
653 				*bp++ = pwc & 0x007f;
654 				++length;
655 			}
656 			break;
657 		case G1MASK:
658 			if (_currentOUT != G1 || prevcsize != csize) {
659 				_currentOUT = G1;
660 				if (csize == 2) {
661 					/*
662 					 * Emit escape sequences
663 					 */
664 					 *bp++ = ESC;
665 					 *bp++ = 0x24;
666 					 *bp++ = 0x29;
667 					 *bp++ = FINAL;
668 					 length += 4;
669 				}
670 				else {
671 					/*
672 					 * Emit escape sequences
673 					 */
674 					 *bp++ = ESC;
675 					 *bp++ = 0x29;
676 					 *bp++ = FINAL;
677 					 length += 3;
678 				}
679 				*bp++ = ESC; *bp++ = LS1R;
680 				length += 2;
681 			}
682 
683 			/*
684 			 * If state is G1 or G2, or G3, assume that
685 			 * this is 8bit characters. To do this more
686 			 * accurately, wide character needs to be
687 			 * larger than 16 bits to keep more information.
688 			 */
689 			pwc |= 0x8080;
690 			if (csize == 1) {
691 				*bp++ = pwc & 0x00ff;
692 				++length;
693 			}
694 			else {
695 				*bp++ = (pwc & 0xff00) >> 8;
696 				++length;
697 				*bp++ = pwc & 0x00ff;
698 				++length;
699 			}
700 			break;
701 		case G2MASK:
702 			if (_currentOUT != G2 || prevcsize != csize) {
703 				_currentOUT = G2;
704 				if (csize == 2) {
705 					/*
706 					 * Emit escape sequences
707 					 */
708 					 *bp++ = ESC;
709 					 *bp++ = 0x24;
710 					 *bp++ = 0x2A;
711 					 *bp++ = FINAL;
712 					 length += 4;
713 				}
714 				else {
715 					/*
716 					 * Emit escape sequences
717 					 */
718 					 *bp++ = ESC;
719 					 *bp++ = 0x2A;
720 					 *bp++ = FINAL;
721 					 length += 3;
722 				}
723 				*bp++ = ESC; *bp++ = LS2R;
724 				length += 2;
725 			}
726 			/*
727 			 * If state is G1 or G2, or G3, assume that
728 			 * this is 8bit characters. To do this more
729 			 * accurately, wide character needs to be
730 			 * larger than 16 bits to keep more information.
731 			 */
732 			pwc |= 0x8080;
733 			if (csize == 1) {
734 				*bp++ = pwc & 0x00ff;
735 				++length;
736 			}
737 			else {
738 				*bp++ = (pwc & 0xff00) >> 8;
739 				++length;
740 				*bp++ = pwc & 0x00ff;
741 				++length;
742 			}
743 			break;
744 		case G3MASK:
745 			if (_currentOUT != G3 || prevcsize != csize) {
746 				_currentOUT = G3;
747 				if (csize == 2) {
748 					/*
749 					 * Emit escape sequences
750 					 */
751 					 *bp++ = ESC;
752 					 *bp++ = 0x24;
753 					 *bp++ = 0x2B;
754 					 *bp++ = FINAL;
755 					 length += 4;
756 				}
757 				else {
758 					/*
759 					 * Emit escape sequences
760 					 */
761 					 *bp++ = ESC;
762 					 *bp++ = 0x2B;
763 					 *bp++ = FINAL;
764 					 length += 3;
765 				}
766 				*bp++ = ESC; *bp++ = LS3R;
767 				length += 2;
768 			}
769 			/*
770 			 * If state is G1 or G2, or G3, assume that
771 			 * this is 8bit characters. To do this more
772 			 * accurately, wide character needs to be
773 			 * larger than 16 bits to keep more information.
774 			 */
775 			pwc |= 0x8080;
776 			if (csize == 1) {
777 				*bp++ = pwc & 0x00ff;
778 				++length;
779 			}
780 			else {
781 				*bp++ = (pwc & 0xff00) >> 8;
782 				++length;
783 				*bp++ = pwc & 0x00ff;
784 				++length;
785 			}
786 			break;
787 		}
788 		break;
789 	default:	/* Should never happens */
790 		return (-1);
791 		break;
792 	}
793 
794 	prevcsize = csize;
795 
796 	if (length > n) {
797 		return (-1);	/* buffer too small */
798 	}
799 	for (i = 0; i < length; i++) {
800 		*s++ = buf[i];
801 	}
802 #ifdef DDDebug
803 	printf ("\t(");
804 	for (i = 0; i < length; i++) {
805 		printf ("%x,", buf[i]);
806 	}
807 	printf (")\n");
808 #endif
809 	return (length);
810 }
811 
812 /*
813  * wcstombs
814  */
815 size_t
816 _wcstombs_iso(char *s, wchar_t *pwcs, int n)
817 {
818 	int acclen = 0;
819 	char buf[MMB_CUR_MAX];
820 	int ret1;
821 	int i;
822 
823 	if (n < 0)
824 		return (-1);
825 	/*
826 	 * Initialize State
827 	 */
828 	 _savestates(); _initializestates();
829 	 while (acclen < n) {
830 		ret1 = _wctomb_iso ((unsigned char *)buf, *pwcs);
831 		/*
832 		 * end of string ?
833 		 */
834 		if (ret1 == 1 && buf[0] == 0) {
835 			*s = 0;
836 			/*
837 			 * restore states
838 			 */
839 			_restorestates();
840 			return (acclen);
841 		}
842 		/*
843 		 * Error ?
844 		 */
845 		if (ret1 < 0)
846 			return (-1);
847 		acclen += ret1;
848 		for (i = 0; i < ret1; i++)
849 			*s++ = buf[i];
850 		++pwcs;
851 	 }
852 
853 	/*
854 	 * restore states
855 	 */
856 	_restorestates();
857 
858 	 /*
859 	  * return the length
860 	  */
861 	 return (acclen);
862 }
863 
864 
865 /*
866  * Supplementary routines
867  */
868 
869 void
870 _initializestates(void)
871 {
872 	_currentG0 = G0;
873 	_currentG1 = G1;
874 
875 	_des_states[G0].width = -1;	/* This makes it Initialize */
876 
877 	_currentOUT = G0;
878 	prevcsize = 1;
879 }
880 
881 static char SAVED_currentG0;
882 static char SAVED_currentG1;
883 static struct state SAVED_des_states[NUM_OF_STATES];
884 static struct state SAVED_Invoked_G0, SAVED_Invoked_G1;
885 static char SAVED_currentOUT = G0; /* G0, G1, G2 or G3 */
886 static int	SAVED_prevcsize = 1;
887 
888 void
889 _savestates(void)
890 {
891 
892 	SAVED_currentG0 = _currentG0;
893 	SAVED_currentG1 = _currentG1;
894 
895 	SAVED_des_states[G0] = _des_states[G0];
896 	SAVED_des_states[G1] = _des_states[G1];
897 	SAVED_des_states[G2] = _des_states[G2];
898 	SAVED_des_states[G3] = _des_states[G3];
899 
900 	SAVED_Invoked_G0 = Invoked_G0;
901 	SAVED_Invoked_G1 = Invoked_G1;
902 
903 	SAVED_currentOUT = _currentOUT;
904 	SAVED_prevcsize = prevcsize;
905 }
906 
907 void
908 _restorestates(void)
909 {
910 	_currentG0 = SAVED_currentG0;
911 	_currentG1 = SAVED_currentG1;
912 
913 	_des_states[G0] = SAVED_des_states[G0];
914 	_des_states[G1] = SAVED_des_states[G1];
915 	_des_states[G2] = SAVED_des_states[G2];
916 	_des_states[G3] = SAVED_des_states[G3];
917 
918 	Invoked_G0 = SAVED_Invoked_G0;
919 	Invoked_G1 = SAVED_Invoked_G1;
920 
921 	_currentOUT = SAVED_currentOUT;
922 	prevcsize = SAVED_prevcsize;
923 }
924