/*
 *  TEX Device Driver  ver 2.02-
 *  (c) copyright 1988, 1989 by TSG, 1990-93 by SHIMA
 *
 *  main.c : MAIN MODULE
 *      Apr. 22, 1989 : 1st edition
 *      Jun.  1, 1989 : 2nd edition
 *
 *  1991 changed by hideki
 *	Modified for IBM-PC with DOS/V by SOLITON 12/10/1991
 *  This module becomes device-dependent which can be
 *  comment out by #undef IBMPC
 *	very slightly modified against warnings by Oh-Yeah? 25 May 1992
 *  modifed for LIPS3 by SHIMA 18 June 1992
 *  Modified for PC-9801 High-Resolution Mode by OKI 07/23/1992
 *	modified for LIPS3+ESC/Page by OkI & H.Tomiie 30 Sept. 1992
 *	slightly modified for JGfont(3D-Bezier) by Naochan! 12 Nov 1992
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#ifdef   UNIX
#include <unistd.h>
#else
#ifdef MSVC
#include "msvcdir.h"
#else
#include <dir.h>
#endif
#include <io.h>
# ifdef	GCC1
#include <djgppstd.h>
# else
#ifdef MSVC
#include <malloc.h>
#else
#include <alloc.h>
#endif
# endif
#endif

#include "dd.h"
#include "err.h"
#include "vfont.h"
#include "option.h"
#include "inter.h"
#ifdef	USE_SUBFONT
#include "subfont.h"
int sfd_count(int);
extern struct a_sfd_record {
  char *sfd_name, *sub_name;
  unsigned int vector[256];
} *sfd_record;
#endif

#define OPTION_FLG    '-'
#define	EXTENSION_FLG '.'
#define	F_GOTH		1
#ifndef	WIN32
static char *const default_dvifile_ext = "dvi";
#endif
#ifdef	HYPERTEX
extern int	n_h_box;
extern int max_h_box;
extern int n_h_name;
extern int max_h_name;
extern int pt_hyper_str;
extern char *hyper_str;
extern int max_hyper_str;
#endif

static void information_out(DIMENSION *);
#ifndef WIN32
static void dvifile_open(DVIFILE_INFO *, int, char **);
static void dvifile_close(DVIFILE_INFO *);
static 
#endif
char *name_link(char *, char *);
static void buffer_information(DIMENSION *);

extern int test_flg;

/* -f があるかどうか ( definition in init.c ) */
extern DIMENSION dviout_dimension;

/* name of the env-variable for pk-font path */

extern char *const title_name;
extern char *const title_comment;
extern char *const title_copyright;

static void information_out(DIMENSION *dim);
void show_fontinfo(FONT_INFO *, int *, int);

extern int f_flush_pk;
extern uint num_char;

uint resume_info;
int ARGC;

extern int f_wait;

/* init.c */
extern void get_config(int, char **);
extern void initialize(DVIFILE_INFO *, DIMENSION *);
void help_out(void);
#ifdef	DVI_ADD
int GetAddSize(int);
int GetAddTotal(void);
char *GetAddName(int);
#endif

BOOL f_resume;
extern char *resume_file;
static BOOL f_resume_file;

/* putdvi.c */
void put_dvi(DVIFILE_INFO *, DIMENSION *, int, char **);
extern int current_page;

/* vfont.c */
extern V_JFM *v_tfm;

/* buffer.c */
void *marea(unsigned int);

/* err.c */
BOOL ask_retry(void);

/* fontdef.c */
char *get_font_name(FONT_INFO *);
char *path_cash_info(void);

/* loadpk.c */
int resume_fontfile(int);

#ifndef	NOVFONT
/* vfont.c */
extern V_FONT *vfont[];
char *check_ftt(char *);
#endif

#ifdef TTFONT
/* sptopxl.asm  */
PIXEL sptopixel(SCALED_PT);
#endif

