/********************************************

	Gaiji Func

*********************************************/
#include    "defs.h"

#define	GAIJI_TOP	0x7521
#define	GAIJI_MAX	188

#define	ZEN_SIZE	32		/* 16x16 */
#define	ZEN_BLOCK	32		/* 1024 / ZEN_SIZE */

#define	HAN_SIZE	16		/* 8x16 */
#define	HAN_BLOCK	64		/* 1024 / ZEN_SIZE */

#define	MAP_HASH	16
#define	MAP_MASK	(MAP_HASH - 1)

#define	HAN_MATCH	001
#define	ZEN_MATCH	002

typedef	struct _GP {
	struct	_GP	*next;
	ushort		code;
	ushort		extc;
	short		id;
} GAITAB;

typedef	struct _GMP {
	struct	_GMP	*next;
	ushort		extc;
	char		hzflag;
	char		str[1];
} GAIMAP;

	int	dicin_gaiji_flag = 0;
	ulong	zen_gaiji_start_block = 0L;
	ulong	zen_gaiji_end_block   = 0L;
	ulong	han_gaiji_start_block = 0L;
	ulong	han_gaiji_end_block   = 0L;
	char	*gaiji_map_file = NULL;

static	GAIMAP	*gaiji_map[MAP_HASH] = {
		NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
		NULL, NULL, NULL, NULL,	NULL, NULL, NULL, NULL
	};
static	ushort	zen_gaiji_top_code = 0xA121;
static	ushort	han_gaiji_top_code = 0xA1A1;
static	GAITAB	gaiji_tab[GAIJI_MAX];
static	GAITAB	*gaiji_top = NULL;
static	uchar	gaiji_buf[BLOCK_SIZE + ZEN_SIZE];

