/*
 * Copyright (C) 1995	Edward Der-Hua Liu, Hsin-Chu, Taiwan
 */

#include "big5con.h"

#define b2cpy(a,b) memcpy(a,b,2)

extern u_char  *ch_pho;
extern char    *ph_pho[];

extern int      ityp3_pho;
extern u_char   typ_pho[];
extern char     inph[];

extern u_short  idxnum_pho, idx_pho[];
extern u_short  hash_pho[];
extern PHOKBM   phkbm;

char            tsfname[64] = "";
char            tsidxfname[64] = "";
static int      phcount, a_phcount;
static int      hashidx[256];
static int     *phidx;

typedef struct {
    u_char          ch[2];
    u_short         ph;
}               ITPH;

static ITPH    *sel1st;
static u_short  sel1st_hash[256];
static int      sel1st_n;
int             going_key = 0;

#define MAX_PH_BF (42)
static u_char   ch_buf[MAX_PH_BF + 1][2];
static u_char   ch_obuf[MAX_PH_BF + 1][2];
static u_short  ph_buf[MAX_PH_BF + 1];
static u_char   pox[MAX_PH_BF + 1];
static u_char   psta[MAX_PH_BF + 1];
static int      psta_cnt[MAX_PH_BF + 1];
static int      c_idx, c_len, c_x, c_xlen, ph_sta = -1;
static FILE    *fph;
static int      sel_pho;
extern int      cursor_x;
static int      eng_ph = 1, ph_hf = 0;
static int      save_frm, save_to, save_mode;

static u_short  tk[5];
static u_char   tch[5][2];
static u_long   sti, edi;

static void 
prch(u_char * s)
{
    char            tt[3];
    if (s[0] > 128)
	b2cpy(tt, s);
    else {
	tt[0] = *s;
	tt[1] = 0;
    }
    tt[2] = 0;
    xprintf("%s", tt);
    /* printf("### %s\n",tt); */
}

static void 
drawcursor()
{
#if	0
    printf("idx:%d %d\n", c_idx, pox[c_idx]);
#endif
    gotox(c_x = pox[c_idx]);
    set_att(InAreaColor);
    prch(ch_buf[c_idx]);
    set_att(NormalColor);
}

static void 
clrcursor()
{
#if	0
    printf("c_idx:%d %d\n", c_idx, pox[c_idx]);
#endif
    gotox(pox[c_idx]);
    prch(ch_buf[c_idx]);
}

static void 
putbuf(u_char s[][2], int len)
{
    u_char          tt[128];
    int             i, idx;

    for (idx = i = 0; i < len; i++) {
	if (s[i][0] >= 128) {
	    b2cpy(&tt[idx], &s[i][0]);
	    idx += 2;
	} else
	    tt[idx++] = s[i][0];
    }
    tt[idx] = 0;
    putstr(tt);
}

static void 
prbuf()
{
    int             i;
    ClrSelArea();
    for (i = 0; i <= c_len; i++) {
	pox[i] = cursor_x;
	prch(ch_buf[i]);
    }
    drawcursor();
}

static void 
restore_ai()
{
    if (sel_pho)
	return;
    ClrSelArea();
    clrin_pho();
    disp_in_area_pho();
    prbuf();
}

static void 
clr_ch_buf()
{
    int             i;
    for (i = 0; i <= MAX_PH_BF; i++) {
	ch_buf[i][0] = ' ';
	ch_buf[i][1] = 0;
	psta[i] = 0xff;
    }
    ph_sta = -1;
}


void 
show_stat()
{
    static char    *str_eng_ph[] = {"­^", "ª`"};

    gotox(0);
    xprintf("[µü­µ/%s]", str_eng_ph[eng_ph]);
}


