
/*
 * Copyright (C) 1995	Edward Der-Hua Liu, Hsin-Chu, Taiwan
 */
/*
.tab struct
  TableHead*1
  keymap(1)*KeyNum
  kname(2)*KeyNum
  idx1(2)*(KeyNum+1)
  ITEM*chno
    TableHead is 
    KeyNum is count(%keyname)+1
    keymap is keymap[KeyNum] = cmd[0](key)
    kname is arg(ch[2])
    idx1 is index of keymap
    ITEM is (u_long key, u_char ch[2])
 */
#include "big5con.h"

FILE           *fr, *fw;
int             lineno;

void
p_err(char *fmt,...)
{
    va_list         args;

    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    fprintf(stderr, "\n");
    exit(-1);
}

char           *
skip_spc(char *s)
{
    while ((*s == ' ' || *s == '\t') && *s)
	s++;
    return s;
}

char           *
to_spc(char *s)
{
    while (*s != ' ' && *s != '\t' && *s)
	s++;
    return s;
}

void
del_nl_spc(char *s)
{
    char           *t;

    int             len = strlen(s);
    if (!*s)
	return;
    t = s + len - 1;
    while (*t == '\n' || *t == ' ' && *t == '\t' && s > t)
	t--;
    *(t + 1) = 0;
}


void
get_line(u_char * tt)
{
    while (!feof(fr)) {
	fgets(tt, 128, fr);
	lineno++;
	if (tt[0] == '#')
	    continue;
	else
	    break;
    }
}

void
cmd_arg(u_char * s, u_char ** cmd, u_char ** arg)
{
    char           *t;

    get_line(s);
    if (!*s) {
	*cmd = *arg = s;
	return;
    }
    s = skip_spc(s);
    t = to_spc(s);
    *cmd = s;
    if (!(*t)) {
	*arg = t;
	return;
    }
    *t = 0;
    t++;
    t = skip_spc(t);
    del_nl_spc(t);
    *arg = t;
}

int
sequ(char *s, char *t)
{
    return (!strcmp(s, t));
}

typedef struct {
    u_long          key;
    u_char          ch[2];
    u_short         oseq;
}               ITEM2;

#define MAX_K (25000)
ITEM2           itar[MAX_K], itmp[MAX_K];
ITEM            itout[MAX_K], lastit;
int             use_oseq = 0;

int
qcmp2(ITEM2 * a, ITEM2 * b)
{
    if (a->key > b->key)
	return 1;
    if (a->key < b->key)
	return -1;
    if (a->ch[0] > b->ch[0])
	return 1;
    if (a->ch[0] < b->ch[0])
	return -1;
    if (a->ch[1] > b->ch[1])
	return 1;
    if (a->ch[1] < b->ch[1])
	return -1;
    fprintf(stderr, "%c%c is multiply defined with the same key\n",
	    a->ch[0], a->ch[1]);
    return 0;
}

int
qcmp(ITEM2 * a, ITEM2 * b)
{
    if (a->key > b->key)
	return 1;
    if (a->key < b->key)
	return -1;
    return (int)a->oseq - (int)b->oseq;
}

/* this function is used to avoid 4-byte bus-alignment */
u_long 
CONVT(char *s)
{
    u_long          kk;
    memcpy(&kk, s, 4);
    return kk;
}

int
qcmp_ser(ITEM * a, ITEM * b)
{
    if (a->ch[0] > b->ch[0])
	return 1;
    if (a->ch[0] < b->ch[0])
	return -1;
    if (a->ch[1] > b->ch[1])
	return 1;
    if (a->ch[1] < b->ch[1])
	return -1;
    if (CONVT(a->key) > CONVT(b->key))
	return 1;
    if (CONVT(a->key) < CONVT(b->key))
	return -1;
    return 0;
}

#define mtolower(ch) (ch>='A'&&ch<='Z'?ch+0x20:ch)

char            kno[128];

