static char rcsid[] = "@(#)$Id: cs_iso2022.c,v 1.42 2006/04/09 07:37:08 hurtta Exp $";

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.42 $   $State: Exp $
 *
 *  Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
 *****************************************************************************/

#include "headers.h"
#include "s_me.h"
#include "cs_imp.h"
#include "cs_terminal.h"

DEBUG_VAR(Debug,__FILE__,"charset");

static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str) 
     char *str;
{
    return (unsigned char *)str;
}

static char *us2s P_((unsigned char *str));
static char *us2s(str) 
     unsigned char *str;
{
    return(char *)str;
}


/* ------------------------------------------------------------------------- */


static void map_init_bad P_((struct  map_info *map));
static void map_init_bad(map)
     struct  map_info *map;
{
    panic("STRING PANIC",__FILE__,__LINE__,"map_init_bad",
	  "map_init_bad called",0);
}

/* ISO 2022 maps */

static struct  map_info * open_iso2022_mapset P_((const char * map_name));
static struct  map_info * open_iso2022_mapset(map_name)
     CONST char * map_name;
{
    /* Indexes to iso2022_map_list[] */

    int setlist[ISO2022_SET_COUNT]; 
    int count = 0;
    static struct  map_info * ret = NULL;
    char * WALK = NULL;
    int i;

    char * X = safe_strdup(map_name), *X1;

    for (X1 = mime_parse_content_opts(X, &WALK); X1 && *X1; 
	 X1 = mime_parse_content_opts(NULL, &WALK)) {
	if (count >= ISO2022_SET_COUNT) {
	    lib_error(CATGETS(elm_msg_cat, MeSet, MeTooManyMaps,
			      "Too many maps on %s"),
		      map_name);
	    break;
	}
	setlist[count] = find_iso2022_map_spec(X1);
	if (-1 == setlist[count]) {
	    free(X);
	    return NULL;
	}
	count++;
    }
    free(X);

    ret = safe_malloc(sizeof (struct map_info));
    ret -> map_type = &cs_iso2022;
    ret -> map_name = safe_strdup(map_name);
    ret -> b.setlist = safe_malloc(sizeof (* (ret -> b.setlist)));
    ret -> map_initialized = 1;
    ret -> map_init_it = map_init_bad;

    for (i = 0; 
	 i < sizeof (ret->b.setlist->setlist) / 
	     sizeof (ret->b.setlist->setlist[0]); 
	 i++) {
	ret->b.setlist->setlist[i] = i < count ? setlist[i] : -1;
    }
    
    return ret;
}

/* EUC maps */

static struct  map_info * open_euc_mapset P_((const char * map_name));
static struct  map_info * open_euc_mapset(map_name)
     CONST char * map_name;
{
    /* Indexes to iso2022_map_list[] */

    int setlist[ISO2022_SET_COUNT]; 
    int count = 0;
    static struct  map_info * ret = NULL;
    char * WALK = NULL;
    int i;

    char * X = safe_strdup(map_name), *X1;

    for (X1 = mime_parse_content_opts(X, &WALK); X1 && *X1; 
	 X1 = mime_parse_content_opts(NULL, &WALK)) {
	if (count >= ISO2022_SET_COUNT) {
	    lib_error(CATGETS(elm_msg_cat, MeSet, MeTooManyMaps,
			      "Too many maps on %s"),
		      map_name);
	    break;
	}
	setlist[count] = find_iso2022_map_spec(X1);
	if (-1 == setlist[count])
	    return NULL;
	count++;
    }
    free(X);

    ret = safe_malloc(sizeof (struct map_info));
    ret -> map_type = &cs_euc;
    ret -> map_name = safe_strdup(map_name);
    ret -> b.setlist = safe_malloc(sizeof (* (ret -> b.setlist)));
    ret -> map_initialized = 1;
    ret -> map_init_it = map_init_bad;

    for (i = 0; 
	 i < sizeof (ret->b.setlist->setlist) / 
	     sizeof (ret->b.setlist->setlist[0]); 
	 i++) {
	ret->b.setlist->setlist[i] = i < count ? setlist[i] : -1;
    }
    
    return ret;
}

static void find_with_list P_((struct iso2022_setid **p,
			       struct  map_info *map));
static void find_with_list(p,map)
     struct iso2022_setid **p;
     struct  map_info *map;
{
    int count = 0;

    DPRINT(Debug,61,(&Debug,
		     "find_with_list iso2022 indexes for %s:",
		     map->map_name ? map->map_name : "???"));

    
    for (count = 0; p[count]; count++) {
	int i;
	if (count >= 
	    sizeof (map->b.setlist->setlist) / 
	    sizeof (map->b.setlist->setlist[0]))
	    panic("STRING PANIC",__FILE__,__LINE__,"find_with_list",
		      "Too many maps",0);
	
	for (i = 0; i < iso2022_map_list_count; i++) {
	    if (iso2022_map_list[i].setid == p[count]) 
		break;	    
	}
	if (i >= iso2022_map_list_count)
	    panic("STRING PANIC",__FILE__,__LINE__,"find_with_list",
		  "Set not found",0);
	if (!iso2022_map_list[i].map)
	    panic("STRING PANIC",__FILE__,__LINE__,"find_with_list",
		  "No map for set",0);
	map->b.setlist->setlist[count] = i;

	DPRINT(Debug,61,(&Debug," %d",map->b.setlist->setlist[count]));
    }

    DPRINT(Debug,61,(&Debug,"\n"));

    while (count < sizeof (map->b.setlist->setlist) / 
	   sizeof (map->b.setlist->setlist[0]))
	map->b.setlist->setlist[count++] = -1;
}

/* ASCII -------------------------------------------------------------- */

static void map_init_ASCII P_((struct  map_info *map));
static void map_init_ASCII(map)
     struct  map_info *map;
{
    struct iso2022_setid *XX[2] = { NULL, NULL };

    map -> b.setlist = safe_malloc(sizeof (* (map -> b.setlist)));

    XX[0] = ASCII_BANK;

    find_with_list(XX,map);

    map->map_initialized = 1;
    
    DPRINT(Debug,5,(&Debug,
		    "Map %s (%s) initialized\n",
		    map->map_name,map->map_type->type_name));
}

struct  map_info map_ISO2022_ascii = { 
    &cs_iso2022, "US-ASCII", 0, map_init_ASCII, 0 
};

struct  map_info map_EUC_ascii = { 
    &cs_euc, "US-ASCII", 0, map_init_ASCII, 0 
};


/* ASCII / ISO-8859-1 ---------------------------------------------------- */

static void map_init_ASCII_latin1 P_((struct  map_info *map));
static void map_init_ASCII_latin1(map)
     struct  map_info *map;
{
    struct iso2022_setid *XX[3] = { NULL, NULL,
				   NULL };

    map -> b.setlist = safe_malloc(sizeof (* (map -> b.setlist)));

    XX[0] = ASCII_BANK;
    XX[1] = LATIN1_BANK;

    find_with_list(XX,map);


    map->map_initialized = 1;
    
    DPRINT(Debug,5,(&Debug,
		    "Map %s (%s) initialized\n",
		    map->map_name,map->map_type->type_name));
}

struct  map_info map_ISO2022_ascii_latin1 = { 
    &cs_iso2022, "ISO-8859-1", 0, map_init_ASCII_latin1, 0 
};

struct  map_info map_EUC_ascii_latin1 = { 
    &cs_euc, "ISO-8859-1", 0, map_init_ASCII_latin1, 0 
};

/* ====================================================================== */

#define CS_ISO2022_magic	0xF301

struct charset_type cs_iso2022;

struct mb_data {
    unsigned short       magic;          /* CS_ISO2022_magic    */

    struct mb_data_part {
	int set_index;        /* Refers to iso2022_info (struct setlist) ... 
				 -1 if control characters   
                                     (also space with 94, 94x94 sets)
				 -2 if bad iso2022 bank
			      */
	int  iso2022_map_index;   /* index to iso2022_map_list[] */

        enum iso2022_settype type;        /* iso2022_other for controls */

	uint16          *words; /* range:   1 - 94             (bank 94) 
					    0 - 95             (bank 96)   
                                                      0 == 'space' 
					    1 - (96*96)-1      (bank 94x94)
					    0 - (96*96)-1      (bank 96x96)

					    0 - 32,128-160     (if control)
				*/
	int             word_count;
					 
    } * parts;    
    int part_count;

};

#define STATE_ISO2022_magic     0xF302

/* NOTE:    state_iso2022              is used for for input state
            struct display_settings    is used for for output state
*/

struct state_iso2022 {
    unsigned short       magic;            /* STATE_ISO2022_magic    */
    enum iso2022_bank     bank;            /* initially bank_unspecified (-1),
				              also bank_unspecified if control
                                              character (or perhaps space)
					   */

    struct {
	enum iso2022_settype  type;
	int  iso2022_info_index;           /* index to iso2022_info (setlist) 
                                                 of charset
					      -1 if not on list
					   */
	unsigned char         bytes[ISO2022_SETID_LEN];
    } banks[ISO2022_BANK_NUM];

    enum iso2022_bank    CL_bank;                 /* Bank for 32  - 127 */
    enum iso2022_bank    CR_bank;                 /* Bank for 160 - 255 */

    /* raw_byte is used during parsing */
    unsigned char    raw_bytes[ISO2022_SETID_LEN + 4];
    int              raw_bytes_count;

    uint16     word;          /* code position on gived bank / type */
};

#if ANSI_C
#define S_(x) static x;
#else
#define S_(x)
#endif

static struct mb_data * alloc_mb_data P_((void));
static struct mb_data * alloc_mb_data()
{
    struct mb_data *ret = safe_malloc(sizeof (* ret));

    /* defined in hdrs/defs.h */
    bzero((void *) ret, sizeof (*  ret));

    ret->magic       = CS_ISO2022_magic;
    ret->parts       = NULL;
    ret->part_count  = 0;   

    return ret;
}

S_(cs_init_string cs_init_iso2022_gen)
static void cs_init_iso2022_gen(str)
     struct string *str;
{
    str->p->len = 0;
    str->p->private_flag = 0;

    str->p->a.data         = alloc_mb_data();
}

static void free_parts P_((struct mb_data  * X1));
static void free_parts(X1)
     struct mb_data    * X1;
{
    if (X1->parts) {
	int i;
   
	for (i = 0; i < X1->part_count; i++) {		
	    if (X1->parts[i].words) {
		free (X1->parts[i].words);
		X1->parts[i].words = NULL;
	    }
	    X1->parts[i].word_count = 0;
	}

	free(X1->parts);
	X1->parts = NULL;
    }
    X1->part_count = 0;
    
}

static void free_mb_data P_((struct mb_data ** ptr));
static void free_mb_data(ptr)
     struct mb_data **ptr;
{
    if (*ptr) {	
	if (CS_ISO2022_magic != (*ptr)->magic)
	    panic("ISO2022 PANIC",__FILE__,__LINE__,"free_mb_data",
		  "Bad magic number",0);
	
	free_parts(*ptr);
		
	(*ptr)->magic = 0;   /* Invalidate magic */

	/* defined in hdrs/defs.h */
	bzero((void *) *ptr, sizeof (*  (*ptr)));
	free(*ptr);
	*ptr = NULL;
    }
}

S_(cs_free_string cs_free_iso2022_gen)
static void cs_free_iso2022_gen(str)
     struct string *str;
{
    free_mb_data ( & (str->p->a.data));

    str->p->len = 0;
}

static struct mb_data_part * get_part P_((struct mb_data       * X1,
					  int                  index,
					  enum iso2022_settype type));

static struct mb_data_part * get_part(X1,index,type)
     struct mb_data       * X1;
     int                  index;
     enum iso2022_settype type;
{
    struct mb_data_part  * X3 = NULL;

    if (X1->part_count < 1 ||
	X1->parts[X1->part_count-1].set_index != index ||
	X1->parts[X1->part_count-1].type      != type) {
	
	X1->parts = safe_realloc(X1->parts, 
				 ( X1->part_count+1) *
				 sizeof (X1->parts[0]));
	X1->parts[X1->part_count].set_index  = index;
	X1->parts[X1->part_count].iso2022_map_index = -1;  /* Filled later */
	X1->parts[X1->part_count].type       = type;
	X1->parts[X1->part_count].words      = NULL;
	X1->parts[X1->part_count].word_count = 0;

#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "get_part: %d: type=%d set_index=%d (new part)\n",
			 X1->part_count,type,index));
#endif	

	X1->part_count++;
    }

    X3 = & (X1->parts[X1->part_count-1] );

    return X3;
}

static void fill_iso2022_map_index P_((struct setlist       *iso2022_info,
				       struct mb_data       *X1,
				       struct  map_info *map));
static void fill_iso2022_map_index(iso2022_info,X1,map)
     struct setlist * iso2022_info;
     struct mb_data * X1;
     struct  map_info *map;
{
    int i;

    if (map -> map_type != &cs_iso2022 &&
	map -> map_type != &cs_euc) {
	panic("ISO2022 PANIC",__FILE__,__LINE__,"fill_iso2022_map_index",
	      "Bad map type",0);
    }

    if (!map->map_initialized)
	map->map_init_it(map);

    for (i = 0; i < X1->part_count; i++) {
	if (X1->parts[i].set_index >= 0 &&
	    -1 == X1->parts[i].iso2022_map_index) {

	    if (X1->parts[i].set_index <  
		sizeof (iso2022_info->sets) / 
		sizeof (iso2022_info->sets[0]) &&
		iso2022_info->sets[X1->parts[i].set_index]) {

		X1->parts[i].iso2022_map_index =
		    give_iso2022_index(map->b.setlist->setlist,
				       sizeof (map->b.setlist->setlist) / 
				       sizeof (map->b.setlist->setlist[0]),
				       iso2022_info->sets[X1->parts[i].
							  set_index]);
	    } else
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "fill_iso2022_map_index",
		      "Bad data set_index",0);			       

	}
    }
}

static int find_index P_((struct setlist *list,enum iso2022_settype type,
			  unsigned char bytes[ISO2022_SETID_LEN]));
static int find_index(list,type,bytes)
     struct setlist *list;
     enum iso2022_settype type;
     unsigned char bytes[ISO2022_SETID_LEN];
{
    int i;

    for (i = 0; i < sizeof(list->sets) / sizeof(list->sets[0]); i++) {
	if (! list->sets[i])
	    break;
	if (type == list->sets[i]->type &&
	    0 == memcmp(bytes,list->sets[i]->bytes,sizeof (list->sets[i]->bytes)))
	    return i;
    }

    return -2;  /* unknown */
}

static int convert_index P_((int d_index, struct setlist *d_list,
			     struct setlist *list,enum iso2022_settype type));
static int convert_index(d_index,d_list,list,type)
     int d_index; 
     struct setlist *d_list;
     struct setlist *list;
     enum iso2022_settype type;
{
    int index = -2;

    if (d_index >= 0 && 
	d_index <  sizeof (d_list->sets) / sizeof (d_list->sets[0]) &&
	d_list->sets[d_index]) {
	unsigned char bytes[ISO2022_SETID_LEN];

	if (type != d_list->sets[d_index]->type)
	    panic("ISO2022 PANIC",__FILE__,__LINE__,"convert_index",
		  "Bank type mismatch",0);
	
	if (sizeof(bytes) !=  
	    sizeof(d_list->sets[d_index]->bytes))
	    panic("ISO2022 PANIC",__FILE__,__LINE__,"convert_index",
		  "size mismatch on ISO2022_SETID",0);
		    
	memcpy(bytes,d_list->sets[d_index]->bytes,
	       sizeof(bytes));

	index = find_index(list,type,bytes);
	
    } else
	panic("ISO2022 PANIC",__FILE__,__LINE__,"convert_index",
	      "Bad data set_index",0);			       
    
    return index;
}

/* FIXME: This call should be replaced with more effective */

/* iso2022_word can not be uint16 becaus ethat causes error message
   about promotion
*/
static void add_iso2022_word P_((struct mb_data_part  * X3,
				 unsigned iso2022_word));
static void add_iso2022_word(X3,iso2022_word)
     struct mb_data_part  * X3;
     unsigned iso2022_word;
{
    X3->words = safe_realloc(X3->words, (X3->word_count+1) * 
			     sizeof (X3->words[0]));    
    X3->words[X3->word_count++] = iso2022_word;    
}

#ifdef DEBUG
static void debug_iso2022_info_index P_((int level,int index, 
					 struct setlist *iso2022_info));
