
/*
 *  TEX Device Driver  ver 2.02-
 *  (c) copyright 1988, 1989 by TSG, 1990-93 by SHIMA
 *
 *  pret.c : interpret module
 *     Jul.  1, 1989 : 2nd edition
 *     17 April 1992 : xxx1() modified for tpic specials by Oh-Yeah?
 *     14 June  1992 : modified for ptex by Oh-Yeah? (not finished yet ^^;)
 *                     Based on the specifications in pTeX 2.99 j1.7 1.0.9F
 *     30 June  1992 : modified for LIPS3 by SHIMA
 *     22 July  1992 : modified for ptex by Naochan (almost finished...)
 *                     Based on the specifications in pTeX 2.99 j1.7 1.0.9F
 *     8 August 1992 : modified for pTeX+LIPS3 by OkI
 */

#include <stdio.h>
#include <stdlib.h>
#include <mem.h>
#include <dos.h>
#define _DEF_STDIO_H_
#include "dd.h"
#include "err.h"
#include "dviread.h"
#ifdef LBP
# include "prtout.h"
#endif
static SCALED_PT h, v, w, x, y, z;
#ifndef NOPS
static SCALED_PT old_v;
#endif

char ptex_d;	/* ptex direction: 0 = yoko, 1 = tate */
char ptex_mode;
int use_lateral_kanji = 0;
int f_break_bitmap;	/* bitmap buffer is destroyed? */

static PIXEL H0, V0;

#ifdef	LBP
int f_first_split;	/* 最初のスプリット描画中であることを示す。
					   プリンタダウンロードフォントや内蔵フォントは
					   この時のみ出力される。*/
#endif

static FILE *dvi;
static long c[10];

/* count0-9 ( count0 is already read in init.c for making page-index ) */
static FONT_INFO *font;
int g_font;

/* current font */

/* bitmap.c */
void write_font(PIXEL, PIXEL, PREAMBLE *);
void write_rule(PIXEL, PIXEL, PIXEL, PIXEL);
void alter_bitblt_rt(BOOL flag);

/* clrbuf.asm ( or buffer.c ) */
void clear_buf(BUF_INFO *);

/* putdvi.c */
void init_output(OUTPUT_INFO *);

#ifndef	NOTPIC_EXTENSION
/* externals from bitblt.c */
extern BOOL rotate;		/* \special{rt}に回転・移動 */
extern int rot_angle;	/* \special{rt}による回転の角 */
void rotate_address(PIXEL *xp, PIXEL *yp);
#endif

/* buffer.c */
char *marea(unsigned int size);

/* getfont.c */
PREAMBLE *get_font(uint*, FONT_INFO *);

/* size.c, prtsize.c */
PIXEL sptopixel(SCALED_PT);
PIXEL vtopixel(SCALED_PT);

/* mult20.asm */
SCALED_PT mult20(SCALED_PT, SCALED_PT);

extern FONT_INFO *font_info_root;
extern char *goth;
extern BOOL draw_baseline;
extern BOOL draw_boxpic;
extern BOOL f_resize;

/* stack.c */
struct STACK {
	/* stack */
	SCALED_PT h, v, w, x, y, z;
	char ptex_d;	/* ptex direction: 0 = yoko, 1 = tate */
};

extern struct STACK *stack_buf;
extern int depth, STACK_MAX;
extern long sp_per_h, v_per_h;

#ifndef NOTPIC
/* tpic.c */
extern BOOL (*tpic_special) (char *special);

/* ptr to func. interpret or ignore special. Ret TRUE if interpreted */
#endif

#ifndef NOPS
/* epsbox.c */
extern BOOL (*epsbox_special)(char *special);
#endif

extern int f_assigned;

#ifdef	FDOWN
#define	D_BASE		0	/* arrange of dot height of downloaded fonts.
						   larger number means upper position. */

#define	MIN_COUNT	4	/* minimal number of occurency / fonts to download */

extern int f_download;
extern int f_jdwn;
extern int d_mincount;
extern int maxdfont;
extern long cur_dsize;
extern int f_font_on_edge;

int d_download(FONT_INFO *, int);
void d_work(void);
void d_init(void);
void d_resume(void);
static void d_put(uint);

#endif

void interpret(OUTPUT_INFO *output);
void do_special(char *special);

#ifdef	JDWN
int search_djtable(uint code, uint font_code);
#endif

/* static SCALED_PT spwidth( PREAMBLE* preamble ); */
static SCALED_PT cput(uint num);
static SCALED_PT rput(void);
static void font_change(int num);
static void set1(int code);
static void set_rule(void);
static void put1(int code);
static void put_rule(void);
static void nop(void);
static void push();
static void pop();
static void right1(int code);
static void w0();
static void w1(int code);
static void x0();
static void x1(int code);
static void down1(int code);
static void y0();
static void y1(int code);
static void z0();
static void z1(int code);
static void fnt1(int code);
static void xxx1(int code);
static void fnt_def_1(int code);
static void illegal(int code);
static void	draw_frame(OUTPUT_INFO *out);
static int work(void);

char *read_special(FILE * fp, unsigned int len);
PIXEL get_current_x(void);
PIXEL get_current_y(void);