void 
init_tab_pp(int usenow)
{
    FILE           *fr;
    int             i, cou;
    unsigned int    ttt;
    extern char     TabDir[];
    extern char    *tabfname[];
    char            phofname[128];

    if (!ch_pho)
	init_tab_pho(0);

    if (phcount) {
disp_prom:
	show_stat();
	restore_ai();
	return;
    }
    if (!tsfname[0]) {
	char            tt[128];
	char            vv[128];
	DIR            *dir;
#ifndef  NO_PRIVATE_TSIN
	strcpy(tt, (char *)getenv("HOME"));
	strcat(tt, "/xcin_dir");
	seteuid(getuid());
	if ((dir = opendir(tt)) == NULL) {
	    void            (*sigf) (int);
	    mkdir(tt, 0755);
	    sprintf(vv, "/bin/cp %s/tsin* %s > /dev/null 2>&1", TabDir, tt);
	    sigf = signal(SIGCHLD, SIG_DFL);
	    system(vv);
	    signal(SIGCHLD, sigf);
	} else
	    closedir(dir);
	seteuid(0);
	strcat(tt, "/tsin");
	strcpy(tsfname, tt);
#else
	strcpy(tsfname, TabDir);
	strcat(tsfname, "tsin");
#endif
    }
    strcpy(tsidxfname, tsfname);
    strcat(tsidxfname, ".idx");

    if ((fr = fopen(tsidxfname, "r")) == NULL) {
	error("Cannot open %s\n", tsidxfname);
	return;
    }
    fread(&phcount, 4, 1, fr);
#if	0
    printf("phcount:%d\n", phcount);
#endif
    a_phcount = phcount + 256;
    fread(&hashidx, 1, sizeof(hashidx), fr);
    if ((phidx = (int *)malloc(a_phcount * 4)) == NULL) {
	p_err("malloc err pp 1");
    }
    fread(phidx, 4, phcount, fr);
    fclose(fr);

    strcpy(phofname, TabDir);
    strcat(phofname, "pho.sel1st");
    if ((fr = fopen(phofname, "r")) == NULL) {
	error("Cannot open %s", phofname);
	return;
    }
    fread(&sel1st_n, 4, 1, fr);
    fread(sel1st_hash, 2, 256, fr);
    if ((sel1st = (ITPH *) malloc(sel1st_n * sizeof(ITPH))) == NULL)
	p_err("malloc err pp 2");
    fread(sel1st, sizeof(ITPH), sel1st_n, fr);
    fclose(fr);
    /* printf("1st_n:%d\n", sel1st_n); */

    seteuid(getuid());
    if ((fph = fopen(tsfname, "r+")) == NULL) {
	error("Cannot open %s", tsfname);
	return;
    }
    seteuid(0);

    tabfname[6] = (char *)1;
    clr_ch_buf();
    goto disp_prom;
}

#if	0
void 
prph(u_short kk)
{
    u_int           k1, k2, k3, k4;
#define pk ph_pho
    k4 = (kk & 7) << 1;
    kk >>= 3;
    k3 = (kk & 15) << 1;
    kk >>= 4;
    k2 = (kk & 3) << 1;
    kk >>= 2;
    k1 = (kk & 31) << 1;
    printf("%c%c%c%c%c%c%c%c",
	   pk[0][k1], pk[0][k1 + 1],
	   pk[1][k2], pk[1][k2 + 1],
	   pk[2][k3], pk[2][k3 + 1],
	   pk[3][k4], pk[3][k4 + 1]);
#undef pk
}
#endif	/* 0 */

static 
phseq(u_char * a, u_char * b)
{
    int             lena, lenb, i, mlen;
    u_short         ka, kb;

    lena = *(a++);
    lenb = *(b++);
    mlen = lena > lenb ? lenb : lena;
    for (i = 0; i < mlen; i++) {
	memcpy(&ka, a, 2);
	memcpy(&kb, b, 2);
	if (ka > kb)
	    return 1;
	if (ka < kb)
	    return -1;
	a += 2;
	b += 2;
    }
    if (lena > lenb)
	return 1;
    if (lena < lenb)
	return -1;
    return 0;
}