static void debug_iso2022_info_index(level,
				     index,iso2022_info)
     int level;
     int index; 
     struct setlist *iso2022_info;
{
    if (index >= 0 && 
	index <  sizeof (iso2022_info->sets) / 
	sizeof (iso2022_info->sets[0]) &&
	iso2022_info->sets[index]) {

	char *x = iso2022_codestr(iso2022_info->sets[index]->bytes,
				  sizeof (iso2022_info->sets[index]));

	DPRINT(Debug,level,(&Debug,
			    "bank=%d type=%d",
			    iso2022_info->sets[index]->bank,
			    iso2022_info->sets[index]->type));

	if (x) {
	    DPRINT(Debug,level,(&Debug," bytes=%s",x));
	    free(x);
	}				  
    }
}
#endif

static void iso2022_add_char P_((struct string *str, 
				 struct charset_state *state));
static void iso2022_add_char(str,state)
     struct string *str; 
     struct charset_state *state;
{
    int                  index  = -1;
    enum iso2022_settype type   = iso2022_other;

    struct state_iso2022 * X  = state->p->a.iso2022;
    struct mb_data       * X1 = str->p->a.data;
    struct mb_data_part  * X3 = NULL, *debug_ptr;

    if (STATE_ISO2022_magic != X->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"iso2022_add_char",
	      "Bad magic number (state)",0);

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"iso2022_add_char",
	      "Bad magic number (string)",0);
    
    if (bank_unspecified == X->bank) {
	index = -1;
	type   = iso2022_other;
    } else if (X->bank >= 0 && X->bank <  ISO2022_BANK_NUM) {
	if (-1 == X->banks[X->bank].iso2022_info_index) {
	    index = -2;   /* BAD */
	    type  = X->banks[X->bank].type;

	} else if (str->string_type->iso2022_info) {

	    if (str->string_type != state->charset) {
		/* If different character set then we must search about bank */

		if (state->charset->iso2022_info) {
		    int d_index = X->banks[X->bank].iso2022_info_index;
		
		    if (str->string_type->iso2022_info)
			index = convert_index (d_index,
					       state->charset->iso2022_info,
					       str->string_type->iso2022_info,
					       type);
		    else
			index = -2;  /* Bad bank */
		} else
		    index = -2;  /* Bad set */

	    } else {
		index = X->banks[X->bank].iso2022_info_index; /* Assume correct index */
		
		if (index >= 0 && 
		    index <  sizeof (str->string_type->iso2022_info->sets) / 
		    sizeof (str->string_type->iso2022_info->sets[0]) &&
		    str->string_type->iso2022_info->sets[index]) {
		    
		    type  = X->banks[X->bank].type;
		    
		    if (str->string_type->iso2022_info->sets[index]->type !=
			X->banks[X->bank].type)
			panic("ISO2022 PANIC",__FILE__,__LINE__,"iso2022_add_char",
			      "Bank type mismatch",0);			       
		    
		} else
		    panic("ISO2022 PANIC",__FILE__,__LINE__,"iso2022_add_char",
			  "Bad iso2022_info_index",0);			       
	    }
	} else {
	    index = -2;       /* Default: Bad bank */	    
	    type  = X->banks[X->bank].type;
	}

    } else   
	panic("ISO2022 PANIC",__FILE__,__LINE__,"iso2022_add_char",
	      "Bad bank number",0);
	
    
    debug_ptr = NULL;
    if (X1->part_count > 0)
	debug_ptr = & (X1->parts[X1->part_count-1]);

    X3 = get_part(X1,index,type);

#ifdef DEBUG
    if (Debug.active > 58 && X3 != debug_ptr) {
	DPRINT(Debug,59,(&Debug,
			 "iso2022_add_char: %d: type=%d set_index=%d <",
			 X1->part_count-1,
			 type, index));
	if (str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
    }
#endif	
    
    add_iso2022_word(X3, X->word);
    str->p->len++;
}

/* sets state to be ready and pops raw_byte, 1 if popped 
   does not parse escape sequences
*/
static int streambyte_make_code_1 P_((struct charset_state *st,
				      enum iso2022_bank single_shift_bank));
static int streambyte_make_code_1(st,single_shift_bank)
     struct charset_state *st;     
     enum iso2022_bank single_shift_bank;
{
    struct state_iso2022 * X  = st->p->a.iso2022;
    unsigned char ch1;
    int upper;
    enum iso2022_bank bank;

    if (X->raw_bytes_count < 1)
	return 0;

    /* raw_bytes is unsigned */
    if (X->raw_bytes[0] < 32) {
	goto add_control;
    }

    upper = X->raw_bytes[0] & 128;
    ch1   = X->raw_bytes[0] & 127;

    if (single_shift_bank >= 0)              /* Normally left, but EUC uses rigth bank */	    
	bank = single_shift_bank;
    else
	bank  = upper ? X->CR_bank : X->CL_bank;

    if (ch1 > 32 && ch1 < 127 &&
	bank >= 0 && bank < ISO2022_BANK_NUM &&
	iso2022_94 == X->banks[bank].type) {
	X->bank = bank;
	X->word = ISO2022_1byte_to_word(ch1);

	X->raw_bytes_count--;
	if (X->raw_bytes_count > 0)
	    memmove(X->raw_bytes, X->raw_bytes+1, X->raw_bytes_count);

	DPRINT(Debug,61,(&Debug,
			 "got [94] bank=%d ISO2022 word=%02x   ch=%c upper=%d\n",
			 X->bank,X->word,    ch1,upper));

	st->p->ready          = 1;
	return 1;
    }

    if (ch1 >= 32 && 
	bank >= 0 && bank < ISO2022_BANK_NUM &&
	iso2022_96 == X->banks[bank].type) {
	X->bank = bank;
	X->word = ISO2022_1byte_to_word(ch1);

	X->raw_bytes_count--;
	if (X->raw_bytes_count > 0)
	    memmove(X->raw_bytes, X->raw_bytes+1, X->raw_bytes_count);

	DPRINT(Debug,61,(&Debug,
			 "got [96] bank=%d ISO2022 word=%02x   ch=%c upper=%d\n",
			 X->bank,X->word,    ch1,upper));

	st->p->ready          = 1;
	return 1;
    }

    if (X->raw_bytes_count > 1) {
	unsigned char ch2;

	if (upper != X->raw_bytes[1] & 128) {
	    /* BAD */
	    goto add_control;
	}
	ch2   = X->raw_bytes[1] & 127;

	if (ch1 > 32 && ch1 < 127 &&
	    ch2 > 32 && ch2 < 127 &&
	    bank >= 0 && bank < ISO2022_BANK_NUM &&
	    iso2022_94x94 == X->banks[bank].type) {

	    X->bank = bank;
	    X->word = ISO2022_2byte_to_word(ch1,ch2);

	    X->raw_bytes_count -= 2;
	    if (X->raw_bytes_count > 0)
		memmove(X->raw_bytes, X->raw_bytes+2, X->raw_bytes_count);

	    DPRINT(Debug,61,(&Debug,
			     "got [94x94] bank=%d ISO2022 word=%04x   ch=%c%c upper=%d\n",
			     X->bank,X->word,    ch1,ch2,upper));


	    st->p->ready          = 1;
	    return 1;
	}

	if (ch1 >= 32 && 
	    ch2 >= 32 && 
	    bank >= 0 && bank < ISO2022_BANK_NUM &&
	    iso2022_96x96 == X->banks[bank].type) {

	    X->bank = bank;
	    X->word = ISO2022_2byte_to_word(ch1,ch2);

	    X->raw_bytes_count -= 2;
	    if (X->raw_bytes_count > 0)
		memmove(X->raw_bytes, X->raw_bytes+2, X->raw_bytes_count);

	    DPRINT(Debug,61,(&Debug,
			     "got [96x96] bank=%d ISO2022 word=%04x   ch=%c%c upper=%d\n",
			     X->bank,X->word,    ch1,ch2,upper));


	    st->p->ready          = 1;
	    return 1;
	}
    }

    if (bank >= 0 && bank < ISO2022_BANK_NUM &&
	(iso2022_96x96 == X->banks[bank].type ||
	 iso2022_94x94 == X->banks[bank].type) &&
	X->raw_bytes_count < 2) {
	
	return 0;
    }

    /* This is not really supported because we do not know
       number of bytes per characters
    */

    if (bank >= 0 && bank < ISO2022_BANK_NUM &&
	iso2022_other == X->banks[bank].type) {
	/* Like controls */

	X->bank = bank;
	X->word = X->raw_bytes[0];

	X->raw_bytes_count--;
	if (X->raw_bytes_count > 0)
	    memmove(X->raw_bytes, X->raw_bytes+1, X->raw_bytes_count);

	DPRINT(Debug,61,(&Debug,
			 "got [other] bank=%d ISO2022 word=%02x\n",
			 X->bank,X->word));


	st->p->ready          = 1;
	return 1;
    }

 add_control:
    X->bank = bank_unspecified;
    X->word = X->raw_bytes[0];
    
    X->raw_bytes_count--;
    if (X->raw_bytes_count > 0)
	memmove(X->raw_bytes, X->raw_bytes+1, X->raw_bytes_count);
    
    DPRINT(Debug,61,(&Debug,
		     "got [ctrl] bank=%d ISO2022 word=%02x\n",
		     X->bank,X->word));

    st->p->ready          = 1;
    return 1;   
}

/* 0 == overflow or bad char, 1 == OK */
static int state_add_raw P_((struct state_iso2022 * X , int ch));
static int state_add_raw(X,ch)
     struct state_iso2022 * X; 
     int ch;
{
    if (ch < 0 || ch > 0xFF)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "state_add_raw",
	      "Value not in range 0-255",0);

    if (X->raw_bytes_count >= sizeof (X->raw_bytes)) {
	DPRINT(Debug,4,(&Debug,
			"state_add_raw: Overlow (already %d bytes)\n",
			X->raw_bytes_count));
	return 0;    /* Overflow */
    }
    X->raw_bytes[X->raw_bytes_count++] = ch;   /* store it */

    return 1;
}

/* -1  == not enough
    0  == not ok
    1  == processed
*/

static int streambyte_make_code_2 P_((struct charset_state *st,
				      struct state_iso2022 * X));

static int streambyte_make_code_2(st,X)
     struct charset_state *st;     
     struct state_iso2022 * X;
{        
    int T;

    if (X->raw_bytes_count < 1) {
	DPRINT(Debug,1,(&Debug,
			 "streambyte_make_code_2: len=%d\n",
			 X->raw_bytes_count));

	return -1;
    }

    T = X->raw_bytes[0] & 127;
    if (T < 32) {   /* Is on control area ...  ( 0 - 31 or 128 - 159) */
	enum iso2022_bank     Bank;
	enum shift_mode       LR;
	struct iso2022_setid  Setid;

	int l;
    
	/* Try then if this is bank switch */
	l = eat_iso2022_bank_switch(&Bank,&LR,
				    X->raw_bytes,
				    X->raw_bytes_count);
	if (l > 0) {
	    
	    char buffer[sizeof (X->raw_bytes)];
	    int  buffer_len;
	    /* For backup of single-shift */
	    
	    memcpy(buffer,X->raw_bytes,X->raw_bytes_count);
	    buffer_len = X->raw_bytes_count;
	    
	    X->raw_bytes_count -= l;
	    if (X->raw_bytes_count > 0)
		memmove(X->raw_bytes, X->raw_bytes+l, X->raw_bytes_count);
	
	    switch (LR) {
	    case lock_shift_left:
		X->CL_bank   = Bank;
		
		DPRINT(Debug,61,(&Debug,
				 "got bank shift  lower bank=%d\n",
				 X->CL_bank));
		
		break;
	    case lock_shift_right:
		X->CR_bank   = Bank;
		
		DPRINT(Debug,61,(&Debug,
				 "got bank shift  upper bank=%d\n",
				 X->CR_bank));
		
		break;
	    case single_shift:
		
		DPRINT(Debug,61,(&Debug,
				 "looking for single shift .. bank=%d\n",
				 Bank));
		
		if (streambyte_make_code_1(st,Bank) > 0)
		    break;  /* OK */
		
		memcpy(X->raw_bytes,buffer,buffer_len);
		X->raw_bytes_count = buffer_len;
		
		DPRINT(Debug,8,(&Debug,
				"streambyte_make_code_2: single shift not complete (len=%d)\n",
			    buffer_len));
		return -1;
	    }
	    return 1;  /* try eat next code */
	}

	if (l < 0) {
	    DPRINT(Debug,8,(&Debug,
			    "streambyte_make_code_2: incomplete bank switch (len=%d)\n",
			    X->raw_bytes_count));
	    return -1;
	}
	
	/* Try then if this is setid */
	
	l = eat_iso2022_setid(&Setid,X->raw_bytes,X->raw_bytes_count);
	if (l > 0) {
	    if (Setid.bank >= 0 && Setid.bank <  ISO2022_BANK_NUM) {
		
		X->banks[Setid.bank].type = Setid.type;
		memcpy(X->banks[Setid.bank].bytes,
		       Setid.bytes,sizeof X->banks[Setid.bank].bytes);
		
		DPRINT(Debug,61,(&Debug,
				 "got bank %d  type=%d  bytes=%.*s\n",
				 Setid.bank,
				 X->banks[Setid.bank].type,
				 sizeof X->banks[Setid.bank].bytes,
				 X->banks[Setid.bank].bytes));
		
		X->banks[Setid.bank].iso2022_info_index =
		    find_index(st->charset->iso2022_info,
			       X->banks[Setid.bank].type,
			       X->banks[Setid.bank].bytes);
		
		if ( X->banks[Setid.bank].iso2022_info_index < 0) {
		    X->banks[Setid.bank].iso2022_info_index = -1;
		    DPRINT(Debug,8,(&Debug,
				    "streambyte_make_code_2: setid is not part of charset\n"));
		}
		
		DPRINT(Debug,61,(&Debug,
				 "  ... iso2022_info_index %d\n",
				 X->banks[Setid.bank].iso2022_info_index));
		
		X->raw_bytes_count -= l;
		if (X->raw_bytes_count > 0)
		    memmove(X->raw_bytes, X->raw_bytes+l, X->raw_bytes_count);
		return 1; /* try eat next code */
	    }
	    
	    DPRINT(Debug,8,(&Debug,
			    "streambyte_make_code_2: bad bank %d on setid\n",
			    Setid.bank));			    	    
	}
	
	if (l < 0) {
	    DPRINT(Debug,8,(&Debug,
			    "streambyte_make_code_2: incomplete setting of bank (setid, len=%d)\n",
			    X->raw_bytes_count));
	    return -1;
	}
    }
    
    if (!streambyte_make_code_1(st,bank_unspecified)) {
	DPRINT(Debug,8,(&Debug,
			"streambyte_make_code_2: Incomplete character (len=%d)\n",
			X->raw_bytes_count));
	return -1;
	
    }       	
    return 1;
}

static void cs_soft_reset_s_iso2022_gen P_((struct charset_state *str));

S_(cs_add_streambyte_to_string cs_add_streambyte_to_iso2022_gen)
static int cs_add_streambyte_to_iso2022_gen(str,ch)
     struct string *str;
     int ch;
{
    int c;
    struct state_iso2022 * X ;

    if (!str->p->state)
	str->p->state = new_state_1(str->string_type);

    if (str->p->state->charset != str->string_type)
	panic("STRING PANIC",__FILE__,__LINE__,"cs_add_streambyte_to_iso2022_gen",
	      "Bad state",0);

    X = str->p->state->p->a.iso2022;
    
    if (STATE_ISO2022_magic != X->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_add_streambyte_to_iso2022_gen",
	      "Bad magic number (state)",0);

    if (X->raw_bytes_count > 0) {
	DPRINT(Debug,8,(&Debug,
			"cs_add_streambyte_to_iso2022: %d bytes already\n",
			X->raw_bytes_count));

	/* Try first read extra characters from buffer */
	if (streambyte_make_code_2(str->p->state,X) > 0) {
	    if (str->p->state->p->ready) {
		/* Got it */
		iso2022_add_char(str,str->p->state);
		cs_soft_reset_s_iso2022_gen(str->p->state);
	    }
	}
    }

    if (!state_add_raw(X,ch)) {
	DPRINT(Debug,8,(&Debug,
			"cs_add_streambyte_to_iso2022_gen: failed to add code\n"));
	return 0;
    }
    
    while ((c = streambyte_make_code_2(str->p->state,X)) > 0) {
	/* Handle case where several characters generated */
	if (str->p->state->p->ready) {
	    /* Got it */
	    iso2022_add_char(str,str->p->state);
	    cs_soft_reset_s_iso2022_gen(str->p->state);
	}	
    }
   
    if (0 == c) {
	DPRINT(Debug,8,(&Debug,
			"cs_add_streambyte_to_iso2022_gen: failed to parse code\n"));
	return 0;
    }

    return 1;
}