#ifdef LBP
int p_out_char(PIXEL, PIXEL, FONT_INFO *, uint, PREAMBLE *);
#endif

#ifndef NO_NTTRPL
uint ntt_to_jis(uint, int);
extern BOOL ntt_subst;
#endif

/* bitmap.c */
void boxpic(PIXEL h, PIXEL v, PIXEL w, PIXEL d);

/* epsbox.c */
extern 	int current_gsps;

#ifdef FDOWN
 #ifndef NEMS

/* prtinit.c */
extern int system_ems[];

/* buffer.c */
int set_ems(int);

 #endif
#endif


extern DIMENSION dviout_dimension;
extern BOOL	f_use_new_size_option;

void rewrite_preamble_ptex(PREAMBLE *, uint);

void interpret(OUTPUT_INFO *output)
{
	int i;

	ENTER("interpret");
#define	F_PRINTER	0x80

resume:
	font = NULL;
	h = v = w = x = y = z = ptex_d
#ifndef	NOPS
		= old_v = current_gsps
#endif
		= 0;
	dvi = output->dvifile_ptr;
	H0 = output->h_0;
	V0 = output->v_0;
#ifdef	LBP
	f_first_split=(dviout_dimension.split == 1 || output->split == 1);
#endif
	if ((uchar)read_byte(dvi) != BOP)
		error(COMMAND_ERROR, "No BOP");

	for (i = 0; i < 10; ++i)
		c[i] = read_long(dvi);

	fseek(dvi, 4L, SEEK_CUR);
	/* skip file-offset of next page */

#ifdef	FDOWN
	if (f_download == 1)
		d_work();
	else
#endif
	{
		if (work() == FALSE){
			output->bitmap_ptr = (HUGE_BUF *)bitmap_buf_pointer->start;
			init_output(output);
			clear_buf(bitmap_buf_pointer);
			goto resume;
		}
	}
	if ((dviout_dimension.prt_type & F_PRINTER) && f_use_new_size_option)
		draw_frame(output);
	END();
}

static void	draw_frame(OUTPUT_INFO *out)
{
	int length;

#if !defined(NOTPIC) && !defined(NOTPIC_EXTENSION)
	alter_bitblt_rt(FALSE);									/* rt を解除 */
#endif
	if (out->split == 1){
		write_rule(0,0,-1,dviout_dimension.text_width);			/* top */
	}
	if (out->split == dviout_dimension.split){
		length = dviout_dimension.text_height
				- dviout_dimension.buf_height*(out->split-1) - 1;
		write_rule(0,length,1,dviout_dimension.text_width);		/* bottom */
	}
	else
		length = out->height - 1;
	write_rule(0,0,-length,1);									/* left */
	write_rule(dviout_dimension.text_width-1,0,-length,1);		/* right */
}

/* static SCALED_PT spwidth( PREAMBLE* preamble ) */
/* return scaled-pt width of current character */
/*
{
    SCALED_PT width;
    width = (preamble->tfm_width * (font->size_para >> 12) ) >> 8;
    width +=
	((preamble->tfm_width >> 4 )*( (font->size_para  >> 4 ) & 0xff )) >> 12;
	return( mult20( preamble->tfm_width, font->size_para ) );
}
 */

static SCALED_PT cput(uint num)
	/* put character num on (h,v) ( not change both h and v ) */
	/* return sp-width of the character */
{
	PIXEL H, V, feed;
	int g_loop, tmp;
	PREAMBLE *preamble;
	long tfmwidth;
#ifdef	FDOWN
	PIXEL H1, V1;
#endif

	ENTER("cput");

#ifndef NO_NTTRPL
	if (ntt_subst && (font->code_offset >= 0))
		num = ntt_to_jis(num, font->code_offset);
#endif
	tfmwidth = (preamble = get_font(&num, font))->tfm_width;
	if (ptex_mode
#ifdef LBP
		&& (font->font_type != JLBP || draw_boxpic)
#endif
		)
		rewrite_preamble_ptex(preamble, num);

	H = sptopixel(h) - H0;
	V = vtopixel(v) - V0;
	if (draw_baseline != 0) {
		if (ptex_d == 1) {		/* 縦書きの場合 */
			feed = vtopixel(preamble->tfm_width);
			write_rule(H, V + feed, feed, 1);
		}
		else {
			write_rule(H, V, 1, sptopixel(preamble->tfm_width));
		}
	}
	
#ifdef FDOWN
	if (f_assigned){
 #if	!defined(NOTPIC) && !defined(NOTPIC_EXTENSION)
		if (rot_angle % 90 != 0
 #endif
 #ifdef	BIGFONT
			|| f_assigned >= 3
 #endif
		) goto no_dw;
			/* downloaded character */
		if (f_first_split || f_font_on_edge){
			if (dviout_dimension.print_direction == HORIZONTAL){
				H1 = dviout_dimension.x_offset;
				V1 = dviout_dimension.y_offset;
			}
			else{
				H1 = dviout_dimension.y_offset;
				V1 = dviout_dimension.x_offset;
			}
			if (ptex_d == 1)
				H1 += D_BASE;
			else
				V1 += preamble->height + D_BASE;
			if (p_out_char(H + H0 + H1, V + V0 + V1, font, num, preamble) != 0)
				goto no_dw;
		}
		goto end;
	}
#endif
#ifdef LBP
	if (g_font & F_LBP) {		/* scalable font */
		/* 回転角, H1,V1,H2,V2 については extern で直接参照 */
		if (f_first_split)
			p_out_char(H, V, font, num, preamble);
		goto end;
	}
#endif
no_dw:
	g_loop = (g_font & F_GOTH);
rep:
	write_font(H, V, preamble);
	if (g_loop
#if	defined(FDOWN) || defined(BIGFONT)
		&& f_assigned <= 3
#endif
	) {
		g_loop = 0;
		if (ptex_d == 1)
			V++;
		else
			H++;
		goto rep;
	}
end:
	RETURN(tfmwidth);
}