/* device.c */
void device_end(void);

/* epsbox.c */
int sizeofBMPdata(int);

/* putdvi.c */
extern BOOL device_open_flag;

/* misc.c */
#ifdef UNIX
void cbreak(int,int);
#endif

void Exit( int );
#ifndef WIN32
# if !defined(GCC)
static int	c_break( void );
# endif
static void get_start_page( void );
#endif

DVIFILE_INFO dvifile;

#ifndef	WIN32G
char *INIT_PARA =
"-G=goth;jisg"
#ifdef NO_OUTP
" -O"
#endif
;
#endif

#ifdef	WIN32G

void ShowInformation(void)
{
	information_out(&dviout_dimension);
}

void ShowBuffer(void)
{
	buffer_information(&dviout_dimension);
}

#else

# ifdef WIN32C
int f_osversion;
# endif
void main(int argc, char **argv)
{
	int i;

	ARGC = argc;
	error(DIRECT, 
			"%s%s%s\n\n", title_name, title_comment, title_copyright);
#if defined(UNIX)
	cbreak(0,0);
#elif !defined(GCC)
	ctrlbrk( c_break );
#endif
# ifdef WIN32C
	f_osversion = get_version();
# endif
	SetPara(INIT_PARA, SET_OPTION);
	get_config(argc, argv);

	dvifile_open(&dvifile, argc, argv);

	initialize(&dvifile, &dviout_dimension);

	/* dviファイル名よりレジューム情報を作成 */
	if (resume_file != NULL && *resume_file != '-') {
		if (*resume_file == '+' || *resume_file == 0){
			for (i = strlen(dvifile.file_name) - 4; i >= 0; i--)
				resume_info += ((int)dvifile.file_name[i]<<(i&7));
			f_resume = TRUE;
		}
		else get_start_page();
	}

	if (test_flg) 
		put_dvi(&dvifile, &dviout_dimension, argc, argv);
	if (test_flg == 3)
		Exit(0);
	information_out(&dviout_dimension);
	dvifile_close(&dvifile);
	resume_fontfile(0x7000);

	buffer_information(&dviout_dimension);

	EXIT(0);
}
#endif

#if	!defined(GCC) && !defined(WIN32)
static int	c_break( void )
{
	return( 1 );
}
#endif

void Exit(int para)
{
	FILE *fp;

	if (f_resume_file && (fp = fopenf(resume_file, "w")) != NULL){
		fprintf(fp, "%s %d\n", dvifile.file_name, current_page);
		fclose(fp);
	}
	if (device_open_flag)
		device_end();
#ifdef	UNIX
		cbreak(0,1);
#endif
	exit(para);
}

int no_extension(unsigned char *name)
{
	int flag = 1;
#ifdef	WINAPI
	BOOL f_japanese;
	f_japanese = IsJapanese();
#endif

	while(*name){
		if(*name == '\\' || *name == '/')
			flag = 1;
		else if(*name == '.')
			flag = 0;
		else if(
#ifdef	WINAPI
		  f_japanese &&
#endif
		   *name >= 0x81 && *name <= 0xef  && 
		  (*name <= 0x9f || *name >= 0xe0) && name[1] != 0)
			name++;
		name++;
	}
	return flag;
#if 0
	int len, len0;

	len0 = ((len = strlen(name)) > 4) ? len - 4 : 0;
	while (--len >= len0) {
		if (name[len] == EXTENSION_FLG)
			return (0);
		else if (name[len] == '\\' || name[len] == '/')
			break;
	}
	return (1);
#endif
}

