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

/******************************************************************************
 *  The Elm (ME+) Mail System  -  $Revision: 1.14 $   $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"

DEBUG_VAR(Debug,__FILE__,"charset");

#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif         

static FILE *null_charmap_copy_callback P_((const char *name, 
					    const char *pathname));
static FILE *null_charmap_copy_callback(name,pathname)
     CONST char *name;
     CONST char *pathname;
{
    return NULL;
}

static charmap_copy_callback * copy_cb = null_charmap_copy_callback;

void set_charmap_copy_callback(cb)
     charmap_copy_callback *cb;
{
    copy_cb = cb;

}

int is_on_mapdir(name)
     CONST char *name;
{
    return  NULL == strpbrk(name,"/$\\;{}()");
}

FILE * open_mapname(name,fn)
     CONST char *name;
     char **fn;
{
    int err = 0;
    int map_dir = 0;
      
    if ('\0' == *name)
        return NULL;
    if (is_on_mapdir(name)) {
	/* give_dt_estr_as_str adds / to end */
	char * map_txtdir_val = give_dt_estr_as_str(&map_txtdir_e,
						    "map-text-dir");
	if (!map_txtdir_val)
	    return NULL;
	
	if (0 != access(map_txtdir_val,ACCESS_EXISTS)) {
	    int err = errno;
	    lib_error(CATGETS(elm_msg_cat, MeSet,MeNoTxtMapDir,
			      "Map %s: no map-text-dir exist: %s: %s"),
		      name,map_txtdir_val,error_description(err));
	    return NULL;
	}
	*fn = elm_message(FRM("%s%s"),map_txtdir_val,name);
	map_dir++;
    } else {
	char buffer[STRING];
	if (expand_meta(buffer,name,sizeof buffer) < 0 ||
	    '/' != buffer[0]) {
	    lib_error(CATGETS(elm_msg_cat, MeSet,MeBadMapName,
			      "Map %s: bad map name"),
		      name);
	    return NULL;
	}
	*fn = safe_strdup(buffer);
    }

    err = can_open(*fn,"r");

    if (ENOENT == err && map_dir) {
	FILE *F = copy_cb(name,*fn);
	if (F) {
	    return F;
	}
    }

    if (0 != err) {
	lib_error(CATGETS(elm_msg_cat, MeSet,MeMapCantOpen,
			  "Map %s: can't open %s: %s"),
		  name,*fn,error_description(err));
	
    } else {
	FILE *F = fopen(*fn,"r");
	if (!F) {
	    int err = errno;
	    lib_error(CATGETS(elm_msg_cat, MeSet,MeMapCantOpen,
			      "Map %s: can't open %s: %s"),
		      name,*fn,error_description(err));
	    return NULL;
	}

	return F;
    }
    return NULL;
}

#define ISO2022_MAPINFO_magic   0xF303

struct iso2022_mapinfo {
    unsigned short magic;                /* ISO2022_MAPINFO_magic */
    enum iso2022_settype type;

    struct  map_info *builtin_map;        /* refers builtin ISO8859-X maps */

    char         * name;
    int            flag;

    int            vlen;
    uint16       * vector;


};

#define   PF_RANGE 4

#define   PF_lower 0
#define   PF_upper 2
#define   PF_upper_lower_mask    (PF_lower|PF_upper)

#define   PF_3COL2                1
#define   PF_ascii_lower          (PF_IS_BUILTIN | PF_ascii   | PF_lower )
#define   PF_ascii_upper          (PF_IS_BUILTIN | PF_ascii   | PF_upper )
#define   PF_bytemap_lower        (PF_IS_BUILTIN | PF_bytemap | PF_lower )
#define   PF_bytemap_upper        (PF_IS_BUILTIN | PF_bytemap | PF_upper )
#define   PF_RANGE_lower          (PF_RANGE | PF_lower)
#define   PF_RANGE_upper          (PF_RANGE | PF_upper)