static SCALED_PT rput(void)
	/* put rule on (h,v) ( not change both h and v ) */
	/* return sp-width of the rule */
{
	PIXEL A, B;
	SCALED_PT a, b;

	ENTER("rput");

	a = read_long(dvi);
	b = read_long(dvi);
	if (ptex_d == 1) {
		if (b > 0 && a != 0) {
			A = sptopixel(a + ((a > 0) ? (sp_per_h) : (-sp_per_h)));
			B = vtopixel(b + v_per_h);
			write_rule(sptopixel(h) - H0, vtopixel(v + v_per_h + b) - V0,
					   B, A);
		}
	}
	else {
		if (b > 0 && a != 0) {
			A = vtopixel(a + ((a > 0) ? (v_per_h) : (-v_per_h)));
			B = sptopixel(b + sp_per_h);
			write_rule(sptopixel(h) - H0, vtopixel(v) - V0, A, B);
		}
	}
	RETURN(b);
}

static void font_change(int num)
	/* change current font into font 'num' */
{

	ENTER("font_change");
	for (font = font_info_root; font != NULL;) {
		if (font->font_code == num) {
			g_font = (font->f_goth & (F_LBP | F_DWN | F_ATTR));
			END();
		}
		font = (font->font_code < num) ?
			font->after_font : font->before_font;
	}

	error(FONT_MISMATCH, "%d", num);
	END();
}

static void set1(int code)
{
	SCALED_PT tmp;

	ENTER("set1");
	tmp = cput((uint)read_n(dvi, code - SET1 + 1));
	if (ptex_d == 1)
		v += tmp;
	else
		h += tmp;
	END();
}

static void set_rule(void)
{
	SCALED_PT tmp;

	ENTER("set_rule");

	tmp = rput();
	if (ptex_d == 1)
		v += tmp;
	else
		h += tmp;
	END();
}

static void put1(int code)
{
	ENTER("put1");

	(void)cput((uint)read_n(dvi, code - PUT1 + 1));
	END();
}

static void put_rule(void)
{
	ENTER("put_rule");

	(void)rput();
	END();
}

static void nop(void)
{
}

static void push()
{
	struct STACK *stack;

	ENTER("push");

	(stack = &(stack_buf[depth]))->h = h;
	stack->v = v;
	stack->w = w;
	stack->x = x;
	stack->y = y;
	stack->z = z;
	stack->ptex_d = ptex_d;
	if (++depth >= STACK_MAX)
		error(PROGRAM_STOP, "Stack Over flow");

	END();
}

static void pop()
{
	struct STACK *stack;

	ENTER("pop");

	if (--depth < 0)
		error(PROGRAM_STOP, "Stack Under flow");

	h = (stack = &(stack_buf[depth]))->h;
	v = stack->v;
	w = stack->w;
	x = stack->x;
	y = stack->y;
	z = stack->z;
	ptex_d = stack->ptex_d;

	END();
}

static void right1(int code)
{
	SCALED_PT tmp;

	ENTER("right1");
	tmp = signed_read_n(dvi, code - RIGHT1 + 1);
	if (ptex_d == 1)
		v += tmp;
	else
		h += tmp;
	END();
}

static void w0()
{
	if (ptex_d == 1)
		v += w;
	else
		h += w;
}

static void w1(int code)
{
	ENTER("w1");
	w = signed_read_n(dvi, code - W1 + 1);
	if (ptex_d == 1)
		v += w;
	else
		h += w;
	END();
}

static void x0()
{
	if (ptex_d == 1)
		v += x;
	else
		h += x;
}

static void x1(int code)
{
	ENTER("x1");

	x = signed_read_n(dvi, code - X1 + 1);
	if (ptex_d == 1)
		v += x;
	else
		h += x;
	END();
}

static void down1(int code)
{
	SCALED_PT tmp;

	ENTER("down1");
	tmp = signed_read_n(dvi, code - DOWN1 + 1);
	if (ptex_d == 1)
		h -= tmp;
	else
		v += tmp;
	END();
}

static void y0()
{
	if (ptex_d == 1)
		h -= y;
	else
		v += y;
}

static void y1(int code)
{
	ENTER("y1");
	y = signed_read_n(dvi, code - Y1 + 1);
	if (ptex_d == 1)
		h -= y;
	else
		v += y;
	END();
}