int ToDviDir(void)
{
#ifdef	UNIX
	char fname[MAX_PATH];
#else
	char drive[MAXDRIVE], dir[MAXDIR], fname[MAXFILE], ext[MAXEXT];
#endif
	int len;

	if(dvifile.file_name == NULL)
		return 2;
#ifdef	UNIX
	strcpy(fname, dvifile.file_name);
	len = strlen(fname);
	while(--len >= 0){
		if(fname[len] == PATH_SEP){
			fname[len] = 0;
			break;
		}
	}
#else
	fnsplit(current_name, drive, dir, fname, ext);
	if( (len = tolower(*drive)) < 'a' || len > 'z')
		return 1;
	strcpy(fname, drive);
	strcat(fname, dir);
	if((len = strlen(fname)-1) >= 0 && fname[len] == PATH_SEP)
		fname[len] = 0;
#endif
	chdir(fname);
	return 0;
}

#ifndef	WIN32G
static void get_start_page(void)
{
	FILE *fp;
	int ch;
	char *fname;

	f_resume_file = TRUE;
	if ((fp = fopenf(resume_file, "r")) == NULL) return;
	for (fname = dvifile.file_name; *fname; fname++){
		if (fgetc(fp) != *fname) goto end;
	}
	if (fgetc(fp) == ' '){
		while((ch = fgetc(fp) - '0') >= 0 && ch <= 9)
			dviout_dimension.start_page = dviout_dimension.start_page*10 + ch;
	}
end:
	fclose(fp);
}


static void dvifile_open(DVIFILE_INFO *dvi, int argc, char **argv)
	/*  コマンドラインよりｄｖｉファイルをオープン
	 *  拡張子(.dvi)も考慮する．
	 */
{
	ENTER("dvifile_open");
	while (--argc) {
		if (**++argv != OPTION_FLG) {
			dvi->file_name = *argv;
			if (no_extension(*argv))
				dvi->file_name = name_link(*argv, default_dvifile_ext);
			while ((dvi->file_ptr = fopenf(dvi->file_name, "rb")) == NULL) {
				f_wait = 0;
				error(NO_FILE, dvi->file_name);
			}
			return;
		}
	}
	help_out();
}
#endif

#ifndef	WIN32G
static void dvifile_close(DVIFILE_INFO *dvi)
	/* ｄｖｉファイルをクローズ
	 */
{
	fclose(dvi->file_ptr);
}

static 
#endif
char *name_link(char *base, char *ext)
	/* ベース名と，拡張子をくっつける．
	 */
{
	static char name[MAX_PATH+1];
	int base_len;

	ENTER("name_link");

	if((base_len = strlen(base)) + strlen(ext) > MAX_PATH - 2)
		name[0] = 0;
	else{
		strcpy(name, base);
		name[base_len] = EXTENSION_FLG;
		strcpy(name + base_len + 1, ext);
	}
	RETURN(name);
}