static void 
save_phrase()
{
    int             tt, ofs, top, bottom, mid, ord, ph_ofs, hashno, hashno_end,
                    i;
    FILE           *fw;
    u_char          len, tbuf[24], sbuf[24], ch[16];

    if (save_frm == save_to)
	return;
    if (save_frm > save_to) {
	tt = save_frm;
	save_frm = save_to;
	save_to = tt;
    }
    if (save_to == c_len)
	save_to--;

    len = save_to - save_frm + 1;
    if (len < 2 || len > 5)
	return;

    for (i = save_frm; i <= save_to; i++)
	if (!ph_buf[i])
	    return;

    tbuf[0] = len;
    memcpy(&tbuf[1], &ph_buf[save_frm], 2 * len);
    memcpy(&tbuf[2 * len + 1], ch_buf[save_frm], 2 * len);

    hashno = ph_buf[save_frm] >> 6;
    for (mid = hashidx[hashno]; mid < hashidx[hashno + 1]; mid++) {
	ph_ofs = phidx[mid];
	fseek(fph, ph_ofs, SEEK_SET);
	fread(sbuf, 1, 1, fph);
	fread(&sbuf[1], 4, sbuf[0], fph);
	if ((ord = phseq(sbuf, tbuf)) >= 0)
	    break;
    }

    tt = sbuf[0] * 2;
    if (!ord && !memcmp(&sbuf[tt + 1], ch_buf[save_frm], tt)) {
	bell();
	goto cursor_end;
    }
    for (i = phcount; i >= mid; i--)
	phidx[i + 1] = phidx[i];

    fseek(fph, 0, SEEK_END);
    ph_ofs = ftell(fph);
    phidx[mid] = ph_ofs;
    phcount++;
    if (phcount >= a_phcount) {
	a_phcount += 256;
	if (!(phidx = (int *)realloc(phidx, a_phcount * 4))) {
	    p_err("tsin.c:realloc err");
	}
    }
    fwrite(tbuf, 1, 4 * len + 1, fph);
    fflush(fph);

    if (hashidx[hashno] > mid)
	hashidx[hashno] = mid;
    hashno++;
    for (; hashno < 256; hashno++)
	hashidx[hashno]++;

    seteuid(getuid());
    if ((fw = fopen(tsidxfname, "w")) == NULL) {
	error("%s create err", tsidxfname);
	return;
    }
    seteuid(0);

    fwrite(&phcount, 4, 1, fw);
    fwrite(&hashidx, sizeof(hashidx), 1, fw);
    fwrite(phidx, 4, phcount, fw);
    fclose(fw);

cursor_end:

    clrcursor();
    ph_sta = -1;
    c_idx = c_len;
    drawcursor();

}

static void 
shift_ins()
{
    int             i, j;

    if (!c_idx && c_xlen >= MAX_PH_BF) {
	c_len--;
	c_xlen -= 2;
    } else if (c_xlen >= MAX_PH_BF) {
	int             ofs;

	if (!(ch_buf[0][0] & 0x80) && (ch_buf[1][0] & 0x80)) {
	    putbuf(ch_buf, 2);
	    ofs = 2;
	    c_xlen -= 3;
	    c_x -= 3;
	} else if (!(ch_buf[0][0] & 0x80) && !(ch_buf[1][0] & 0x80)) {
	    putbuf(ch_buf, 2);
	    ofs = 2;
	    c_xlen -= 2;
	    c_x -= 2;
	} else {
	    putbuf(ch_buf, 1);
	    ofs = 1;
	    c_xlen -= 2;
	    c_x -= 2;
	}
	ph_sta -= ofs;
	for (j = 0; j < MAX_PH_BF - ofs; j++) {
	    memcpy(ch_buf[j], ch_buf[j + ofs], 2);
	    memcpy(ch_obuf[j], ch_obuf[j + ofs], 2);
	    ph_buf[j] = ph_buf[j + ofs];
	    psta[j] = psta[j + ofs] - ofs;
	}
	c_idx -= ofs;
	c_len -= ofs;
	prbuf();
    }
    c_len++;
    if (c_idx < c_len - 1) {
	for (j = c_len; j >= c_idx; j--) {
	    memcpy(ch_buf[j + 1], ch_buf[j], 2);
	    memcpy(ch_obuf[j + 1], ch_obuf[j], 2);
	    ph_buf[j + 1] = ph_buf[j];
	    psta[j + 1] = psta[j] + 1;
	}
	ch_buf[c_len][0] = ' ';
	/* prbuf(); */
    }
}


static u_char   selstr[6][5][2], sellen[6];
static int      maxi, selidx[6];
static void 
sel_phr()
{
    int             sti, edi, i, j;
    u_short         key, tk[10];
    u_char          len, mlen, tch[10][2], tt[3];

    mlen = c_len - c_idx;
    if (mlen > 5)
	mlen = 5;
    key = ph_buf[c_idx];
    j = key >> 6;
    sti = hashidx[j];
    edi = hashidx[j + 1];
    maxi = 0;
    ClrSelArea();
    while (sti < edi && maxi < 5) {
	i = phidx[sti];
	fseek(fph, i, SEEK_SET);
	fread(&len, 1, 1, fph);
	if (len > mlen) {
	    sti++;
	    continue;
	}
	fread(tk, 2, len, fph);
	if (!memcmp(&ph_buf[c_idx], tk, 2 * len)) {
	    fread(tch, 2, (int)len, fph);
	    sellen[maxi] = len;
	    selidx[maxi] = sti;
	    memcpy(selstr[maxi++], tch, 2 * len);
	    xprintf("%d", maxi);
	    for (i = 0; i < len; i++) {
		xprintf("%c%c", tch[i][0], tch[i][1]);
	    }
	    xprintf(" ");
	}
	sti++;
    }
    if (maxi)
	sel_pho = 1;
    else
	sel_pho = 2;
}