static void z0()
{
	if (ptex_d == 1)
		h -= z;
	else
		v += z;
}

static void z1(int code)
{
	ENTER("z1");
	z = signed_read_n(dvi, code - Z1 + 1);
	if (ptex_d == 1)
		h -= z;
	else
		v += z;
	END();
}

static void fnt1(int code)
{
	ENTER("fnt1");

	font_change((int)read_n(dvi, code - FNT1 + 1));
	END();
}

static void xxx1(int code)
	/* specials are handed to external interpreters */
{

#if	!defined(NOTPIC) || !defined(NOPS)
	char *special;
	long size;

	ENTER("xxx1");

	size = read_n(dvi, code - XXX1 + 1);
	if (size >= 0xffffL || (special = read_special(dvi, (uint)size))== NULL){
		error(WARNING, "No memory to read special");
		fseek(dvi, size, SEEK_CUR);
		return;
	}
	do_special(special);
	free(special);
#else
	/* Here may come a call to non-tpic interpreters ... */
		
	    ENTER("xxx1");
	fseek(dvi, (long)read_n(dvi, code - XXX1 + 1), SEEK_CUR);
	/* just ignore and skip it */

#endif

	END();
}

void do_special(char *special)
{
	static int unknown_special;

# ifndef NOTPIC
	if ((tpic_special)(special)) return;		/* found */
# endif
# ifndef NOPS
	if ((epsbox_special)(special)) return;		/* found */
# endif
	if(!unknown_special){
		error(WARNING, "Unknown special:%.160s", special);
		unknown_special = 1;
	}
}

static void fnt_def_1(int code)
{
	int skip;

	ENTER("fnt_def_1");

	fseek(dvi, (long)(code - FNT_DEF_1 + 13), SEEK_CUR);
	skip = (uchar)read_byte(dvi) + (uchar)read_byte(dvi);
	fseek(dvi, (long)skip, SEEK_CUR);
	END();
}

static void illegal(int code)
	/* unknown commands */
{
	ENTER("illegal");
	if (ptex_mode != 0 && code == 255)
		ptex_d = read_byte(dvi);
	else
		error(COMMAND_ERROR, "Illegal command %d", code);
	END();
}

/*      set_char_0,	         0 SET_CHAR_0	*/
static void_func_ptr cmd128[] =
{
	set1,	/* 128 SET1			*/
	set1,	/* 129				*/
	set1,	/* 130				*/
	set1,	/* 131				*/
	set_rule,	/* 132 SET_RULE		*/
	put1,	/* 133 PUT1			*/
	put1,	/* 134				*/
	put1,	/* 135				*/
	put1,	/* 136				*/
	put_rule,	/* 137 PUT_RULE		*/
	nop,	/* 138 NOP			*/
	illegal,	/* 139 BOP			*/
	illegal,	/* 140				*/
	push,	/* 141 PUSH			*/
	pop,	/* 142 POP			*/
	right1,	/* 143 RIGHT1		*/
	right1,	/* 144				*/
	right1,	/* 145				*/
	right1,	/* 146				*/
	w0,/* 147 W0			*/
	w1,/* 148 W1			*/
	w1,/* 149				*/
	w1,/* 150				*/
	w1,/* 151				*/
	x0,/* 152 X0			*/
	x1,/* 153 X1			*/
	x1,/* 154				*/
	x1,/* 155				*/
	x1,/* 156				*/
	down1,	/* 157 DOWN1		*/
	down1,	/* 158				*/
	down1,	/* 159				*/
	down1,	/* 160				*/
	y0,/* 161 Y0			*/
	y1,/* 162 Y1			*/
	y1,/* 163				*/
	y1,/* 164				*/
	y1,/* 165				*/
	z0,/* 166 Z0			*/
	z1,/* 167 Z1			*/
	z1,/* 168				*/
	z1,/* 169				*/
	z1 /* 170				*/
};

/*      fnt_num_0,     171 FNT_NUM_0	*/

static void_func_ptr cmd235[] =
{
	fnt1,	/* 235 FNT1			*/
	fnt1,	/* 236				*/
	fnt1,	/* 237				*/
	fnt1,	/* 238				*/
	xxx1,	/* 239 XXX1			*/
	xxx1,	/* 240				*/
	xxx1,	/* 241				*/
	xxx1,	/* 242				*/
	fnt_def_1,	/* 243 FNT_DEF_1 	*/
	fnt_def_1,	/* 244				*/
	fnt_def_1,	/* 245				*/
	fnt_def_1,	/* 246				*/
	illegal,	/* 247 PRE			*/
	illegal,	/* 248				*/
	illegal,	/* 249				*/
	illegal,	/* 250				*/
	illegal,	/* 251				*/
	illegal,	/* 252				*/
	illegal,	/* 253				*/
	illegal,	/* 254				*/
	illegal	/* 255 EOFNC(pTeX DIR) */
};

static void_func_ptr *cmd128_ptr = cmd128;
static void_func_ptr *cmd235_ptr = cmd235;

/* ptr to command tables. used for override work() */