static int open_num;
static void buffer_information(DIMENSION *dim)
	/* 最後に各バッファの使用状態が表示される */
{
	long size, total;
	int num;
	char *tmp;

	if (test_flg == 2) {
		error(C_MSG, 
					"\nflush = (Open %d, Bit %d, File %d, Raster %d)\n",
			   f_flush_pk, bitmap_buf_pointer->flush,
			   pk_buf_pointer->flush,
			   raster_buf_pointer->flush);
		error(DATATITLE, "State of Buffer Flush");
		return;
	}
#ifdef	WIN32G
	error(C_MSG, "Current ID\t\t: %d\n", id_dvi);

#endif
	error(C_MSG,
			"Files open\t\t: flush%3d, total%7d files\n",
		   f_flush_pk, open_num + 1);
	error(C_MSG, 
#ifdef	WIN32G
			 "Bit map buffer\t\t: flush%3d, total%8ld byte, used%8ld\n",
#else
			 "Bit map buffer\t\t: flush%3d, total%7ld byte, used%7ld "
			 "split%3d\n",
#endif
		   bitmap_buf_pointer->flush,
		   bitmap_buf_pointer->size,
		   (ulong)dim->buf_width / 8L * dim->buf_height,
		   dim->split);
#ifdef	WIN32G
	error(C_MSG, "\t\t\t  buffer size %d x %d,  text size %d x %d\n", 
		dim->buf_width, dim->buf_height,
		dim->text_width, dim->text_height);
#endif

	error(C_MSG, 
#ifdef	WIN32G
			 "Font file buffer\t: flush%3d, total%8lu byte, used%8lu""\n",
#else
			 "Font file buffer\t: flush%3d, total%7lu byte, used%7lu""\n",
#endif
		   pk_buf_pointer->flush, (ulong)pk_buf_pointer->size,
		   (ulong)((HUGE_BUF *)pk_buf_pointer->current
				   - (HUGE_BUF *)pk_buf_pointer->start)
	);
	size = (ulong)((HUGE_BUF *)raster_buf_pointer->current
				- (HUGE_BUF *)raster_buf_pointer->start);
	error(C_MSG,
#ifdef	WIN32G
		"Expanded font buffer\t: flush%3d, total%8lu byte, used%8lu #%u\n",
#else
		"Expanded font buffer\t: flush%3d, total%7lu byte, used%7lu #%u\n",
#endif
		   raster_buf_pointer->flush, (ulong)raster_buf_pointer->size, 
		   size , num_char);
#ifdef	WIN32G
#ifdef	USE_SUBFONT
	if((num = sfd_count(1)) > 0)
		error(C_MSG,
			"Subfont data buffer\t: count%3d, total %7lu byte, #%d\n", 
			num, num*sizeof(struct a_sfd_record), sfd_count(2));
#endif
	tmp = path_cash_info();
	if(*tmp)
		error(C_MSG, "Font Path Cash\t\t: %s\n", tmp);
#endif
#ifdef	HYPERTEX
	if(h_box != NULL){
		error(C_MSG,
		"HyperTeX buffer\t\t: href %d/%d, name %d/%d, string %d/%d\n",
		n_h_box - 2, max_h_box - 2, n_h_name, max_h_name, 
		pt_hyper_str, max_hyper_str);
	}
#endif
#ifdef WIN32G
	for(num = total = 0; (size = sizeofBMPdata(num++)) != 0; )
		total += size;
	if(total){
		error(C_MSG,
		"Color BMP buffer\t: #%7d, total%8ld byte\n",
		num-1, total);
	}
#ifdef	DVI_ADD
	for(num = 0; (size = GetAddSize(num)) >= 0; num++){
		if(!num)
			error(C_MSG, " - Include %d files -\n", GetAddTotal());
		error(C_MSG, " %s\t: %d byte\n", GetAddName(num), size);
	}
#endif
#endif
	error(DATATITLE, "Status of Buffers");
}

#ifndef	NOVFONT
	int vchk_flg;
#endif
#define	MAX_FOPEN	30
	/* test-flag時には，これが表示される．
	 */