S_(cs_add_intdata_to_string cs_add_intdata_to_iso2022_gen)
static void cs_add_intdata_to_iso2022_gen(str,data)
     struct string *str;
     CONST struct string *data;
{
    int i;
    struct mb_data       * X1 = str->p->a.data;
    struct mb_data       * Xd = data->p->a.data;

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_add_intdata_to_iso2022_gen",
	      "Bad magic number (string)",0);

    if (CS_ISO2022_magic != Xd->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_add_intdata_to_iso2022_gen",
	      "Bad magic number (data string)",0);

    for (i = 0; i < Xd->part_count; i++) {
	
	int                  index  = -1;
	enum iso2022_settype type   = Xd->parts[i].type;
	struct mb_data_part  * X3 = NULL, *debug_ptr;
	int j;

#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "cs_add_intdata_to_iso2022_gen: %d: type=%d set_index=%d <",
			 i,type, Xd->parts[i].set_index));
	if (Debug.active > 58 && data->string_type->iso2022_info)
	    debug_iso2022_info_index(59,Xd->parts[i].set_index,
				     data->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,"> (source)\n"));
#endif	

	if (-1 == Xd->parts[i].set_index) {
	    index = -1;
	    if (iso2022_other != type) 
		panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_add_intdata_to_iso2022_gen",
		      "Bad type for control data",0);	    
	} else if (-2 == Xd->parts[i].set_index) {
	    index = -2;          /* bad iso2022 bank */
	} else {
	    index = -2;          /* bad iso2022 bank */
	    
	    if (data->string_type->iso2022_info) {
		int d_index =  Xd->parts[i].set_index;

		if (str->string_type->iso2022_info)
		    index = convert_index(d_index,data->string_type->iso2022_info,
					  str->string_type->iso2022_info,type);
		else
		    index = -2;  /* Bad bank */

	    } else
		index = -2;           /* bad iso2022 bank */
	}

	if (Xd->parts[i].word_count < 1)
	    continue;   /* OOPS -- nothing to do */


	debug_ptr = NULL;
	if (X1->part_count > 0)
	    debug_ptr = & (X1->parts[X1->part_count-1]);

	X3 = get_part(X1,index,type);

#ifdef DEBUG
    if (Debug.active > 58 && X3 != debug_ptr) {
	DPRINT(Debug,59,(&Debug,
			 "cs_add_intdata_to_iso2022_gen: %d: type=%d set_index=%d <",
			 X1->part_count-1,
			 type, index));
	if (str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,"> (target)\n"));
    }
#endif	


	X3->words = safe_realloc(X3->words,
				 (X3->word_count + Xd->parts[i].word_count) *
				 sizeof (X3->words[0]));

	for (j = 0; j < Xd->parts[i].word_count; j++)
	    X3->words[X3->word_count++] = Xd->parts[i].words[j];

	str->p->len += Xd->parts[i].word_count;
    }
}

/* Does compression, recalculation and so on ... 
   so 'const' is not very const
 */
S_(cs_check_length_string cs_check_length_iso2022_gen)
static void cs_check_length_iso2022_gen(str)
     CONST struct string *str;
{    
    int len = 0;

    int i;
    struct mb_data       * X1 = str->p->a.data;
 
    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_check_length_iso2022_gen",
	      "Bad magic number (string)",0);

    for (i = 0; i < X1->part_count; i++) {
	len += X1->parts[i].word_count;
    }

    if (len != str->p->len) {
	DPRINT(Debug,6,(&Debug, 
			"cs_check_length_iso2022_gen: Fixing length %d => %d\n",
			str->p->len,len));
	str->p->len = len;
    }
}

/* Returns 1 if position exists */
static int pos_to_block P_((struct mb_data * X1, int pos, 
			    int *block_number,
			    int *block_index));
static int pos_to_block(X1,pos,block_number,block_index)
     struct mb_data * X1;
     int pos; 
     int *block_number;
     int *block_index;
{
    
    *block_number          = 0;
    *block_index           = pos;

    while (*block_number < X1->part_count &&
	   X1->parts[*block_number].word_count <= *block_index) {
	*block_index -= X1->parts[*block_number].word_count;
	(*block_number)++;
    }

    if (*block_number >= X1->part_count ||
	*block_index >= X1->parts[*block_number].word_count)
	return 0;

    DPRINT(Debug,61,(&Debug, 
		     "  pos=%d => block/index=%d/%d\n",
		     pos,*block_number,*block_index));

    return 1;
}


S_(cs_give_unicode_from_string cs_give_unicode_from_iso2022_gen)
static uint16 cs_give_unicode_from_iso2022_gen(str,pos,found)
     CONST struct string *str;
     int pos;
     int *found;
{
    struct mb_data       * X1 = str->p->a.data;
    int block_number          = 0;
    int block_index           = pos;

    uint16  code;
    int set_index;        /* Refers to iso2022_info (struct setlist) ...
			     -1 if control characters
			     (also space with 94, 94x94 sets)
			     -2 if bad iso2022 bank
			  */
    enum iso2022_settype type;        /* iso2022_other for controls */

    uint16  ret;

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_give_unicode_from_iso2022_gen",
	      "Bad magic number (string)",0);
    
    if (pos < 0 || pos >= str->p->len)
	panic("STRING PANIC",__FILE__,__LINE__,"cs_give_unicode_from_iso2022_gen",
	      "Index out of array",0);

    if (!pos_to_block(X1,pos,&block_number,&block_index))
	panic("STRING PANIC",__FILE__,__LINE__,"cs_give_unicode_from_iso2022_gen",
	      "Index position not found",0);

    /* Fill indexes if current not filled */
    if (-1 == X1->parts[block_number].iso2022_map_index &&
	str->string_type->map_info && str->string_type->iso2022_info)
	fill_iso2022_map_index(str->string_type->iso2022_info,
			       X1,
			       str->string_type->map_info);

    code      = X1->parts[block_number].words[block_index];
    set_index = X1->parts[block_number].set_index;
    type      = X1->parts[block_number].type;

    *found = 0;
    ret = 0x003F;  /* '?' */

    if (-1 == set_index) {    /* Controls maps to unicode directly */
	if (iso2022_other != type) 
	    panic("ISO2022 PANIC",__FILE__,__LINE__,
		  "cs_give_unicode_from_iso2022_gen",
		  "Type is not iso2022_other for controls",0);

	ret    = code;
	*found = 1;
	
    } else {
	int iso2022_map_index;    /* index to iso2022_map_list[] */  

	iso2022_map_index = X1->parts[block_number].iso2022_map_index;

	if (-1 != iso2022_map_index)
	    *found = map_ISO2022_word_to_unicode(code,type,iso2022_map_index,
						   &ret);
	else {
	    DPRINT(Debug,62,(&Debug,
			     "pos %d -- block/index=%d/%d (code %04x set_index %d type %d) -- no iso2022_map_index\n",
			     pos,block_number,block_index,code,set_index,type));

	}
    }

    return ret;
}

static int map_unicode_to_ISO2022_word P_((unsigned unicode,
					   struct setlist       * iso2022_info,
					   int                  * index,
					   enum iso2022_settype * type,
					   uint16               * iso2022_word,
					   struct  map_info *map));

static int map_unicode_to_ISO2022_word(unicode,iso2022_info,
				       iso2022_info_index,
				       type,iso2022_word,
				       map)
     unsigned               unicode;
     struct setlist       * iso2022_info; 
     int                  * iso2022_info_index;
     enum iso2022_settype * type;
     uint16               * iso2022_word;
     struct  map_info     * map;
{
    int found = 0;
    int i;
    
    *iso2022_info_index = -3;    /* MARKER !!!!!!! */

    for (i = 0; 
	 i < sizeof (iso2022_info->sets) / sizeof (iso2022_info->sets[0]);
	 i++) {
	if (iso2022_info->sets[i]) {

	    /* (space (32) and del (127) with 94, 94x94 sets is 
	       on control area ... */ 
	    if ((iso2022_94    == iso2022_info->sets[i]->type ||
		 iso2022_94x94 == iso2022_info->sets[i]->type) &&
		( 32 == unicode || 127 == unicode)) {

		*iso2022_info_index = -1;   /* Control area */
		*iso2022_word       = unicode;
		*type               = iso2022_other;  /* we do not use 
							 iso2022_94 hre, 
							 because we interpret 
							 word as character 
							 32-127 then 
						      */
		found               = 1;
		break;
	    }	    	 
	}
    }

    if (!found && map) {
	int s;

	if (map -> map_type != &cs_iso2022 &&
	    map -> map_type != &cs_euc) 
	    panic("ISO2022 PANIC",__FILE__,__LINE__,
		  "map_unicode_to_ISO2022_word",
		  "Bad map type",0);
    
	if (!map->map_initialized)
	    map->map_init_it(map);

	for (s = 0; s < sizeof (map->b.setlist->setlist) / 
		 sizeof (map->b.setlist->setlist[0]);
	     s++) {
	    int iso2022_map_index = map->b.setlist->setlist[s];

	    if (-1 != iso2022_map_index &&
		map_unicode_to_ISO2022_word_1(unicode,type,iso2022_map_index,
					      iso2022_word)) {


		DPRINT(Debug,52,(&Debug,
				 "map_unicode_to_ISO2022_word: %04x => iso2022_map_index=%d (setlist %d), type=%d word=%04x\n",
				 unicode,iso2022_map_index,s,*type,*iso2022_word));

		/* Search iso2022_info_index */

		*iso2022_info_index = -2;   /* bad iso2022 bank */
		if (iso2022_info) {
		    unsigned char bytes[ISO2022_SETID_LEN];
		    
		    fill_iso2022_map_setlist_bytes(iso2022_map_index,*type,bytes, sizeof bytes);
		    
		    *iso2022_info_index = find_index(iso2022_info,*type,bytes);

		} 
		found = 1;
	   
		break;
	    }
	}
    }

    if (!found) {                       /* Not actually used ... */
	*iso2022_info_index = -2;             /* Bad bank */
	*iso2022_word       = unicode;
	*type               = iso2022_other;  /* we do not use 
						 iso2022_94 here, 
						 because we interpret 
						 word as character 
						 32-127 then 
					      */
    }
    
    DPRINT(Debug,52,(&Debug,
		     "map_unicode_to_ISO2022_word=%d: %04x %s == iso2022_info_index %d, type=%d word=%04x\n",			 
		     found,
		     unicode,
		     found ? "FOUND" : "NOT FOUND",
		     *iso2022_info_index,
		     *type,
		     *iso2022_word));
    
    return found;
}


S_(cs_add_unicodedata_to_string cs_add_unicodedata_to_iso2022_gen)
static void cs_add_unicodedata_to_iso2022_gen(str,len,data)
     struct string *str;
     int len; 
     CONST uint16 *data;
{
    int i;

    struct mb_data       * X1 = str->p->a.data;

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_add_unicodedata_to_iso2022_gen",
	      "Bad magic number (string)",0);

    /* TODO: This should be optimized */
    for (i = 0; i < len; i++) {
	/* Values < 32 are on control block and
	   also correspond 8-bit values
	 */
	
	if (data[i] < 32 ||
	    data[i] > 127 && data[i] < 160 ) {
	    struct mb_data_part * X3 = get_part(X1,-1,iso2022_other);

	    add_iso2022_word(X3, data[i]);
	    str->p->len++;

	} else  {
	    int                  index;
	    enum iso2022_settype type;
	    uint16               iso2022_word;

	    struct mb_data_part * X3, *debug_ptr;

	    /* map_unicode_to_ISO2022_word() also puts 32 and 127
	       to control area if needed
	    */

	    if (! str->string_type->iso2022_info ||
		! map_unicode_to_ISO2022_word(data[i],
					      str->string_type->iso2022_info,
					      &index,&type,&iso2022_word,
					      str->string_type->map_info
					      )) {
		/* Put as bad data ... 
		   add_char1_stream() will print
		   that as question mark
		*/
		
		index        = -2;             /* Bad bank */
		type         = iso2022_other;  /* Also controls */
		iso2022_word = data[i];
	    }

	    debug_ptr = NULL;
	    if (X1->part_count > 0)
		debug_ptr = & (X1->parts[X1->part_count-1]);

	    X3 = get_part(X1,index,type);

#ifdef DEBUG
    if (Debug.active > 58 && X3 != debug_ptr) {
	DPRINT(Debug,59,(&Debug,
			 "cs_add_unicodedata_to_iso2022_gen: %d: type=%d set_index=%d <",
			 X1->part_count-1,
			 type, index));
	if (str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
    }
#endif	

	    add_iso2022_word(X3,iso2022_word);
	    str->p->len++;
	}
    }
}

S_(cs_cmp_string cs_cmp_iso2022_gen)
static int cs_cmp_iso2022_gen(str1,str2)
     CONST struct string *str1;
     CONST struct string *str2;
{
    struct mb_data       * X1 = str1->p->a.data;
    struct mb_data       * X2 = str1->p->a.data;
    int i;

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_cmp_iso2022_gen",
	      "Bad magic number (string 1)",0);

    if (CS_ISO2022_magic != X2->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_cmp_iso2022_gen",
	      "Bad magic number (string 2)",0);
  
    for (i = 0; i < X1->part_count && i < X2->part_count; i++) {
	int j;

	for (j = 0; j < X1->parts[i].word_count && 
		 j < X1->parts[i].word_count; j++) {
	    if (X1->parts[i].words[j] < X2->parts[i].words[j])
		return -1;
	    if (X1->parts[i].words[j] > X2->parts[i].words[j])
		return 1;
	}

	/* not necessary correct */

	if (j < X1->parts[i].word_count)
	    return 1;
	if (j < X2->parts[i].word_count)
	    return -1;
    }

    if (i < X1->part_count)
	return 1;
    if (i < X2->part_count)
	return -1;
    return 0;
}

static void add_bytes_stream P_((unsigned char         **ret,
				 int                    *len,
				 int                    *alloced,
				 unsigned char          *c,
				 int                    l));
static void add_bytes_stream(ret,len,alloced,c,l)
     unsigned char         **ret;
     int                    *len;
     int                    *alloced;
     unsigned char          *c;
     int                    l;
{
    if (*alloced < *len + l) {
	*alloced = *len + l + 15;

	*ret = safe_realloc(*ret,*alloced);
    }

    memcpy((*ret)+(*len),c,l);
    *len += l;
}

static int select_upper_lower P_((unsigned char         **ret,
				  int                    *len,
				  int                    *alloced,
				  struct iso2022_setid   *ID,
				  screen_info_p          output_state,
				  int                    *width));

static int select_upper_lower(ret,len,alloced,ID,output_state,width)
     unsigned char         **ret;
     int                    *len;
     int                    *alloced;
     struct iso2022_setid   *ID;
     screen_info_p          output_state;
     int                    *width;
{
    int is_upper = 0;

    int setpos = iso2022_give_setpos(ID,output_state);
    int printit = 0;

    if (-1 == setpos) {
	char * c;
	
	if (output_state->set_count <
	    sizeof (output_state->sets) /
	    sizeof (output_state->sets[0])) {
	    setpos = output_state->set_count++;
	} else if (iso2022_94 == ID->type) {
	    setpos = 0;
	    DPRINT(Debug,7,(&Debug,
			    "select_upper_lower: Too many sets on output state, replacing set %d\n",
			    setpos));
	    printit++;
	} else {
	    setpos = 1;
	    DPRINT(Debug,7,(&Debug,
			    "select_upper_lower: Too many sets on output state, replacing set %d\n",
			    setpos));
	    printit++;
	}

	output_state->sets[setpos]  = *ID;
	output_state->width[setpos] = -1;           /* No terminal information so no width */

	DPRINT(Debug,58,(&Debug,
			 "select_upper_lower: set %d selected\n",
			 setpos));

	/* iso2022_change_helper_1 does both
	   iso2022_setid_stream() and lock_shift(), but does nothing
	   if bank is already occupied. 
	   This function sets 	    
	   output_state->bank[ID->bank] = setpos;

	*/
	c = iso2022_change_helper_1(output_state,*ID,setpos,NULL,0);
	if (c) {
	    int l = strlen(c);
	    
	    add_bytes_stream(ret,len,alloced,s2us(c),l);	

#ifdef DEBUG
	    {
		int x;
		DPRINT(Debug,58,(&Debug,
				 "select_upper_lower: Setting %d to bank %d: ",
				 setpos,ID->bank));
		for (x = 0; x < l; x++) {
		    DPRINT(Debug,58,(&Debug," %02x",c[x]));
		}
		DPRINT(Debug,58,(&Debug,"\n"));
	    }
	    if (Debug.active > 57)
		printit++;
#endif
	    free(c);
	}
    }
	
    /* If on bank have currently other set selected, change it */
    if (ID->bank  != bank_unspecified
	&& output_state->bank[ID->bank] != setpos) {
	char * c;
	
	output_state->bank[ID->bank] = -1;   /* Forget previous assignment */
	
	c = iso2022_setid_stream(*ID,NULL,0);
	if (c) {
	    int l = strlen(c);
	
	    /* iso2022_setid_stream() does not set this */
	    output_state->bank[ID->bank] = setpos;

	    add_bytes_stream(ret,len,alloced,s2us(c),l);		

#ifdef DEBUG
	    {
		int x;
		DPRINT(Debug,58,(&Debug,
				 "select_upper_lower: Changing %d to bank %d: ",
				 setpos,ID->bank));
		for (x = 0; x < l; x++) {
		    DPRINT(Debug,58,(&Debug," %02x",c[x]));
		}
		DPRINT(Debug,58,(&Debug,"  (width %d)\n",
				 output_state->width[setpos] 
				 ));
		if (Debug.active > 57)
		    printit++;
	    }
#endif
	    free(c);
	}
    }
    
    if (output_state->current_L == ID->bank)
	is_upper = 0;
    else if (output_state->current_R == ID->bank)
	is_upper = 1;
    else {             /* If either left nor right is selected for this
			  bank currently, select left bank because
			  iso2022 sets are usually 7-bit only
		       */
	char buffer1[10];
	char * c;
	
	is_upper    = 0;
	output_state->current_L = ID->bank;
	
	c = lock_shift(is_upper,output_state->current_L,
		       buffer1,sizeof buffer1);
	if (c) {
	    int l = strlen(c);
	
	    add_bytes_stream(ret,len,alloced,s2us(c),l);		

#ifdef DEBUG
	    {
		int x;
		DPRINT(Debug,58,(&Debug,
				 "select_upper_lower: setting %s to bank %d: ",
				 is_upper ? "upper" : "lower",
				 setpos));
		for (x = 0; x < l; x++) {
		    DPRINT(Debug,58,(&Debug," %02x",c[x]));
		}
		DPRINT(Debug,58,(&Debug,"\n"));
		if (Debug.active > 57)
		    printit++;
	    }
#endif

	}
    }	

    if (printit) 
	debug_display_settings(output_state,0,1);

    *width  = output_state->width[setpos];
    return is_upper;
}