static int work(void)
{

	int code;

	ENTER("work");

	while ((code = (uchar)read_byte(dvi)) != EOP) {
		if (code < 128)
			if (ptex_d == 1)
				v += cput((uint)code);
			else
				h += cput((uint)code);
		else if (code < FNT_NUM_0)
			(cmd128_ptr[code - 128]) (code);
		else if (code < FNT1)
			font_change((int)(code - FNT_NUM_0));
		else{
			(cmd235_ptr[code - FNT1]) (code);
			if (f_break_bitmap){
				f_break_bitmap = 0;
				return(FALSE);
			}
		}
	}
	RETURN(TRUE);
}

#ifdef	FDOWN
/*
void d_init( void )
{

}
*/

#ifdef	JDWN
#define	MAX_DJ	0x6000
char far *djfont_top;
char far *djfont_last;
uint dj_current;
DJTABLE* dj;
uchar dj_font_code;
uchar dj_code;
int f_gaiji;

extern char *f_out;
extern FILE *fp_out;

extern trans_jis(uint);
#endif

void d_put(uint code)
{
	int i;
#ifdef	JDWN
	unsigned int far *to;
	DJFONT *pt;
#endif

#ifndef NO_NTTRPL
	if (ntt_subst && (font->code_offset >= 0))
		code = ntt_to_jis(code, font->code_offset);
#endif

	font->ext.count++;

	if (font->font_code & 0xff00) return;
	if (code & 0xff00){
#ifdef	JDWN
		if (!f_jdwn) return;
		if (dj_current == 0){
			djfont_top = (char far *)bitmap_buf_pointer->current
							+ sizeof(struct DJFONT_COUNT);
			(HUGE_BUF *)bitmap_buf_pointer->current += MAX_DJ;
			if ((HUGE_BUF *)bitmap_buf_pointer->current >
				(HUGE_BUF *)bitmap_buf_pointer->end) goto no_mem;
		}
		for (pt = (DJFONT *)font->char_info[(CHAR_ROOT-1)&code];;){
			if (pt->code == code){
				if (pt->count < 0xff) pt->count++;
				return;
			}
			to = (pt->code > code)? &(pt->after):&(pt->before);
			if (!*to) break;
			pt = (DJFONT *)(djfont_top + *to);
		}
		if (dj_current < MAX_DJ - sizeof(struct DJFONT_COUNT)){
			pt = (DJFONT*)(djfont_top + dj_current);
			if(font->char_info[(CHAR_ROOT-1)&code] == NULL)
				font->char_info[(CHAR_ROOT-1)&code] = (CHAR_INFO*)pt;
			else
				*to = dj_current;
			dj_current += sizeof(struct DJFONT_COUNT);
			pt->before = pt->after = pt->count = 0;
			pt->code = code;
			pt->font_code = font->font_code;
		}
		else dj_code = 1;
#endif
		return;
	}

	if (font->pk == NULL) {
/*		font->ext.count = 1;	*/
		font->pk = bitmap_buf_pointer->current;
		(HUGE_BUF *)bitmap_buf_pointer->current += 256;
		if ((HUGE_BUF *)bitmap_buf_pointer->current >
			(HUGE_BUF *)bitmap_buf_pointer->end)
no_mem:		error(NO_MEMORY, "Not enough bitmap buffer");
	}
	if ((font->pk)[code] != 0xff)
		(font->pk)[code]++;
}

#ifdef	JDWN
int search_djtable(uint code, uint font_code)
{
	int	top, last, tmp;
	DJTABLE *dj;

	top = 0;
	last = dj_current-1;

#ifndef	NEMS
	if (system_ems[1] >= 0) set_ems(system_ems[1]);
#endif
	while(top <= last){
		tmp = (top + last)/2;
		dj = ((DJTABLE*)djfont_top) + tmp;
		if (dj->code == code){
			if(dj->font_code < font_code) goto former;
			else if(dj->font_code > font_code) goto later;
			dj_code = dj->new_code;
			dj_font_code = dj->new_font_code;
			return(1);
		}
		if (dj->code > code)
later:		top  = tmp + 1;
		else
former:		last = tmp - 1;
	}
	return(0);
}
#endif