int
main(int argc, char **argv)
{
    int             i;
    char            fname[64];
    char            fname_cin[64];
    char            fname_tab[64];
    char            fname_rev[64];
    char            fname_quick[64];
    char            fname_sel1st[64];
    char            fname_phr[64];
    char            tt[128];
    u_char         *cmd, *arg;
    struct TableHead th;
    int             KeyNum;
    char            kname[128][2];
    char            keymap[64];
    int             chno, cpcount;
    u_short         idx1[256];
    char            def1[256];
    u_char          quick[50][10][2];
    u_char          sel1st[3000][2];
    int             quick_def;
    int             sel1st_def;
    int             chardef_def;
    int             phridx[12000], phr_cou = 0;
    char            phrbuf[32768];
    int             prbf_cou = 0;

    if (argc <= 1) {
	printf("Enter table file name [.cin] : ");
	scanf("%s", fname);
    } else
	strcpy(fname, argv[1]);
    strcpy(fname_cin, fname);
    strcpy(fname_tab, fname);
    strcat(fname_cin, ".cin");
    strcat(fname_tab, ".tab");
    strcpy(fname_rev, fname_tab);
    strcpy(fname_quick, fname_tab);
    strcpy(fname_sel1st, fname_tab);
    strcpy(fname_phr, fname_tab);
    strcat(fname_rev, ".rev");
    strcat(fname_quick, ".quick");
    strcat(fname_sel1st, ".sel1st");
    strcat(fname_phr, ".phr");

    if ((fr = fopen(fname_cin, "r")) == NULL)
	p_err("Cannot open %s\n", fname_cin);
    bzero(&th, sizeof(th));
    bzero(kno, sizeof(kno));
    bzero(keymap, sizeof(keymap));
    bzero(itar, sizeof(itar));
    bzero(itout, sizeof(itout));
    th.M_DUP_SEL = 9;		/* set M_DUP_SEL default: 9 */

    while (!feof(fr)) {
	cmd_arg(tt, &cmd, &arg);
	if (sequ(cmd, "%ename") && (*arg)) {
	    arg[15] = 0;
	    strcpy(th.ename, arg);
	} else if ((sequ(cmd, "%cname") || sequ(cmd, "%prompt")) && (*arg)) {
	    th.cname[15] = 0;
	    if(strlen(arg) <= 4) {
	    	sprintf(th.cname, "Ħi%sĦj", arg);
	    } else if(strlen(arg) <= 6) {
	    	sprintf(th.cname, "[%s]", arg);
	    } else
	    	strcpy(th.cname, arg);
	} else if (sequ(cmd, "%selkey") && (*arg)) {
	    strcpy(th.selkey, arg);
	} else if (sequ(cmd, "%dupsel") && (*arg)) {
	    th.M_DUP_SEL = atoi(arg);
	} else if (sequ(cmd, "%keyname") && sequ(arg, "begin")) {
	    for (KeyNum = 0;;) {
		char            k;
		cmd_arg(tt, &cmd, &arg);
		if (sequ(cmd, "%keyname"))
		    break;
		k = mtolower(cmd[0]);
		if (kno[k])
		    p_err("%d:  key %c is already used", lineno, k);
		kno[k] = ++KeyNum;
		keymap[KeyNum] = k;
		memcpy(&kname[KeyNum][0], arg, 2);
	    }
	    keymap[0] = kname[0][0] = kname[0][1] = ' ';
	    KeyNum++;
	    th.KeyS = KeyNum;	/* include space */
	} else if (sequ(cmd, "%quick") && sequ(arg, "begin")) {
	    puts("%quick");
	    bzero(quick, sizeof(quick));
	    for (quick_def = 0;;) {
		char            k;
		int             len;
		cmd_arg(tt, &cmd, &arg);
		if (sequ(cmd, "%quick"))
		    break;
		k = kno[mtolower(cmd[0])] - 1;
		len = strlen(arg);
		for (i = 0; i < len; i += 2)
		    memcpy(quick[k][i >> 1], &arg[i], 2);
		quick_def++;
	    }
	    if (quick_def) {
		if ((fw = fopen(fname_quick, "w")) == NULL)
		    p_err("can not create file");
		fwrite(quick, 2, (KeyNum - 1) * 10, fw);
		fclose(fw);
	    }
	} else if (sequ(cmd, "%sel1st") && sequ(arg, "begin")) {
	    puts("%sel1st");
	    for (sel1st_def = 0;;) {
		cmd_arg(tt, &cmd, &arg);
		if (sequ(cmd, "%sel1st"))
		    break;
		memcpy(sel1st[sel1st_def++], cmd, 2);
	    }
	    if (sel1st_def) {
		if ((fw = fopen(fname_sel1st, "w")) == NULL)
		    p_err("can not create file");
		fwrite(sel1st, 2, sel1st_def, fw);
		fclose(fw);
	    }
	} else if (sequ(cmd, "%chardef") && sequ(arg, "begin")) {
#ifdef	DEBUG
	    puts("%chardef");
#endif
	    chno = 0;
	    for (chardef_def = 0;;) {
		int             len;
		u_long          kk;
		int             k;
		char            out[3];
		cmd_arg(tt, &cmd, &arg);
		if (sequ(cmd, "%chardef"))
		    break;
		if (!cmd[0] || !arg[0])
		    break;
		/* printf("%s %s\n", cmd, arg); */
		len = strlen(cmd);
		if (len > th.MaxPress)
		    th.MaxPress = len;
		if (len > 5)
		    p_err("%d:  only <= 5 keys is allowed", lineno);
		kk = 0;
		for (i = 0; i < len; i++) {
		    k = kno[mtolower(cmd[i])];
		    kk |= k << (24 - i * 6);
		}
		memcpy(&itar[chno].key, &kk, 4);
		if ((len = strlen(arg)) == 2) {
		    memcpy(out, arg, 2);
		    memcpy(itar[chno].ch, out, 2);
		} else {
		    itar[chno].ch[0] = phr_cou >> 8;
		    itar[chno].ch[1] = phr_cou & 0xff;
		    phridx[phr_cou++] = prbf_cou;
		    strcpy(&phrbuf[prbf_cou], arg);
#ifdef	DEBUG
		    printf("prbf_cou:%d  %s\n", prbf_cou, arg);
#endif
		    prbf_cou += len;
		}
		itar[chno].oseq = chno;
		chno++;
	    }
	}
    }
    fclose(fr);

    if (phr_cou) {
	phridx[phr_cou++] = prbf_cou;
	if ((fw = fopen(fname_phr, "w")) == NULL)
	    p_err("Cannot create %s\n", fname_phr);
	printf("cou:%d\n", phr_cou);
	fwrite(&phr_cou, 4, 1, fw);
	fwrite(phridx, 4, phr_cou, fw);
	fwrite(phrbuf, 1, prbf_cou, fw);
	fclose(fw);
    }
    th.DefC = chno;
    qsort(itar, chno, sizeof(ITEM2), (void *)qcmp2);

    bzero(&lastit, sizeof(ITEM));
    cpcount = 0;
    for (i = 0; i < chno; i++)
	if (memcmp(&itar[i], &lastit, sizeof(ITEM))) {
	    memcpy(&itmp[cpcount++], &itar[i], sizeof(ITEM2));
	    memcpy(&lastit, &itar[i], sizeof(ITEM));
	}
    printf("%d DefC:%d\n", chno, cpcount);
    chno = cpcount;
    qsort(itmp, chno, sizeof(ITEM2), (void *)qcmp);

    for (i = 0; i < chno; i++) {
	memcpy(&itout[i], &itmp[i], sizeof(ITEM));
    }

    bzero(def1, sizeof(def1));
    bzero(idx1, sizeof(idx1));
    for (i = 0; i < chno; i++) {
	int             kk = (CONVT(itout[i].key) >> 24) & 0x3f;
	if (!def1[kk]) {
	    idx1[kk] = (u_short) i;
	    def1[kk] = 1;
	}
    }

    idx1[KeyNum] = chno;
    for (i = KeyNum - 1; i > 0; i--)
	if (!def1[i])
	    idx1[i] = idx1[i + 1];

    printf("KeyNum: %d\n", KeyNum);
#if	0
    for (i = 0; i <= KeyNum; i++)
	printf("%d\n", (int)idx1[i]);
#endif
    if ((fw = fopen(fname_tab, "w")) == NULL) {
	p_err("Cannot create");
    }
    fwrite(&th, 1, sizeof(th), fw);
    fwrite(keymap, 1, KeyNum, fw);
    fwrite(kname, 2, KeyNum, fw);
    fwrite(idx1, 2, KeyNum + 1, fw);
    fwrite(itout, sizeof(ITEM), chno, fw);
    fclose(fw);

    if ((fw = fopen(fname_rev, "w")) == NULL) {
	p_err("Cannot create");
    }
    qsort(itout, chno, sizeof(ITEM), (void *)qcmp_ser);

    bzero(def1, sizeof(def1));
    bzero(idx1, sizeof(idx1));
    for (i = 0; i < chno; i++) {
	int             kk = itout[i].ch[0];
	if (!def1[kk]) {
	    idx1[kk] = (u_short) i;
	    def1[kk] = 1;
	}
    }

    idx1[255] = chno;
    for (i = 254; i > 0; i--)
	if (!def1[i])
	    idx1[i] = idx1[i + 1];

#if	0
    for (i = 0; i <= 255; i++)
	printf("%02x %d\n", i, (int)idx1[i]);
#endif

    fwrite(idx1, sizeof(u_short), 256, fw);
    fwrite(itout, sizeof(ITEM), chno, fw);

    fclose(fw);
    return 0;
}