struct iso2022_mapinfo latin_iso2022_map_ascii = {
    ISO2022_MAPINFO_magic, iso2022_94, &map_ascii, 
    NULL,   PF_ascii_lower, 0, NULL }; /* ASCII */

struct  iso2022_mapinfo latin_iso2022_map_latin1 = {
    ISO2022_MAPINFO_magic, iso2022_96, &map_latin1,   
    NULL, PF_ascii_upper, 0, NULL };   /* ISO-8859-1 */ 


#if ANSI_C
static set_map_callmap  NULL_set_map_callmap;
#endif
static int NULL_set_map_callmap(name,map_info,l1,l2,fn)
     CONST char *name;
     struct map_info *map_info;
     long l1;
     long l2;
     CONST char *fn;
{
    panic("ISO2022 PANIC",__FILE__,__LINE__,"NULL_set_map_callmap",
	  "NULL_set_map_callmap called",0);

    return 1;
}

#define MAX_ERROR  5

void read_map_format_a(name,map_info,iso2022_map_info,
		       F,pass_caller,
		       field_count, vector,
		       fn
		       )
     CONST char *name; 
     struct map_info *map_info;
     struct iso2022_mapinfo *iso2022_map_info;
     FILE *F; 
     set_map_callmap * pass_caller;
     int field_count;
     enum  field_type  *vector;
     CONST char *fn;
{
    int l;
    char buffer[STRING];

    int ok = 0;
    int ok_iso2022 = 0;
    int lineno = 0;
    int error_count = 0;


    struct X {
	char * N;
	long   l;
    } * col;

    if (field_count < 2) 
	panic("ISO2022 PANIC",__FILE__,__LINE__,"read_map_format_a",
	      "too few fields",0);

    col   = safe_malloc ( field_count * sizeof (col[0]));

    while (0 < (l = mail_gets(buffer,sizeof buffer,F))) {
	int count = 0;
	int i;

	long l1  = -1;
	long l2  = -1;
	long lmb = -1;

	for (i = 0; i < field_count; i++) {
	    col[i].N = NULL;
	    col[i].l = -1;
	}

	if (buffer[l-1] != '\n') {
	    lib_error(CATGETS(elm_msg_cat, MeSet,MeMapTooLongLine,
			      "Map %s: %s: Too long line: %s"),
		      name,fn,buffer);
	} else {
	    l--;
	    buffer[l] = '\0';
	    lineno++;
	}

	if (buffer[0] == '#')
	    continue;
		
	col[0].N = buffer;
	for (i = 0; i < l; i++) {

	    switch (buffer[i]) {
	    case '\t': {
	    field_separator:
		count++;
		
		
		buffer[i] = '\0';
		
		if (count < field_count) {		   	       		

		    /* Jump column forward  --- THIS is not necessary correct */
		    while (i < l-1 && whitespace(buffer[i+1]))
			i++;

		    col[count].N = &(buffer[i+1]);
		}
	    }
	    break;
	    case ' ': {       /* KSX1001.TXT is not really TAB separated */ 

		if (count < field_count &&
		    vector[count] != val_comment)
		    goto field_separator;

	    }
	    break;
	    }
	}

	if (count < field_count-1 && 
	    val_comment != vector[count+1]) {
	    int i;

	    if (++error_count > MAX_ERROR)
		continue;


	    DPRINT(Debug,9,(&Debug,
			    "%s: line %d -- %d fields:\n",
			    name, lineno,count+1));
	    for (i = 0; i <= count && i < field_count; i++) {
		DPRINT(Debug,9,(&Debug," ... field %d: %s\n",
				i,col[i].N));
	    }
	    DPRINT(Debug,9,(&Debug,
			    " ... line %d: %s\n",
			    lineno,buffer));

	    lib_error(CATGETS(elm_msg_cat, MeSet,MeMapBadLine,
			      "Map %s: %s: line %d: Bad line: %s..."),
		      name,fn,lineno,buffer);

	    if (error_count == MAX_ERROR)
		lib_error(CATGETS(elm_msg_cat, MeSet,MeMapTooManyErr,
				  "Map %s: %s: Too many errors ... rest ignored"),
			  name,fn);
	    continue;
	}

	for (i = 0; i < field_count; i++) {
	    char * end;

	    if (val_comment == vector[i])
		continue;

	    if (count <= i) {
		DPRINT(Debug,12,(&Debug,
				 "%s: line %s... no field %d\n",
				 name, buffer, i));
	    }

	    if (col[i].N == NULL ||
		'\0' == col[i].N[0] ||
		'#' == col[i].N[0]) {

		DPRINT(Debug,9,(&Debug,
				"%s: line %s... no mapping\n",
				name, buffer));

		goto no_mapping;
	    }

	    col[i].l = strtol(col[i].N,&end,16);

	    if (*end != '\0' || col[i].l < 0) {

		if (++error_count <= MAX_ERROR) 
		    lib_error(CATGETS(elm_msg_cat, MeSet,MeMapBadValueLineNo,
				      "Map %s: %s: line %d: Bad value: %s"),
			      name,fn,lineno,col[i].N);

		if (error_count == MAX_ERROR)
		    lib_error(CATGETS(elm_msg_cat, MeSet,MeMapTooManyErr,
				      "Map %s: %s: Too many errors ... rest ignored"),
			      name,fn);
		
		goto no_mapping;
            }

	    switch (vector[i]) {
		int a,b;
	    case val_unicode:          /* We do not support values > 0xFFFF */
		if (col[i].l > 0xFFFF) {
		    if (++error_count <= MAX_ERROR) 
			lib_error(CATGETS(elm_msg_cat, MeSet,MeMapBadValueLineNo,
					  "Map %s: %s: line %d: Bad value: %s"),
				  name,fn,lineno,col[i].N);

		    if (error_count == MAX_ERROR)
			lib_error(CATGETS(elm_msg_cat, MeSet,MeMapTooManyErr,
					  "Map %s: %s: Too many errors ... rest ignored"),
				  name,fn);

		    goto no_mapping;
		}
		break;
	    case val_byte:
		if (col[i].l > 0xFF) {
		    if (++error_count < MAX_ERROR) 
			lib_error(CATGETS(elm_msg_cat, MeSet,MeMapBadValueLineNo,
					  "Map %s: %s: line %d: Bad value: %s"),
				  name,fn,lineno,col[i].N);

		    if (error_count == MAX_ERROR)
			lib_error(CATGETS(elm_msg_cat, MeSet,MeMapTooManyErr,
					  "Map %s: %s: Too many errors ... rest ignored"),
				  name,fn);

		    goto no_mapping;
		}
		break;

	    case val_iso2022_mb:    /* Both bytes should be on range 
				       0x20 -- 0x7F
				    */
		
		a = col[i].l / 256;
		b = col[i].l % 256;

		if (a < 0x20 || b < 0x20 || a > 0x7F || b > 0x7F) {
		    if (++error_count <= MAX_ERROR) 
			lib_error(CATGETS(elm_msg_cat, MeSet,MeMapBadValueLineNo,
					  "Map %s: %s: line %d: Bad value: %s"),
				  name,fn,col[i].N);

		    if (error_count == MAX_ERROR)
			lib_error(CATGETS(elm_msg_cat, MeSet,MeMapTooManyErr,
					  "Map %s: %s: Too many errors ... rest ignored"),
				  name,fn);

		    goto no_mapping;
		}   
		break;
	    }

	    if (val_unicode == vector[i]) {
		l2 = col[i].l;

	    } else if (val_byte == vector[i] && -1 == l1) {
		l1   = col[i].l;
	    } else if (val_iso2022_mb == vector[i] && -1 == lmb) {
		lmb  = col[i].l;
	    } 
	}

	if (NULL_set_map_callmap != pass_caller) {
	    if (l1 != -1 && l2 != -1) {
		if (!pass_caller(name,map_info,l1,l2,fn))
		    continue;
		ok ++;
	    } else {
		DPRINT(Debug,12,(&Debug,
				 "%s: line %s... no intresting values l1=%ld l2=%ld\n",
				 name, buffer,l1,l2));
	    }
	}

	if (iso2022_map_info) {
	    if ( 256 == iso2022_map_info->vlen && 
		 iso2022_other == iso2022_map_info->type) {
		if (l1 >= 0 && l1 < iso2022_map_info->vlen && l2 != -1) {
		    iso2022_map_info->vector[l1] = l2;
		    ok_iso2022++;
		} else {
		    DPRINT(Debug,12,(&Debug,
				     "%s: line %s... no intresting values l1=%ld l2=%ld\n",
				     name, buffer,l1,l2));
		}
	    } else if (96 == iso2022_map_info->vlen &&
		       ( iso2022_94 == iso2022_map_info->type || 
			 iso2022_96 == iso2022_map_info->type )) {
		uint16 Z;

		int A = l1;

		if (PF_upper & iso2022_map_info->flag)
		    A = l1 - 128;

		if (A >= 32 && A < 128 && l2 != -1 &&
		    (Z = ISO2022_1byte_to_word(A)) < iso2022_map_info->vlen) {
		    iso2022_map_info->vector[Z] = l2;
		    ok_iso2022++;
		} else {
		    DPRINT(Debug,12,(&Debug,
				     "%s: line %s... no intresting values l1=%ld l2=%ld\n",
				     name, buffer,l1,l2));	     
		}
	    } else if (96*96 == iso2022_map_info->vlen &&
		       ( iso2022_94x94 == iso2022_map_info->type || 
			 iso2022_96x96 == iso2022_map_info->type )) {
		uint16 Z;
		if (lmb >= 0 && l2 != -1 &&
		    (Z = ISO2022_2byte_to_word(lmb / 256, lmb % 256)) < 
		    iso2022_map_info->vlen) {
		    iso2022_map_info->vector[Z] = l2;
		    ok_iso2022++;
		} else {
		    DPRINT(Debug,12,(&Debug,
				     "%s: line %s... no intresting values lmb=%ld l2=%ld\n",
				     name, buffer,lmb,l2));	    
		}						    
	    } else {
		panic("ISO2022 PANIC",__FILE__,__LINE__,"read_map_format_a",
		      "Bad iso2022_map_info ?",0);
	    }
	}

    no_mapping:
	;
    }

    free(col);
    col = NULL;

    DPRINT(Debug,8,(&Debug,
		    "%s: %d / %d items read\n",
		    name,
		    ok,ok_iso2022));
}
			  