static 
u_short_seq(u_short * a, u_short * b, int len)
{
    int             i;
    for (i = 0; i < len; i++)
	if (a[i] > b[i])
	    return 1;
	else if (a[i] < b[i])
	    return -1;

    return 0;
}

static u_char 
scanphr(u_short * pp, int plen)
{
    int             i, top, bot, mid, cmp;
    u_short         ss[21];
    u_char          len, mlen;

    i = *pp >> 6;
    top = hashidx[i];
    bot = edi = hashidx[i + 1];
    while (top <= bot) {
	mid = (top + bot) >> 1;
	fseek(fph, phidx[mid], SEEK_SET);
	sti++;
	fread(&len, 1, 1, fph);
	fread(ss, 2, len, fph);
	if (len > plen)
	    mlen = plen;
	else
	    mlen = len;
	cmp = u_short_seq(ss, pp, mlen);

	if (!cmp && len < plen)
	    cmp = -1;
	if (cmp > 0)
	    bot = mid - 1;
	else if (cmp < 0)
	    top = mid + 1;
	else
	    break;
    }

    if (cmp)
	return 0;

    for (; mid >= 0; mid--) {
	fseek(fph, phidx[mid], SEEK_SET);
	fread(&len, 1, 1, fph);
	fread(tk, 2, len, fph);
	if (len >= plen && !u_short_seq(tk, pp, plen))
	    continue;
	break;
    }

    mid++;
    sti = mid;
    fseek(fph, phidx[mid], SEEK_SET);
    fread(&len, 1, 1, fph);
    fread(tk, 2, len, fph);
    fread(tch, 2, len, fph);
    return len;
}

static 
raise_phr(int c)
{
    int             i, j, tmp;
    FILE           *fp;

    if (!c)
	return;
    i = selidx[c];
    j = selidx[0];
    tmp = phidx[i];
    phidx[i] = phidx[j];
    phidx[j] = tmp;
    selidx[0] = tmp;
    seteuid(getuid());
    if ((fp = fopen(tsidxfname, "r+")) == NULL) {
	error("%s modify err", tsidxfname);
	return;
    }
    seteuid(0);
    fseek(fp, sizeof(phcount) + sizeof(hashidx) + j * 4, SEEK_SET);
    fwrite(&phidx[j], 4, (c + 1), fp);
    fclose(fp);
}

char            ochars[] = "<,>.?/:;\"'{[}]_-+=|\\~`";