void d_resume(void)
{
	BUFFER *pt;
	FONT_INFO *dfont;
	uchar *dw;
	long maxcount;
	int i, j, k, c_max;
	uchar b;
#ifdef	JDWN
	DJFONT *dpt;
	DJFONT *dpt0;
	DJTABLE *dpt1;
	DJFONT *dpt_last;
	char *kname;
	unsigned int num;
	long lnum;

	dpt_last = (DJFONT*)(djfont_top + dj_current);
	if (!dj_current) goto nojdwn;

			/* sort by the number of times used (KANJI FONT) */
	for (dpt = (DJFONT*)djfont_top; dpt < dpt_last; ){
		if (f_gaiji) dpt->code = trans_jis(dpt->code);
		num = *(unsigned int far*)&((dpt0 = dpt)->font_code);
		k = num & 0xff;
		j = dpt0->code;
		while (dpt-- > (DJFONT*)djfont_top){
			if (f_gaiji){
				if (dpt->font_code < k) break;
				if (dpt->font_code == k && dpt->code < j) break;
				goto transpos;
			}
			if (num >= 0x100 && num > *(unsigned int far *)&(dpt->font_code)){
transpos:		*(unsigned int far*)&((dpt+1)->font_code) =
					*(unsigned int far*)&(dpt->font_code);
				(dpt+1)->code = dpt->code;
			}
			else break;
		}
		dpt++;
		*(unsigned int far*)&(dpt->font_code) = num;
		dpt->code = j;
		dpt = dpt0 + 1;
	}

	if (f_gaiji){
		k = -1;
		if (fp_out == NULL) fp_out = stdout;
		dw = (fp_out == stdout)? "\n":"\xd\xa";
		if (dj_code) fprintf(fp_out, "\n## Over");
		for (i = j = 0, dpt = (DJFONT*)djfont_top; dpt < dpt_last; i++, dpt++){
			if (k != dpt->font_code){
				font_change(k = dpt->font_code);
				for(num = 0; num < CHAR_ROOT; num++)
					font->char_info[num] = NULL;
				num = dpt->code;
				get_font(&num, font);
				kname = ((num = GAIJI - font->font_type) <= (GAIJI - ZS_FONT))?
					font->ext.kdir->name:"";
				if (f_out == NULL || (!num && font->ext.kdir->width == 1)){
					fprintf(fp_out, "\n# %s %s%s# %3d:%d:%dx%d(%dx%d)%s",
						get_font_name(font), kname, dw,
						font->font_code, num, font->k_width, font->k_height,
						font->ext.kdir->width, font->ext.kdir->height, dw);
					j = 1;
				}
				else j = 0;
			}
			if (j == 1)
				fprintf(fp_out, "%04X%5d%s", dpt->code, dpt->count + 1, dw);
		}
		exit(0);
	}
		/* ignore the characters rarely used (KANJI FONT) */
	while (dpt_last-- > (DJFONT *)djfont_top && dpt_last->count < d_mincount);
	dpt_last++;
nojdwn:
	dj_current = (djfont_last = (char far*)dpt_last) - djfont_top;

#endif

	i = 0;
	for (font = first_font_info; font; font = font->next_font) {
		font->last = 0;
		if ((pt = font->pk) == NULL){
#ifndef NO_NTTRPL
			if (ntt_subst && (font->code_offset >= 0)
							&& (font->family_code != font->font_code))
				continue;
#endif
			if(font->ext.count > 0) maxdfont--;
			continue;
		}
		for (c_max = 0xff; c_max >= 0x80 && pt[c_max] == 0; c_max--);
		i += (font->last = (c_max >= 0x80) ? (256 >> 3) : (128 >> 3));
	}

	if (i > 0)
		dw = marea(i);

	for (font = first_font_info; font; font = font->next_font) {
		if ((pt = font->pk) == NULL) {
			font->ext.count = 0;
			for(i = 0; i < CHAR_ROOT; i++) font->char_info[i] = NULL;
			continue;
		}
		font->pk = NULL;
		c_max = (font->last << 3);
		font->d_flag = dw;
		for (i = -1, j = k = b = 0; j < c_max; b <<= 1, j++) {
			if (b == 0) {
				b = 1;
				dw[++i] = 0;
			}
			if (pt[j] >= d_mincount && (j & 0x7f) != 0x20) {
				dw[i] |= b;
				k = j;
			}
		}
		if (k < 128)
			font->last = (128 >> 3);
		dw += font->last;
	}

	fprintf(stderr, "\nDownloading: ");
	for (;;) {
		for (maxcount = MIN_COUNT - 1, dfont = NULL, font = first_font_info;
			 font; font = font->next_font) {
			if ((font->f_goth & F_DWN) == 0
				&& font->last != 0
				&& font->font_type < JXL
				&& font->ext.count > maxcount) {
				maxcount = font->ext.count;
				dfont = font;
			}
		}
		if (dfont == NULL)
			break;				/* no more font to download */
		dfont->ext.count = 0;
		if (d_download(dfont, 0) != 0)
			goto end;
		if (dfont->last > (128 >> 3) && d_download(dfont, 0x80) != 0)
			goto end;
		dfont->last = 0;
	}
#ifdef	JDWN
	for (dfont = first_font_info; dfont; dfont = dfont->next_font) {
		if ((dfont->f_goth & F_DWN) == 0){
			if (d_download(dfont, 0x100) != 0) break;
			if (d_download(dfont, 0x180) != 0) break;
		}
	}
#endif
  end:
#ifdef	JDWN
	for ((void far*)dpt = (void far*)dpt1 = (void far*)djfont_top;
	  dpt < dpt_last; dpt++){
		if (dpt->after == 5){
			dpt1->code =  dpt->code;
			dpt1->font_code = dpt->font_code;
			dpt1->new_code = dpt->count;
			dpt1->new_font_code = dpt->before;
			dpt1++;
		}
	}
	djfont_last = (void far*)dpt1;
	dj_current = djfont_last - djfont_top;

		/* sort characters in DJ TABLE */
	for (dpt1 = (DJTABLE*)djfont_top + 1; dpt1 < (DJTABLE*)djfont_last; ){
		(DJTABLE*)dpt0 = dpt1;
		while ( dpt1-- > (DJTABLE*)djfont_top ){
			if ( dpt1->code < (dpt1+1)->code
			  || (dpt1->code == (dpt1+1)->code
				&& dpt1->font_code < (dpt1+1)->font_code)){
				lnum = *(long far *)(dpt1+1);
				*(long far *)(dpt1+1) = *(long far *)dpt1;
				*(long far *)dpt1 = lnum;
				num = (dpt1+1)->new_font_code;
				(dpt1+1)->new_font_code = dpt1->new_font_code;
				dpt1->new_font_code = num;
			 }
			 else break;
		}
		dpt1 = ((DJTABLE*)dpt0) + 1;
	}
	if (dj_current > 0){

 #ifndef	NEMS
		if (system_ems[1] >= 0)
			set_ems(system_ems[1]);
 #endif
		movedata(FP_SEG(djfont_top), FP_OFF(djfont_top), 
				 FP_SEG(dj), FP_OFF(dj), dj_current);
	}
	dj_current /= sizeof(struct DJFONT_TABLE);
	djfont_top = (char far*)dj;
#endif
	bitmap_buf_pointer->current = bitmap_buf_pointer->start;
	for (font = first_font_info; font; font = font->next_font){
		if(font->font_type == UNKNOWN)
			font->ext.count = 0;
	}
	fprintf(stderr, " %dK byte", (int)((cur_dsize + 512) >> 10));
	f_download++;
}