/***************************************

	外字フォントの設定

****************************************/
static	int	Gaiji_set(int code, char *font)
{
#ifdef	FMRGAIJI
    union REGS regs;
    struct SREGS segs;
    char far     *p;

    p = (char far *)font;
    regs.h.ah = 0x08;
    regs.h.dh = 16;
    regs.h.dl = 16;
    regs.h.bh = (uchar)code;
    regs.h.bl = (uchar)(code >> 8);
    regs.x.di = FP_OFF(p);
    segs.ds   = FP_SEG(p);
    int86x(0x91, &regs, &regs, &segs);		/* VDBIOS */
    return (regs.h.ah);
#else
    return ERR;
#endif
}
static	void	Gaiji_bitmap(ushort code, int w, int h, uchar *map)
{
    int     wb, x, y, b;
    uchar   *p;

    printf("Code : %04X\n", code);

    wb = (w + 7) / 8;
    for ( y = 0 ; y < h ; y++ ) {
	p = map;
	b = 0x80;
	for ( x = 0 ; x < w ; x++ ) {
	    putchar((*p & b) ? '#':'-');
	    if ( (b >>= 1) == 0 ) {
		p++;
		b = 0x80;
	    }
	}
	map += wb;
        putchar('\n');
    }
}
void	Gaiji_zenkaku_bitmap()
{
    int     n, max;
    int     wd, he;
    ushort  code = 0xA121;
    ulong   block;

    if ( zen_gaiji_end_block == 0L )
	return;

    block = zen_gaiji_start_block;
    if ( CD_read_sect(block++, 1, gaiji_buf) )
	return;

    wd = gaiji_buf[8];
    he = gaiji_buf[9];
    code = toshort(gaiji_buf + 10);
    max = toshort(gaiji_buf + 12);

    while ( max > 0 && block <= zen_gaiji_end_block ) {
	if ( CD_read_sect(block++, 1, gaiji_buf) )
	    return;
	for ( n = 0 ; n < ZEN_BLOCK && max > 0 ; n++,max-- ) {
	    Gaiji_bitmap(code++, wd, he, gaiji_buf + n * ZEN_SIZE);
	    if ( (code & 0x00FF) > 0x007E )
		code = (code & 0xFF00) + 0x0121;
	}
	for ( n = 0 ; n < ZEN_BLOCK && max > 0 ; n++,max-- ) {
	    Gaiji_bitmap(code++, wd, he, gaiji_buf + 1024 + n * ZEN_SIZE);
	    if ( (code & 0x00FF) > 0x007E )
		code = (code & 0xFF00) + 0x0121;
	}
    }
}
void	Gaiji_hankaku_bitmap()
{
    int     n, max;
    int     wd, he;
    ushort  code = 0xA121;
    ulong   block;

    if ( han_gaiji_end_block == 0L )
	return;

    block = han_gaiji_start_block;
    if ( CD_read_sect(block++, 1, gaiji_buf) )
	return;

    wd = gaiji_buf[8];
    he = gaiji_buf[9];
    code = toshort(gaiji_buf + 10);
    max = toshort(gaiji_buf + 12);

    while ( max > 0 && block <= han_gaiji_end_block ) {
	if ( CD_read_sect(block++, 1, gaiji_buf) )
	    return;
	for ( n = 0 ; n < HAN_BLOCK && max > 0 ; n++,max-- ) {
	    Gaiji_bitmap(code++ | 0x80, wd, he, gaiji_buf + n * HAN_SIZE);
	    if ( (code & 0x00FF) > 0x007E )
		code = (code & 0xFF00) + 0x0121;
	}
	for ( n = 0 ; n < HAN_BLOCK && max > 0 ; n++,max-- ) {
	    Gaiji_bitmap(code++ | 0x80, wd, he, 
				gaiji_buf + 1024 + n * HAN_SIZE);
	    if ( (code & 0x00FF) > 0x007E )
		code = (code & 0xFF00) + 0x0121;
	}
    }
}
void	Gaiji_tab_init()
{
    int    n, code;

    gaiji_top = NULL;
    code = GAIJI_TOP;
    for ( n = 0 ; n < GAIJI_MAX ; n++ ) {
	gaiji_tab[n].next = gaiji_top;
	gaiji_top = &(gaiji_tab[n]);
	gaiji_tab[n].id   = (-1);
	gaiji_tab[n].extc = 0;
	gaiji_tab[n].code = code++;
	if ( (code & 0x00FF) > 0x007E )
	    code = (code & 0xFF00) + 0x0121;
    }
}
void	Gaiji_init(int zen, int han)
{
    ulong  start_block;
    ulong  end_block;

    if ( dicin_gaiji_flag != 0 ) {
	if ( (dicin_gaiji_flag & 1) == 0 )
	    zen_gaiji_end_block   = 0L;
	if ( (dicin_gaiji_flag & 2) == 0 )
	    han_gaiji_end_block   = 0L;
	goto INIT;
    }

    zen_gaiji_end_block   = 0L;
    han_gaiji_end_block   = 0L;

    start_block = file_start_block;
    end_block   = file_end_block;

    if ( zen != 0 && !CD_file_open(zen) ) {
	zen_gaiji_start_block = file_start_block;
	zen_gaiji_end_block   = file_end_block;
    }
    if ( han != 0 && !CD_file_open(han) ) {
	han_gaiji_start_block = file_start_block;
	han_gaiji_end_block   = file_end_block;
    }

    file_start_block = start_block;
    file_end_block   = end_block;

INIT:
    if ( zen_gaiji_end_block != 0L ) {
	if ( CD_read_sect(zen_gaiji_start_block, 1, gaiji_buf) )
	    zen_gaiji_end_block = 0L;
	else
	    zen_gaiji_top_code = toshort(gaiji_buf + 10);
    }

    if ( han_gaiji_end_block != 0L ) {
	if ( CD_read_sect(han_gaiji_start_block, 1, gaiji_buf) )
	    han_gaiji_end_block = 0L;
	else
	    han_gaiji_top_code = toshort(gaiji_buf + 10) | 0x0080;
    }
}
void	Gaiji_close()
{
    zen_gaiji_end_block   = 0L;
    han_gaiji_end_block   = 0L;
}
uchar	*Gaiji_convert(uint *extc)
{
    int     n;
    uint    a, b;
    ulong   block;
    uint    offset;
    int     len;
    GAITAB  *gp, *bp;
    GAIMAP  *mp;

    mp = gaiji_map[*extc & MAP_MASK];
    while ( mp != NULL ) {
	switch(mp->hzflag) {
	case HAN_MATCH:
	case ZEN_MATCH:
	    if ( *extc == mp->extc )
		return mp->str;
	    break;
	case HAN_MATCH | ZEN_MATCH:
	    if ( (*extc & 0xFF7F) == mp->extc )
		return mp->str;
	    break;
	}
	mp = mp->next;
    }

    if ( gaiji_flag == FALSE || gaiji_top == NULL )
	goto ERROR2;

    bp = gp = gaiji_top;
    for ( ; ; ) {
	if ( gp->extc == *extc && gp->id == now_dev_id ) {
	    if ( gp != bp ) {
	        bp->next = gp->next;
	        gp->next = gaiji_top;
	        gaiji_top = gp;
	    }
	    *extc = gp->code;
	    return NULL;
	}
	if ( gp->next == NULL )
	    break;
	bp = gp;
	gp = gp->next;
    }
    bp->next = gp->next;
    gp->next = gaiji_top;
    gaiji_top = gp;
    gp->extc = *extc;
    gp->id   = now_dev_id;

    if ( (*extc & 0x0080) == 0 ) {		/* ZenKaku */
	a = *extc - zen_gaiji_top_code;
	b = ((a >> 8) & 0x00FF) * 94 + (a & 0x00FF);
	a = b / ZEN_BLOCK;
	b = b % ZEN_BLOCK;
	block  = zen_gaiji_start_block + (a / 2) + 1;
	offset = b * ZEN_SIZE + (a & 1) * 1024;
	len    = ZEN_SIZE;
	if ( block < zen_gaiji_start_block || block > zen_gaiji_end_block )
	    goto ERROR;

    } else {					/* HanKaku */
	a = *extc - han_gaiji_top_code;
	b = ((a >> 8) & 0x00FF) * 94 + (a & 0x00FF);
	a = b / HAN_BLOCK;
	b = b % HAN_BLOCK;
	block  = han_gaiji_start_block + (a / 2) + 1;
	offset = b * HAN_SIZE + (a & 1) * 1024;
	len    = HAN_SIZE;
	if ( block < han_gaiji_start_block || block > han_gaiji_end_block )
	    goto ERROR;
    }

    if ( CD_read_sect(block, 1, gaiji_buf) )
	goto ERROR;

    if ( len == HAN_SIZE ) {		/* 8x16 Onry */
	for ( n = HAN_SIZE - 1 ; n >= 0 ; n-- ) {
	    gaiji_buf[offset + n * 2 + 1] = gaiji_buf[offset + n] << 4;
	    gaiji_buf[offset + n * 2 + 0] = gaiji_buf[offset + n] >> 4;
	}
    }

    if ( Gaiji_set(gp->code, gaiji_buf + offset) )
	goto ERROR;

    *extc = gp->code;
    return NULL;

ERROR:
    gp->extc = 0;

ERROR2:
    if ( gaiji_map_file == NULL ) {
        *extc = 0x2222;
        return NULL;
    }
    sprintf(gaiji_buf, "[%04X]", *extc);
    return gaiji_buf;
}
int	Gaiji_config(char *file)
{
    int     n, ch;
    int     hzflag;
    FILE    *fp;
    GAIMAP  *gp;
    char    *p;
    int     code;

    if ( gaiji_map_file != NULL )
	free(gaiji_map_file);

    for ( n = 0 ; n < MAP_HASH ; n++ ) {
	while ( (gp = gaiji_map[n]) != NULL ) {
	    gaiji_map[n] = gp->next;
	    free(gp);
	}
    }

    gaiji_map_file = strdup(file);

    if ( (fp = fopen(file, "r")) == NULL )
	return ERR;

    while ( fgets(gaiji_buf, 128, fp) != NULL ) {
	if ( (p = strchr(gaiji_buf, '\n')) != NULL )
	    *p = '\0';
	for ( p = gaiji_buf ; isspace((uchar)*p) ; p++ )
	    ;

	if ( (ch = toupper(*p)) == 'H' || ch == 'Z' )
	    p++;

	if ( (code = htoi(p)) == 0 )
	    continue;

	while ( isxdigit(*p) )
	    p++;

	if ( *p == 'h' || *p == 'H' || ch == 'H' ) {
	    hzflag = HAN_MATCH;
	    code |= 0x0080;
	    p++;
	} else if ( *p == 'z' || *p == 'Z' || ch == 'Z' ) {
	    hzflag = ZEN_MATCH;
	    code &= 0xFF7F;
	    p++;
	} else if ( (code & 0x0080) != 0 ) {
	    hzflag = HAN_MATCH;
	} else {
	    hzflag = HAN_MATCH | ZEN_MATCH;
	}

	while ( isspace((uchar)*p) || *p == '=' )
	    p++;

	if ( (gp = (GAIMAP *)malloc(sizeof(GAIMAP) + strlen(p))) == NULL ) {
	    fprintf(stderr, "Gaiji Maping Memory Alloc Error\n");
	    fclose(fp);
	    return ERR;
	}

	gp->next = gaiji_map[code & MAP_MASK];
	gaiji_map[code & MAP_MASK] = gp;
	gp->extc = code;
	gp->hzflag = hzflag;
	strcpy(gp->str, p);
    }

    fclose(fp);
    return FALSE;
}
int	Gaiji_maping(int code, char *str)
{
    int     n;
    FILE    *fp;
    GAIMAP  *gp;

    for ( gp = gaiji_map[code & MAP_MASK] ; gp != NULL ; gp = gp->next ) {
	if ( gp->extc == code )
	    gp->extc = 0;
    }

    if ( (gp = (GAIMAP *)malloc(sizeof(GAIMAP) + strlen(str))) == NULL ) {
	fprintf(stderr, "Gaiji Maping Memory Alloc Error\n");
	return ERR;
    }

    gp->next = gaiji_map[code & MAP_MASK];
    gaiji_map[code & MAP_MASK] = gp;
    gp->extc = code;
    gp->hzflag = (code & 0x0080) ? HAN_MATCH:ZEN_MATCH;
    strcpy(gp->str, str);

    if ( gaiji_map_file == NULL )
	return FALSE;

    if ( (fp = fopen(gaiji_map_file, "w")) == NULL )
	return ERR;

    for ( n = 0 ; n < MAP_HASH ; n++ ) {
        for ( gp = gaiji_map[n] ; gp != NULL ; gp = gp->next ) {
	    if ( gp->extc != 0 )
	        fprintf(fp, "%04X%s=%s\n", 
			gp->extc & 0xFF7F, 
			gp->hzflag == HAN_MATCH ? "h":
			gp->hzflag == ZEN_MATCH ? "z":"",
			gp->str);
	}
    }

    fclose(fp);

    return FALSE;
}
int	Gaiji_display(ushort extc)
{
    uint    a, b;
    ulong   block;
    uint    offset;
    int     wd;

    if ( extc < 0xA121U || extc > 0xFEFEU )
	goto ERROR;

    if ( zen_gaiji_end_block == 0L && han_gaiji_end_block == 0L ) {
	if ( now_dic_menu != NULL )
	    Gaiji_init(now_dic_menu->gaz, now_dic_menu->gah);
	else if ( dicin_gaiji_flag != 0 )
	    Gaiji_init(0, 0);
    }

    if ( (extc & 0x0080) == 0 ) {		/* ZenKaku */
	a = extc - zen_gaiji_top_code;
	b = ((a >> 8) & 0x00FF) * 94 + (a & 0x00FF);
	a = b / ZEN_BLOCK;
	b = b % ZEN_BLOCK;
	block  = zen_gaiji_start_block + (a / 2) + 1;
	offset = b * ZEN_SIZE + (a & 1) * 1024;
	wd = 16;
	if ( block < zen_gaiji_start_block || block > zen_gaiji_end_block )
	    goto ERROR;

    } else {					/* HanKaku */
	a = extc - han_gaiji_top_code;
	b = ((a >> 8) & 0x00FF) * 94 + (a & 0x00FF);
	a = b / HAN_BLOCK;
	b = b % HAN_BLOCK;
	block  = han_gaiji_start_block + (a / 2) + 1;
	offset = b * HAN_SIZE + (a & 1) * 1024;
	wd = 8;
	if ( block < han_gaiji_start_block || block > han_gaiji_end_block )
	    goto ERROR;
    }

    if ( CD_read_sect(block, 1, gaiji_buf) )
	goto ERROR;

    Gaiji_bitmap(extc, wd, 16, gaiji_buf + offset);
    return FALSE;

ERROR:

#ifdef	DEBUG
printf("%04x %08lx \n%08lx %08lx \n%08lx %08lx\n",
	extc, block,
	zen_gaiji_start_block, zen_gaiji_end_block,
	han_gaiji_start_block, han_gaiji_end_block);
#endif

    return ERR;
}