#define SELKEY (9)
feedkey_pp(int xkey, int kbstate)
{
    static char     ctyp;
    static u_int    i, ii, ttt, end;
    static u_short  key, tkey;
    u_char         *pp;
    static int      cpg;
    static int      startf;
    static u_char   len;
    static          pho1st_lidx;
    extern u_char   fullchar[];
    int             shift_m = kbstate & KEY_SHIFT_MASK;
    int             j, jj, kk;
    char            tt[3], kno;

    switch (xkey) {
    case VK_Escape:
	save_mode = 0;
	clrin_pho();
	prbuf();
	clr_in_area_pho();
	cpg = sel_pho = 0;
	return 1;
    case VK_Enter:
	if (c_len) {
	    if (shift_m) {
		save_frm = c_idx;
		save_to = c_len - 1;
		save_phrase();
		return 1;
	    }
	    putbuf(ch_buf, c_len);
	    ClrSelArea();
	    c_len = c_xlen = c_idx = 0;
	    c_x = SelAreaX;
	    clr_ch_buf();
	    return 1;
	}
	return 0;
    case VK_Home:
	if (!c_len)
	    return 0;
	clrcursor();
	c_idx = 0;
	c_x = SelAreaX;
	drawcursor();
	return 1;
    case VK_End:
	if (!c_len)
	    return 0;
	clrcursor();
	c_idx = c_len;
	drawcursor();
	return 1;
    case VK_Left:
	if (c_idx) {
	    clrcursor();
	    c_idx--;
	    drawcursor();
	    c_x = pox[c_idx];
	    return 1;
	}
	return 0;
    case VK_Right:
	if (c_idx < c_len) {
	    clrcursor();
	    c_idx++;
	    drawcursor();
	    c_x = pox[c_idx];
	    return 1;
	}
	return 0;
    case VK_Tab:
	eng_ph ^= 1;
	clrcursor();
	if (c_idx == c_len) {
	    if (eng_ph || HalfFull) {
		ch_buf[c_len][0] = 0xa1;
		ch_buf[c_len][1] = 0x40;
	    } else
		ch_buf[c_len][0] = ' ';
	}
	show_stat();
	drawcursor();
	return 1;
    case VK_KP_Multiply:
	if (save_mode) {
	    save_to = c_idx;
	    save_phrase();
	    save_mode = 0;
	    bell();
	} else {
	    save_frm = c_idx;
	    save_mode = 1;
	    bell();
	}
	return 1;
    case VK_Delete:
#if	!DELETE_K
	return 1;
#endif
    case VK_BackSpace:
	ityp3_pho = 0;
	for (j = 3; j >= 0; j--)
	    if (typ_pho[j]) {
		typ_pho[j] = 0;
		disp_in_area_pho();
		return 1;
	    }
	if (!c_idx)
	    return 0;
	{
	    int             k, pst;
	    clrcursor();
	    c_idx--;
	    pst = k = psta[c_idx];
	    if (ch_buf[c_idx][0] & 0x80)
		c_xlen -= 2;
	    else
		c_xlen--;
	    for (k = c_idx; k < c_len; k++) {
		memcpy(ch_buf[k], ch_buf[k + 1], 2);
		memcpy(ch_obuf[k], ch_obuf[k + 1], 2);
		ph_buf[k] = ph_buf[k + 1];
		psta[k] = psta[k + 1] - 1;
	    }
	    c_len--;
	    prbuf();
	    if (!c_idx) {
		ph_sta = -1;
	    } else {
		k = c_idx - 1;
		pst = psta[k];
		while (k > 0 && psta[k] == pst)
		    k--;
		if (psta[k] != pst)
		    k++;
		len = c_idx - k;
		if (!(len = scanphr(&ph_buf[k], len)))
		    ph_sta = -1;
		else
		    ph_sta = k;
	    }
	    return 1;
	}
    case ' ':
    case VK_Down:
    case VK_Up:
	if (going_key && xkey == ' ' &&
	    !typ_pho[0] && !typ_pho[1] && !typ_pho[2] && !typ_pho[3]
	    )
	    goto asc_char;
	/*
	 * if (!going_key && xkey==VK_Down) return 0;
	 */
	if (!eng_ph)
	    goto asc_char;
	if (!ityp3_pho && (typ_pho[0] || typ_pho[1] || typ_pho[2])) {
	    ctyp = 3;
	    kno = 0;
	    if (typ_pho[0] && !typ_pho[1] && !typ_pho[2] && !typ_pho[3]) {
		char            tch = inph[0];
		if (phkbm.phokbm[tch][1][1] == 2) {
		    typ_pho[0] = 0;
		    typ_pho[2] = phkbm.phokbm[tch][1][0];
		}
	    }
	    goto llll1;
	}
	if (c_len) {
	    if (sel_pho == 2) {
		if (xkey == VK_Up) {
		    if (cpg >= SELKEY)
			cpg -= SELKEY;
		    else {
			while ((startf + ((cpg + SELKEY) << 1)) < end)
			    cpg += SELKEY;
		    }
		} else {
		    ii = startf + ((cpg + SELKEY) << 1);
		    if (ii < end)
			cpg += SELKEY;
		    else
			cpg = 0;
		}
	    } else if (!sel_pho && c_len - c_idx >= 2) {
		sel_phr();
		if (sel_pho == 1)
		    return 1;
	    } else
		sel_pho = 2;
	    if (c_idx == c_len)
		key = ph_buf[c_idx - 1];
	    else
		key = ph_buf[c_idx];
	    if (!key)
		return 1;
	    i = hash_pho[key >> 9];
	    while (i < idxnum_pho) {
		ttt = idx_pho[i];
		if (ttt >= key)
		    break;
		i += 2;
	    }
	    if (ttt != key) {
		/* error("err in table"); */
		return 1;
	    }
	    ClrSelArea();
	    ii = idx_pho[i + 1];
	    end = idx_pho[i + 3];
	    startf = ii;
	    ii += cpg << 1;
	    i = 0;
	    while (i < SELKEY && ii < end) {
		u_char          t[3];
		b2cpy(t, &ch_pho[ii]);
		t[2] = 0;
		xprintf("%c%s ", phkbm.selkey[i], t);
		ii += 2;
		i = i + 1;
	    }
	    if (ii < end) {
		if (cpg)
		    xprintf("<\\");
		else
		    xprintf(" ");
		xprintf(">");
	    } else
		xprintf("<");
	    maxi = i;
	    return 1;
	}
	return 0;
    default:
	if ((pp = strchr(phkbm.selkey, xkey)) && maxi && sel_pho) {
	    int             c = pp - phkbm.selkey;
	    if (c < maxi) {
		if (sel_pho == 1) {
		    memcpy(ch_buf[c_idx], selstr[c], sellen[c] * 2);
		    raise_phr(c);
		} else {
		    int             ofs = startf + ((cpg + c) << 1);
		    i = c_idx == c_len ? c_idx - 1 : c_idx;
		    memcpy(ch_buf[i], &ch_pho[ofs], 2);
		    key = ph_buf[i];
		    if (i && psta[i] < i)
			memcpy(ch_buf[i - 1], ch_obuf[i - 1], 2);
#if	Auto_First
		    j = key >> 6;
		    for (i = sel1st_hash[j]; i < sel1st_hash[j + 1]; i++)
			if (sel1st[i].ph == key)
			    break;
		    if (sel1st[i].ph == key)
			memcpy(sel1st[i].ch, &ch_pho[ofs], 2);
		    else
			error("tsin.c:bug1");
#endif
		}
		prbuf();
		cpg = maxi = sel_pho = ityp3_pho = 0;
		ph_sta = -1;
	    }
	    return 1;
	}
	if (xkey > 127 && !is_kp_num(xkey))
	    return 0;
	sel_pho = cpg = 0;
    }

    if (!eng_ph || shift_m || is_kp_num(xkey)) {
	u_char          tt;
asc_char:
	if (is_kp_num(xkey))
	    xkey &= 0xff;
	if (xkey >= 127 || xkey < ' ')
	    return 0;
	if (shift_m && eng_ph) {
	    char           *ppp = strchr(ochars, xkey);
	    if (!(kbstate & KEY_CAPS_MASK) && ppp && !((ppp - ochars) & 1))
		xkey = *(ppp + 1);
	    if (kbstate & KEY_CAPS_MASK && islower(xkey))
		xkey -= 0x20;
	    else if (!(kbstate & KEY_CAPS_MASK) && isupper(xkey))
		xkey += 0x20;
	}
	tt = xkey;		/* endian conv */
	shift_ins();
	gotox(c_x);
	pox[c_idx] = c_x;
	if (HalfFull) {
	    b2cpy(ch_buf[c_idx], &fullchar[(xkey - ' ') << 1]);
	    c_xlen += 2;
	    c_x += 2;
	} else {
	    ch_buf[c_idx][0] = tt;
	    c_xlen++;
	    c_x++;
	}
	prch(ch_buf[c_idx]);
	ph_buf[c_idx] = 0;
	c_idx++;
	pox[c_idx] = c_x;
	if (c_idx < c_len)
	    prbuf();
	if (c_idx == c_len) {
	    if (HalfFull) {
		ch_buf[c_len][0] = 0xa1;
		ch_buf[c_len][1] = 0x40;
	    } else
		ch_buf[c_len][0] = ' ';
	}
	drawcursor();
	return 1;
    } else {			/* pho */
	if (xkey >= 'A' && xkey <= 'Z')
	    xkey += 0x20;
	ctyp = -1;
	for (i = 2; i >= 0; i--)
	    if (typ_pho[i])
		break;
	kno = phkbm.phokbm[xkey][0][0];
	ctyp = phkbm.phokbm[xkey][0][1];
	for (j = 0; j < 3; j++)
	    if (phkbm.phokbm[xkey][j][1] > i) {
		kno = phkbm.phokbm[xkey][j][0];
		ctyp = phkbm.phokbm[xkey][j][1];
		break;
	    }
	if (!kno)
	    return 0;
	typ_pho[ctyp] = kno;
	inph[ctyp] = xkey;
llll1:
	jj = 0;
	kk = 1;
llll2:
	if (ctyp == 3)
	    ityp3_pho = 1;	/* last key is entered */
	disp_in_area_pho();
	key = (u_short) typ_pho[0] << 9 | (u_short) typ_pho[1] << 7 |
	    (u_short) typ_pho[2] << 3 | typ_pho[3];
	j = key >> 6;
	for (i = sel1st_hash[j]; i < sel1st_hash[j + 1]; i++) {
	    ttt = sel1st[i].ph;
	    if (!typ_pho[0])
		ttt &= ~(31 << 9);
	    if (!typ_pho[1])
		ttt &= ~(3 << 7);
	    if (!typ_pho[2])
		ttt &= ~(15 << 3);
	    if (!typ_pho[3])
		ttt &= ~(7);
	    if (ttt == key)
		break;
	}
	if (ttt != key || ityp3_pho && sel1st[i].ph != key) {
	    while (jj < 4) {
		while (kk < 3)
		    if (phkbm.phokbm[inph[jj]][kk][0]) {
			ctyp = phkbm.phokbm[inph[jj]][kk - 1][1];
			typ_pho[ctyp] = 0;
			kno = phkbm.phokbm[inph[jj]][kk][0];
			ctyp = phkbm.phokbm[inph[jj]][kk][1];
			typ_pho[ctyp] = kno;
#if	0
			printf("## jj:%d kk:%d kno:%d ctyp:%d\n", jj, kk, kno, ctyp);
#endif	/* 0 */
			kk++;
			goto llll2;
		    } else
			kk++;
		jj++;
		kk = 1;
	    }
	    if (ityp3_pho) {
		bell();
		clrin_pho();
		clr_in_area_pho();
		return 1;
	    }
	}
	if (key == 0 || !ityp3_pho)
	    return 1;
    }				/* pho */

    shift_ins();

    pho1st_lidx = i;
    memcpy(ch_buf[c_idx], (char *)sel1st[i].ch, 2);
    memcpy(ch_obuf[c_idx], (char *)sel1st[i].ch, 2);
    gotox(c_x);
    prch(ch_buf[c_idx]);
    ph_buf[c_idx] = key;
    pox[c_idx] = c_x;
    c_idx++;
    c_x += 2;
    c_xlen += 2;
    pox[c_idx] = c_x;
    if (c_idx < c_len - 1)
	prbuf();
    drawcursor();
    clrin_pho();
    clr_in_area_pho();
    if (ph_sta < 0) {
restart:
	if (len = scanphr(&ph_buf[c_idx - 1], 1))
	    ph_sta = c_idx - 1;
	psta[c_idx - 1] = c_idx - 1;
	return 1;
    } else {
	j = c_idx - 1 - ph_sta;
	if (j < len && tk[j] == key) {
	    if (memcmp(ch_buf[ph_sta], tch[0], 2)) {
		gotox(c_x - 4);
		prch(tch[0]);
		memcpy(ch_buf[ph_sta], tch[0], 2);
	    }
	    memcpy(ch_buf[c_idx - 1], tch[j], 2);
	    psta[c_idx - 1] = ph_sta;
	    gotox(c_x - 2);
	    prch(tch[j]);
	    return 1;
	}
	while (sti < edi) {
	    i = phidx[sti];
	    fseek(fph, i, SEEK_SET);
	    fread(&len, 1, 1, fph);
	    if (j >= len) {
		sti++;
		continue;
	    }
	    fread(&tk, 2, len, fph);
	    fread(tch, 2, len, fph);
	    sti++;
	    for (i = 0; i <= j; i++)
		if (tk[i] != ph_buf[ph_sta + i])
		    break;
	    if (i <= j) {
		if (tk[i] < ph_buf[ph_sta + i])
		    continue;
		else
		    break;
	    }
	    memcpy(&ch_buf[ph_sta], tch, (j + 1) * 2);
	    psta[c_idx - 1] = ph_sta;
	    gotox(pox[ph_sta]);
	    for (i = 0; i <= j; i++) {
		prch(tch[i]);
	    }
	    return 1;
	}
	ph_sta = -1;
	goto restart;
    }
    return 1;

}