int iso2022_parseflag_ok (flag)
     CONST char * flag;
{
    if (0 == istrcmp("3col=2",flag))
	return PF_3COL2;
    if (0 == istrcmp("ascii=lower",flag))
	return PF_ascii_lower;
    if (0 == istrcmp("ascii=upper",flag))
	return PF_ascii_upper;
    if (0 == istrcmp("one-byte-map=lower",flag))
	return PF_bytemap_lower;
    if (0 == istrcmp("one-byte-map=upper",flag))
	return PF_bytemap_upper;
    if (0 == istrcmp("range=lower",flag))
	return PF_RANGE_lower;
    if (0 == istrcmp("range=upper",flag))
	return PF_RANGE_upper;
    return 0;
}

/* name on STRDUPed --- caller must malloc/strdup name !!! */
static struct iso2022_mapinfo *alloc_iso2022_mapinfo P_((char *name,
							 enum iso2022_settype 
							 type,
							 int code));
static struct iso2022_mapinfo *alloc_iso2022_mapinfo(name,type,code)
     char *name;
     enum iso2022_settype type;
     int code;
{
    struct iso2022_mapinfo * ret = NULL;
    ret = safe_malloc(sizeof (*ret));
    
    ret->magic       = ISO2022_MAPINFO_magic;
    ret->type        = type;
    ret->name        = name;
    ret->flag        = code;
    ret->builtin_map = NULL; 
    
    ret->vlen    = 0;
    ret->vector  = NULL;
    
    return ret;
}