static void add_char_stream_helper P_((unsigned char         **ret,
				       int                    *len,
				       int                    *alloced,
				       unsigned char          *temp,
				       int                    temp_l,
				       int                    temp_size,
				       enum iso2022_settype   type,
				       unsigned               iso2022_word,
				       int                    is_upper
				       ));
			      
			      
static void add_char_stream_helper(ret,len,alloced,temp,temp_l,temp_size,type,
				   iso2022_word,is_upper)
     unsigned char         **ret;
     int                    *len;
     int                    *alloced;
     
     unsigned char          *temp;
     int                    temp_l;
     int                    temp_size;
     
     enum iso2022_settype   type;
     unsigned               iso2022_word;
     int                    is_upper;
{
    switch(type) {

    case iso2022_94:   
	if (iso2022_word < 1 || iso2022_word > 94)
	    panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream_helper",
		  "Bad iso2022_94 character",0);
	/* FALLTHRU */
    case iso2022_96:
	if (iso2022_word > 95)
	    panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream_helper",
		  "Bad iso2022_96 character",0);

	if (temp_l+1 > temp_size)
	    panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream_helper",
		  "Overflow",0);
	    
	temp[temp_l++] =  iso2022_word + 32 + (is_upper ?  128 : 0);

	DPRINT(Debug,63,(&Debug,
			 "add_char_stream_helper: Adding 1-byte: %02x (%s)  [iso2022_word %04x]\n", 
			 temp[temp_l-1],
			 is_upper ? "upper" : "lower",			 
			 iso2022_word      
			 ));
	
	add_bytes_stream(ret,len,alloced,temp,temp_l);
	break;
    case iso2022_94x94:
    case iso2022_96x96:
	if (iso2022_word > 96*96-1)
	    panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream_helper",
		  "Bad iso2022_94x94 or iso2022_96x96 character",0);

	if (temp_l+2 > temp_size)
	    panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream_helper",
		  "Overflow",0);
	
	temp[temp_l++] =  iso2022_word/96  + 32 + (is_upper ?  128 : 0);
	temp[temp_l++] =  iso2022_word%96  + 32 + (is_upper ?  128 : 0);

	DPRINT(Debug,63,(&Debug,
			 "add_char_stream_helper: Adding 2-byte: %02x %02x (%s) [iso2022_word %04x]\n", 
			 temp[temp_l-2],temp[temp_l-1],
			 is_upper ? "upper" : "lower",
			 iso2022_word));
	
	add_bytes_stream(ret,len,alloced,temp,temp_l);
	break;

    case iso2022_other:
	if (iso2022_word < 256) {

	    if (temp_l+1 > temp_size)
		panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream_helper",
		      "Overflow",0);

	    temp[temp_l++] =  iso2022_word;    /* Not actually work correctly */

	    DPRINT(Debug,63,(&Debug,
			     "add_char_stream_helper: Adding other: %02x  [iso2022_word %04x]\n", 
			     temp[temp_l-1],
			     iso2022_word));
	    
	    add_bytes_stream(ret,len,alloced,temp,temp_l);
	    break;
	}
	/* FALLTHRU */
    default:
	    panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream_helper",
		  "Unsupported iso2022 settype",0);
    }

}




/* iso2022_word can't be uint16 because that causes error
   messages about promotion ...
*/


typedef int add_char_stream_t P_((unsigned char         **ret,
				  int                    *len,
				  int                    *alloced,
				  struct iso2022_setid   *set,
				  screen_info_p          output_state,
				  unsigned               iso2022_word,
				  struct iso2022_setid  *ctrlset,
				  struct cs_printable_len *printable_len));


/* Return 0 if overflow printable_len else 1 */
S_(add_char_stream_t add_char_stream_euc)
static int add_char_stream_euc(ret,len,alloced,set, output_state,iso2022_word,
			       ctrlset,printable_len)
     unsigned char         **ret;
     int                    *len;
     int                    *alloced;
     struct iso2022_setid   *set;          /* NULL, if control characters */
     screen_info_p          output_state;
     unsigned               iso2022_word;
     struct iso2022_setid  *ctrlset;      /* 'set' used when outputing control
					     characters */
     struct cs_printable_len *printable_len;
{
    int width = -1;
    enum iso2022_bank bank = bank_unspecified;
    struct iso2022_setid ID;
    
    if (set) {	
	int i;

	ID = *set;	
	i = iso2022_give_setpos(&ID,output_state);

	bank = ID.bank;

	if (i < 0 || bank_unspecified == bank) {

	    /* BAD */  
	    DPRINT(Debug,9,(&Debug,
			    "add_char_stream_euc: Bad bank or set? (printing space instead)\n"));
	    iso2022_word = 32;
	    set = NULL;
	    goto restart;
	}

	width  = output_state->width[i];

    } else {
	/* iso2022_word is character itself */
 restart:
	
	if (32 == iso2022_word) {   /* SPACE */
	    width = 1;
	} else {                   /* Control characters have no width */
	    width = 0;
	}
    }

    if (printable_len && width < 0) {
	DPRINT(Debug,9,(&Debug,
			"add_char_stream_euc: Can't print character because width is not available (printing space instead) [width=%d]\n",
			width));
	iso2022_word = 32;
	set = NULL;
	goto restart;
    }

    if (printable_len && 
	printable_len->max_len < printable_len->ret_len + width) {
	DPRINT(Debug,9,(&Debug,
			"add_char_stream_euc: No space for character  ret_len=%d width=%d max_len=%d\n",
			printable_len->ret_len,width,printable_len->max_len));
	return 0;
    }

    if (set) {
	int l = 0;
	unsigned char temp[5];
	int is_upper = -1;
    
	if (bank == bank_unspecified) {
	    DPRINT(Debug,9,(&Debug,
			    "add_char_stream_euc: No bank (printing space instead)\n"));
	    iso2022_word = 32;
	    set = NULL;
	    goto restart;
	}

	if (bank == output_state->current_L)
	    is_upper = 0;
	else if (bank == output_state->current_R)
	    is_upper = 1;
	else {
	    is_upper = 1;

	    if ((l = do_single_shift(temp,sizeof temp,bank,is_upper)) < 1) {
		DPRINT(Debug,9,(&Debug,
				"add_char_stream_euc: Can't single shift to bank %d (printing space instead), ret=%d\n",
				bank,l));
		iso2022_word = 32;
		set = NULL;
		goto restart;
	    }
	}
	
	add_char_stream_helper(ret,len,alloced, temp,l,sizeof temp,ID.type,
			       iso2022_word,is_upper);
	
    } else {
      	unsigned char temp[1];

	/* We are printing control characters or space 
	   iso2022_word is character itself 
	   -- BAD characters are also stored as control
	   characters therefore all codes between 0 - 255
	   are possible.
	*/
	if (iso2022_word > 255)
	        panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream_euc",
		      "Bad control character",0);
	
	temp[0] = iso2022_word;
	
	DPRINT(Debug,63,(&Debug,
			 "add_char_stream_euc: Adding ctrl: %02x  [iso2022_word %04x]\n", 
			 temp[0],iso2022_word));

	add_bytes_stream(ret,len,alloced,temp,1);
    }

    if (printable_len)
	printable_len->ret_len += width;

    return 1;
}

/* Return 0 if overflow printable_len else 1 */
S_(add_char_stream_t add_char_stream)
static int add_char_stream(ret,len,alloced,set, output_state,iso2022_word,
			   ctrlset,printable_len)
     unsigned char         **ret;
     int                    *len;
     int                    *alloced;
     struct iso2022_setid   *set;          /* NULL, if control characters */
     screen_info_p          output_state;
     unsigned               iso2022_word;
     struct iso2022_setid  *ctrlset;      /* 'set' used when outputing control
					     characters */
     struct cs_printable_len *printable_len;
{
    int is_upper;

    struct iso2022_setid ID;
    int have_id;
    int width;


 restart:
    have_id   = 0;
    is_upper = 0;
    
    ID.bank = bank_unspecified;
    ID.type = iso2022_other;

    if (!set) {
	/* If set is NULL, then we have ouputting control characters
	   (or space). Most ISO-2022-x   mime sets require that we switch 
	   ascii before outputting control characters (or space) -- in that
	   case iso2022_word is control character itself. */

	/* ASCII must be first set declared so that works correctly */
	if (ctrlset) {
	    ID = *ctrlset;    /* ASCII? */
	    have_id++;
	}
       
    } else {
	ID = *set; 
	have_id++;
    }

    width     = 1;
    if (have_id) 
	is_upper = select_upper_lower(ret,len,alloced,&ID,output_state,&width);
    
    if (!set) {
	/* iso2022_word is character itself */
	
	if (32 == iso2022_word) {   /* SPACE */
	    if (width < 1) width = 1;
	} else {                   /* COntrol characters have no width */
	    width = 0;
	}
    }
    
    if (printable_len && width < 0) {
	DPRINT(Debug,9,(&Debug,
			"add_char_stream: Can't print character because width is not available (printing space instead) [width=%d]\n",
			width));
	iso2022_word = 32;
	set = NULL;
	goto restart;
    }

    if (printable_len && 
	printable_len->max_len < printable_len->ret_len + width) {
	DPRINT(Debug,9,(&Debug,
			"add_char_stream: No space for character  ret_len=%d width=%d max_len=%d\n",
			printable_len->ret_len,width,printable_len->max_len));
	return 0;
    }

    if (!set) {
	unsigned char temp[1];
	/* We are printing control characters or space 
	   iso2022_word is character itself 
	   -- BAD characters are also stored as control
	   characters therefore all codes between 0 - 255
	   are possible.
	*/
	if (iso2022_word > 255)
	        panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream",
		      "Bad control character",0);
	
	temp[0] = iso2022_word;
	
	DPRINT(Debug,63,(&Debug,
			 "add_char_stream: Adding ctrl: %02x  [iso2022_word %04x]\n", 
			 temp[0],iso2022_word));

	add_bytes_stream(ret,len,alloced,temp,1);

    } else if (!have_id)
	panic("STRING PANIC",__FILE__,__LINE__,"add_char_stream",
	      "have_id is not set",0);    
    else {
	unsigned char temp[2];
	
	add_char_stream_helper(ret,len,alloced, temp,0,sizeof temp,ID.type,
			       iso2022_word,is_upper);
    }


    if (printable_len)
	printable_len->ret_len += width;

    return 1;
}

/* Find ASCII bank (or other similar) */
static struct iso2022_setid  *find_ctrlset P_((struct setlist * iso2022_info));

static struct iso2022_setid  *find_ctrlset(iso2022_info)
     struct setlist       * iso2022_info;
{
    int i;
    struct iso2022_setid *ctrlset = NULL;

    for (i = 0; 
	 i < sizeof (iso2022_info->sets) / sizeof (iso2022_info->sets[0]);
	 i++) {
	if (iso2022_info->sets[i]) {
	    /* Find ASCII bank (or other similar) */
	    if (iso2022_94    == iso2022_info->sets[i]->type &&
		bank_G0       == iso2022_info->sets[i]->bank) {
		ctrlset = iso2022_info->sets[i];
		break;
	    }
	}
    }
 
    return ctrlset;
}

typedef void charset_reset_routine P_((unsigned char         **ret,
				       int                    *len,
				       int                    *alloced,
				       screen_info_p          output_state,
				       struct setlist       * iso2022_info));

S_(charset_reset_routine reset_iso2022)
static void reset_iso2022(ret,len,alloced,output_state,iso2022_info)
     unsigned char         **ret;
     int                    *len;
     int                    *alloced;
     screen_info_p          output_state;
     struct setlist       * iso2022_info;
{
    int i;

    output_state->current_L = bank_unspecified;
    output_state->current_R = bank_unspecified;
    
    for (i = 0; 
	 i < sizeof (output_state->bank) / 
	     sizeof (output_state->bank[0]);
	 i++)
	output_state->bank[i] = -1;


    SIGDPRINT(Debug,8,(&Debug,
		       "reset_iso2022: Doing initial ISO 2022 assignments\n"));
	    
    if (bank_unspecified != iso2022_info->initial_L) {
	char *c;
	output_state->current_L = iso2022_info->initial_L;

	c = lock_shift(0,output_state->current_L,NULL,0);
	
	if (c) {
	    int l = strlen(c);
	    
	    add_bytes_stream(ret,len,alloced,s2us(c),l);	
#ifdef DEBUG
	    {
		int x;
		DPRINT(Debug,58,(&Debug,
				 "reset_iso2022: setting left to bank %d: ",
				 output_state->current_L));
		for (x = 0; x < l; x++) {
		    DPRINT(Debug,58,(&Debug," %02x",c[x]));
		}
		DPRINT(Debug,58,(&Debug,"\n"));
	    }	    
#endif	    
	    free(c);
	}	       
    }

    if (bank_unspecified != iso2022_info->initial_R) {
	char *c;
	output_state->current_R = iso2022_info->initial_R;
		
	c = lock_shift(1,output_state->current_R,NULL,0);
	if (c) {
	    int l = strlen(c);
	    
	    add_bytes_stream(ret,len,alloced,s2us(c),l);	
#ifdef DEBUG
	    {
		int x;
		DPRINT(Debug,58,(&Debug,
				 "reset_iso2022: setting rigth to bank %d: ",
				 output_state->current_R));
		for (x = 0; x < l; x++) {
		    DPRINT(Debug,58,(&Debug," %02x",c[x]));
		}
		DPRINT(Debug,58,(&Debug,"\n"));
	    }	    
#endif	    
	    free(c);
	}	       
    }
	    
    for (i = 0; 
	 i < sizeof (iso2022_info->initial_bank) / 
	     sizeof (iso2022_info->initial_bank[0]);
	 i++) {
	int x = iso2022_info->initial_bank[i];
		
	if (-1 != x) {
	    struct iso2022_setid ID;
	    char *c = NULL;

	    if (x < 0 ||
		x >= sizeof (iso2022_info->sets)  /
		sizeof (iso2022_info->sets[0]) ||
		! iso2022_info->sets[x]) 
		panic("STRING PANIC",__FILE__,__LINE__,
		      "reset_iso2022",
		      "Bad initial_bank (set)",
		      0);
	    
	    ID = * (iso2022_info->sets[x]);
		    
	    if (ID.bank != i)
		panic("STRING PANIC",__FILE__,__LINE__,
		      "reset_iso2022",
		      "Bad initial_bank (bank number)",
		      0);
	    
	    set_initial_bank(&c,ID,output_state,NULL,0,0);

	    if (c) {
		int l = strlen(c);
		
		add_bytes_stream(ret,len,alloced,s2us(c),l);	
#ifdef DEBUG
		{
		    int x;
		    DPRINT(Debug,58,(&Debug,
				     "reset_iso2022: setting initial bank %d: ",
				     i));
		    for (x = 0; x < l; x++) {
			DPRINT(Debug,58,(&Debug," %02x",c[x]));
		    }
		    DPRINT(Debug,58,(&Debug,"\n"));
		}	    
#endif	    
		free(c);
	    }	       
	}
    }
}