void d_work(void)
{
	/*      set_char_0,	         0 SET_CHAR_0	*/
	static uchar cmd128[] =
	{
		0x31,	/* 128 SET1			*/
		0x32,	/* 129				*/
		0x33,	/* 130				*/
		0x34,	/* 131				*/
		8,	/* 132 SET_RULE		*/
		1,	/* 133 PUT1			*/
		2,	/* 134				*/
		3,	/* 135				*/
		4,	/* 136				*/
		8,	/* 137 PUT_RULE		*/
		0,	/* 138 NOP			*/
		0x10,	/* 139 BOP			*/
		0x10,	/* 140				*/
		0,	/* 141 PUSH			*/
		0,	/* 142 POP			*/
		1,	/* 143 RIGHT1		*/
		2,	/* 144				*/
		3,	/* 145				*/
		4,	/* 146				*/
		0,	/* 147 W0			*/
		1,	/* 148 W1			*/
		2,	/* 149				*/
		3,	/* 150				*/
		4,	/* 151				*/
		0,	/* 152 X0			*/
		1,	/* 153 X1			*/
		2,	/* 154				*/
		3,	/* 155				*/
		4,	/* 156				*/
		1,	/* 157 DOWN1		*/
		2,	/* 158				*/
		3,	/* 159				*/
		4,	/* 160				*/
		0,	/* 161 Y0			*/
		1,	/* 162 Y1			*/
		2,	/* 163				*/
		3,	/* 164				*/
		4,	/* 165				*/
		0,	/* 166 Z0			*/
		1,	/* 167 Z1			*/
		2,	/* 168				*/
		3,	/* 169				*/
		4	/* 170				*/
	};

	/*      fnt_num_0,     171 FNT_NUM_0	*/

	static uchar cmd235[] =
	{
		0x41,	/* 235 FNT1			*/
		0x42,	/* 236				*/
		0x43,	/* 237				*/
		0x44,	/* 238				*/

		0x51,	/* 239 XXX1			*/
		0x52,	/* 240				*/
		0x53,	/* 241				*/
		0x54,	/* 242				*/

		0x21,	/* 243 FNT_DEF_1 	*/
		0x22,	/* 244				*/
		0x23,	/* 245				*/
		0x24,	/* 246				*/

		0x10,	/* 247 PRE			*/
		0x10,	/* 248				*/
		0x10,	/* 249				*/
		0x10,	/* 250				*/
		0x10,	/* 251				*/
		0x10,	/* 252				*/
		0x10,	/* 253				*/
		0x10,	/* 254				*/
		0x10	/* 255 EOFNC		*/
	};
	int code, mode;
	long tmp;

	while ((code = (uchar)read_byte(dvi)) != EOP) {
		if (code < 128)
			d_put((uint)code);
		else if (code < FNT_NUM_0) {
			mode = cmd128[code - 128];
			goto work;
		}
		else if (code < FNT1)
			font_change((int)(code - FNT_NUM_0));
		else {
			mode = cmd235[code - FNT1];
work:
			if (mode >= 0x30)
				tmp = (long)read_n(dvi, mode & 0xf);
			switch (mode >> 4) {

			  case (0):
				  while (mode--)
					  (void)read_byte(dvi);
				  break;

			  case (1):
				  illegal(code);
				  break;

			  case (2):
				  fseek(dvi, (long)((mode & 0xf) + 12), SEEK_CUR);
				  tmp =
					  (uchar)read_byte(dvi) + (uchar)read_byte(dvi);
skip:			  while (tmp--)
					  (void)read_byte(dvi);
				  /* fseek( dvi,  tmp, SEEK_CUR ); the above is quicker */
				  break;

			  case (3):
				  d_put((int)tmp);
				  break;

			  case (4):
				  font_change((int)tmp);
				  break;

			  case (5):
				  goto skip;
			}
		}
	}
}