struct iso2022_mapinfo * make_iso2022_map(builtin_map,type,code,flag)
     struct  map_info *builtin_map;
     enum iso2022_settype type;
     int code;
     CONST char *flag;
{
    int ok = 0;
    struct iso2022_mapinfo * ret = NULL;    
   
    switch(type) {
    case iso2022_94: 
	if (builtin_map -> map_type == &cs_ascii)
	    ok = 1;
	if (builtin_map -> map_type == &cs_onebyte)
	    ok = 1;
	break;
    case iso2022_96:       
	if (builtin_map -> map_type == &cs_ascii)
	    ok = 1;
	if (builtin_map -> map_type == &cs_onebyte)
	    ok = 1;
	break;
    }
    
    if (!ok) {
	lib_error(CATGETS(elm_msg_cat, MeSet,MeBuiltinISO2022Unsupported,
			  "Builtin ISO2022 map %s is unsupported or is different type"),
		  builtin_map->map_name);
	
	return NULL;
    }

    ret = alloc_iso2022_mapinfo(NULL,type,code);
    ret->builtin_map = builtin_map;

    return ret;
}

struct iso2022_mapinfo * read_iso2022_map(filename,type,code,flag)
     CONST char *filename;
     enum iso2022_settype type;
     int code;
     CONST char *flag;
{
    struct iso2022_mapinfo * ret = NULL;
    char *fn = NULL;    
    FILE * F; 
    
    if ( (code & PF_RANGE) &&
	 type != iso2022_94 && type != iso2022_96) {
	lib_error(CATGETS(elm_msg_cat, MeSet,MeUnsupportedFlag,
			  "Flag %s is not supported with that bank type"),
		  flag);	
	return NULL;
    }


    F = open_mapname(filename,&fn);

    if (F) {
	int i;

	ret = alloc_iso2022_mapinfo(safe_strdup(filename),type,code);

	switch(type) {
	case iso2022_other:                     ret->vlen = 256;   break;
	case iso2022_94: case iso2022_96:       ret->vlen = 96;    break;
	case iso2022_94x94: case iso2022_96x96: ret->vlen = 96*96; break;
	default:
	    panic("ISO2022 PANIC",__FILE__,__LINE__,"read_iso2022_map",
		  "bad type",0);
	}


	ret->vector = safe_malloc(ret->vlen  * sizeof (ret->vector[0]));

	for (i = 0; i < ret->vlen; i++) {
	    ret->vector[i] = MAPPING_NONE;
	}

	switch (code) {

	case PF_3COL2: {
	    static enum  field_type vector_BYTE3[4] =  { 
		val_ignore, val_byte, val_unicode, val_comment
	    };	
	    static enum  field_type vector_MB3[4] =  { 
		val_ignore, val_iso2022_mb, val_unicode, val_comment
	    };	

	    if (ret->vlen > 256)
		read_map_format_a(filename,NULL,ret,F,
				  NULL_set_map_callmap,
				  4,vector_MB3,fn);
	    
	    else
		read_map_format_a(filename,NULL,ret,F,
				  NULL_set_map_callmap,
				  4,vector_BYTE3,fn);

	}
	break;
	
	case PF_RANGE_lower: case PF_RANGE_upper: {
	    static enum  field_type vector_BYTE2[3] =  { 
		val_byte, val_unicode, val_comment
	    };	

	    read_map_format_a(filename,NULL,ret,F,
			      NULL_set_map_callmap,
			      3,vector_BYTE2,fn);

	}
	break;
	    

	case 0: {
	    static enum  field_type vector_BYTE2[3] =  { 
		val_byte, val_unicode, val_comment
	    };	
	    static enum  field_type vector_MB2[3] =  { 
		val_iso2022_mb, val_unicode, val_comment
	    };	

	    if (ret->vlen > 256)
		read_map_format_a(filename,NULL,ret,F,
				  NULL_set_map_callmap,
				  3,vector_MB2,fn);
	    
	    else
		read_map_format_a(filename,NULL,ret,F,
				  NULL_set_map_callmap,
				  3,vector_BYTE2,fn);
	}
	break;
	}

	fclose(F);
    }
    if (fn)
	free(fn);
    return ret;
}