S_(charset_reset_routine reset_euc)
static void reset_euc(ret,len,alloced,output_state,iso2022_info)
     unsigned char         **ret;
     int                    *len;
     int                    *alloced;
     screen_info_p          output_state;
     struct setlist       * iso2022_info;
{
    /* NO reset on EUC ! */
    return;
}


/* Return -1 when must quit */
static int add_char1_stream_GEN P_((add_char_stream_t  *ADD_CHAR_STREAM, 
				    unsigned char         **ret,
				    int                    *len,
				    int                    *alloced,
				    screen_info_p          output_state,
				    struct setlist       * iso2022_info,
				    struct  map_info     * map_info,
				    struct iso2022_setid * ctrlset,
				    int                    printable,
				    struct mb_data_part  * part,
				    int                    j,
				    int                  * need_reset,
				    struct cs_printable_len *printable_len,
				    charset_reset_routine *RESET_ROUTINE
				    ));

static int add_char1_stream_GEN(ADD_CHAR_STREAM,
				ret,len,alloced,output_state,iso2022_info,map_info,
				ctrlset,printable,part,j,need_reset,printable_len,
				RESET_ROUTINE
				)
     add_char_stream_t    * ADD_CHAR_STREAM;
     unsigned char       ** ret;
     int                  * len;
     int                  * alloced;
     screen_info_p          output_state;
     struct setlist       * iso2022_info;
     struct  map_info     * map_info;
     struct iso2022_setid * ctrlset;
     int                    printable;
     struct mb_data_part  * part;
     int                    j;
     int                  * need_reset;
     struct cs_printable_len * printable_len;
     charset_reset_routine *RESET_ROUTINE;
{
    int char_added = 0;

    if (*need_reset) {

	RESET_ROUTINE(ret,len,alloced,output_state,iso2022_info);

	*need_reset = 0;
    }
	
    switch (part->set_index) {
    case -1:   /* control characters  , (also space with 94, 94x94 sets) 			  
		*/

	if (printable && 32 != part->words[j])
	    goto bad_char;
	
	if (ADD_CHAR_STREAM(ret,len,alloced,NULL,output_state,
			    part->words[j],ctrlset,printable_len) < 1) {
	    return -1;
	}
	char_added++;

	if (part->words[j] < 32) {
	    /* 
	       Reapply lock shifts and bank assigments after controls
	       so that these appear on every line (at least)
	    */
	    *need_reset = 1;
	}

	break;
    case -2:  /* bad iso2022 bank */
    bad_char:
    
    if (iso2022_info && map_info) {
	int                  index;
	enum iso2022_settype type;
	uint16               iso2022_word;

	if (map_unicode_to_ISO2022_word(0x003F /* '?' */,
					iso2022_info,
					&index,&type,&iso2022_word,
					map_info)
	    && index >= 0) {
	    
	    if (index > sizeof (iso2022_info->sets) / 
		sizeof (iso2022_info->sets[0]) ||
		! iso2022_info->sets[index])
		panic("ISO2022 PANIC",__FILE__,__LINE__,"add_char1_stream_GEN",
		      "Bad index",0);
	    
	    if (ADD_CHAR_STREAM(ret,len,alloced,
				iso2022_info->sets[index],
				output_state,
				iso2022_word,
				ctrlset,printable_len) < 1) {
		return -1;
	    }	   
	    char_added++;

	    break;
	} 
    }
    if (ctrlset) { /* We can add space instead */
	if (ADD_CHAR_STREAM(ret,len,alloced,NULL,output_state,32,ctrlset,printable_len) < 1) {
	    return -1;
	}
	char_added++;
    }
    break;
    
    default:
	if (printable) {
	    /* Require printable character */
	    
	    int iso2022_map_index = part->iso2022_map_index;

	    if (-1 != iso2022_map_index) {
		uint16  code;		
		int found = map_ISO2022_word_to_unicode(part->words[j],
					    part->type,
					    iso2022_map_index,
					    &code);
		if (!found)
		    goto bad_char;      /* No mapping available */
		if (!unicode_ch(code,UOP_printable))
		    goto bad_char;      /* Not printable */
	    } else
		goto bad_char;  /* No mapping available */
	}

	if (ADD_CHAR_STREAM(ret,len,alloced,
			    iso2022_info->sets[part->set_index],
			    output_state,
			    part->words[j],ctrlset,printable_len) < 1) {
	    return -1;
	}
	char_added++;
	break;
    }

    return char_added;
}

/* Return -1 when must quit */

static int add_char1_stream P_((unsigned char         **ret,
				int                    *len,
				int                    *alloced,
				screen_info_p          output_state,
				struct setlist       * iso2022_info,
				struct  map_info     * map_info,
				struct iso2022_setid * ctrlset,
				int                    printable,
				struct mb_data_part  * part,
				int                    j,
				int                  * need_reset,
				struct cs_printable_len *printable_len));
static int add_char1_stream(ret,len,alloced,output_state,iso2022_info,map_info,
			    ctrlset,printable,part,j,need_reset,printable_len)
     unsigned char         **ret;
     int                    *len;
     int                    *alloced;
     screen_info_p          output_state;
     struct setlist       * iso2022_info;
     struct  map_info     * map_info;
     struct iso2022_setid * ctrlset;
     int                    printable;
     struct mb_data_part  * part;
     int                    j;
     int                  * need_reset;
     struct cs_printable_len *printable_len;
{

    return add_char1_stream_GEN(add_char_stream, 				
				ret,len,alloced,output_state,iso2022_info,map_info,
				ctrlset,printable,part,j,need_reset,printable_len,
				reset_iso2022
				);
}

static void fill_euc_state P_((screen_info_p  output_state,
			       struct setlist  *iso2022_info));
static void fill_euc_state(output_state,iso2022_info)
     screen_info_p  output_state;
     struct setlist  *iso2022_info;
{
    int i;

    
    if (bank_unspecified != iso2022_info->initial_L) 
	output_state->current_L    = iso2022_info->initial_L;
    else
	output_state->current_L    = bank_G0;

    if (bank_unspecified != iso2022_info->initial_R)
	output_state->current_R    = iso2022_info->initial_R;
    else
	output_state->current_R    = bank_G1;
    output_state->set_count    = 0;

    for (i =0; 
	 i < sizeof (iso2022_info->sets) / sizeof (iso2022_info->sets[0]) &&
	     iso2022_info->sets[i];
	 i++) {

	enum iso2022_bank bank = iso2022_info->sets[i]->bank;
	int num = -1;
	int j;

	if (bank_unspecified == bank) {
	    if (iso2022_94 == iso2022_info->sets[i]->type &&
		-1 == output_state->bank[0])
		bank = bank_G0;

	}

	for (j = 0; 
	     j <  output_state->set_count;
	     j++) {

	    if (output_state->sets[j].type == iso2022_info->sets[i]->type &&
		0 == strncmp(us2s(output_state->sets[j].bytes),
			     us2s(iso2022_info->sets[i]->bytes),
			     sizeof (output_state->sets[j].bytes))) {
		DPRINT(Debug,6,(&Debug,
				"fill_euc_state: same set given several times\n"));

		num = j;
		break;
	    }
	}

	if (-1 == num) {
	    if (output_state->set_count +1 >= 
	        sizeof(output_state->sets) / sizeof(output_state->sets[0]))
		panic("ISO2022 PANIC",__FILE__,__LINE__,"fill_euc_state",
		      "Too many sets",0);
	    num = output_state->set_count;
	     
	    output_state->sets[num].bank =   bank;       /* Not needed */
	    output_state->sets[num].type =  iso2022_info->sets[i]->type;
	    memcpy(output_state->sets[num].bytes,
		   iso2022_info->sets[i]->bytes,
		   sizeof (output_state->sets[num].bytes));
	    
	    output_state->set_count++;
	}

	if (bank >= 0 && bank < ISO2022_BANK_NUM) {
	    
	    if (-1 != output_state->bank[bank]) 
		panic("ISO2022 PANIC",__FILE__,__LINE__,"fill_euc_state",
		      "Multiple sets on bank",0);
	    output_state->bank[bank] = num;
	}
    }
    DPRINT(Debug,9,(&Debug,
		    "fill_euc_state: %d sets\n",output_state->set_count));
}

S_(cs_stream_from_string cs_stream_from_euc)
static unsigned char * cs_stream_from_euc(str,printable,terminal,reslen)
     CONST struct string *str;
     int printable;
     screen_info_p terminal;
     int *reslen;
{
    screen_info_p  output_state = terminal;

    int             alloced  = str->p->len+1;
    unsigned char * ret      = safe_malloc(alloced);
    int             RESLEN   = 0;
    int             i;

    int need_reset = 0;

    struct mb_data       * X1 = str->p->a.data;

    struct iso2022_setid  *ctrlset = NULL;

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_stream_from_euc",
	      "Bad magic number (string)",0);
   
    if (!output_state) {
	output_state = create_terminal_info();
	if (str->string_type->iso2022_info)
	    fill_euc_state(output_state,str->string_type->iso2022_info);
    }

    if (DISPLAY_STATE_magic != output_state->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_stream_from_euc",
	      "Bad magic number (output state)",0);

    /* Fill indexes if current not filled */
    if (printable &&
	str->string_type->map_info && str->string_type->iso2022_info)
	fill_iso2022_map_index(str->string_type->iso2022_info,
			       X1,
			       str->string_type->map_info);

	
    /* Find ASCII bank (or other similar) */
    if (str->string_type->iso2022_info) 
	ctrlset = find_ctrlset(str->string_type->iso2022_info);

     for (i = 0; i < X1->part_count; i++) {
	int j;

#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "cs_stream_from_euc: %d: type=%d set_index=%d <",
			 i,X1->parts[i].type, X1->parts[i].set_index));
	if (Debug.active > 58 && str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,X1->parts[i].set_index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
#endif	

	switch (X1->parts[i].set_index) {
	case -1:
	    DPRINT(Debug,58,(&Debug,
			     "cs_stream_from_euc: %d control characters\n",
			     X1->parts[i].word_count));


	    if (iso2022_other != X1->parts[i].type)
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "cs_stream_from_euc",
		      "Bad type for control characters",0);
	    break;
	case -2:
	    DPRINT(Debug,58,(&Debug,
			     "cs_stream_from_iso2022: %d bad characters\n",
			     X1->parts[i].word_count));

	    break;

	default:
	    DPRINT(Debug,58,(&Debug,
			     "cs_stream_from_euc: %d characters from set %d\n",
			     X1->parts[i].word_count,
			     X1->parts[i].set_index));

	    if (X1->parts[i].set_index < 0 || 
		!str->string_type->iso2022_info ||
		X1->parts[i].set_index > sizeof (str->string_type->iso2022_info->sets) / 
		sizeof (str->string_type->iso2022_info->sets[0]) ||
		! str->string_type->iso2022_info->sets[X1->parts[i].set_index])
		panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_stream_from_euc",
		      "Bad set_index",0);
	    break;		
	}

	for (j = 0; j < X1->parts[i].word_count; j++) {
	    int r = add_char1_stream_GEN(add_char_stream_euc,
					 &ret,&RESLEN,&alloced,output_state,
					 str->string_type->iso2022_info,
					 str->string_type->map_info,
					 ctrlset,printable,& (X1->parts[i]),j,
					 &need_reset,NULL,
					 reset_euc
					 );	
	    if (r < 0) {
		goto out;
	    }

	}
     }

 out:

#if 0            /* NOT needed on EUC? */
     /* Reset to 94 bank */
     if (ctrlset) {
	 struct iso2022_setid ID = *ctrlset;    /* ASCII? */
	 int width;

	 DPRINT(Debug,63,(&Debug,
			  "cs_stream_from_iso2022: Returning to 94 bank\n"));
	 select_upper_lower(&ret,&RESLEN,&alloced,&ID,output_state,&width);	
     }
#endif
     
     if (output_state != terminal)
	 free_terminal_info(&output_state);


     *reslen = RESLEN;    /* Do not count final \0 to reslen */     
     {
	 unsigned char temp[1];
	 
	 temp[0] = '\0';
	 add_bytes_stream(&ret,&RESLEN,&alloced,temp,1);
     }
     
     return ret;
}

S_(cs_stream_from_string cs_stream_from_iso2022)
static unsigned char * cs_stream_from_iso2022(str,printable,terminal,reslen)
     CONST struct string *str;
     int printable;
     screen_info_p terminal;
     int *reslen;
{
    screen_info_p  output_state = terminal;

    int             alloced  = str->p->len+1;
    unsigned char * ret      = safe_malloc(alloced);
    int             RESLEN   = 0;
    int             i;

    int need_reset = 0;

    struct mb_data       * X1 = str->p->a.data;

    struct iso2022_setid  *ctrlset = NULL;

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_stream_from_iso2022",
	      "Bad magic number (string)",0);
   
    if (!output_state) {
	output_state = create_terminal_info();
    }

    if (DISPLAY_STATE_magic != output_state->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_stream_from_iso2022",
	      "Bad magic number (output state)",0);

    /* Fill indexes if current not filled */
    if (printable &&
	str->string_type->map_info && str->string_type->iso2022_info)
	fill_iso2022_map_index(str->string_type->iso2022_info,
			       X1,
			       str->string_type->map_info);

	
    /* Find ASCII bank (or other similar) */
    if (str->string_type->iso2022_info) 
	ctrlset = find_ctrlset(str->string_type->iso2022_info);

     for (i = 0; i < X1->part_count; i++) {
	int j;

#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "cs_stream_from_iso2022: %d: type=%d set_index=%d <",
			 i,X1->parts[i].type, X1->parts[i].set_index));
	if (Debug.active > 58 && str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,X1->parts[i].set_index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
#endif	

	switch (X1->parts[i].set_index) {
	case -1:
	    DPRINT(Debug,58,(&Debug,
			     "cs_stream_from_iso2022: %d control characters\n",
			     X1->parts[i].word_count));


	    if (iso2022_other != X1->parts[i].type)
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "cs_stream_from_iso2022",
		      "Bad type for control characters",0);
	    break;
	case -2:
	    DPRINT(Debug,58,(&Debug,
			     "cs_stream_from_iso2022: %d bad characters\n",
			     X1->parts[i].word_count));

	    break;

	default:
	    DPRINT(Debug,58,(&Debug,
			     "cs_stream_from_iso2022: %d characters from set %d\n",
			     X1->parts[i].word_count,
			     X1->parts[i].set_index));

	    if (X1->parts[i].set_index < 0 || 
		!str->string_type->iso2022_info ||
		X1->parts[i].set_index > sizeof (str->string_type->iso2022_info->sets) / 
		sizeof (str->string_type->iso2022_info->sets[0]) ||
		! str->string_type->iso2022_info->sets[X1->parts[i].set_index])
		panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_stream_from_iso2022",
		      "Bad set_index",0);
	    break;		
	}

	for (j = 0; j < X1->parts[i].word_count; j++) {
	    int r = add_char1_stream(&ret,&RESLEN,&alloced,output_state,
				     str->string_type->iso2022_info,
				     str->string_type->map_info,
				     ctrlset,printable,& (X1->parts[i]),j,
				     &need_reset,NULL);	
	    if (r < 0) {
		goto out;
	    }

	}
     }

 out:
     /* Reset to 94 bank */
     if (ctrlset) {
	 struct iso2022_setid ID = *ctrlset;    /* ASCII? */
	 int width;

	 DPRINT(Debug,63,(&Debug,
			  "cs_stream_from_iso2022: Returning to 94 bank\n"));
	 select_upper_lower(&ret,&RESLEN,&alloced,&ID,output_state,&width);	
     }
     
     if (output_state != terminal)
	 free_terminal_info(&output_state);


     *reslen = RESLEN;    /* Do not count final \0 to reslen */     
     {
	 unsigned char temp[1];
	 
	 temp[0] = '\0';
	 add_bytes_stream(&ret,&RESLEN,&alloced,temp,1);
     }
     
     return ret;
}

