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