static void information_out(DIMENSION *dim)
{
	FONT_INFO *font;
	int font_num, i;
	char *fname;

	int f_open[MAX_FOPEN];

	ENTER("information_out");

#ifndef	WIN32G
	error(C_MSG, "\n");
#endif

#ifndef	NOVFONT
	vchk_flg =
#endif
	font_num = open_num = 0;
	for (i = 0; i < MAX_FOPEN; i++)
		f_open[i] = 0;
	for (font = first_font_info; font != NULL; font = font->next_font) {
		font_num++;
		if (test_flg != 0) show_fontinfo(font, f_open, 0);
	}
#ifndef	WIN32G
	if (test_flg == 2 || test_flg < 0)
		return;
#endif
#ifdef	JAPANESE
	error(C_MSG,
			   "\n使用フォント\t\t: 以上 %d 個, (%d dpi)"
# ifdef	WIN32G
		",  "
# else
		"\n"
# endif
			   , font_num, dim->dpi);
	error(C_MSG, "magnification\t\t: %4d\n", dim->mag);
# ifndef	WIN32G
	error(C_MSG, "総ページ数\t\t: %4d\n", dim->total_page);
	error(C_MSG, "１ページ分割数\t\t: %4d\n\n", dim->split);
	error(C_MSG, "展開ビットマップサイズ\t: %d x %d dot\n", 
			dim->buf_width, dim->buf_height);
	error(C_MSG, "文書サイズ\t\t: %d x %d dot\n\n",
			dim->text_width, dim->text_height);
# endif
#else
	error(C_MSG, "font : total %d (%d dpi)"
# ifdef	WIN32G
		",  "
# else
		"\n"
# endif
		, font_num, dim->dpi);
	error(C_MSG, "mag  : %d\n", dim->mag);
# ifndef	WIN32G
	error(C_MSG, "page : %d\n", dim->total_page);
	error(C_MSG, "split: %d\n", dim->split);
	error(C_MSG, "buffer size : %d x %d\n", dim->buf_width, dim->buf_height);
	error(C_MSG, "text   size : %d x %d\n\n",
			dim->text_width, dim->text_height);
# endif
#endif
#ifdef	USE_SUBFONT
	for(i = 0; (fname = get_sfd_path(i++)) != NULL; ){
		if(i == 1)
			error(C_MSG, "\n---subfont---\n");
		error(C_MSG, "%2d %s\n", i, fname);
	}
#endif
	error(DATATITLE, "Status of Fonts");
}