CONST char * iso2022_mapname(map)
     struct iso2022_mapinfo *map;
{
    if (ISO2022_MAPINFO_magic != map->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"iso2022_mapname",
	      "Bad magic number",0);

    if (!map->name) {
	if (! (map->flag & PF_IS_BUILTIN))
	    panic("ISO2022 PANIC",__FILE__,__LINE__,"iso2022_mapname",
		  "No map_name",0);
	    
	if (!map->builtin_map)
	    panic("ISO2022 PANIC",__FILE__,__LINE__,"iso2022_mapname",
		  "No builtin_map",0);

	return map->builtin_map->map_name;
    }
    return map->name;
}

CONST char * iso2022_mapflags(map)
     struct iso2022_mapinfo *map;
{
    if (ISO2022_MAPINFO_magic != map->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"iso2022_mapflags",
	      "Bad magic number",0);

    switch(map->flag) {

    case PF_3COL2: 
	return "3col=2";

    case PF_ascii_lower:
	return "ascii=lower";
    case PF_ascii_upper:
	return "ascii=upper";

    case PF_bytemap_lower:
	return "one-byte-map=lower";
    case PF_bytemap_upper:
	return "one-byte-map=upper";

    case PF_RANGE_lower:
	return "range=lower";
    case PF_RANGE_upper:
	return "range=upper";

    }