S_(cs_can_ascii_string cs_can_ascii_iso2022_gen)
static int cs_can_ascii_iso2022_gen(str)
     CONST struct string *str;
{
    struct mb_data       * X1 = str->p->a.data;
    int             i;

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_can_ascii_iso2022_gen",
	      "Bad magic number (string)",0);

    /* Fill indexes if current not filled */
    if (str->string_type->map_info && str->string_type->iso2022_info)
	fill_iso2022_map_index(str->string_type->iso2022_info,
			       X1,
			       str->string_type->map_info);

    for (i = 0; i < X1->part_count; i++) {
	int j;

#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "cs_can_ascii_iso2022_gen: %d: type=%d set_index=%d <",
			 i,X1->parts[i].type, X1->parts[i].set_index));
	if (Debug.active > 58 && str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,X1->parts[i].set_index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
#endif	

	switch (X1->parts[i].set_index) {
	case -1:
	    if (iso2022_other != X1->parts[i].type)
		panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_can_ascii_iso2022_gen",
		      "Bad type for control characters",0);
	    break;

	case -2:
	    return 0;   /* Unknown bank -- can not convert to ascii 
			   (well, we can not output this either ... so is this correct?
			    we anyway output '?' on here...)
			*/

	default:
	    if (X1->parts[i].set_index < 0 || 
		!str->string_type->iso2022_info ||
		X1->parts[i].set_index > sizeof (str->string_type->iso2022_info->sets) / 
		sizeof (str->string_type->iso2022_info->sets[0]) ||
		! str->string_type->iso2022_info->sets[X1->parts[i].set_index])
		panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_can_ascii_iso2022_gen",
		      "Bad set_index",0);
	    break;		
	}
	
	for (j = 0; j < X1->parts[i].word_count; j++) {
	    switch (X1->parts[i].set_index) {
		int iso2022_map_index;    /* index to iso2022_map_list[] */  

	    case -1: /* control characters  , (also space with 94, 94x94 sets) 			  
		      */
		if (X1->parts[i].words[j] > 127)
		    return 0;               /* If C1 control area */
		break;
	    default:
		
		iso2022_map_index = X1->parts[i].iso2022_map_index;

		if (-1 != iso2022_map_index) {		 
		    uint16  code;
		    int found = map_ISO2022_word_to_unicode(X1->parts[i].words[j],
							X1->parts[i].type,
							iso2022_map_index,
							&code);
		    if (!found || code > 127)
			return 0;    /* Not ASCII */
		} else
		    return 0;   /* No mapping available */	
		break;
	    }
	}
    }
   
    return 1;            /* No NON-ASCII character found */
}

static int may_add P_((int width, struct cs_printable_len *printable_len));
static int may_add(width,printable_len)
     int width; 
     struct cs_printable_len *printable_len;
{
    if (printable_len->max_len < printable_len->ret_len + width)
	return 0;
    
    printable_len->ret_len += width;

    return 1;
}

static int may_add_from_set P_((struct iso2022_setid   *set,
				screen_info_p          output_state,
				struct cs_printable_len *printable_len));
static int may_add_from_set(set,output_state,printable_len)
     struct iso2022_setid   *set;
     screen_info_p          output_state;
     struct cs_printable_len *printable_len;
{
    struct iso2022_setid   ID = *set;
    int setpos = iso2022_give_setpos(&ID,output_state);
    int r;

    if (setpos < 0) {
	DPRINT(Debug,49,(&Debug,
			 "may_add_from_set: setpos = %d  no information for estimating of width\n",
			 setpos));

	return -1;
    }
    if (output_state->width[setpos] < 0) {
	DPRINT(Debug,49,(&Debug,
			 "may_add_from_set: setpos = %d, width = %d  no information for estimating of width\n",
			 setpos,output_state->width[setpos]));
	return -1;
    }
    r = may_add(output_state->width[setpos],printable_len);

    return r;
}

/* Return number of characters consumed */
S_(cs_estimate_clip_string cs_estimate_clip_iso2022)
static int cs_estimate_clip_iso2022(str,pos,len,terminal,printable_len)
     CONST struct string *str;
     int pos; 
     int len;      /* UPPER LIMIT */
     screen_info_p terminal;
     struct cs_printable_len *printable_len;
{
    struct mb_data       * X1 = str->p->a.data;
    int block_number       = 0;
    int block_index        = pos;
    int counter            = 0;


    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_estimate_clip_iso2022",
	      "Bad magic number (string)",0);

    printable_len->ret_len = 0;             

    /* Fill indexes if current not filled */
    if (str->string_type->map_info && str->string_type->iso2022_info)
	fill_iso2022_map_index(str->string_type->iso2022_info,
			       X1,
			       str->string_type->map_info);


    if (!pos_to_block(X1,pos,&block_number,&block_index))
	return 0;   /* No characters consumed */

    while (block_number < X1->part_count && counter < len) {

#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "cs_estimate_clip_iso2022: %d: type=%d set_index=%d <",
			 block_number,X1->parts[block_number].type, 
			 X1->parts[block_number].set_index));
	if (Debug.active > 58 && str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,X1->parts[block_number].set_index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
#endif	

	switch (X1->parts[block_number].set_index) {
	case -1:
	    DPRINT(Debug,58,(&Debug,
			     "cs_estimate_clip_iso2022: %d control characters\n",
			     X1->parts[block_number].word_count - block_index));


	    if (iso2022_other != X1->parts[block_number].type)
		panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_estimate_clip_iso2022",
		      "Bad type for control characters",0);
	    break;
	    
	case -2:
	    DPRINT(Debug,58,(&Debug,
			     "cs_estimate_clip_iso2022: %d bad characters\n",
			     X1->parts[block_number].word_count - block_index));

	    goto bail_out;
	    
	default:

	    DPRINT(Debug,58,(&Debug,
			     "cs_estimate_clip_iso2022: %d characters from set %d\n",
			     X1->parts[block_number].word_count - block_index,
			     X1->parts[block_number].set_index));


	    if (X1->parts[block_number].set_index < 0 || 
		!str->string_type->iso2022_info ||
		X1->parts[block_number].set_index > sizeof (str->string_type->iso2022_info->sets) / 
		sizeof (str->string_type->iso2022_info->sets[0]) ||
		! str->string_type->iso2022_info->sets[X1->parts[block_number].set_index])
		panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_estimate_clip_iso2022",
		      "Bad set_index",0);
	    break;		
	}

	while  (block_index < X1->parts[block_number].word_count
		&& counter < len) {

	    switch (X1->parts[block_number].set_index) {
	    case -1:   /* control characters  , (also space with 94, 94x94 sets) 			  
			*/

		/* However do not handle controls */
		if (32 != X1->parts[block_number].words[block_index])
		    goto bail_out;
		
		/* Asumed that space have width 1 always */
		if (!may_add(1,printable_len)) {

		    DPRINT(Debug,49,(&Debug,
				     "cs_estimate_clip_iso2022: %d: ended at at %d, counter=%d (ctrl)\n",
				     block_number,block_index,counter));                                

		    goto out;
		}
		counter++;
		break;
	    case -2:
		/* Not occur */
		break;
	    default:
		if (-1 == X1->parts[block_number].iso2022_map_index ||
		    !str->string_type->iso2022_info) {
		    DPRINT(Debug,49,(&Debug,
				     "cs_estimate_clip_iso2022:  iso2022_map_index=%d or no iso2022_info\n",
				     X1->parts[block_number].iso2022_map_index));
		    goto bail_out;
		} else {
		    uint16  code;
		    int r;		
		    int found = map_ISO2022_word_to_unicode(X1->parts[block_number].words[block_index],
							    X1->parts[block_number].type,
							    X1->parts[block_number].iso2022_map_index,
							    &code);
		    if (!found) {
			DPRINT(Debug,49,(&Debug,
					 "cs_estimate_clip_iso2022: %d: at %d, counter=%d -- iso2022 character %04x type %d with map index %d not found\n",
					 block_number,block_index,counter,	
					 X1->parts[block_number].words[block_index],
					 X1->parts[block_number].type,
					 X1->parts[block_number].iso2022_map_index));
			goto bail_out;      /* No mapping available */
		    }
		    if (!unicode_ch(code,UOP_printable)) {
			DPRINT(Debug,49,(&Debug,
					 "cs_estimate_clip_iso2022: %d: at %d, counter=%d -- unicode character %04x not printable\n",
					 block_number,block_index,counter,code));                              
			goto bail_out;      /* Not printable */
		    }

		    r = may_add_from_set(str->string_type->iso2022_info->
					 sets[X1->parts[block_number].set_index],
					 terminal,
					 printable_len);
		    if (r < 0)
			goto bail_out;
		    if (!r) {
			DPRINT(Debug,49,(&Debug,
					 "cs_estimate_clip_iso2022: %d: ended at at %d, counter=%d (no space)\n",
					 block_number,block_index,counter));                                
			goto out;
		    }
	
		    counter++;
		}
		break;
	    }
	    block_index++;
	}
	block_number++;
	block_index = 0;
    }

 out:
    
    return counter;
 bail_out:

    DPRINT(Debug,49,(&Debug,
		     "cs_estimate_clip_iso2022: %d: bailing out at %d, counter=%d\n",
		     block_number,block_index,counter));

    if (counter > 0)
	return counter;

    return -1;
}

S_(cs_streamclip_from_string cs_streamclip_from_euc)
static unsigned char * cs_streamclip_from_euc(str,pos,len,terminal,printable_len)
     CONST struct string *str;
     int *pos; 
     int len;
     screen_info_p terminal;
     struct cs_printable_len *printable_len;
{
     screen_info_p  output_state = terminal;

    struct mb_data       * X1 = str->p->a.data;
    int block_number       = 0;
    int block_index        = *pos;
    int start_pos          = *pos;

    int             alloced  = 0;
    unsigned char * ret      = NULL;
    int             RESLEN   = 0;


    struct iso2022_setid  *ctrlset = NULL;
    int need_reset = 0;


    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_streamclip_from_euc",
	      "Bad magic number (string)",0);

    if (*pos < 0)
	panic("STRING PANIC",__FILE__,__LINE__,"cs_streamclip_from_euc",
	      "Index out of array",0);
    
    if (len < 0)
	panic("STRING PANIC",__FILE__,__LINE__,"cs_streamclip_from_euc",
	      "Negative size",0);

    if (printable_len)
	printable_len->ret_len = 0;             

    if (!pos_to_block(X1,*pos,&block_number,&block_index)) {
	
	unsigned char * S = safe_malloc(1);
	*S = '\0';
	
	return S;
    }

    alloced  = len+1;
    ret      = safe_malloc(alloced);

    if (!output_state) {
	output_state = create_terminal_info();
	if (str->string_type->iso2022_info)
	    fill_euc_state(output_state,str->string_type->iso2022_info);
    }

    /* Fill indexes if current not filled */
    if (str->string_type->map_info && str->string_type->iso2022_info)
	fill_iso2022_map_index(str->string_type->iso2022_info,
			       X1,
			       str->string_type->map_info);
	
    /* Find ASCII bank (or other similar) */
    if (str->string_type->iso2022_info) 
	ctrlset = find_ctrlset(str->string_type->iso2022_info);


    while (block_number < X1->part_count && *pos - start_pos < len) {

#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "cs_streamclip_from_euc: %d: type=%d set_index=%d <",
			 block_number,X1->parts[block_number].type, 
			 X1->parts[block_number].set_index));
	if (Debug.active > 58 && str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,X1->parts[block_number].set_index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
#endif	

	switch (X1->parts[block_number].set_index) {
	case -1:
	    DPRINT(Debug,58,(&Debug,
			     "cs_streamclip_from_euc: %d control characters\n",
			     X1->parts[block_number].word_count - block_index,
			     X1->parts[block_number].set_index));


	    if (iso2022_other != X1->parts[block_number].type)
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "cs_streamclip_from_euc",
		      "Bad type for control characters",0);
	    break;

	case -2:
	    DPRINT(Debug,58,(&Debug,
			     "cs_streamclip_from_euc: %d bad characters\n",
			     X1->parts[block_number].word_count - block_index,
			     X1->parts[block_number].set_index));

	    break;
	    
	default:

	    DPRINT(Debug,58,(&Debug,
			     "cs_streamclip_from_euc: %d characters from set %d\n",
			     X1->parts[block_number].word_count - block_index,
			     X1->parts[block_number].set_index));
	    

	    if (X1->parts[block_number].set_index < 0 || 
		!str->string_type->iso2022_info ||
		X1->parts[block_number].set_index > sizeof (str->string_type->iso2022_info->sets) / 
		sizeof (str->string_type->iso2022_info->sets[0]) ||
		! str->string_type->iso2022_info->sets[X1->parts[block_number].set_index])
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "cs_streamclip_from_euc",
		      "Bad set_index",0);
	    break;		
	}

	while  (block_index < X1->parts[block_number].word_count
		&& *pos - start_pos < len) {
	   
	    int r = add_char1_stream_GEN(add_char_stream_euc,
					 &ret,&RESLEN,&alloced,output_state,
					 str->string_type->iso2022_info,
					 str->string_type->map_info,
					 ctrlset,1,& (X1->parts[block_number]),
					 block_index,&need_reset,printable_len,
					 reset_euc
					 );

	    if (r < 0)
		goto out;

	    if (r > 0) {
		/* nothing to count */
	    } else {
		DPRINT(Debug,1,(&Debug,
				"cs_streamclip_from_euc: FAILED to add char to steam\n"));
	    }

	    block_index++;
	    (*pos)++;
	}
	
	block_index = 0;
	block_number++;
    }
 out:


#if 0                 /* NOT needed on EUC? */
    /* Reset to 94 bank 
     */
    if (ctrlset) {
	struct iso2022_setid ID = *ctrlset;    /* ASCII? */
	int width;

	DPRINT(Debug,63,(&Debug,
			 "cs_streamclip_from_euc: Returning to 94 bank\n"));

	select_upper_lower(&ret,&RESLEN,&alloced,&ID,output_state,&width);	
    }
#endif    

    if (output_state != terminal)
	free_terminal_info(&output_state);
    
    {
	unsigned char temp[1];
	
	temp[0] = '\0';
	add_bytes_stream(&ret,&RESLEN,&alloced,temp,1);
    }
    
    return ret;

}

S_(cs_streamclip_from_string cs_streamclip_from_iso2022)
static unsigned char * cs_streamclip_from_iso2022(str,pos,len,terminal,printable_len)
     CONST struct string *str;
     int *pos; 
     int len;
     screen_info_p terminal;
     struct cs_printable_len *printable_len;
{
    screen_info_p  output_state = terminal;

    struct mb_data       * X1 = str->p->a.data;
    int block_number       = 0;
    int block_index        = *pos;
    int start_pos          = *pos;

    int             alloced  = 0;
    unsigned char * ret      = NULL;
    int             RESLEN   = 0;


    struct iso2022_setid  *ctrlset = NULL;
    int need_reset = 0;


    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_streamclip_from_iso2022",
	      "Bad magic number (string)",0);

    if (*pos < 0)
	panic("STRING PANIC",__FILE__,__LINE__,"cs_streamclip_from_iso2022",
	      "Index out of array",0);
    
    if (len < 0)
	panic("STRING PANIC",__FILE__,__LINE__,"cs_streamclip_from_iso2022",
	      "Negative size",0);

    if (printable_len)
	printable_len->ret_len = 0;             

    if (!pos_to_block(X1,*pos,&block_number,&block_index)) {
	
	unsigned char * S = safe_malloc(1);
	*S = '\0';
	
	return S;
    }

    alloced  = len+1;
    ret      = safe_malloc(alloced);

    if (!output_state) {
	output_state = create_terminal_info();
    }

    /* Fill indexes if current not filled */
    if (str->string_type->map_info && str->string_type->iso2022_info)
	fill_iso2022_map_index(str->string_type->iso2022_info,
			       X1,
			       str->string_type->map_info);
	
    /* Find ASCII bank (or other similar) */
    if (str->string_type->iso2022_info) 
	ctrlset = find_ctrlset(str->string_type->iso2022_info);


    while (block_number < X1->part_count && *pos - start_pos < len) {

#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "cs_streamclip_from_iso2022: %d: type=%d set_index=%d <",
			 block_number,X1->parts[block_number].type, 
			 X1->parts[block_number].set_index));
	if (Debug.active > 58 && str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,X1->parts[block_number].set_index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
#endif	

	switch (X1->parts[block_number].set_index) {
	case -1:
	    DPRINT(Debug,58,(&Debug,
			     "cs_streamclip_from_iso2022: %d control characters\n",
			     X1->parts[block_number].word_count - block_index,
			     X1->parts[block_number].set_index));


	    if (iso2022_other != X1->parts[block_number].type)
		panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_streamclip_from_iso2022",
		      "Bad type for control characters",0);
	    break;

	case -2:
	    DPRINT(Debug,58,(&Debug,
			     "cs_streamclip_from_iso2022: %d bad characters\n",
			     X1->parts[block_number].word_count - block_index,
			     X1->parts[block_number].set_index));

	    break;
	    
	default:

	    DPRINT(Debug,58,(&Debug,
			     "cs_streamclip_from_iso2022: %d characters from set %d\n",
			     X1->parts[block_number].word_count - block_index,
			     X1->parts[block_number].set_index));


	    if (X1->parts[block_number].set_index < 0 || 
		!str->string_type->iso2022_info ||
		X1->parts[block_number].set_index > sizeof (str->string_type->iso2022_info->sets) / 
		sizeof (str->string_type->iso2022_info->sets[0]) ||
		! str->string_type->iso2022_info->sets[X1->parts[block_number].set_index])
		panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_streamclip_from_iso2022",
		      "Bad set_index",0);
	    break;		
	}

	while  (block_index < X1->parts[block_number].word_count
		&& *pos - start_pos < len) {
	   
	    int r = add_char1_stream(&ret,&RESLEN,&alloced,output_state,
				     str->string_type->iso2022_info,
				     str->string_type->map_info,
				     ctrlset,1,& (X1->parts[block_number]),
				     block_index,&need_reset,printable_len);

	    if (r < 0)
		goto out;

	    if (r > 0) {
		/* nothing to count */
	    } else {
		DPRINT(Debug,1,(&Debug,
				"cs_streamclip_from_iso2022: FAILED to add char to steam\n"));
	    }

	    block_index++;
	    (*pos)++;
	}
	
	block_index = 0;
	block_number++;
    }
 out:

    /* Reset to 94 bank 
     */
    if (ctrlset) {
	struct iso2022_setid ID = *ctrlset;    /* ASCII? */
	int width;

	DPRINT(Debug,63,(&Debug,
			  "cs_streamclip_from_iso2022: Returning to 94 bank\n"));

	select_upper_lower(&ret,&RESLEN,&alloced,&ID,output_state,&width);	
    }
    
    if (output_state != terminal)
	free_terminal_info(&output_state);
    
    {
	unsigned char temp[1];
	
	temp[0] = '\0';
	add_bytes_stream(&ret,&RESLEN,&alloced,temp,1);
    }
    
    return ret;
}

