/*
 *  TEX Device Driver  ver 2.02-
 *  copyright(c) 1988, 1989 by TSG, 1990-93 by SHIMA
 *
 *  loadpk.c :
 *            April 15, 1989 : first edition
 *                             programed by T.IWAI
 *  1991 changed by hideki
 *	very slightly modified against warnings by Oh-Yeah? 25 May 1992
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>

#ifdef   UNIX
#include <unistd.h>
#define  O_BINARY   0
#else
#include <io.h>
#endif

#include "dd.h"
#include "dviread.h"
#include "err.h"
#include "inter.h"
#include "jfm.h"

#ifndef min
#  define min(a,b) ( (a) < (b) ? (a) : (b) )
#endif
#ifndef max
#  define max(a,b) ( (a) > (b) ? (a) : (b) )
#endif

#if DEBUG & MEM_CHK
static void (*_bufchk) ();

#endif

/* buffer.c */
void pk_buf_flush(void);

/* loadpk.c */
char *to_font_name(char *);

/* option.c */
int make_path(char *, char *, char *, char *);

/* vfont.c */
int flush_vfn(int);
char *check_myftt(char *, int);

/* fontdef.c */
BOOL kpse_search(char *, char *);
BOOL copy_token(char *, char **, int);

#ifdef	USE_WINAPI
void get_windows_directory(char *);
#endif

char *GetOutPath(char *);

int file_read(int, BUFFER *, int);
int ask_pk_buf(long size);
int openf(char *, int);
int resume_fontfile(int);
static int flush_pk(int);
static int flush_jpk(int);

#ifdef TTFONT
static int load_tfm(char *);
#endif

int f_flush_pk;

#ifdef TTFONT
#include "ttfont.h"
/* ttfont.c */
uchar *get_cmttinfo(int, int);
extern char *tfm_search_path;
#endif

extern char *root_search_path;
extern char *new_tfm_search_path;

#define READ_SIZE (1024*8)
/*  一度に読み込むサイズ */

static void buf_load(int fd, BUFFER *buf, long size)
	/*  bufにsizeだけ読み込みます．途中でファイルが終っても
	 *  エラーにはなりません．ファイルもクローズしません．
	 */
{
	if (file_read(fd, buf, size) == FAILURE)
		error(FILE_FAULT, "fail to read FONT");
}

FILE *fopenf(char *name, char *mode)
{
	FILE *fp;
#if	defined(USE_WINAPI)||defined(UNIX)
	char tmp[0x200];
/*	int len;	*/

	if(SetPath(tmp, name))
		name = tmp;
#endif
	if (*mode != 'w' && access(name, 0) != 0) return( NULL );
	if ((fp = fopen(name, mode)) != NULL)
		return( fp );
	if( flush_pk(1) ){
		if ((fp = fopen(name, mode)) != NULL)
			return( fp );
	}
	if( flush_jpk(1) ){
		if ((fp = fopen(name, mode)) != NULL)
			return( fp );
	}
#ifndef	NOVFONT
	flush_vfn(1);
#endif
	return( fopen(name, mode) );
}

int openf(char *name, int mode)
{
	int fd;
#if	defined(USE_WINAPI)||defined(UNIX)
	char tmp[300];

	if(SetPath(tmp, name))
		name = tmp;
#endif
	if ((fd = open(name, mode)) > 0 || errno != EMFILE )
		return (fd);
	if( flush_pk(1) ){
		if ((fd = open(name, mode)) > 0 || errno != EMFILE )
			return (fd);
	}
	if( flush_jpk(1) ){
		if ((fd = open(name, mode)) > 0 || errno != EMFILE )
			return (fd);
	}
#ifndef	NOVFONT
	flush_vfn(1);
#endif
	return( open(name,mode) );
}

static int flush_pk(int number)
{
	int count;
	static FONT_INFO *font;
	FONT_INFO *fontc;

	if(number == 0){
		font = NULL;
		return 0;
	}
	count = 0;
	if (font == NULL || number > 1)
		font = first_font_info;
	if((fontc = font) == NULL)
		return 0;
	do {
		if ((fontc->font_type == PKD_FONT
#ifdef VFD
			|| fontc->font_type == VFD_FONT
#endif
#ifdef TTFONT
			|| fontc->font_type == CMTTF
#endif
			|| fontc->font_type == JXL)
			&& fontc->ext.fh > 0) {
			close(fontc->ext.fh);
			f_flush_pk++;
			fontc->ext.fh = 0;
			if((font = font->next_font) == NULL)
				font = first_font_info;
			if(++count >= number)
				return( count );
		}
		fontc = fontc->next_font;
		if (fontc == NULL)
			fontc = first_font_info;
	} while (font != fontc);
	return( count );
}