    return NULL;
}

uint16 ISO2022_1byte_to_word(ch1)
     int ch1;
{
    if (ch1 < 32 || ch1 > 127)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"ISO2022_1byte_to_word",
	      "bad byte",0);

    return ch1 -32;
}

uint16 ISO2022_2byte_to_word(ch1,ch2)
     int ch1; 
     int ch2;
{
    if (ch1 < 32 || ch1 > 127 ||
	ch2 < 32 || ch2 > 127)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"ISO2022_2byte_to_word",
	      "bad bytes",0);

    return (ch1 - 32) * 96 + (ch2 - 32);
}

/* 0 == not found, 1 == found */
int map_ISO2022_word_to_unicode(word,type,iso2022_map_index,ret)
     unsigned word;
     enum iso2022_settype type;
     int iso2022_map_index;
     uint16  *ret;
{
    struct iso2022_mapinfo *Mx;

    if (iso2022_map_index < 0 || iso2022_map_index >= iso2022_map_list_count)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "map_ISO2022_word_to_unicode",
	      "iso2022_map_index out of range",0);

    if (!iso2022_map_list[iso2022_map_index].map) {
	DPRINT(Debug,10,(&Debug,
			 "map_ISO2022_word_to_unicode: No map with iso2022_map_index %d\n",
			 iso2022_map_index));
	
	return 0;
    }
    Mx = iso2022_map_list[iso2022_map_index].map; 

    if (ISO2022_MAPINFO_magic != Mx->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,"map_ISO2022_word_to_unicode",
	      "Bad magic number",0);
    
    if (Mx->type != type) 
	panic("ISO2022 PANIC",__FILE__,__LINE__,"map_ISO2022_word_to_unicode",
	      "Map type mismatch",0);

    if (Mx->builtin_map) {
	unsigned int ch = '\0';
	int found;

	switch((Mx->flag) & PF_upper_lower_mask) {
	case PF_lower:

	    if (iso2022_94 == type ||
		iso2022_96 == type) {
		if (word >= 96) {
		    DPRINT(Debug,10,(&Debug,
				     "map_ISO2022_word_to_unicode: word %u out of range (type iso2022_94 or iso2022_96)",
				     word));
		    return 0;
		}
		ch = word + 32;
	    } else 
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "map_ISO2022_word_to_unicode",
		      "unsupported type for PF_BUILTIN_lower",0);
	       
	    break;
	case PF_upper:
	    
	    if (iso2022_94 == type ||
		iso2022_96 == type) {
		if (word >= 96) {
		    DPRINT(Debug,10,(&Debug,
				     "map_ISO2022_word_to_unicode: word %u out of range (type iso2022_94 or iso2022_96)",
				     word));
		    return 0;
		}
		ch = word + 32 + 128;
	    } else 
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "map_ISO2022_word_to_unicode",
		      "unsupported type for PF_BUILTIN_upper",0);
	    
	    break;
	default:
	    panic("ISO2022 PANIC",__FILE__,__LINE__,
		  "map_ISO2022_word_to_unicode",
		  "Bad or unsupported map->flag",0);

	}
	
	if (&cs_onebyte == Mx->builtin_map->map_type)
	    *ret = cs_unicode_bytemap_helper_1(ch,Mx->builtin_map,&found);

	else if (&cs_ascii == Mx->builtin_map->map_type)
	    *ret = cs_unicode_ascii_helper_1(ch,Mx->builtin_map,&found);

	else
	    panic("ISO2022 PANIC",__FILE__,__LINE__,
		  "map_ISO2022_word_to_unicode",
		  "Unsupported builtin map type",0);

	DPRINT(Debug,61,(&Debug,
			 "ISO2022 word %04x type %d map index %d => %04x (found=%d) builtin ch=%c\n",
			 word,type,iso2022_map_index,*ret,found,ch));

	return found;    
    } else {
	if (word >= Mx->vlen) {
	    DPRINT(Debug,10,(&Debug,
			    "map_ISO2022_word_to_unicode: word %u out of range (vector len=%d)",
			     word,Mx->vlen));
	} else if (MAPPING_NONE != Mx->vector[word]) {
	    *ret = Mx->vector[word];

	    DPRINT(Debug,61,(&Debug,
			     "ISO2022 word %04x type %d map index %d => %04x (found) \n",
			     word,type,iso2022_map_index,*ret));
	    
	    return 1;
	}
    }

    DPRINT(Debug,61,(&Debug,
		     "ISO2022 word %04x type %d map index %d => %04x (NOT FOUND)\n",
		     word,type,iso2022_map_index,*ret));
    
    return 0;
}

