/*
 *		knjfont.exe    Make KANJI FONT file
 *						supported dviout.exe dviprt.exe v2.06-
 *				v1.0	June 1990, written by SHIMA
 *
 *		modified by sempa for Turbo C++ on IBM PC
 */
#include	"stdio.h"
#include	"stdlib.h"
#include	"io.h"
#ifdef	CC_JPN
#include	"jctype.h"
#else
unsigned short jistojms(unsigned short);
unsigned short jmstojis(unsigned short);
int iskanji(unsigned short);

#endif

#define is_white(c) (c==' '||c=='\t'||c=='\n')
#define is_hex(c)   ((c>='0'&&c<='9')||(c>='a'&&c<='f')||(c>='A'&&c<='F'))
#define is_oct(c)   (c>='0'&&c<='7')
#define is_dig(c)   (c>='0'&&c<='9')
#define hex_to_dig(c)   ((c>='0'&&c<='9')?(c-'0'):(toupper(c)-('A'-10)))
#define to_dig(c)   (c-'0')
#define	DEBUG			0
#define	MAX_CODE		0x737e
#define	MAX_CHAR	((((unsigned int)MAX_CODE>>8)-0x21)*94 + (MAX_CODE & 0xff) - 0x21)

#define	LINE_BUF_SIZE	0x1000
#define	FONT_BUF_SIZE	0x4000

char line_buf[LINE_BUF_SIZE];
char font_buf[FONT_BUF_SIZE];

int f_make;
int f_test;
int height;
long shift;

void skip_sp(unsigned char **);
long stol(unsigned char **);
void usage(void);

void main(int argc, char **argv)
{
	FILE *fpr, *fpw, *fpd;
	char *data_file;
	unsigned char *ptr;
	int i, sc, sc_end, block, width, b_width;
	unsigned int t_num, b_num, num, tm_num, bm_num;
	long pos, dest;
	unsigned int k_code;

	if (argc < 4)
		usage();

	width = atoi(argv[3]);

	for (i = 4; i < argc; i++) {
		if (argv[i][0] == '-') {
			switch (argv[i][1]) {
			  case ('f'):
				  data_file = argv[i] + 2;
				  break;
			  case ('m'):
				  f_make = 1;
				  break;
			  case ('s'):
				  shift = atoi(argv[i] + 2);
				  break;
			  case ('t'):
				  f_test = 1;
				  break;
			}
		}
		else
			height = atoi(argv[i]);
	}
	if (height == 0 && (height = width) == 0)
		usage();
	b_width = (width + 7) / 8;
	block = b_width * height;
	if (block > FONT_BUF_SIZE) {
		printf("Too large font");
		exit(1);
	}
	if ((fpr = fopen(argv[1], "rb")) == NULL) {
		printf("Cannot open %s", argv[1]);
		exit(1);
	}
	if (f_make == 0) {
		if ((fpw = fopen(argv[2], "r+b")) == NULL) {
			printf("Cannot open %s", argv[2]);
			exit(1);
		}
	}
	else {
		if ((fpw = fopen(argv[2], "wb")) == NULL) {
			printf("Cannot open [%s]", argv[2]);
			exit(1);
		}
		if (chsize(fileno(fpw), (long)MAX_CHAR * block) == -1) {
			printf("Probably not enough Disk space");
			exit(1);
		}
	}
	if (data_file == NULL)
		exit(0);
	if ((fpd = fopen(data_file, "r")) == NULL) {
		printf("Cannot open %s", data_file);
		exit(1);
	}
	while (fgets(ptr = line_buf, LINE_BUF_SIZE, fpd), !feof(fpd)) {
		skip_sp(&ptr);
		if (!is_dig(*ptr))
			continue;
		num = stol(&ptr);
		pos = (long)num *block + shift;

		skip_sp(&ptr);

		if (iskanji(*ptr)) {
			k_code = *ptr++ << 8;
			k_code += *ptr++;
			t_num = jmstojis(k_code);
		}
		else {
			if (!is_dig(*ptr)) {
			  err_d:printf("Error in %s", data_file);
				exit(1);
			}
			t_num = stol(&ptr);
		}
		skip_sp(&ptr);

		if (iskanji(*ptr)) {
			k_code = *ptr++ << 8;
			k_code += *ptr++;
			b_num = jmstojis(k_code);
		}
		else {
			if (!is_dig(*ptr))
				goto err_d;
			b_num = stol(&ptr);
		}

		tm_num = jistojms(t_num);
		bm_num = jistojms(b_num);
		printf("%4d(%7ld), %04x(%c%c) -> %04x(%c%c)\n", num, pos,
			   t_num, tm_num >> 8, tm_num & 0xff, b_num, bm_num >> 8, bm_num & 0xff);
		if (f_test)
			continue;

		if (fseek(fpr, pos, 0)) {
		  err_r:printf("Error in %s", argv[1]);
			exit(1);
		}
		sc = (((unsigned int)t_num >> 8) - 0x21) * 94;
		sc += ((t_num & 0xff) - 0x21);
		dest = (long)sc *block;

		if (fseek(fpw, dest, 0)) {
		  err_w:printf("Error in writing %s", argv[2]);
			exit(1);
		}
		sc_end = (((unsigned int)b_num >> 8) - 0x21) * 94;
		sc_end += ((b_num & 0xff) - 0x21);
		while (sc++ <= sc_end) {
			if (fread(font_buf, block, 1, fpr) != 1)
				goto err_r;
			if (fwrite(font_buf, block, 1, fpw) != 1)
				goto err_w;
		}
	}
	flushall();
}