void show_fontinfo(FONT_INFO *font, int *f_open, int depth)
{
	int f_kanji, i, fh;
	char *fname, *ftype;
	char *indent;
	char vec[8];
	V_JFM *vjfm;

	f_kanji = 0;
	ftype = "?";
	fname = "";
	switch (font->font_type) {

	  case (SUBTFM):
		  ftype = "TFM";
		  break;

	  case (SUBJFM):
		  ftype = (font->name[1] == '<')?"Unresolved":"JFM";
		  break;

	  case (PK_FONT):
		  ftype = "PK";
		  break;

	  case (PKD_FONT):
		  ftype = "PKD";
		  goto jxl;

#ifdef VFD
	  case (VFD_FONT):
		  ftype = "VFD";
		  goto jxl;
#endif
#ifdef TTFONT
	  case (CMTTF):
		  ftype = "TT";
		  goto jxl;
#endif

	  case (JXL):
		  ftype = "JXL";
jxl:	  if (font->ext.fh > 0) {
			  fname = "+";
			  open_num++;
		  } else {
			  fname = "-";
		  }
		  break;

#ifdef	VIRTUALFONT
	  case (VIRTUAL_FONT):
		  ftype = "Virtual";
		  break;
#endif
	  case (ROM_FONT):
		  ftype = "ROM";
		  f_kanji = 1;
		  break;
#ifndef	NOVFONT
#ifdef BEZIERFONT
	  case (JG_FONT):
#endif
#ifdef TTFONT
	  case (TT_FONT):
#endif
	  case (ZS_FONT):
		  strcpy(vec,"Vec(**)");
		  ftype = vec;
		  vjfm = get_vjfm((font->ext.kdir)->fh);
		  ftype[4] = (char)vjfm->long_wide;
		  ftype[5] = (char)vjfm->slant;
		  fname = (font->ext.kdir)->name;
		  f_kanji = 1;
		  if (vchk_flg++ == 0) {
			  for (i = 0; i < MAX_VFONT; i++) {
				  if (vfont[i] != NULL &&
					  vfont[i]->status == V_OPEN) {
					  open_num++;
					  if (vfont[i]->v_fh[1] > 0) open_num++;
#ifdef BEZIERFONT
					  if (vfont[i]->v_fh[2] > 0) open_num++;
#endif
				  }
			  }
		  }
		  break;
#endif
#ifdef	USE_WINFONT
	  case (WINTT_FONT):
winttf:	  vjfm = (V_JFM *)(font->vjfm);
ttf:	  fname = (vjfm==v_tfm)?check_ftt(font->n)
			:(vfont[vjfm->font_no]->v_font_name + 1);
		  ftype = "WinAPI";
		  break;

	  case (WINJTT_FONT):
		  f_kanji = 1;
		  vjfm = get_vjfm((font->ext.kdir)->fh);
		  goto ttf;
#endif
#ifdef	LBP
	  case (JLBP):
		  ftype = "LBPfont";
		  goto kfont0;
#endif

	  case (JIS_FONT):
		  ftype = "";
kfont:		  if ((fh = font->ext.kdir->fh) > 0) {
			  for (i = 0; i < MAX_FOPEN; i++) {
				  if (f_open[i] == fh)
					  break;
				  else if (f_open[i] == 0) {
					  f_open[i] = fh;
					  open_num++;
					  break;
				  }
			  }
		  }
kfont0:	  fname = (font->ext.kdir)->name;
		  f_kanji = 1;
		  break;

	  case (JIS_PK):
		  ftype = "PK";
		  goto kfont;

	  case (JIS_PKH):
		  ftype = "PK/H";
		  goto kfont;

	  case (GAIJI):
		  ftype = "KG";
		  goto kfont;

	  case (PXL1001):
		  ftype = "PXL1001";
		  break;

	  case (PXL1002):
		  ftype = "PXL1002";
		  break;

	  case (PXL1003):
		  ftype = "PXL1003";
		  break;

	  case (ETF_FONT):
		  switch(font->etf_type){
			 case CMTTF:
				ftype = "Embed TT";
				break;
			 case TT_FONT:
				ftype = "Embed JTT";
				break;
			 case PK_FONT:
				ftype = "Embed PK";
				break;
			 case VIRTUAL_FONT:
				ftype = "Embed VF";
				break;
			 case WINTT_FONT:
			 case WINJTT_FONT:
				ftype = "WinAPI";
				goto winttf;
			 default:
				ftype = "Embed ?";
				break;
		  }
		  break;
	}
#ifndef	WIN32G
	if (test_flg == 2 || test_flg < 0) return;
#endif
	i = font->n[MAX_NAME_LEN-1];
	indent = "\t\t\t\t\t" + 5 - ((depth > 5)? 5 : depth);
	error(C_MSG, "%s%5d %s(%d)%c%s\t%s %s", indent,  
		  font->font_code, font->n, font->dpi,
		  (font->font_type<=ONDEMAND2 || font->texpk_pos<0)?
			' ':((i==' ')?'^':i),
		  (strlen(font->n) <= 3)?"  ":"",
		  get_font_name(font), fname);
	if (f_kanji != 0) {
		error(C_MSG, "(%dx%d)", font->k_width, font->k_height);
		if (font->f_goth & K_DBL)
			error(C_MSG, "2");
		if (font->f_goth & F_GOTH)
			error(C_MSG, "G");
	}
#ifdef USE_SUBFONT
	if( (font->font_type == WINJTT_FONT || font->font_type == WINTT_FONT)
	  && font->sfd_id >= 0 )
		error(C_MSG, ":%s", sfd_record[font->sfd_id].sfd_name);
#endif
#ifdef TTFONT
	if (font->font_type == CMTTF) {
		error(C_MSG, "(%d)", sptopixel(font->size_para));
	}
#endif
	error(C_MSG, " %s\n", ftype);
#ifdef	VIRTUALFONT
	if (font->font_type == VIRTUAL_FONT
#ifdef	USE_ETF
	  || (font->font_type == ETF_FONT && font->etf_type == VIRTUAL_FONT)
#endif
	) {
		FONT_INFO *lf;
		for (lf = font->ext.local_font, i=0; lf && i++ < 256;
		  lf = lf->next_font) {
			show_fontinfo(lf, f_open, depth + 1);
		}
	}
#endif
}
