Home | History | Annotate | Download | only in common
      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