/* 0 == not found, 1 == found */
int  map_unicode_to_ISO2022_word_1(unicode,type,iso2022_map_index,iso2022_word)
     unsigned               unicode;
     enum iso2022_settype * type;
     int                    iso2022_map_index;
     uint16               * iso2022_word;
{
    struct iso2022_mapinfo *Mx;

    if (iso2022_map_index < 0 || iso2022_map_index >= iso2022_map_list_count)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "map_unicode_to_ISO2022_word_1",
	      "iso2022_map_index out of range",0);

    if (!iso2022_map_list[iso2022_map_index].map) {
	DPRINT(Debug,10,(&Debug,
			 "map_unicode_to_ISO2022_word_1: No map with iso2022_map_index %d\n",
			 iso2022_map_index));
	
	return 0;
    }

    Mx = iso2022_map_list[iso2022_map_index].map; 

    if (ISO2022_MAPINFO_magic != Mx->magic)
	panic("ISO2022 PANIC",__FILE__,__LINE__,
	      "map_unicode_to_ISO2022_word_1",
	      "Bad magic number",0);

    *type = Mx->type;

    if (Mx->builtin_map) {
	int ch = '\0';
	int found = 0;

	if (&cs_onebyte == Mx->builtin_map->map_type)
	    ch = cs_map_bytemap_rev(Mx->builtin_map,unicode,&found);

	else if (&cs_ascii == Mx->builtin_map->map_type)
	    ch = cs_map_ascii_rev(Mx->builtin_map,unicode,&found);
	
	else
	    panic("ISO2022 PANIC",__FILE__,__LINE__,
		  "map_unicode_to_ISO2022_word_1",
		  "Unsupported builtin map type",0);
		

	if (found) 
	    switch((Mx->flag) & PF_upper_lower_mask) {
	    case PF_lower:

		if (iso2022_94 == Mx->type ||
		    iso2022_96 == Mx->type) {
		    if (ch < 32 || ch > 127) {
			DPRINT(Debug,10,(&Debug,
					 "map_unicode_to_ISO2022_word_1: char %c (unicode %u)  out of range (type iso2022_94 or iso2022_96, PF_BUILTIN_lower)",
					 ch,unicode));
			return 0;
		    }

		    *iso2022_word = ch - 32;

		    DPRINT(Debug,63,(&Debug,
				     "map_unicode_to_ISO2022_word_1: iso2022_map_index=%d %04x => %04x (ch=%02x lower) [%s]\n",
				     iso2022_map_index,unicode,
				     *iso2022_word,ch,
				     Mx->builtin_map->map_name ? 
				     Mx->builtin_map->map_name :
				     "???"));


		    return 1;
		} else 
		    panic("ISO2022 PANIC",__FILE__,__LINE__,
			  "map_unicode_to_ISO2022_word_1",
			  "unsupported type for PF_BUILTIN_lower",0);

		break;
	    case PF_upper:

		if (iso2022_94 == Mx->type ||
		    iso2022_96 == Mx->type) {
		    if (ch < 32 + 128) {
			DPRINT(Debug,10,(&Debug,
					 "map_unicode_to_ISO2022_word_1: char %c (unicode %u)  out of range (type iso2022_94 or iso2022_96, PF_BUILTIN_upper)",
					 ch,unicode));
			return 0;
		    }
		    
		    *iso2022_word = ch - (32 + 128);

		    DPRINT(Debug,63,(&Debug,
				     "map_unicode_to_ISO2022_word_1: iso2022_map_index=%d %04x => %04x (ch=%02x upper) [%s]\n",
				     iso2022_map_index,unicode,
				     *iso2022_word,ch,
				     Mx->builtin_map->map_name ? 
				     Mx->builtin_map->map_name :
				     "???"));

		    return 1;
		} else 
		    panic("ISO2022 PANIC",__FILE__,__LINE__,
			  "map_unicode_to_ISO2022_word_1",
			  "unsupported type for PF_BUILTIN_upper",0);
		
		break;
	    default:
		panic("ISO2022 PANIC",__FILE__,__LINE__,
		      "map_ISO2022_word_to_unicode",
		      "Bad or unsupported map->flag",0);		
	    }

	DPRINT(Debug,63,(&Debug,
			 "map_unicode_to_ISO2022_word_1: iso2022_map_index=%d %04x  (ch=%02x) not found [%s]\n",
			 iso2022_map_index,unicode,
			 ch,
			 Mx->builtin_map->map_name ? 
			 Mx->builtin_map->map_name :
			 "???"));

    } else {
	int i;
	/* TODO: Fix this
	   -- VERY ineffective 
	*/

	for (i = 0; i < Mx->vlen; i++) {
	    if (unicode == Mx->vector[i]) {
		*iso2022_word = i;

		DPRINT(Debug,63,(&Debug,
				 "map_unicode_to_ISO2022_word_1: iso2022_map_index=%d %04x => %04x\n",
				 iso2022_map_index,unicode,
				 *iso2022_word));

		return 1;
	    } 
	}
	DPRINT(Debug,63,(&Debug,
			 "map_unicode_to_ISO2022_word_1: iso2022_map_index=%d %04x   not found (len=%d)\n",
			 iso2022_map_index,unicode,Mx->vlen));

    }
       
    return 0;
}

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


syntax highlighted by Code2HTML, v. 0.9.1