S_(cs_clip_from_string cs_clip_from_iso2022_gen)
static void cs_clip_from_iso2022_gen(ret,str,pos,len)
     struct string *ret;
     CONST struct string *str;
     int *pos; 
     int len;
{
    struct mb_data       * X1 = str->p->a.data;
    struct mb_data       * X2 = ret->p->a.data;
    int block_number       = 0;
    int block_index        = *pos;
    int start_pos          = *pos;

    if (ret->string_type->charset_type !=
	str->string_type->charset_type) 
	panic("STRING PANIC",__FILE__,__LINE__,"cs_clip_from_iso2022_gen",
	      "String type mismatch",0);

    if (*pos < 0)
	panic("STRING PANIC",__FILE__,__LINE__,"cs_clip_from_iso2022_gen",
	      "Index out of array",0);

    if (len < 0)
	panic("STRING PANIC",__FILE__,__LINE__,"cs_clip_from_iso2022_gen",
	      "Negative size",0);

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_clip_from_iso2022_gen",
	      "Bad magic number (string)",0);

    if (CS_ISO2022_magic != X2->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_clip_from_iso2022_gen",
	      "Bad magic number (ret)",0);

    free_parts(X2);	 /* Quarantee */
    ret->p->len = 0;

    if (!pos_to_block(X1,*pos,&block_number,&block_index))  {
	
	return ;
    }

    /* FIXME: Optimeze this */

    while (block_number < X1->part_count && *pos - start_pos < len) {

	int l1      = X1->parts[block_number].word_count - block_index;
	int new_len;
	struct mb_data_part  * X3;

	if (l1 < 1)
	    continue;   /* Avoid job */


#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "cs_clip_from_iso2022_gen: %d: type=%d set_index=%d <",
			 block_number,X1->parts[block_number].type, 
			 X1->parts[block_number].set_index));
	if (Debug.active > 58 && str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,X1->parts[block_number].set_index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
#endif	


	X3 = get_part(X2,
		     X1->parts[block_number].set_index,
		     X1->parts[block_number].type);

	new_len = X3->word_count + l1;

	X3->words = safe_realloc(X3->words, 
				 (new_len) * 
				 sizeof (X3->words[0]));    

	while  (block_index < X1->parts[block_number].word_count &&
		X3->word_count < new_len  &&
		*pos - start_pos < len) {

	    X3->words[X3->word_count++] = 
		X1->parts[block_number].words[block_index];
	    ret->p->len++;
	    
	    block_index++;
	    (*pos)++;	   
	}
	
	block_index = 0;
	block_number++;
    }
}

S_(cs_find_pattern_from_string cs_find_pattern_from_iso2022_gen)
static int cs_find_pattern_from_iso2022_gen(str,pattern,ignore_case)
     CONST struct string *str;
     CONST struct string *pattern;
     int ignore_case;
{
    /* FIXME: pattern match should be done on here */

    DPRINT(Debug,63,(&Debug, 
		     "cs_find_pattern_from_iconv_gen=-1\n"));	
    return -1;   /* Use UNICODE comparision on upper level instead */
}

/* Returns number of bytes added */
S_(cs_add_streambytes_to_string cs_add_streambytes_to_iso2022_gen)
static int cs_add_streambytes_to_iso2022_gen(str,count,data,errors)
     struct string *str;
     int count;
     CONST unsigned char *data;
     int *errors;
{    
    int i = 0;
    struct state_iso2022 * X ;
    
    *errors = 0;

    if (!str->p->state)
	str->p->state = new_state_1(str->string_type);

    if (str->p->state->charset->charset_type != &cs_iso2022 &&
	str->p->state->charset->charset_type != &cs_euc
	)
	panic("STRING PANIC",__FILE__,__LINE__,"cs_add_streambytes_to_iso2022_gen",
	      "Bad state",0);

    X = str->p->state->p->a.iso2022;
    
    if (STATE_ISO2022_magic != X->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_add_streambytes_to_iso2022_gen",
	      "Bad magic number (state)",0);

    while (1) {
	if (str->p->state->p->ready) {
	    iso2022_add_char(str,str->p->state);
	    cs_soft_reset_s_iso2022_gen(str->p->state);
	} else {
	    int c = -1;

	    if (X->raw_bytes_count > 0) {
		DPRINT(Debug,8,(&Debug,
				"cs_add_streambytes_to_iso2022_gen: %d bytes collected\n",
				X->raw_bytes_count));

		c = streambyte_make_code_2(str->p->state,X);
	    }

	    if (c < 0) {
		/* need more characters */
		if (i < count) {
		    if (!state_add_raw(X,data[i])) {
			DPRINT(Debug,8,(&Debug,
					"cs_add_streambytes_to_iso2022_gen: failed to add code\n"));

			/* Failed to add character */
			(*errors)++;
			cs_soft_reset_s_iso2022_gen(str->p->state);
			X->raw_bytes_count = 0;
		    }
 
		    i++;
		    
		} else {
		    break;   /* All characters entered */
		}
	    }

	    if (0 == c) {
		DPRINT(Debug,8,(&Debug,
				"cs_add_streambytes_to_iso2022_gen: bad code\n"));
		(*errors)++;
		cs_soft_reset_s_iso2022_gen(str->p->state);
	    }
	}
    }

    return i;
}

S_(cs_find_map_type cs_find_euc)
static struct  map_info *cs_find_euc(map_name)
     CONST char * map_name;
{
    int i;
    struct  map_info *ret;

    static struct  map_info ** dyn_maps  = NULL;
    static  int           dyn_map_count  = 0;

    static struct  map_info * maps[] = { &map_EUC_ascii, 
					 &map_EUC_ascii_latin1, 
					 NULL };

    for (i = 0; maps[i]; i++)
	if (0 == strcmp(map_name,maps[i]->map_name))
	    return maps[i];


    for (i =0; i < dyn_map_count; i++)
	if (0 == strcmp(dyn_maps[i]->map_name,map_name))
	    return dyn_maps[i];

    ret = open_euc_mapset(map_name);
    
    if (ret) {
	dyn_maps = safe_realloc(dyn_maps,
				(dyn_map_count + 1) * 
				sizeof (struct  map_info *));
	dyn_maps[dyn_map_count++] = ret;
    }
    return ret;
}

S_(cs_find_map_type cs_find_iso2022)
static struct  map_info *cs_find_iso2022(map_name)
     CONST char * map_name;
{
    int i;
    struct  map_info *ret;

    static struct  map_info ** dyn_maps  = NULL;
    static  int           dyn_map_count  = 0;

    static struct  map_info * maps[] = { &map_ISO2022_ascii, 
					 &map_ISO2022_ascii_latin1, 
					 NULL };

    for (i = 0; maps[i]; i++)
	if (0 == strcmp(map_name,maps[i]->map_name))
	    return maps[i];


    for (i =0; i < dyn_map_count; i++)
	if (0 == strcmp(dyn_maps[i]->map_name,map_name))
	    return dyn_maps[i];

    ret = open_iso2022_mapset(map_name);
    
    if (ret) {
	dyn_maps = safe_realloc(dyn_maps,
				(dyn_map_count + 1) * 
				sizeof (struct  map_info *));
	dyn_maps[dyn_map_count++] = ret;
    }
    return ret;
}

S_(cs_remove_control cs_remove_control_iso2022_gen)
static void cs_remove_control_iso2022_gen(str)
     CONST struct string *str;
{
    struct mb_data       * X1 = str->p->a.data;
    struct mb_data   * new_X1 = alloc_mb_data();
    int i;

    if (CS_ISO2022_magic != X1->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_remove_control_iso2022_gen",
	      "Bad magic number (string)",0);

  
    /* Fill indexes if current not filled */
    if (str->string_type->map_info && str->string_type->iso2022_info)
	fill_iso2022_map_index(str->string_type->iso2022_info,
			       X1,
			       str->string_type->map_info);

    /* FIXME: This is very inefficient -- we rebuild string internally */
  
    for (i = 0; i < X1->part_count; i++) {
	int j;

#ifdef DEBUG
	DPRINT(Debug,59,(&Debug,
			 "cs_remove_control_iso2022_gen: %d: type=%d set_index=%d <",
			 i,X1->parts[i].type, X1->parts[i].set_index));
	if (Debug.active > 58 && str->string_type->iso2022_info)
	    debug_iso2022_info_index(59,X1->parts[i].set_index,
				     str->string_type->iso2022_info);
	DPRINT(Debug,59,(&Debug,">\n"));
#endif	

	switch (X1->parts[i].set_index) {
	case -1:
	    if (iso2022_other != X1->parts[i].type)
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "cs_remove_control_iso2022_gen",
		      "Bad type for control characters",0);
	    break;
	case -2:
	    break;
	default:
	    if (X1->parts[i].set_index < 0 || 
		!str->string_type->iso2022_info ||
		X1->parts[i].set_index > 
		sizeof (str->string_type->iso2022_info->sets) / 
		sizeof (str->string_type->iso2022_info->sets[0]) ||
		! str->string_type->iso2022_info->sets[X1->parts[i].set_index])
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "cs_remove_control_iso2022_gen",
		      "Bad set_index",0);
	    break;		
	}
	
	for (j = 0; j < X1->parts[i].word_count; j++) {
	    switch (X1->parts[i].set_index) {
		struct mb_data_part  * X3;
		int iso2022_map_index;

	    case -1:   /* control characters  , 
			  (also space with 94, 94x94 sets) 		   
			*/
		if (32 != X1->parts[i].words[j])
		    goto bad_char;

		X3 = get_part(new_X1,
			      X1->parts[i].set_index,
			      X1->parts[i].type);
		add_iso2022_word(X3, X1->parts[i].words[j]);

		break;

	    case -2: bad_char:
	    		
		if (str->string_type->iso2022_info && 
		    str->string_type->map_info) {
		    int                  index;
		    enum iso2022_settype type;
		    uint16               iso2022_word;
		    
		    if (map_unicode_to_ISO2022_word(0x003F /* '?' */,
						    str->string_type->
						    iso2022_info,
						    &index,&type,&iso2022_word,
						    str->string_type->
						    map_info)
			&& index >= 0) {
			
			if (index > 
			    sizeof (str->string_type->iso2022_info->sets) / 
			    sizeof (str->string_type->iso2022_info->sets[0]) ||
			    ! str->string_type->iso2022_info->sets[index])
			    panic("ISO2022 PANIC",__FILE__,__LINE__,
				  "cs_remove_control_iso2022_gen",
				  "Bad index",0);
			
			X3 = get_part(new_X1,index,type);
			add_iso2022_word(X3,iso2022_word);
			
			break;
		    }
		}
		/* We can add space instead */
		X3 = get_part(new_X1,-1,iso2022_other);
		add_iso2022_word(X3,32);

		break;

	    default:
	    
		iso2022_map_index = X1->parts[i].iso2022_map_index;
 
		if (-1 != iso2022_map_index) {		 
		    uint16  code;	       
		    int found = map_ISO2022_word_to_unicode(X1->parts[i].words[j],
						X1->parts[i].type,
						iso2022_map_index,
						&code);
		    if (!found)
			goto bad_char;      /* No mapping avaiulable */
		    if (!unicode_ch(code,UOP_printable))
			goto bad_char;      /* Not printable */
		} else
		    goto bad_char;  /* No mapping available */

		X3 = get_part(new_X1,
			      X1->parts[i].set_index,
			      X1->parts[i].type);
		add_iso2022_word(X3, X1->parts[i].words[j]);
		
		break;

	    }
	}
    }

    
    free_mb_data(&X1);
    str->p->a.data = new_X1;

    {
	int l = str->p->len;

	str->p->len = 0;
	for (i = 0; i < new_X1->part_count; i++) {
	    str->p->len += new_X1->parts[i].word_count;
	}
	
	if (l != str->p->len) {
	    DPRINT(Debug,6,(&Debug, 
			    "cs_remove_control_iso2022_gen: length changed %d => %d\n",
			    l,str->p->len));

	}
    }
}

S_(cs_add_state_to_string cs_add_state_to_iso2022_gen)
static void cs_add_state_to_iso2022_gen(str,ch)
     struct string *str;
     struct charset_state *ch;
{    
    if (str->string_type->charset_type !=
	ch->charset->charset_type) 
	panic("STRING PANIC",__FILE__,__LINE__,"cs_add_state_to_iso2022_gen",
	      "String/state type mismatch",0);

    iso2022_add_char(str,ch);
}

static void set_initial_state P_((struct charset_state *st));
static void set_initial_state(st)
     struct charset_state *st;
{
    if (STATE_ISO2022_magic != st->p->a.iso2022->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "set_initial_state",
	      "Bad magic number",0);

    if (st->charset->iso2022_info) {
	int i;

	if (sizeof (st->charset->iso2022_info->initial_bank)  /
	    sizeof (st->charset->iso2022_info->initial_bank[0]) !=

	    sizeof (st->p->a.iso2022->banks) / 
	    sizeof (st->p->a.iso2022->banks[0]))
	    
	    panic("ISO2022 PANIC",__FILE__,__LINE__,
		  "set_initial_state",
		  "Array sizes should be same",0);

	for (i = 0; 
	     i < sizeof (st->charset->iso2022_info->initial_bank) / 
		 sizeof (st->charset->iso2022_info->initial_bank[0]);
	     i++) {
	    int x = st->charset->iso2022_info->initial_bank[i];

	    if (-1 != x) {

		if (x < 0 ||
		    x >= sizeof (st->charset->iso2022_info->sets)  /
		    sizeof (st->charset->iso2022_info->sets[0]) ||
		    ! st->charset->iso2022_info->sets[x]) 

		    panic("STRING PANIC",__FILE__,__LINE__,
			  "set_initial_state",
			  "Bad initial_bank (set)",
			  0);

		if (sizeof (st->p->a.iso2022->banks[i].bytes) !=
		    sizeof (st->charset->iso2022_info->sets[x]->bytes))
		    panic("STRING PANIC",__FILE__,__LINE__,
			  "set_initial_state",
			  "Bad size",
			  0);
		    
		st->p->a.iso2022->banks[i].iso2022_info_index = x;

		st->p->a.iso2022->banks[i].type =
		    st->charset->iso2022_info->sets[x]->type;
		memcpy(st->p->a.iso2022->banks[i].bytes,
		       st->charset->iso2022_info->sets[x]->bytes,
		      sizeof  st->p->a.iso2022->banks[i].bytes);

	    }
	}
    }
}

S_(cs_init_state cs_init_s_iso2022)
static void cs_init_s_iso2022(st)
     struct charset_state *st;
{
    int i;

    st->p->a.iso2022 = safe_malloc(sizeof (*st->p->a.iso2022));
    
    /* defined in hdrs/defs.h */
    bzero((void *)st->p->a.iso2022, sizeof (*st->p->a.iso2022));

