
/*
 *  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 <fcntl.h>
#include <io.h>
#include <errno.h>
#include "dd.h"
#include "dviread.h"
#if defined(TURBOC) || defined(MSC)
#ifndef _DEF_DOS_H_
#include <dos.h>
#define _DEF_DOS_H_
#endif
#endif
#include "err.h"

#define min(a,b) ( (a) < (b) ? (a) : (b) )
#define max(a,b) ( (a) > (b) ? (a) : (b) )

#if DEBUG & MEM_CHK
static void (*_bufchk) ();

#endif

/* buffer.c */
void pk_buf_flush(void);

/* loadpk.c */
char *to_font_name(char *);

int file_read(int, BUFFER *, int);
int ask_pk_buf(long size);
int openf(char *, int);
int flush_pk(void);
void flush_jpk(void);

int f_flush_pk;

#define READ_SIZE (1024*8)
/*  一度に読み込むサイズ */

static void buf_load(int fd, BUFFER *buf, long size)
	/*  bufにsizeだけ読み込みます．途中でファイルが終っても
     *  エラーにはなりません．ファイルもクローズしません．
     */
{
	int tmp_size;

	ENTER("buf_load");

	while (!eof(fd) && size > 0) {
		tmp_size = (int)min(READ_SIZE, size);
#if DEBUG & MEM_CHK
		(*_bufchk) (buf);
#endif
		if (file_read(fd, buf, tmp_size) == FAILURE)
			error(FILE_FAULT, "fail to read FONT");

		size -= tmp_size;
		buf += tmp_size;
	}
	END();
}

FILE *fopenf(char *name, char *mode)
{
	FILE *fp;

	if (*mode != 'w' && access(name, 0) != 0) return( NULL );
	if ((fp = fopen(name, mode)) == NULL){
		if( !flush_pk() || (fp = fopen(name, mode)) == NULL){
			flush_jpk();
			fp = fopen(name, mode);
		}
	}
	return( fp );
}

int openf(char *name, int mode)
{
	int fd;

	if ((fd = open(name, mode)) > 0 || errno != EMFILE )
		return (fd);
	if( flush_pk() ){
		if ((fd = open(name, mode)) > 0 || errno != EMFILE )
			return (fd);
	}
	flush_jpk();
	return( open(name,mode) );
}

int flush_pk()
{
	static FONT_INFO *font;
	FONT_INFO *fontc;

	if (font == NULL)
		font = first_font_info;
	fontc = font;
	do {
#ifndef VFD
		if ((fontc->font_type == PKD_FONT || fontc->font_type == JXL)
#else
		if ((fontc->font_type == PKD_FONT ||
			 fontc->font_type == VFD_FONT || fontc->font_type == JXL)
#endif
			&& fontc->ext.fh > 0) {
			close(fontc->ext.fh);
			f_flush_pk++;
			fontc->ext.fh = 0;
			font = font->next_font;
			return( 1 );
		}
		fontc = fontc->next_font;
		if (fontc == NULL)
			fontc = first_font_info;
	} while (font != fontc);
	return( 0 );
}


void flush_jpk()
{
	static FONT_INFO *font;
	static int flush_id;
	int fh;
	FONT_INFO *fontc;

	if (font == NULL)
		font = first_font_info;
	fontc = font;
	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;
			font = font->next_font;
			for( fontc = first_font_info; fontc; fontc = fontc->next_font ){
				if(fontc->font_type >= JIS_FONT && fontc->ext.kdir->fh == fh)
					fontc->ext.kdir->fh = flush_id;
			}
			return;
		}
		fontc = fontc->next_font;
		if (fontc == NULL)
			fontc = first_font_info;
	} while (font != fontc);
}


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)
{
	if ((HUGE_BUF *)pk_buf_pointer->end -
		(HUGE_BUF *)pk_buf_pointer->current <= size + 32) {
		if (pk_buf_pointer->size < size || size > 0xffe0L)
			return (FAILURE);
		pk_buf_flush();
	}
	return (NOTHING);
}

static BUFFER *
    load_pk_data(char *name)
	/*  load_pkのスケルトンモジュール． nameのフォントファイル
     *  を一括して bufに読み込む． バッファを溢れるときは，flush
     *  を呼び出す．
     *  返値は格納した場所．
     */
{
	int fd, i;
	long file_pos, file_size;
	long far *jxl_info;
	long tmp;
	FILE *fp;
	BUFFER *pk;

	ENTER("load_pk_data");

	if (*name == '*') {
		file_pos = *((long *)(name + 1));
		file_size = *((long *)(name + 5));
		if ((fd = openf(name + 9, O_RDONLY | O_BINARY)) == FAILURE
			|| lseek(fd, file_pos, SEEK_SET) == -1L)
			error(NO_FILE, name+9);
	}
	else {
		if ((fd = openf(name, O_RDONLY | O_BINARY)) == FAILURE)
			error(NO_FILE, name);
		file_size = filelength(fd);
	}
	_read(fd, &tmp, 4);
	if (tmp == 0x258B0100L) {
		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 ((*((long far *)pk_buf_pointer->current) = tmp) == 0x258B0100L) {
		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);
	}
	else {
		buf_load(fd, pk_buf_pointer->current + 4, file_size - 4);
		close(fd);
	}
	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

BUFFER *
    load_pk(char *name)
	/*  nameのfontを，一括して　_pk_bufに読み込む．
     */
{
	ENTER("load_pK");

#if DEBUG & MEM_CHK
	_bufchk = _pkbufchk;
	/* buffer access check */
#endif

	RETURN(load_pk_data(name));
}

#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);
}

#elif defined(x68k)
int file_read(int fd, BUFFER *buf, int size)
{
	return (read(fd, buf, size) == size ? 0 : FAILURE);
}

#endif

/* end of file : loadpk.c */
