/*
 * KON - Kanji ON Linux Console - Copyright (C) 1992, 1993 Takashi MANABE
 * (manabe@tut.ac.jp)
 * 
 * KON is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 * 
 * KON is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 * 
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 675
 * Mass Ave, Cambridge, MA 02139, USA.
 */
/*
 * Modified for Big5Con by Hung-Chi Chu <hcchu@r350.ee.ntu.edu.tw>
 */

#include	"big5con.h"

int             forceLoad = 1;
struct fontInfo fi;

u_char         *FontLoadBdf();
u_char         *FontLoadSmf();

static struct {
    char           *type;
    u_char         *(*loader) (FILE * fp);
}               fontLoaders[] = {
    {
	"bdf", FontLoadBdf
    },
    {
	"smf", FontLoadSmf
    },
    {
	NULL, NULL
    }
};

void 
UnloadShmem(char fnum)
{
    key_t           shmkey;
    int             shmid;
    struct shmid_ds shmseg;

    shmkey = 5000 + (fnum & 0x7F);
    if ((shmid = shmget(shmkey, sizeof(struct fontInfo), 0444)) < 0)
	return;
    shmctl(shmid, IPC_STAT, &shmseg);
    if (shmseg.shm_nattch < 1) {
	shmctl(shmid, IPC_RMID, 0);
    }
}

int 
CheckLoadedFont(char fnum)
{
    key_t           shmkey;
    extern int      forceLoad;

    if (forceLoad)
	return (EOF);
    shmkey = 5000 + (fnum & 0x7F);
    if (shmget(shmkey, 1, 0444) == EOF)
	return (EOF);
    return (0);
}

static
void 
ShmFont(char *prog, u_char * font, struct fontInfo * fi)
{
    key_t           shmkey;
    int             shmid;
    u_char         *shmbuff;

    shmkey = 5000 + (fi->type & 0x0000007F);
    shmid = shmget(shmkey, fi->size + sizeof(struct fontInfo),
		   IPC_CREAT | 0666);
    fprintf(stderr, "%ld\n", fi->size + sizeof(struct fontInfo));
    shmbuff = shmat(shmid, 0, 0);
    memcpy(shmbuff, fi, sizeof(struct fontInfo));
    memcpy(shmbuff + sizeof(struct fontInfo), font, fi->size);
    shmdt(shmbuff);
    fprintf(stderr, "%s> load %s in shmem(%d): %d Bytes\n",
	    prog,
	    (fi->type & CHR_DBC) ?
	    fDRegs[fi->type & ~CHR_DFLD].registry :
	    fSRegs[fi->type & ~CHR_SFLD].registry,
	    shmid, fi->size);
}

int 
SetFont(char *prog, u_char * font, struct fontInfo * fi)
{
    int             s;

    if ((s = SocketClientOpen()) > 0) {
	SocketSendCommand(s, CHR_UNLOAD);
	close(s);
    }
    ShmFont(prog, font, fi);
    if ((s = SocketClientOpen()) > 0) {
	SocketSendCommand(s, CHR_LOAD);
	close(s);
    }
    return (0);
}

u_char         *
ShowShmem(u_char fnum)
{
    key_t           shmkey;
    int             shmid;
    struct fontInfo *fi;

    shmkey = 5000 + (fnum & 0x7F);
    if ((shmid = shmget(shmkey, sizeof(struct fontInfo), 0444)) < 0)
	return (0);
    fi = (struct fontInfo *) shmat(shmid, 0, SHM_RDONLY);
    if (fi) {
	printf("%3X %6d %-15s %2dx%2d %7d\n",
	       fnum & ~CHR_SFLD,
	       shmid,
	       (fnum & CHR_DBC) ?
	       fDRegs[fnum & ~CHR_DFLD].registry :
	       fSRegs[fnum & ~CHR_SFLD].registry,
	       fi->width,
	       fi->high,
	       fi->size);
    }
}

void 
ShowFont()
{
    int             i;

    i = 0;
    printf(" No. ShmId Font Name	   Size  MemSize\n"
	   "+---+-----+---------------+-----+-------+\n");
    while (fSRegs[i].registry) {
	ShowShmem(i | CHR_SFLD);
	i++;
    }
    i = 0;
    while (fDRegs[i].registry) {
	ShowShmem(i | CHR_DFLD);
	i++;
    }
}

/*
  ex: "cat /usr/local/lib/fonts/kc8x16.smf | /usr/local/bin/b5cfld -t smf -n\n" 
 */

int 
main(argc, argv)
    int             argc;
    char           *argv[];
{
    int             i, n;
    FILE           *fp = stdin;
    enum {
	ST_ARG, ST_UNLOAD, ST_TYPE
    }               st = ST_ARG;
    int             ST_STDOUT = 0;
    char            file[256], *type, *p;
    u_char         *font;

    if ((p = index(argv[0], '.')) != NULL)
	type = p + 1;
    for (i = 1; i < argc; i++) {
	p = argv[i];
	switch (st) {
	case ST_UNLOAD:
	    if (isxdigit(*p)) {
		sscanf(p, "%X", &n);
		fprintf(stderr, "%s> unload %X(%s)\n", argv[0], n,
			(n & CHR_DBC) ?
			fDRegs[n & ~CHR_DFLD].registry :
			fSRegs[n & ~CHR_SFLD].registry);
		UnloadShmem(n | CHR_SFLD);
		break;
	    }
	    st = ST_ARG;
	case ST_ARG:
	    if (*p == '-') {
		++p;
		switch (*p) {
		case 'c':
		    ST_STDOUT = 1;
		    break;
		case 'n':
		    forceLoad = 0;
		    break;
		case 'u':
		    st = ST_UNLOAD;
		    break;
		case 't':
		    st = ST_TYPE;
		    break;
		case 'i':
		    ShowFont();
		    exit(0);
		    break;
		}
	    } else {
		if (!(fp = fopen(argv[i], "r"))) {
		    fprintf(stderr, "%s> Can not open font file.\n", argv[0]);
		    exit(EOF);
		}
	    }
	    break;
	case ST_TYPE:
	    type = p;
	    st = ST_ARG;
	    break;
	}
    }
    if (st == ST_UNLOAD)
	exit(0);
    i = 0;
    while (fontLoaders[i].type) {
	if (!strcasecmp(fontLoaders[i].type, type))
	    break;
	i++;
    }
    if (!fontLoaders[i].type) {
	fprintf(stderr, "%s> type %s is not supported.\n",
		argv[0], type);
	exit(EOF);
    }
    font = fontLoaders[i].loader(fp);
    if (font == NULL) {
	fprintf(stderr, "%s> Can not load font.\n", argv[0]);
	exit(EOF);
    }
    if (fp != stdin)
	fclose(fp);
    if (ST_STDOUT) {
	u_char         *temp;
	printf("Hi!");
	temp = (u_char *) malloc(fi.size + sizeof(struct fontInfo));
	memcpy(temp, &fi, sizeof(struct fontInfo));
	memcpy(temp + sizeof(struct fontInfo), font, fi.size);
	fwrite(temp, fi.size + sizeof(struct fontInfo), 1, stdout);
	free(temp);
    } else
	exit(SetFont(argv[0], font, &fi));
    return 0;
}