    st->p->a.iso2022->magic = STATE_ISO2022_magic;
    st->p->a.iso2022->bank  = bank_unspecified;

    for (i = 0; 
	 i < sizeof (st->p->a.iso2022->banks) / 
	     sizeof (st->p->a.iso2022->banks[0]);
	 i++) {
	st->p->a.iso2022->banks[i].type                 = iso2022_other;
	st->p->a.iso2022->banks[i].iso2022_info_index   = -1;
	bzero(st->p->a.iso2022->banks[i].bytes,
	       sizeof (st->p->a.iso2022->banks[i].bytes));
    }
    st->p->a.iso2022->CL_bank  = bank_G0;   /* G0 assumed initially */
    st->p->a.iso2022->CR_bank  = bank_unspecified; /* no assumption for
						      8-bit characters */
    st->p->a.iso2022->raw_bytes_count = 0;
    st->p->a.iso2022->word            = 0;

    set_initial_state(st);
}

S_(cs_init_state cs_init_s_euc)
static void cs_init_s_euc(st)
     struct charset_state *st;
{
    int i;

    st->p->a.iso2022 = safe_malloc(sizeof (*st->p->a.iso2022));
    
    /* defined in hdrs/defs.h */
    bzero((void *)st->p->a.iso2022, sizeof (*st->p->a.iso2022));

    st->p->a.iso2022->magic = STATE_ISO2022_magic;
    st->p->a.iso2022->bank  = bank_unspecified;

    for (i = 0; 
	 i < sizeof (st->p->a.iso2022->banks) / 
	     sizeof (st->p->a.iso2022->banks[0]);
	 i++) {
	st->p->a.iso2022->banks[i].type                 = iso2022_other;
	st->p->a.iso2022->banks[i].iso2022_info_index   = -1;
	bzero(st->p->a.iso2022->banks[i].bytes,
	       sizeof (st->p->a.iso2022->banks[i].bytes));
    }
    st->p->a.iso2022->CL_bank  = bank_G0;   /* G0 is left on EUC */
    st->p->a.iso2022->CR_bank  = bank_G1;   /* G1 is for 8-bit characters on 
					       EUC  */
    st->p->a.iso2022->raw_bytes_count = 0;
    st->p->a.iso2022->word            = 0;

    set_initial_state(st);
    
    if (st->charset->iso2022_info) {

	for (i = 0; 
	     i < sizeof (st->charset->iso2022_info->sets)  /
		 sizeof (st->charset->iso2022_info->sets[0]) &&
		 st->charset->iso2022_info->sets[i];
	     i++) {

	    enum iso2022_bank bank = st->charset->iso2022_info->sets[i]->bank;

	    if (bank == bank_unspecified &&
		iso2022_94 == st->charset->iso2022_info->sets[i]->type &&
		iso2022_other == st->p->a.iso2022->banks[bank_G0].type)
		bank = bank_G0;

	    if (bank >= 0 && bank < ISO2022_BANK_NUM) {

		st->p->a.iso2022->banks[bank].iso2022_info_index = i;
		st->p->a.iso2022->banks[bank].type =
                    st->charset->iso2022_info->sets[i]->type;

		memcpy(st->p->a.iso2022->banks[bank].bytes,
		       st->charset->iso2022_info->sets[i]->bytes,
		       sizeof  st->p->a.iso2022->banks[bank].bytes);
	    }
	}
    }
}

S_(cs_free_state cs_free_s_iso2022_gen)
static void cs_free_s_iso2022_gen(st)
     struct charset_state *st;
{
    if (st->p->a.iso2022) {
	if (STATE_ISO2022_magic != st->p->a.iso2022->magic)
	    panic("ISO2022 PANIC",__FILE__,__LINE__,"cs_free_s_iso2022",
		  "Bad magic number",0);

	st->p->a.iso2022->magic = 0;        /* Invalidate magic */

	free(st->p->a.iso2022);
	st->p->a.iso2022 = NULL;
    }
}

S_(cs_add_streambyte_to_state cs_add_streambyte_to_s_iso2022_gen)
static int cs_add_streambyte_to_s_iso2022_gen(st,ch)
     struct charset_state *st; 
     int ch;
{
    struct state_iso2022 * X  = st->p->a.iso2022;

    
    if (STATE_ISO2022_magic != X->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_add_streambyte_to_s_iso2022_gen",
	      "Bad magic number (state)",0);

    if (!state_add_raw(X,ch))
	return 0;
    
    while (X->raw_bytes_count > 0) {
	int code;

	if (st->p->ready) {
	    DPRINT(Debug,4,(&Debug,
			    "cs_add_streambyte_to_s_iso2022_gen: characters lost!\n"
			    ));
	}

	code = streambyte_make_code_2(st,X);

	if (code < 0) {
	    DPRINT(Debug,8,(&Debug,
			    "cs_add_streambyte_to_s_iso2022_gen: too few characters (len = %d)\n",
			    X->raw_bytes_count));
	    return 1;
	}
	if (0 == code) {
	    DPRINT(Debug,8,(&Debug,
			    "cs_add_streambyte_to_s_iso2022_gen: bad code\n"));
	    return 0;
	}
    }
    
    return 1;
}

S_(cs_soft_reset_state cs_soft_reset_s_iso2022_gen)
static void cs_soft_reset_s_iso2022_gen(st)
     struct charset_state *st;
{
    struct state_iso2022 * X  = st->p->a.iso2022;

    if (STATE_ISO2022_magic != X->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_soft_reset_s_iso2022_gen",
	      "Bad magic number (state)",0);
    
    X->raw_bytes_count = 0;
    st->p->ready = 0;
}

S_(cs_give_unicode_from_state cs_give_unicode_from_s_iso2022)
static uint16 cs_give_unicode_from_s_iso2022(st,found)
     struct charset_state *st;
     int *found;
{
    uint16 ret = 0x003F;  /* '?' */

    struct state_iso2022 * X  = st->p->a.iso2022;

    if (STATE_ISO2022_magic != X->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_give_unicode_from_s_iso2022",
	      "Bad magic number (state)",0);

    *found = 0;

    if (bank_unspecified == X-> bank) {
	/* Control characters map directrly to unicode */

	ret = X->word;
	*found = 1;

    } else if (X->bank >= 0 && X->bank <  ISO2022_BANK_NUM) {
       
        if (0 <= X->banks[X->bank].iso2022_info_index &&
	    st->charset->iso2022_info &&
	    st->charset->map_info) {
	    int iso2022_map_index;

	    if (X->banks[X->bank].iso2022_info_index >=
		sizeof (st->charset->iso2022_info->sets) /
		sizeof (st->charset->iso2022_info->sets[0]) ||
		! st->charset->iso2022_info->sets
		[X->banks[X->bank].iso2022_info_index])

		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "cs_give_unicode_from_s_iso2022",
		      "Bad iso2022_info_index",0);

	    if (!st->charset->map_info->map_initialized)
		st->charset->map_info->map_init_it(st->charset->map_info);
						  	       
	    iso2022_map_index = 
		give_iso2022_index(st->charset->map_info->b.setlist->setlist,
				   sizeof (st->charset->map_info->b.setlist->
					   setlist) / 
				   sizeof (st->charset->map_info->
					   b.setlist->setlist[0]),
				   st->charset->iso2022_info->
				   sets[X->banks[X->bank].iso2022_info_index]);
	    
	    if (-1 != iso2022_map_index)
		*found = map_ISO2022_word_to_unicode(X->word,
						     X->banks[X->bank].type,
						     iso2022_map_index,
						     &ret);
	}
    } else   
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_give_unicode_from_s_iso2022",
	      "Bad bank number",0);
	   
    return ret;
}

S_(cs_state_same_char cs_s_iso2022_same_char_gen)
static int cs_s_iso2022_same_char_gen(A,B,ignore_case)
     struct charset_state *A;
     struct charset_state *B;
     int ignore_case;
{
    int r = -1;

    struct state_iso2022 * XA  = A->p->a.iso2022;
    struct state_iso2022 * XB  = B->p->a.iso2022;
   
    if (STATE_ISO2022_magic != XA->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_soft_reset_s_iso2022",
	      "Bad magic number (state A)",0);

    if (STATE_ISO2022_magic != XB->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_soft_reset_s_iso2022",
	      "Bad magic number (state B)",0);


    /* If control character */
    if (bank_unspecified == XA->bank && bank_unspecified == XB->bank)
	r = XA->word == XB->word;
    else if (bank_unspecified == XA->bank || bank_unspecified == XB->bank)
	r = -1;   /* Use UNICODE values for comparision */
    else if (XA->bank >= 0 && XB->bank >= 0 &&
	     XA->bank <= ISO2022_BANK_NUM && 
	     XB->bank <= ISO2022_BANK_NUM) {

	if (-1 == XA->banks[XA->bank].iso2022_info_index &&
	    -1 == XB->banks[XB->bank].iso2022_info_index &&
	    0 == memcmp(XA->banks[XA->bank].bytes,
			XB->banks[XB->bank].bytes,
			sizeof (XA->banks[XA->bank].bytes)))
	    r = XA->word == XB->word;

	else if (0 <= XA->banks[XA->bank].iso2022_info_index &&
	      XA->banks[XA->bank].iso2022_info_index ==
	      XB->banks[XB->bank].iso2022_info_index)
	    r = XA->word == XB->word;

	else
	    r = -1;   /* Use UNICODE values for comparision */

    } else 
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_s_iso2022_same_char_gen",
	      "Bad bank number",0);

    if (0 == r && ignore_case) 
	r = -1;  /* Use UNICODE values for comparision */
    
    return r;
}

S_(cs_state_printable cs_s_iso2022_printable_gen)
static int cs_s_iso2022_printable_gen(st)
     struct charset_state *st;
{
    int r = -1;

    struct state_iso2022 * X  = st->p->a.iso2022;
    
    if (STATE_ISO2022_magic != X->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_s_iso2022_printable_gen",
	      "Bad magic number (state)",0);

    if (bank_unspecified == X->bank)
	r = 32 == X->word;          /* Assume that space is only printable
					control character */
    else
	r = -1;   /* Use UNICODE to look printable characters */

    return r;
}

/* If character corresponds one byte on stream, returns it.
 * Otherwise returns 0. This is used implement ReadCh().
 * It is assumed that returned character corresponds to
 * code character set (and perhaps also US-ASCII)
 */
S_(cs_state_is_onebyte cs_s_iso2022_is_onebyte_gen)
static int cs_s_iso2022_is_onebyte_gen(st)
     struct charset_state *st;
{
    int r = 0;

    struct state_iso2022 * X  = st->p->a.iso2022;
    
    if (STATE_ISO2022_magic != X->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_s_iso2022_is_onebyte_gen",
	      "Bad magic number (state)",0);

    if (bank_unspecified == X-> bank) {
	if (X->word < 128)
	    r = X->word;
    } else if (X->bank >= 0 && X->bank <  ISO2022_BANK_NUM) {
	/* NOTE:
	   I think that it is better not to test
	           iso2022_96 == X->banks[X->bank].type
	   although it is one byte set. One byte sets (without
	   escape switching use range 160-255) for that normally
	*/

	if (iso2022_94 == X->banks[X->bank].type) {
	    if (X->word >= 96)
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "cs_s_iso2022_is_onebyte_gen",
		      "Bad word on iso2022_94 or iso2022_96",0);
		
	    r = X->word + 32;
	}
    } else
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "cs_s_iso2022_is_onebyte_gen",
	      "Bad bank number",0);

    return r;
}

S_(cs_set_properties cs_iso2022_properties_gen)
static int cs_iso2022_properties_gen(st)
     charset_t st;
{
    int prop = 0;

    if (st->map_info && st->iso2022_info)
	prop |= CS_mapping | CS_printable | CS_printable_len;

    return prop;
}

S_(cs_iso2022_info_set cs_iso2022_info_set_iso2022)
static int cs_iso2022_info_set_iso2022(new_vals, new_setlist,setcount)
     struct charcode_info *new_vals;
     struct setlist       *new_setlist;
     int setcount;
{
    int i;

    /* No requirements? */

    for (i = setcount; 
	 i < sizeof (new_setlist->sets) / sizeof (new_setlist->sets[0]);
	 i++)
	new_setlist->sets[i] = NULL;


    new_vals->iso2022_info = loc_setlist(*new_setlist);
    new_vals->flags       &= ~SET_nodata;

    return 1;
}

S_(cs_iso2022_info_set cs_iso2022_info_set_euc)
static int cs_iso2022_info_set_euc(new_vals, new_setlist,setcount)
     struct charcode_info *new_vals;
     struct setlist       *new_setlist;
     int setcount;
{
    int banks[ISO2022_BANK_NUM];

    int i;

    for (i = 0; i < ISO2022_BANK_NUM; i++)
	banks[i] = -1;
    
    for (i = 0; i < setcount; i++) {
	if (new_setlist->sets[i]->bank >= 0 &&
	    new_setlist->sets[i]->bank <= ISO2022_BANK_NUM) {
	    if (-1 == banks[new_setlist->sets[i]->bank])
		banks[new_setlist->sets[i]->bank] = i;
	    else {
		lib_error(CATGETS(elm_msg_cat, MeSet, MeNoSeveralBank,
				  "Charset type %s does not allow several bank-G%d specifications"),
			  new_vals->charset_type->type_name,
			  new_setlist->sets[i]->bank);
		return 0; /* Discard bank defination */
	    }
	}
    }

    for (i = setcount; 
	 i < sizeof (new_setlist->sets) / sizeof (new_setlist->sets[0]);
	 i++)
	new_setlist->sets[i] = NULL;


    new_vals->iso2022_info = loc_setlist(*new_setlist);
    new_vals->flags       &= ~SET_nodata;

    return 1;
}


struct charset_type cs_iso2022    =  { "iso2022",
				       cs_init_iso2022_gen,
				       cs_free_iso2022_gen,
				       cs_add_streambyte_to_iso2022_gen,
				       cs_add_intdata_to_iso2022_gen,
				       cs_check_length_iso2022_gen,
				       cs_give_unicode_from_iso2022_gen,
				       cs_add_unicodedata_to_iso2022_gen,
				       cs_cmp_iso2022_gen,
				       cs_stream_from_iso2022,
				       cs_can_ascii_iso2022_gen,  
				       cs_streamclip_from_iso2022,
				       cs_clip_from_iso2022_gen,  
				       cs_find_pattern_from_iso2022_gen,
				       cs_add_streambytes_to_iso2022_gen,
				       cs_find_iso2022,
				       cs_remove_control_iso2022_gen,   
				       cs_add_state_to_iso2022_gen,
				       cs_init_s_iso2022,
				       cs_free_s_iso2022_gen,
				       cs_add_streambyte_to_s_iso2022_gen,
				       cs_soft_reset_s_iso2022_gen,
				       cs_give_unicode_from_s_iso2022,
				       cs_s_iso2022_same_char_gen,
				       cs_s_iso2022_printable_gen,
				       cs_s_iso2022_is_onebyte_gen,
				       cs_iso2022_properties_gen,
				       cs_estimate_clip_iso2022,
				       cs_iso2022_info_set_iso2022,
				       &cs_euc,
};

struct charset_type cs_euc        =  { "euc",
				       cs_init_iso2022_gen,
				       cs_free_iso2022_gen,
				       cs_add_streambyte_to_iso2022_gen,
				       cs_add_intdata_to_iso2022_gen, 
				       cs_check_length_iso2022_gen,
				       cs_give_unicode_from_iso2022_gen,
				       cs_add_unicodedata_to_iso2022_gen,
				       cs_cmp_iso2022_gen,
				       cs_stream_from_euc,
				       cs_can_ascii_iso2022_gen,  
				       cs_streamclip_from_euc,
				       cs_clip_from_iso2022_gen,  
				       cs_find_pattern_from_iso2022_gen,  
				       cs_add_streambytes_to_iso2022_gen, 
				       cs_find_euc, 
				       cs_remove_control_iso2022_gen,   
				       cs_add_state_to_iso2022_gen, 
				       cs_init_s_euc, 
				       cs_free_s_iso2022_gen,
				       cs_add_streambyte_to_s_iso2022_gen, 
				       cs_soft_reset_s_iso2022_gen, 
				       cs_give_unicode_from_s_iso2022,
				       cs_s_iso2022_same_char_gen, 
				       cs_s_iso2022_printable_gen, 
				       cs_s_iso2022_is_onebyte_gen, 
				       cs_iso2022_properties_gen, 
				       cs_estimate_clip_iso2022,
				       cs_iso2022_info_set_euc,
				       NULL 
};



/*
 * Local Variables:
 *  mode:c
 *  c-basic-offset:4
 *  buffer-file-coding-system: iso-8859-1
 * End:
 */


syntax highlighted by Code2HTML, v. 0.9.1