static int flush_jpk(int number)
{
	static FONT_INFO *font;
	static int flush_id;
	int fh;
	int count;
	FONT_INFO *fontc;
	FONT_INFO *fontt;

	if(number == 0){
		font = NULL;
		return 0;
	}
	count = 0;
	if (font == NULL)
		font = first_font_info;
	if((fontc = font) == NULL)
		return 0;
	do {
		if ((fontc->font_type >= JIS_FONT)
			&& fontc->ext.kdir->fh > 0) {
			close(fontc->ext.kdir->fh);
			f_flush_pk++;
			flush_id--;
			fh = fontc->ext.kdir->fh;
			if((font = font->next_font) == NULL)
				font = first_font_info;
			for( fontt = first_font_info; fontt; fontt = fontt->next_font ){
				if(fontt->font_type >= JIS_FONT && fontt->ext.kdir->fh == fh)
					fontt->ext.kdir->fh = flush_id;
			}
			if(count++ >= number)
				return( count );
		}
		fontc = fontc->next_font;
		if (fontc == NULL)
			fontc = first_font_info;
	} while (font != fontc);
	return( count );
}

int resume_fontfile(int number)
{
	int count;

	count = flush_pk(number);
	count += flush_jpk(number);
#ifndef NOVFONT
	count += flush_vfn(number);
#endif
	return (count);
}

void re_openf(FONT_INFO *font)
{
	int id, fh;
	FONT_INFO *fontc;

	id = font->ext.fh;
	if ( (fh = openf(font->ext.kdir->name, O_BINARY|O_RDONLY)) < 0 )
		error(FILE_FAULT, "Cannot re_open FONT file %s", font->ext.kdir->name);
	for( fontc = first_font_info; fontc; fontc = fontc->next_font ){
		if( fontc->ext.fh == id ) font->ext.fh = fh;
	}
}

int ask_pk_buf(long size)
{
	static int id_flush;
	static int id_fdvi;

	if ((HUGE_BUF *)pk_buf_pointer->end -
		(HUGE_BUF *)pk_buf_pointer->current <= size + 0x100) {
		if (pk_buf_pointer->size < size + 0x100)
			return (FAILURE);

		if(id_page == (id_flush -= 0x2000))
			error(WARNING, "Font buffer size -bf: %d K in [System]"
				" (<- Setup Parameters <- Option)\n is too small.\n"
				"Not an error but it is better to increase the size!", 
				pk_buf_pointer->size/1024);
		else if(id_fdvi != id_page + pk_buf_pointer->size){
				id_fdvi  = id_page + pk_buf_pointer->size;
				id_flush = id_page + 0x2000;
		}
		pk_buf_flush();
	}
	return (NOTHING);
}

BUFFER *
	load_pk(char *name, char *fname)
	/*  load_pkのスケルトンモジュール． nameのフォントファイル
	 *  を一括して bufに読み込む． バッファを溢れるときは，flush
	 *  を呼び出す．
	 *  返値は格納した場所．
	 */
{
	int fd, i;
	long file_pos, file_size;
	long far *jxl_info;
	long tmp;
	uchar ctmp[12];
	FILE *fp;
	BUFFER *pk;
	char *ext;
#ifdef TTFONT
	uchar *s;
	BUFFER *d;
#endif

#define	JXL4_ID		(0x258B0100L)
#define	CMTTF_ID	('t' + 't' + 'f')

	ENTER("load_pk");

	if (*name == '*') {
		file_pos = long_int((void *)(name + 1));
		file_size = long_int((void *)(name + 5));
#ifdef	DBGO
	printf("[%s:%d:%d]", name, file_pos, file_size);
#endif
		if ((fd = openf(name + 9, O_RDONLY | O_BINARY)) == FAILURE
			|| lseek(fd, file_pos, SEEK_SET) == -1L)
			error(NO_FILE, name+9);
	}else if (*name == '<'){
		for(i = 1; i < 12 && (name[i] > '.' || name[i] == '-'); i++)
			ctmp[i-1] = name[i];
		ctmp[i-1] = 0;
		pk = IsInnerJFM(ctmp);
		if(pk)
			return pk;
		goto opn;
	}else {
opn:	if ((fd = openf(name, O_RDONLY | O_BINARY)) == FAILURE)
			error(NO_FILE, name);
		file_size = filelength(fd);
		if(file_size <= 4)
			error(FILE_FAULT, "Corrupt font %s (size %d)", name, file_size);
	}
	read(fd, &ctmp[0], 4);
	tmp = long_int(&ctmp[0]);
#ifdef TTFONT
	/* 拡張子が .ttf なら代わりに TFM を読み込む */
	if ((ext = strrchr(name, '.')) != NULL
	 && strcmpi(ext, ".ttf") == 0) {
		if ((s = get_cmttinfo(fd, *check_myftt(fname, 1))) == NULL)
			error(FILE_FAULT, "Invalid TrueType font %s", name);
		close(fd);
		file_size = sizeof(CMTT_INFO) + 4;
		if( (fname != NULL && (fd == load_tfm(fname)) > 0 )
		  || (fd = load_tfm(name)) > 0 ){
			file_size += filelength(fd);
			((CMTT_INFO *)s)->f_have_tfm = TRUE;
		} else {
			((CMTT_INFO *)s)->f_have_tfm = FALSE;
		}
		DisplayMessage(NULL);
		tmp = CMTTF_ID;
	}
#endif
	if (tmp == JXL4_ID) {
		if (*name=='*')
			error(FILE_FAULT, "%s contains JXL4 file", name + 9);
		file_size = 64L;
		fp = fdopen(fd, "rb");
		fseek(fp, -64L, SEEK_END);
	}
	if (ask_pk_buf(file_size) == FAILURE)
		error(NO_MEMORY, "font file over: %s", to_font_name(name));
	if (save_long(pk_buf_pointer->current, tmp) == JXL4_ID) {
		jxl_info = (long far *)(pk_buf_pointer->current);
		for (i = 15; i > 0; i--)
			*(++jxl_info) = read_long(fp);
		if (read_long(fp) != 0x18B25L)
			error(FILE_FAULT, "JXL4 file %s", name);
		fclose(fp);
	}
#ifdef TTFONT
	else if (tmp == CMTTF_ID) {
		d = pk_buf_pointer->current + 4;
		for (i = sizeof(CMTT_INFO);  i > 0; i--) *d++ = *s++;
		if (fd > 0) {
			buf_load(fd, d, file_size - sizeof(CMTT_INFO) - 4);
			close(fd);
		}
	}
#endif
	else {
		buf_load(fd, pk_buf_pointer->current + 4, file_size - 4);
		close(fd);
	}
ext:
	pk = pk_buf_pointer->current;
	(HUGE_BUF *)pk_buf_pointer->current += file_size;
	RETURN(pk);
}