#endif

/* end of file : pret.c */

/* additional functions by Oh-Yeah? */

#if !defined(NOTPIC) || !defined(NOPS)

char *
    read_special(FILE * fp, unsigned int len)
	/* read str. caution: buffer overwritten */
{
	static char *buf_ptr = NULL;
	char *pt;

	ENTER("read_special");
	buf_ptr = (char *)marea(len + 1);
	if (buf_ptr != NULL) {
		pt = buf_ptr;
		while (len-- > 0)
			*pt++ = getc(fp);
		*pt = '\0';
	}
	RETURN(buf_ptr);
}

PIXEL get_current_x(void)
{
	ENTER("get_current_x");
	RETURN(sptopixel(h) - H0);
}

PIXEL get_current_y(void)
{
	ENTER("get_current_y");
	RETURN(vtopixel(v) - V0);
}

#endif /* end of ifndef NOTPIC */

#ifndef	NOPS
PIXEL get_old_y(void)
{
	ENTER("get_old_y");
    RETURN(vtopixel(old_v) - V0);
}
#endif

void rewrite_preamble_ptex(PREAMBLE *preamble, uint char_code)
	/* フォントの補正・回転などに関する、データの書き換え部
     */
{
	PIXEL p_up, p_right, height, width;
	char p_rotate, p_mirror;

	p_up = p_right = p_rotate = p_mirror = 0;
	if (ptex_d == 1){
		if (font->font_type == JXL){
			p_rotate = 8;
			goto set;
		}
		if (char_code < 0x0100)
			p_rotate = 3;
		else if (font->font_type == UNKNOWN) return;
		else if ((0x2145 < char_code) && (char_code < 0x215C))
			p_rotate = 1;
		else if(char_code < 0x2600){
			/* ptex_d == 1 なので width は漢字送り方向（すなわち縦）*/
#ifdef BIGFONT
			if (f_assigned == 3 && f_resize){
				height = font->k_width;
				width  = font->k_height;
			}else
#endif
			{
				height = preamble->height;
				width  = preamble->width;
			}
			switch (char_code) {
			  case 0x2122:		/* 、。，．*/
			  case 0x2123:
			  case 0x2124:
			  case 0x2125:
				  /* 0.9622 -> 0.353665, 0.504013 */
				  p_up = height * 13 / 20; /* 5/4 */
				  p_right = width * 7 / 10; /* 11/8 */
				  break;
			  case 0x2421:		/* ぁぃぅぇぉっゃゅょゎ */
			  case 0x2423:
			  case 0x2425:
			  case 0x2427:
			  case 0x2429:
			  case 0x2443:
			  case 0x2463:
			  case 0x2465:
			  case 0x2467:
			  case 0x246E:
			  case 0x2521:		/* ァィゥェォッャュョヮヵヶ */
			  case 0x2523:
			  case 0x2525:
			  case 0x2527:
			  case 0x2529:
			  case 0x2543:
			  case 0x2563:
			  case 0x2565:
			  case 0x2567:
			  case 0x256E:
			  case 0x2575:
			  case 0x2576:
				  /* 0.9622 -> 0.747 */
				  p_up = height / 5; /* 4 */
				  p_right = width / 8; /* 6 */
				  break;
			  case 0x213D:		/* ―…‥ */
			  case 0x2144:
			  case 0x2145:
			  case 0x2126:		/* ・‐‖｜ */
			  case 0x213E:
			  case 0x2142:
			  case 0x2143:
			  case 0x2161:		/* ＝≠→←↑↓〓 */
			  case 0x2162:
			  case 0x222A:
			  case 0x222B:
			  case 0x222C:
			  case 0x222D:
			  case 0x222E:
				  p_rotate = 1;
				  break;
			  case 0x213C:		/* ー */
			  case 0x2141:
				  p_rotate = p_mirror = 1;
				  break;		/* 〜 */
			  default:
				  break;
			}
		}
		if (use_lateral_kanji == 0) {
			/* 横書き用フォントの補正使用禁止
			 */
			p_rotate >>= 1;		/* p_rotate:  3 -> 1, 1 -> 0 */
			p_up = p_right = 0;
		}
		else {
			p_rotate &= 1;
			if (p_mirror == 1)
				p_rotate |= 2;
		}
	}
set:
	preamble->shift_up_ptex = p_up;
	preamble->shift_right_ptex = p_right;
	preamble->rotate_ptex = p_rotate;
}

#ifndef  NO_NTTRPL
/* NTTjTeX subfont code -> jis_code 変換　*/
uint ntt_to_jis(uint code, int offset)
{
	uint char_code;
		char_code = offset + code;
		if (offset <= 0x1900) {
			if (offset <= 0xb00)
				char_code = 0x3021 + (char_code % 94) + ((char_code / 94) << 8);
			else {
				char_code -= 0xc00;
				char_code = 0x5021 + (char_code % 94) + ((char_code / 94) << 8);
			}
		}
		else if ((offset == 0x2120) && (char_code >= 0x2184))
			char_code += 0x9c;
	return char_code;
}
#endif
/* end of all */