void skip_sp(unsigned char **ptr_str)
{
	unsigned char *ptr;

	ptr = *ptr_str;
	while (is_white(*ptr))
		ptr++;
	*ptr_str = ptr;
}

long stol(unsigned char **str_ptr)
	/* set string-value to long-integer. Oct- or Hex-values in thought.
     */
{
	long num = 0;
	int sign = 1;
	unsigned char *str;

	str = *str_ptr;
	if (*str == '-') {
		sign = -1;
		str++;
	}
	if (*str == '0') {
		if (*++str == 'x' || *str == 'X') {
			str++;
			while (is_hex(*str)) {
				num *= 16;
				num += hex_to_dig(*str);
				str++;
			}
		}
		else {
			while (is_oct(*str)) {
				num *= 8;
				num += to_dig(*str);
				str++;
			}
		}
	}
	else {
		while (is_dig(*str)) {
			num *= 10;
			num += to_dig(*str);
			str++;
		}
	}
	*str_ptr = str;
	return (num * sign);
}

void usage(void)
{
	printf(
		  "\t<<< knjfont: Make kanji font for dviprt, dviout v2.06.1- >>>\n"
			  "\t\t\t\tver 1.0,  June 1990, written by SHIMA\n\n"
			  "Usage: knjfont original_file font_file width [height]\n"
			  "       [-m][-fdata_file][-sshift][-t]\n"
	);
	exit(1);
}

#ifndef	CC_JPN
unsigned short jistojms(unsigned short c)
{
	int hi, lo;

	hi = (c >> 8) & 0xFF;
	lo = c & 0xFF;
	if (hi & 1)
		lo += 0x1f;
	else
		lo += 0x7d;
	hi = (hi - 0x21 >> 1) + 0x81;
	if (lo >= 0x7f)
		lo++;
	if (hi > 0x9f)
		hi += 0x40;
	return hi << 8 | lo;
}

unsigned short jmstojis(unsigned short c)
{
	int hi, lo;

	hi = (c >> 8) & 0xFF;
	lo = c & 0xFF;
	hi -= (hi <= 0x9f) ? 0x71 : 0xb1;
	hi = hi * 2 + 1;
	if (lo > 0x7f)
		lo--;
	if (lo >= 0x9e) {
		lo -= 0x7d;
		hi++;
	}
	else
		lo -= 0x1f;
	return hi << 8 | lo;
}

int iskanji(unsigned short c)
{
	unsigned short i;

	i = c & 0xFF;
	return ((0x81 <= i) && (i <= 0x9F)) || ((0xE0 <= i) && (i <= 0xFC));
}

#endif