#if DEBUG & MEM_CHK
static void _pkbufchk(BUFFER *ptr)
	/*  pk-bufferのaccess check
	 */
{
	ENTER("_pkbufchk");

	if ((HUGE_BUF *)ptr < (HUGE_BUF *)pk_buf_pointer->start ||
		(HUGE_BUF *)ptr >= (HUGE_BUF *)pk_buf_pointer->end)
		error(MEMORY_FAULT, "pk-buffer");
	END();
}

#endif

#ifdef TTFONT
static int load_tfm(char *name)
{ 
	int fd, len;
	char *tmp, *tmpp, *path, *dir, *ext = ".tfm";
	BOOL token_exist;

	/* フォント名だけ切り出す */
	if ((tmp = strrchr(name, '\\')) != NULL) name = ++tmp;
	if ((tmp = strrchr(name, '/')) != NULL) name = ++tmp;
	sprintf(tmp_buf, "Searching tfm file for %s", name);
	DisplayMessage(tmp_buf);
	path = stpcpy((char *)tmp_buf, name);
	name = (char *)tmp_buf;
	*path++ = '\0';
	dir = new_tfm_search_path;
	do {
		token_exist = copy_token(path, &dir, DELIMITER);
		make_path(path, path, name, ext);
		if(root_search_path != NULL){
			len = strlen(root_search_path);
			tmp = path;
			while( (tmpp = StrStr(tmp, "^r")) != NULL
				|| (tmpp = StrStr(tmp, "%r")) != NULL){
				if(!IsTopChar(tmp,tmpp)){
					tmp = tmpp+1;
					continue;
				}
				tmp = tmpp;
				memmove(tmp, tmp + 2, strlen(tmp));
				memmove(tmp + len, tmp, strlen(tmp) + 1);
				memcpy(tmp, root_search_path, len);
				tmp += len;
			}
		}
#if	!defined(GCC) || defined(USE_WINAPI) || defined(UNIX)
		if(  path[0] == '\\' && path[1] == '\\' && 
			(fd = openf(path, O_RDONLY | O_BINARY)) != FAILURE )
					return (fd);
		if (kpse_search(path, "\\\\") == FALSE){
			if(  path[0] == '/' && path[1] == '/' && 
				(fd = openf(path, O_RDONLY | O_BINARY)) != FAILURE )
					return (fd);
			kpse_search(path, "//");
		}
		do { 
#endif
			if ((fd = openf(path, O_RDONLY | O_BINARY)) != FAILURE)
				return (fd);
#if	!defined(GCC) || defined(USE_WINAPI) || defined(UNIX)
		} while (kpse_search(path, NULL));
#endif
	} while (token_exist);
	make_path(path, NULL, name, ext);
	error(WARNING, "Cannot find %s for TT Font", path);
	return (0);
}
#endif


#if defined(TURBOC) || defined(MSC)
int file_read(int fd, BUFFER *ptr, int size)
	/* セグメント外に直接リード
	 */
{
	union REGS inregs, outregs;
	struct SREGS segregs;

	ENTER("file_read");

	inregs.h.ah = 0x3f;
	segregs.ds = FP_SEG(ptr);
	inregs.x.dx = FP_OFF(ptr);
	inregs.x.cx = size;
	inregs.x.bx = fd;

	intdosx(&inregs, &outregs, &segregs);

	if (outregs.x.cflag)
		RETURN(FAILURE);
	else
		RETURN(outregs.x.ax);
}

#else
int file_read(int fd, BUFFER *buf, int size)
{
	return (read(fd, buf, size) == size ? 0 : FAILURE);
}

#endif

/* end of file : loadpk.c */
