/*
 *  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
 *     8   Nov  1993 : modified for LBP PDL special commands by Sadayuki Iwai
 */

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

#if	defined(WINAPI)
#ifndef MSVC
#include<jctype.h>
#endif
#endif

#ifndef  UNIX
#ifdef MSVC
#include <memory.h>
#else
#include <mem.h>
#endif
#endif

#include "dd.h"
#include "err.h"
#include "dviread.h"
#ifdef LBP
# include "prtout.h"
#endif
#ifdef	WIN32G
#include "inter.h"
#include "vfont.h"
#endif
#ifdef	USE_SUBFONT
#include "subfont.h"
#endif

static SCALED_PT h, v, w, x, y, z;
#ifndef NOPS
static SCALED_PT old_v;
#endif
/* #define sp_to_dot(x) (PIXEL)((float)(x)*300/(65536*72.27)) */

char ptex_d;	/* ptex direction: 0 = yoko, 1 = tate */
char ptex_mode;
BOOL use_lateral_kanji = TRUE;	

static int f_break_bitmap;	/* bitmap buffer is destroyed? */
static PIXEL H0, V0;
static int page;

#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;

BOOL f_grid;
BOOL f_gridO;
int w_grid=947257;			/* Scaled Point 1000 */

typedef int LONG;
typedef struct  tagRECT
{
	LONG left;
	LONG top;
	LONG right;
	LONG bottom;
}	RECT;

static BOOL f_stop=FALSE;	/* 出力の ON/OFF */
BOOL f_killstop=FALSE;		/* 出力の ON/OFF 制御の無効化 */
static int stop;			/* 下のレベルをコピーして利用 */
int  stop_level;			/* 出力の On/OFF 制御オプションにおけるレベル */
int  stop_max;				/* 現在のページのレベルの最大値 */
static int  f_on;			/* ON/OFF の変化 */
static int StopGcount;		/* Current Graphics */
RECT StopG0Rec;				/* New graphic */
RECT StopG1Rec;				/* Graphic to be vanished */

/* current font */

/* main.c */
void Exit(int);

/* 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 */
void *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);

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

#ifdef	VIRTUALFONT
/* virtual.c */
void pret_vf_packet(FONT_INFO *, BUFFER *, int,
					SCALED_PT, SCALED_PT, PIXEL, PIXEL);
/* epsbox.c */
char *GetBMPname(int,int);
#endif

#ifdef	WIN32G
/* winjtt.c */
BOOL PutWinTTChar(V_JFM *, int, int, int, int, int, struct PREAMBLE_REC *, char *);
/* mwndproc.c */
void EnableInitInfo(BOOL flg);
# ifndef NOVFONT
/* vfont.c */
char *check_ftt(char *);
extern V_JFM *v_tfm;
# endif

/* prtinit.c */
int GetAddMemory(char *, char *, int);

/* wmain.c */
BOOL ToSource(char **, int);

/* inter.c */
extern int ff_macro;
extern int id_page;
extern int name_pos;

static BOOL src_special(char *);
void JoinBoundigBox(RECT *, RECT *);

#endif

int count_macro;

extern DIMENSION dviout_dimension;

extern FONT_INFO *font_info_root;
extern char *goth;
extern BOOL draw_baseline;
extern BOOL draw_boxpic;

/* 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_pxl, sp_per_h, v_per_h;

#ifndef NOTPIC
/* tpic.c */
#define TPIC_MI long	/* type of tpic milli-inches (x, y) */
typedef struct {
	PIXEL x, y;
} pixelpoint;

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
#ifndef NOPSFRAG
BOOL header_special(char *special, int mode);
extern BOOL f_hide;
#endif

#ifdef RAWOUT
extern BOOL f_dviprt;
#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;	/* 1: d_work()  2: d_resume()  3: work()  */
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_init(void);
void d_resume(void);
static void d_put(uint);
#endif

void interpret(OUTPUT_INFO *output);
void do_special(char *special);
char *find_key(char *str, char *key);
void SetSearchStr(uchar *s);
void FreeMacro(void);
void FreePause(void);
void set_current_xy(SCALED_PT, SCALED_PT);
void get_current_xy(SCALED_PT *, SCALED_PT *);
static void d_work(void);
static void s_work(void);
static void KeepPause(void);
static BOOL dviout_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 void	draw_grid(OUTPUT_INFO *out);
static int work(void);
static void RectGraph(void);

static 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 *);
void pr_putc(char);
#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;

/*-------------------------------------------------------------------*/
/* for PDL special command file. Functions added by Sadayuki Iwai
			   November  4, 1993,       for dviprt ver.2.41
*/
/*-------------------------------------------------------------------*/
static BOOL pdl_sp_pret(char *str);
static BOOL (*pdl_special)(char *special) = pdl_sp_pret;  

#ifdef	HYPERTEX
static BOOL hyper_sp_pret(char *str);
static BOOL (*hyper_special)(char *special) = hyper_sp_pret;
#endif

static int check_sp(char *str);
#ifdef LBP
static void special_pdl(char *pdl_file, char *type_ext, int type);
extern LBP_FUNC *lbpf;
#endif

#define NOT_PDL 0
#define LP3     1
#define EPG     2
#define	PDL		3

static	char *pdl_fname;
#define	LIPS_STR		"lipsfile"
#define	ESCPAGE_STR		"escpagefile"
#define	PDL_STR			"pdlfile"
/*----*/

#ifdef STR_SEARCH
uint f_s_search;
uint f_s_flags;
uint f_s_dpi;
uint n_found_pt;				/* pointer of positions in DVI */

int	id_papersize = -1;			/* id of papersize special */
int	f_s_space  = 0x10000;		/* space should be       >= f_s_space pt */
int	f_s_fspace = 0x14000;		/* +  space should be    >= f_s_fspace pt */
int	f_s_ospace = 0x40000;		/* other space should be >= f_s_ospace pt */
char *s_font;					/* fonts to be ignored */
char *isp;						/* special to be ignored */
static int f_mid_word;			/* guess word's boundary */
static int f_s_mode;
static int s_haba, s_takasa, s_h, s_v;
static int f_s_font;

static unsigned short *s_str;	/* string to be searched */
static int s_str_pt;			/* matched length	*/
static int s_str_len;			/* length of string */
static int *s_str_pos;			/* positions in DVI for work */
static int *s_found;			/* matched postions in DVI
								/* s_found[2*n_found_pt]:   start position
								   s_found[2*n_found_pt+1]: end position */
static int n_found;				/* number of matched strings */
extern int s_box_pt;			/* positions in a page */

static char *S_TRANS[0x21] =
{
	NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
	NULL, NULL, NULL, "ff", "fi", "fl", "ffi", "ffl",
	"i",  "j",  "`",  "'",  "v",  "u",  "=",  "a",
	"c", "ss", "ae", "oe",  "o", "AE", "OE",  "O",
	NULL
};

static void GetPickString(void);
void ShowPickedString(char *s, char *t);
void jis2sjis(int *h, int *l);
#endif

#ifdef	HYPERTEX
#define	MAX_TAG_LEN			0x100
#define	MAX_HYPER_NAME		0x1000
#define	MAX_HYPER_JUMP		0x1000
#define	MAX_HYPER_STRING	0x20000

int	f_hyper;

struct S_BOX  *h_box;
int max_h_box = MAX_HYPER_JUMP;
int n_h_box;
struct S_BOX *page_box;
char base_href[MAX_PATH+2];

struct H_NAME *h_name;
int max_h_name = MAX_HYPER_NAME;
int n_h_name;

#ifdef	WIN32G
int f_spsh;
int id_current_macro;
BOOL f_nopause;
int count_src_special;
int count_hyper_special;

struct header_list {
	struct header_list *next;
	BOOL page;
	char name[];
};

static struct header_list *header_dviout = NULL;
static int dviout_initialize_id;
static int dviout_initialize_do;
#endif

BUFFER *hyper_str;
int max_hyper_str = MAX_HYPER_STRING;
int pt_hyper_str;

void clear_hyper_buf(void)
{
	if(h_box != NULL){
		Free(h_box);
		h_box = NULL;
		Free(h_name);
		h_name = NULL;
		Free(hyper_str);
		hyper_str = NULL;
	}
}

void flush_hyper(void)
{
	int	i;

	f_hyper &= ~F_H_BOX;
	i = dviout_dimension.total_page;
	if(dviout_dimension.page_index != NULL){
		while(i >= 0)
			dviout_dimension.page_index[i--].hyper0 = 0;
	}
	count_src_special = count_hyper_special = 0;
	if(h_box == NULL)
		return;
	page_box = h_box + 1;
	n_h_box = 2;
	n_h_name = pt_hyper_str = 0;
	page_box->y0 = page_box->y1 = 0;
}

void  close_hyper_box(void)
{
	PIXEL xx, yy, ww;

	struct S_BOX *box;

	if(!(f_hyper & F_H_BOX))
		return;
	f_hyper &= ~F_H_BOX;

	box = h_box + n_h_box;
	if(box->base == -1 && box->x0 == box->x1 && box->y0 == box->y1){
		ww = sptopixel(f_s_ospace);
		if((ww += ww/2) >= 128)
			ww = 127;
		xx = get_current_x();
		if(box->x0 > xx)
			box->x0 = xx;
		else
			box->x1 = xx;
		yy = get_current_y();
		if(box->y0 > yy)
			box->y0 = yy;
		else
			box->y1 = yy;
		if(ptex_d & 1){
			if(box->x1 - box->x0 < ww)
				box->dir |= 2*ww;
			box->base = box->x0;
		}else{
			if(box->y1 - box->y0 < ww){
				box->dir |= 2*ww;
/*				box->y0 = box->y1 -ww; */
			}
			box->base = box->y0;
		}
	}
	n_h_box++;
}

void  open_hyper_box(char *tag)
{
	int size;
	struct S_BOX *box;

	size = strlen(tag) + 1;
	f_hyper |= F_H_BOX;
	if(n_h_box >= max_h_box - 1 || pt_hyper_str + size > max_hyper_str){
		if(page_box == h_box){
			error(WARNING, "Too many href");
		}else{
			flush_hyper();
			f_break_bitmap = 1;
			return;
		}
	}
	if(!page_box->y0++){
		page_box->x0 = n_h_box;
		dviout_dimension.page_index[page].hyper0 = page_box - h_box;
	}
	box = h_box + n_h_box;
	box->base = -1;
	box->x0 = box->x1 = get_current_x();
	box->y0 = box->y1 = get_current_y();
	box->sub.href = strcpy((char *)hyper_str + pt_hyper_str, tag);
	pt_hyper_str += size;
}

/*
 *   box will be expanded by the current box.
 *   If the box is in the same block of the former one and
 *      the baseline doesn't change together with TATE/YOKO mode, 
 *   then the box is connected to the former one to make one box.
 */
void add_hyper_box(PIXEL x, PIXEL y, PIXEL width, PIXEL h, PIXEL d)
{
	struct S_BOX *box;
	char *s;

	if(n_h_box >= max_h_box - 1){
		if(page_box == h_box + 1){
			error(WARNING, "Too many href");
		}else{
			flush_hyper();
			f_break_bitmap = 1;
			return;
		}
	}
	box = h_box + n_h_box;
	if(box->dir == ptex_d){
		if(ptex_d & 1){
			if(box->base < 0)
				box->base = x;
			else if(box->base != x)
				goto new;
			if(box->x0 > h)
				box->x0 = h;
			if(box->x1 < d)
				box->x1 = d;
			if(box->y0 > y)
				box->y0 = y;
			if(box->y1 < y + width)
				box->y1 = y + width;
		}else{
			if(box->base < 0)
				box->base = y;
			else if(box->base != y)
				goto new;
			if(box->y0 > h)
				box->y0 = h;
			if(box->y1 < d)
				box->y1 = d;
			if(box->x0 > x)
				box->x0 = x;
			if(box->x1 < x + width)
				box->x1 = x + width;
		}
	}else{
new:	s = box->sub.href;
		box = h_box + (++n_h_box);
		page_box->y0++;
		box->sub.href = s;
		if((box->dir = ptex_d) & 1){
			box->base = x;
			box->x0 = h;
			box->x1 = d;
			box->y0 = y;
			box->y1 = y + width;
		}else{
			box->base = y;
			box->y0 = h;
			box->y1 = d;
			box->x0 = x;
			box->x1 = x + width;
		}
	}
}


void add_hyper_box0(PIXEL x, PIXEL y, PIXEL xsize, PIXEL ysize)
{
	char tmp;

	tmp = ptex_d;
	ptex_d = 0;
	add_hyper_box(x, y+ysize, xsize, y, y+ysize);
	ptex_d = tmp;
}

void store_hyper_tag(char *tag, int mode)
{
	int size;

	if(h_box == NULL){
		n_h_box = 2;
/*
		if(!max_h_box)
			max_h_box = MAX_HYPER_JUMP;
		if(!max_h_name)
			max_h_name = MAX_HYPER_NAME;
		if(!max_hyper_str)
			max_hyper_str = MAX_HYPER_STRING;
*/
		h_box = 
			(struct S_BOX *)marea(sizeof(struct S_BOX)*(max_h_box +2));
		h_name = (struct H_NAME *)marea(sizeof(struct H_NAME)*max_h_name);
		hyper_str = (BUFFER *)marea(max_hyper_str);
		flush_hyper();
	}

	if(mode == 'h'){
		if(f_hyper & F_H_BOX)
			close_hyper_box();
		open_hyper_box(tag);
	}else if(mode == 'n'){
		size = strlen(tag) + 1;
		if(n_h_name >= max_h_name - 1 || pt_hyper_str + size > max_hyper_str){
			if(page_box == h_box){
				error(WARNING, "Too many hyper tag names or source specials");
			}else{
				flush_hyper();
				f_break_bitmap = 1;
			}
			return;
		}
		if(!page_box->y1++){
			page_box->x1 = n_h_name;
			dviout_dimension.page_index[page].hyper0 = page_box - h_box;
		}
		h_name[n_h_name].x = get_current_x();
		h_name[n_h_name].y = get_current_y();
		h_name[n_h_name++].name = strcpy((char *)hyper_str + pt_hyper_str, 
			tag);
		pt_hyper_str += size;
	}
}
#endif
/*-------------------------------------------------------------------*/

void rewrite_preamble_ptex(PREAMBLE *, uint, FONT_INFO *);

#define	MAX_PRE_PICK	64
#define	MAX_POST_PICK	0x1000
#define	MAX_PICK (MAX_PRE_PICK+MAX_POST_PICK)
#define	VOID_CODE	0xffff

static short unsigned int *pick_string;
PIXEL pick_h, pick_v;
int pt_pick;
int pt_pick_found;
int pick_count;
int pick_source;

void 
interpret(OUTPUT_INFO *output)
{
	int i, j;

	ENTER("interpret");
#define	F_PRINTER	0x80

resume:
	font = NULL;
	h = v = w = x = y = z = ptex_d = f_stop = stop_max
		= StopGcount = StopG0Rec.left=StopG0Rec.right=StopG1Rec.left=StopG1Rec.right
#ifndef	NOPS
		= old_v = current_gsps
#endif
		= 0;
	dvi = output->dvifile_ptr;
	H0 = output->h_0;
	V0 = output->v_0;
	page = output->page;
#ifdef	HYPERTEX
	if(  !dviout_dimension.page_index[page].hyper0	/* not yet checked? */
	  && !(f_hyper & F_H_IGNORE))					/* flag for check? */
		f_hyper &= ~F_H_SKIP; 			/* expand HyperTeX specials */
	else
		f_hyper |= F_H_SKIP;			/* skip HyperTeX specials */
#endif
#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	WIN32G
	if(b_presentation_mode && !f_nopause)
		FreePause();
#endif
#ifdef	FDOWN
	if (f_download == 1){
		d_work();
		END();
	}
#endif
#ifdef	WIN32G
	if (f_spsh == -1){
		s_work();
		END();
	}
#endif
#ifdef	STR_SEARCH
	if(f_s_search == 1){					/* mode for string search? */
		n_found = n_found_pt = s_box_pt = f_mid_word = 0;
		d_work();
		if(!n_found)						/* not exist in this page */
			END();
		f_s_search = 2;
		goto rep;				/* expand this page and calculate boxes */
	}else if(f_s_search == 3){
		pt_pick = pt_pick_found = f_mid_word = pick_count = pick_source = 0;
		pick_string = (short int*)marea(MAX_PICK*sizeof(short int));
		for(i=0; i<MAX_PICK; i++)
			pick_string[i] = 0;
		d_work();
		GetPickString();
		Free0(pick_string);
		goto quit;
	}
#endif
#ifdef	HYPERTEX
	if(f_hyper & F_H_SEARCH){				/* search HyperTeX tag name */
		d_work();
		END();
	}
#endif
#ifdef	WIN32G
	if(dviout_initialize_do){
		struct header_list *p;

		i = 0;
		if(dviout_initialize_id == id_dvi){
			for(p = header_dviout; p != NULL; p = p->next){
				if(p->page)
					i++;
				else if(dviout_initialize_do == 2)
					continue;
				j = 0;
				if(strsubcmp(p->name, "dviout ")){
					for(j = 7; p->name[j] == ' '; j++);
					if(strsubcmp(p->name + j, "`sp "))
						for(j += 4; p->name[j] == ' '; j++);
					else
						j = 0;
				}
				if(j)
					do_special(p->name + j);
				else
					dviout_special(p->name);
			}
		}
		dviout_initialize_do = i?2:0;
	}
#endif
	{
		if (work() == FALSE){
			output->bitmap_ptr = (HUGE_BUF *)bitmap_buf_pointer->start;
rep:		init_output(output);
			clear_buf(bitmap_buf_pointer);
			goto resume;
		}
	}
	if(stop_max)
		RectGraph();
	if (dviout_dimension.prt_type & F_PRINTER)
		draw_frame(output);
	else
		alter_bitblt_rt(FALSE);		/* rt を解除 */
	if(f_grid)
		draw_grid(output);
#ifdef	STR_SEARCH
quit:
	if(f_s_search){					/* EOF string search */
		f_s_search = pick_count = 0;
		SetSearchStr(NULL);
	}
#endif
#ifdef	HYPERTEX
	if(!(f_hyper & F_H_SKIP)){		/* EOF expanding HyperTeX specials */
		if(h_box == NULL || !dviout_dimension.page_index[page].hyper0)
			dviout_dimension.page_index[page].hyper0 = -1;
		else{						/* exist HyperTeX specials in this page */
			page_box = h_box + (n_h_box++);
			page_box->y0 = page_box->y1 = 0;
		}
	}
#ifdef	HYPERTEX
	if(!(f_hyper & F_H_IGNORE) && dviout_dimension.page_index[page].hyper0 > 0){
		if(f_hyper & F_H_BOX)
			close_hyper_box();
		SetColor(8);
	}
#endif
#endif
	f_killstop = TRUE;
	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 void draw_grid(OUTPUT_INFO *out)
{
	int pos, dpos, top;

#define	step w_grid

	if(f_gridO)
		top = 0;
	else{
		top = IN_TO_SP(1);
		top -= (top/step)*step;
	}
	for(pos = top; (dpos = sptopixel(pos)) < dviout_dimension.buf_height; 
	  pos += step)	
		write_rule(0,dpos,1,dviout_dimension.buf_width);	 /* horizontal */
	if(f_gridO)
		pos = 0;
	else{
		pos = IN_TO_SP(1);
		pos -= (pos/step)*step;
	}
	for(pos = top; (dpos = vtopixel(pos)) < dviout_dimension.buf_width; 
	  pos += step)
		write_rule(dpos,0,-dviout_dimension.buf_height,1); 	/* vertical */
}

/* 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 ) );
}
 */

#ifdef	STR_SEARCH
void PickUpString(PIXEL h, PIXEL v, int mode)
{
	pick_h = h;
	pick_v = v;
	f_s_search = 3;
	f_s_mode = mode;
}

void jis2sjis(int *h, int *l)
{
	if (*h & 1) {
		if (*l < 0x60)  *l += 0x1f;
			else		*l += 0x20;
	}else				*l += 0x7e;
	if (*h < 0x5f)		*h = (*h + 0xe1) >> 1;
		else			*h = (*h + 0x161) >> 1;
}


BOOL IsAlpha(uchar ch)
{
	if(ch >= 0x20)
		return isalpha(ch);
	return S_TRANS[ch]?TRUE:FALSE;
}


/*
	02: non-alphabet nor hyphen in ASCII
	03: alphabet or hyphen in ASCII
	44, 46: symbol
	48: Alphabet (2 byte)
	4A: Hiragana
	4B: JIS 0x2133 - 0x2137, 0x213C, 0x213d
	4C: Katakana
	4E: Greek
	50: Russian
	60: Kanji
*/
static int GetCharType(int ch)
{
	int type; 
	type = (ch >> 8);

	if(type == 0x21){
		if( (ch >= 0x2133 && ch <= 0x2137) || ch == 0x213c || ch == 0x213d)
		return 0x4B;
	}
	if(type >= 0x30)
		type = 0x30;
	else if(type != 0x27)		/* for Russian */
		type++;
	return (type == 1 && (IsAlpha(ch)||ch=='-'))?3:(type+type);
}

short GetDibWidth(uchar *);
short GetDibHeight(uchar *);
struct bmp_name_s {
	struct	bmp_name_s *next;
	short int	x_pos;
	short int	y_pos;
	short int	x_size;
	short int	y_size;
	char name[];
};
extern struct bmp_name_s *bmp_name;

static int GetPickFigure(int mode)
{
	int count, x_pos, y_pos, x_size, y_size, type, x_org, y_org;
	uchar  *pBMP;
	char *name, tmp[512], tmp2[64];
	struct bmp_name_s *bmp_pt;

	for(count = 0;
	  (pBMP = (uchar *)GetBMPdata(count++, &x_pos, &y_pos, 
	  &x_size, &y_size, &type)) != NULL; ){
/*
   error(14, "(%d,%d)-(%d,%d):(%d,%d)", x_pos, y_pos, x_pos + x_size,
	y_pos + y_size, pick_h, pick_v);
 */
		if( pick_h < x_pos
		 || pick_h > x_pos + x_size
		 || pick_v < y_pos
		 || pick_v > y_pos + y_size)
			continue;
		if(type < -3 && type != F_WMF && type != F_EMF)
			continue;
		if(mode)
			return count;
		if((name = GetBMPname(count-1, 1)) == NULL)
			name = GetBMPname(count-1, 0);
		if(name == NULL)
			name = "";
#ifdef	WMF
		if(type==F_WMF||type==F_EMF){
			sprintf(tmp, "%cMF %s\n"
						 "Size: %d/%d x %d/%d pixel",
				(type==F_WMF)?'W':'E', name,
				x_size, GetXGray(), y_size, GetYGray());
			goto show;
		}
#endif
		x_org   = GetDibWidth( pBMP );
		y_org   = GetDibHeight( pBMP );
		x_size = (x_size + GetXGray() - 1)/GetXGray();
		y_size = (y_size + GetYGray() - 1)/GetYGray();
		sprintf(tmp, "BMP %s with %d bit color\n"
					 "Size: %d x %d -> %d x %d pixel",
					name, *(pBMP+14), x_org, y_org, x_size, y_size);
show:	sprintf(tmp2, "Pointed figure at (%d,%d)=(%.3f cm, %.3f cm)", 
				pick_h, pick_v,
				(double)2.54*pick_h/GetXDpi(), 
				(double)2.54*pick_v/GetYDpi());
		ShowMessage(tmp, tmp2, SM_OKCONT);
		return 1;
	}
	if(mode != 2){
		for(count=-1, bmp_pt = bmp_name; bmp_pt; 
		  bmp_pt = bmp_pt->next, count--){
/*
   error(14, "%d %s(%d,%d),(%d,%d)-(%d,%d)", mode, bmp_pt->name, pick_h, pick_v, 
   bmp_pt->x_pos, bmp_pt->y_pos,
   bmp_pt->x_pos + bmp_pt->x_size, bmp_pt->y_pos + bmp_pt->y_size);
*/
			if( pick_h < bmp_pt->x_pos
			 || pick_h > bmp_pt->x_pos + bmp_pt->x_size
			 || pick_v < bmp_pt->y_pos
			 || pick_v > bmp_pt->y_pos + bmp_pt->y_size)
				continue;
			if(mode)
				return count;
			sprintf(tmp, "BMP %s with B/W color\n"
				 "Size: %d x %d pixel", bmp_name->name,
				bmp_name->x_size, bmp_name->y_size);
			goto show;
		}
	}
	return 0;
}

char *GetFigurePath(int x, int y, int mode)
{
	int count;
	struct bmp_name_s *bmp_pt;
	
	pick_h = x;
	pick_v = y;
	count = GetPickFigure(mode);
	if(!count)
		return NULL;
	if(count > 0)
		return GetBMPname(count-1, 1);
	if(count < 0){
		for(bmp_pt = bmp_name; bmp_pt ; bmp_pt = bmp_name->next){
			if(++count==0){
				return bmp_pt->name;
			}
		}
	}
	return NULL;
}

static void GetPickString(void)
{
	char tmp[MAX_PICK*4];
	char tmp2[0x30];
	int i, j, k, pt, ch, ch0, h, l, type, cdif, count, done, line;
	char *s, *source;

	V_JFM *vjfm;

	if(!pick_count){
		if(f_s_mode == 1){
			if(!GetPickFigure(0)){
				sprintf(tmp, "at (%d,%d) = (%.3f cm, %.3f cm)\n", 
				pick_h, pick_v,
				(double)2.54*pick_h/GetXDpi(), (double)2.54*pick_v/GetYDpi());
				ShowMessage(tmp, "Point", SM_OKCONT);
			}
		}
		return;
	}
	tmp[1] = tmp[2] = 0;
	if(f_s_mode == 1){					// CTRL + SHIFT + LBUTTON
		if(--pt_pick_found < 0)
			pt_pick_found = MAX_PICK - 1;
		k = pick_string[pt_pick_found]&0xffff;
		if(k == VOID_CODE)
			k = 0;
		else if(k >= 0x2121){
			l = k & 0x7f;
			h = k >> 8;
			jis2sjis(&h, &l);
			tmp[0] = h;
			tmp[1] = l;
		}else
			tmp[0] = (k>=0x21 && k<=0x7e)?k:' ';
		sprintf(tmp + 4, (k <= 0xff)?"%02X":"%04X", k);
		if(font->font_type == WINJTT_FONT){
			vjfm = get_vjfm((font->ext.kdir)->fh);
			goto ttf;
		}
		tmp2[0] = 0;
		if(font->font_type == WINTT_FONT){
			vjfm = (V_JFM *)(font->vjfm);
ttf:		s = (vjfm==v_tfm)?check_ftt(font->n)
				:(vfont[vjfm->font_no]->v_font_name + 1);
			sprintf(tmp2, "\nTrueType:\t\t%s", s);
		}
		sprintf(tmp+16, 
			"pointed at (%d,%d) = (%.3f cm, %.3f cm)",
			pick_h, pick_v,
			(double)2.54*pick_h/GetXDpi(), (double)2.54*pick_v/GetYDpi());
		sprintf(tmp+MAX_PICK,
			"%s (%sH)\nSize:\t\t\t%d x %d %s in (%d, %d)-(%d, %d)\n"
			"Font #%d:\t\t%s\nLocation:\t\t%s%s\n"
			"s-size/d-size:\t\t%d/%d\n",
			tmp, tmp+4, s_haba, s_takasa,
#ifdef	VIRTUALFONT
			(font->font_type == VIRTUAL_FONT)?"?":
#endif
			"pixel", 
			s_h, s_v, s_h + s_haba - 1, s_v + s_takasa - 1,
			font->font_code, font->n, get_font_name(font), tmp2,
			font->size_para, font->des_para);
		if(pick_source){
			sprintf(tmp+MAX_PICK + strlen(tmp+MAX_PICK),
				"location in DVI:\t%d(%XH)\n", pick_source-1, pick_source-1);
			source =  GetDPos2Source(pick_source, &line);
			if(source != NULL){
				s = GetNextSource(1, &i);
				if(s != NULL && !strcmp(s, source))
					sprintf(tmp+MAX_PICK + strlen(tmp+MAX_PICK),
						"line in %s:\t%d - %d", s, line, i-1);
				else if(name_pos > 0)
					sprintf(tmp+MAX_PICK + strlen(tmp+MAX_PICK),
						"line in %s:\t%d - ?", source, line);
				else
					sprintf(tmp+MAX_PICK + strlen(tmp+MAX_PICK),
						"line in %s:\t? - %d ", source, line);
			}
			pick_source = 0;
		}
		error(C_MSG, tmp+MAX_PICK);
		error(DATATITLE, tmp+16);
//		ShowMessage(tmp+MAX_PICK, tmp+16, SM_OKCONT);
		return;
	}
	pick_string[pt_pick] = 0;				// 	SHIFT + LBUTTON
	if(pick_source != 0 && f_srcspecial && f_s_mode == 2){
		source =  GetDPos2Source(pick_source, &line);
		if(source != NULL && ToSource(&source, line))
			return;
	}

	for(i = 1; i < MAX_PRE_PICK; i++){
		if((j = pt_pick_found - i) < 0)
			j+= MAX_PICK;
			if( (ch = pick_string[j])  == '\t' || ch == 0)
				break;
			if(i == 1)
				ch0 = GetCharType(ch);
			else if((cdif = (ch0 - GetCharType(ch))) > 1 || cdif < -1)
				break;
	}
	k = pt_pick_found + MAX_POST_PICK - 1;
	if(k >= MAX_PICK)
		k -= MAX_PICK;
	for(done = count = pt = 0; ; ){
		if(++j >= MAX_PICK)
			j = 0;
		if(j == pt_pick_found)
			done = 1;
		if(j == k || (ch = pick_string[j]) == 0)
			break;
resume:	
		if(pt == 0){
			ch0 = GetCharType(pick_string[j]);
			type = 0;
		}
		if(ch == '\t' && type != 0){
			tmp[pt++] = '\t'-1;
			type = 0;
		}else if(ch <= ' '){
			if((s = S_TRANS[ch]) != NULL){
				h = pick_string[(j+1)%MAX_PICK];
				if(type == 1 || ch0 || (h > 0x21 && h < 0x7f)){	/* ch0 Ver.3.15 */
					if(type == 2){
						if(!done){
							pt = 0;
							goto resume;
						}
						tmp[pt++] = '\t';
					}
					while(*s)
						tmp[pt++] = *s++;
					type = 1;
					if(ch0)
						ch0 = 3;		/* alphabet */
				}
			}
		}else if(ch < 0x7f){
			if(type == 2){
				if(!done){
					pt = 0;
					goto resume;
				}
				tmp[pt++] = '\t';
			}else if(ch0){
				if(type == 1 && pt > 1 && ch0 != GetCharType(ch)){
					if(!done){
						pt = 0;
						goto resume;
					}
					if(count++ <= 1)
						tmp[pt++] = '\t';
					ch0 = 0;
				}
			}
			if(ch0)
				ch0 = GetCharType(ch);
			tmp[pt++] = ch;
			type = 1;
		}else if(ch > 0x2121){
			l = ch & 0x7f;
			h = ch >> 8;
			jis2sjis(&h, &l);
			if(  (ch0 && type != 0 && 
			  (  (cdif = (ch0 - GetCharType(ch))) < -1 || cdif > 1))
			   || type == 1 ){
				if(done <= 0){
					pt = 0;
					goto resume;
				}
				tmp[pt++] = '\t';
				if(count++>1)
					ch0=0;
			}
			if(ch0)
				ch0 = GetCharType(ch);
			tmp[pt++] = h;
			tmp[pt++] = l;
			type = 2;
		}else if(ch == 0x2121){
			tmp[pt++] = 0x81;
			tmp[pt++] = 0x40;
			type = 3;
			ch0 = 0;
		}
	}
	if(!ch)
		tmp[pt++] = '\t';
	tmp[pt] = 0;
	ShowPickedString(tmp, NULL);
	pick_source = 0;
}

void CheckPickUp(PIXEL h0, PIXEL v0, PREAMBLE *pxl, int type)
{
	PIXEL h, v;
	PIXEL haba, takasa;

#ifdef	VIRTUALFONT
	if(type == VIRTUAL_FONT
#ifdef	USE_ETF
	  || (font->font_type == ETF_FONT && font->etf_type == VIRTUAL_FONT)
#endif
	) {					/* 正確ではないがとりあえず */
		haba = takasa = sptopixel(pxl->tfm_width);
		if(ptex_d & 1){
			h = h0 - haba/2;
			v = v0;
		}else{
			h = h0;
			v = v0 - takasa;
		}
	}else
#endif
	{
		haba = pxl->width;
		takasa = pxl->height;
		if (ptex_d & 1) {			/* 縦書きの場合 */
									/* 文字を右・上方向に補正 */
			h = h0 + pxl->depth_offset + pxl->shift_right_ptex;
			h -= ((pxl->rotate_ptex & 1)?takasa:haba);
			v = v0 - pxl->pitch_offset - pxl->shift_up_ptex;

			if (pxl->rotate_ptex & 1) {	/* 文字を90度回転 */
				haba = takasa;
				takasa = pxl->width;
			}
		}
		else {
			h = h0 - pxl->pitch_offset;
			v = v0 - pxl->depth_offset;
		}
	}
/*
error(14, "(%d,%d):(%d,%d)-(%d,%d)", pick_h, pick_v, h, v, h+haba, v+takasa);
*/
	if(h <= pick_h && pick_h <= h + haba 
	  && v <= pick_v && pick_v <= v + takasa){
		pick_count = 1;
		pt_pick_found = pt_pick;
		s_haba = haba;
		s_takasa = takasa;
		s_h = h;
		s_v = v;
		if(!pick_source)
			pick_source = ftell(dvi);
	}
}
#endif


#ifdef	WIN32G
BOOL WriteTTFont(PIXEL hh, PIXEL vv, FONT_INFO *fon, uint num, 
	PREAMBLE *preamble)
{
	if(!f_ttout)
		return FALSE;
#ifdef	USE_ETF
	if(fon->font_type == ETF_FONT){
		if(fon->etf_type == WINTT_FONT)
			goto wintt;
		if(fon->etf_type == WINJTT_FONT)
			goto winjtt;
	}
#endif
	if(fon->font_type == WINTT_FONT){
wintt:
#ifdef	USE_SUBFONT
		if (fon->sfd_id >= 0)
			num = lookup_sfd_record(fon->sfd_id, num);
#endif
		if(PutWinTTChar((V_JFM*)(fon->vjfm), num,
			(fon->size_para+sp_per_pxl/2)/sp_per_pxl,		/* height */
			hh, vv, 0, preamble, fon->n) )
				return TRUE;
	}else if(fon->font_type == WINJTT_FONT){
winjtt:	if(PutWinTTChar((V_JFM*)get_vjfm(fon->ext.kdir->fh), num,
			fon->k_height, hh, vv, 
			fon->ext.kdir->base*1000/fon->k_height,
			preamble, fon->n) )
				return TRUE;
	}
	return FALSE;
}
#endif


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;
	PREAMBLE *preamble;
	long tfmwidth;
#ifdef	FDOWN
	PIXEL H1, V1;
#endif
#ifdef	STR_SEARCH
	int inc_found = 0;
#endif

	ENTER("cput");
#ifdef	STR_SEARCH
	if(f_s_search == 2){
		if(ftell(dvi) == s_found[n_found_pt] && n_found_pt < 2*n_found){
			if(n_found_pt & 1)
				inc_found = 1;
			else{
				n_found_pt++;
				if(s_found[n_found_pt] == s_found[n_found_pt-1])
					inc_found = 1;
			}
		}
	}
#endif
#ifndef NO_NTTRPL
	if (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
		) || (font->f_goth & F_TATE) != 0

		)
		rewrite_preamble_ptex(preamble, num, font);

	H = sptopixel(h) - H0;
	V = vtopixel(v) - V0;
#ifdef	STR_SEARCH
	if(f_s_search == 3){
		if(!pick_count)
			CheckPickUp(H, V, preamble, font->font_type);
		goto end;
	}
#endif
	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));
	}
#ifndef NOPSFRAG
	if (f_hide == TRUE) goto end;
#endif
#ifdef	WIN32G
	if (f_stop == TRUE) goto end;
#endif
#ifdef	VIRTUALFONT
	if (font->font_type == VIRTUAL_FONT
#ifdef	USE_ETF
	  || (font->font_type == ETF_FONT && font->etf_type == VIRTUAL_FONT)
#endif
	) {
		pret_vf_packet(font, preamble->raster, preamble->byte_width,
					   h, v, H0, V0);
#ifdef	STR_SEARCH
		if(inc_found)
			n_found_pt++;
#endif
		goto end;
	}
#endif
#ifdef FDOWN
	if (f_assigned){
# if	!defined(NOTPIC) && !defined(NOTPIC_EXTENSION)
		if (rot_angle % 90 != 0)
			goto no_dw;
# endif
			/* 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
#ifdef	WIN32G
	if(WriteTTFont(H, V, font, num, preamble))
		goto end;
#endif
no_dw:
	g_loop = (g_font & F_GOTH);
rep:
	write_font(H, V, preamble);
#ifdef	STR_SEARCH
	if(inc_found){
		n_found_pt++;
		inc_found = 0;
	}
#endif
	if (g_loop
#if	defined(FDOWN)
		&& 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;

	a = read_long(dvi);
	b = read_long(dvi);
#ifndef NOPSFRAG
	if (f_hide == TRUE) return (b);
#endif
#ifdef WIN32G
	if (f_stop == TRUE) return(b);
#endif
	if(a > 0 && b > 0){
		if (ptex_d & 1) {
			A = sptopixel(a + sp_per_h);
			B = vtopixel(b + v_per_h);
			write_rule(sptopixel(h) - H0, vtopixel(v + v_per_h + b) - V0,
					   B, A);
		}
		else {
			A = vtopixel(a + 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' */
{
	for (font = font_info_root; font != NULL;) {
		if (font->font_code == num) {
			g_font = (font->f_goth & (F_LBP | F_DWN | F_ATTR));
			if(font->font_type <= ONDEMAND2 && font->font_type >= ONDEMAND)
				resolve_font(font);
			END();
		}
		font = (font->font_code < num) ?
			font->after_font : font->before_font;
	}
	error(FONT_MISMATCH, "Illegal font_code %d", num);
}

static void set1(int code)
{
	SCALED_PT tmp;

	tmp = cput((uint)read_n(dvi, code - (SET1 - 1)));
	if (ptex_d & 1)
		v += tmp;
	else
		h += tmp;
}

static void set_rule(void)
{
	SCALED_PT tmp;

	tmp = rput();
	if (ptex_d & 1)
		v += tmp;
	else
		h += tmp;
}

static void put1(int code)
{
	(void)cput((uint)read_n(dvi, code - (PUT1 - 1)));
}

static void put_rule(void)
{
	(void)rput();
}

static void nop(void)
{
}

static void push()
{
	struct STACK *stack;

	(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");
}

static void d_push(void)
{
	struct STACK *stack;

	(stack = &(stack_buf[depth]))->w = w;
	stack->w = w;
	stack->x = x;
	if (++depth >= STACK_MAX)
		error(PROGRAM_STOP, "Stack Over flow");

}

static void d_pop(void)
{
	struct STACK *stack;

	if (--depth < 0)
		error(PROGRAM_STOP, "Stack Under flow");

	w = (stack = &(stack_buf[depth]))->w;
	x = stack->x;
}

static void pop()
{
	struct STACK *stack;

	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;
}

static void right1(int code)
{
	SCALED_PT tmp;

	tmp = signed_read_n(dvi, code - (RIGHT1 - 1));
	if (ptex_d & 1)
		v += tmp;
	else
		h += tmp;
}

static void w0()
{
	if (ptex_d & 1)
		v += w;
	else
		h += w;
}

static void w1(int code)
{
	w = signed_read_n(dvi, code - (W1 - 1));
	if (ptex_d & 1)
		v += w;
	else
		h += w;
}

static void x0()
{
	if (ptex_d & 1)
		v += x;
	else
		h += x;
}

static void x1(int code)
{
	x = signed_read_n(dvi, code - (X1 - 1));
	if (ptex_d & 1)
		v += x;
	else
		h += x;
}

static void down1(int code)
{
	SCALED_PT tmp;

	tmp = signed_read_n(dvi, code - (DOWN1 - 1));
	if (ptex_d & 1)
		h -= tmp;
	else
		v += tmp;
}

static void y0()
{
	if (ptex_d & 1)
		h -= y;
	else
		v += y;
}

static void y1(int code)
{
	y = signed_read_n(dvi, code - (Y1 - 1));
	if (ptex_d & 1)
		h -= y;
	else
		v += y;
}

static void z0()
{
	if (ptex_d & 1)
		h -= z;
	else
		v += z;
}

static void z1(int code)
{
	z = signed_read_n(dvi, code - (Z1 - 1));
	if (ptex_d & 1)
		h -= z;
	else
		v += z;
}

static void fnt1(int code)
{
	font_change((int)read_n(dvi, code - (FNT1 - 1)));
}

static void xxx1(int code)
	/* specials are handed to external interpreters */
{

#if	!defined(NOTPIC) || !defined(NOPS)  || defined(USE_WINAPI)
#	define	SP_BUF_SIZE	0x200
	char *special;
	char sp_buf[SP_BUF_SIZE];
	long size;

	ENTER("xxx1");

	if((size = read_n(dvi, code - XXX1 + 1)) < SP_BUF_SIZE-1){
		special = &(sp_buf[0]);
		while(size--)
			*special++ = getc(dvi);
		*special = 0;
		do_special(&(sp_buf[0]));
	}else if ( (special = read_special(dvi, (uint)size)) == NULL){
		error(WARNING, "No memory to read special");
		fseek(dvi, size, SEEK_CUR);
	}else{
		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();
}

#ifdef WIN32G
#define	MAX_MACRO	0x100
#define	MAX_PAUSE	0x100
static char *dviout_macro[MAX_MACRO];
static int pt_pause;
static int last_pause;
static short int pause_xpos[MAX_PAUSE];
static short int pause_ypos[MAX_PAUSE];

void FreePause(void)
{
	last_pause = pt_pause = 0;
}

static void KeepPause(void)
{
	if(last_pause < MAX_PAUSE){
		if(!f_nopause){
			pause_xpos[last_pause] = get_current_x();
			pause_ypos[last_pause++] = get_current_y();
		}
	}
	else
		error(WARNING, "Too many \"special pause\" in a page");
}

static void NoPause(void)
{
	if(last_pause < MAX_PAUSE){
		if(!f_nopause){
			pause_xpos[last_pause] = 20000;
			pause_ypos[last_pause++] = 20000;
		}
	}
}

int GetPause(int *x, int *y, int mode)
{
	if(mode == 1){						// forward
		if(pt_pause >= last_pause)
			return -1;
		*x = pause_xpos[pt_pause];
		*y = pause_ypos[pt_pause];
			return pt_pause++;
	}else if(mode == -1){				// backward
		if(pt_pause <= 0)
			return -1;
		pt_pause--;
		goto cur;
	}else if(mode == 0){				// current
		if(pt_pause >= last_pause)
			return -1;
cur:	*x = pause_xpos[pt_pause];
		*y = pause_ypos[pt_pause];
		return pt_pause;				// current pointer
	}
	else if(mode == 2)					// number of pause
		return last_pause;
	else{
		mode &= 0xffff;
		if(mode >= last_pause)			// get direct
			return -1;
		*x = pause_xpos[mode];
		*y = pause_ypos[mode];
			return mode;
	}
}

void SetPause(int num)
{
	if(num < last_pause)
		pt_pause = num;
}

static pause_special(char *special)
{
	if(strncmp(special, "pause", 5) || special[5] > ' ')
		return FALSE;
	special += 5;
	while(*special == ' ')
		special++;
	if(*special == '0')
		NoPause();
	else
		KeepPause();
	return TRUE;
}


BOOL ExecMacro(int mode)
{
	int i, j;
//	int id_start_macro;

	if(mode == 2)
		return (dviout_macro[0] != NULL);
	if(!mode){
		if(id_current_macro)
			return FALSE;
		if(dviout_macro[0])
			id_current_macro = id_page;
	}
	for(i = 0; i < MAX_MACRO && dviout_macro[i]; i++){
		if(!DoMacro(dviout_macro[i], 1)){	/* for setting a timer; 1 = DVIOUT_SPECIAL */
			for(j = 0; j <= i; j++)
				Free(dviout_macro[j]);
			for(i = 0; (dviout_macro[i] = dviout_macro[i+j]) != NULL; i++);
			if(!mode)
				count_macro = i+j;
			if(!i){
				FreeMacro();
				PostClearMacro();
			}
			while(++i < MAX_MACRO)
				dviout_macro[i] = NULL;
			return TRUE;
		}
	}
	if(!mode)
		count_macro = i;
	if(i){
		FreeMacro();
		PostClearMacro();
		return TRUE;
	}else
		return FALSE;
}

void FreeMacro(void)
{
	int i;

	for(i = 0; i < MAX_MACRO && dviout_macro[i]; i++){
		Free(dviout_macro[i]);
		dviout_macro[i] = NULL;
	}
}

void CheckMacro(void)
{
	if(id_current_macro && id_current_macro != id_page){
		FreeMacro();
		id_current_macro = 0;
	}
}

BOOL papersize_special(char *str)
{
	int i, j;
	if(strsubcmp(str, "papersize") && str[9] <= '='){
		for(i = 10; str[i] == ' ' || str[i] == '='; i++);
		sprintf(common_work, isalpha(str[i])?"-y=%sP":"-y=F%sP", str+i);
		i=j=3;
		do{
			if(common_work[i] == ',')
				common_work[j++] = ':';
			else if(common_work[i] != ' ')
				common_work[j++] = common_work[i];
			if(i > 256){
				return FALSE;
			}
		}while(common_work[i++]);
		return TRUE;
	}
	return FALSE;
}

static BOOL dviout_special(char *special)
{
	int	i;

	if(strncmp(special, "dviout ", 7)){
		if(!papersize_special(special))
			return FALSE;
		else if(id_dvi == id_papersize)
			return TRUE;
		else
			id_papersize = id_dvi;
	}
	if(!f_dvioutspecial || ff_macro != 1)
		return TRUE;
	if(id_current_macro != id_page){	// different page or file
		if(id_current_macro){
			FreeMacro();
			id_current_macro = 0;
		}
	}else
		return TRUE;
rep:
	if(*special == 'p')
		special = common_work;
	else
		for(special += 7; *special == ' '; special++);
	if(strsubcmp(special, "`initialize")){
		struct header_list *p;

		special += 11;
		while(*special == ' ')
			special++;
		if(*special || id_dvi != dviout_initialize_id)
			return TRUE;
		for(p = header_dviout; p != NULL; p = p->next)
			dviout_special(p->name);
		return TRUE;
	}
	if( *special == '-' || *special == '!' || *special == '`' || 
	  ((*special >= 'A' && *special <= 'Z') || 
	   (*special >='a' && *special <='z')) ){
		for(i = 0; dviout_macro[i]; i++){
			if(i >= MAX_MACRO - 1){
				error(WARNING, "Too many dviout special in a page.");
				return TRUE;
			}
		}
		dviout_macro[i] = dup_string(special);
	}
	return TRUE;
}

int CountDvioutInitialize(void)
{
	int i = 0;
	struct header_list *p;

	if(dviout_initialize_id == id_dvi){
		for(p = header_dviout; p != NULL; p= p->next)
			i++;
	}
	return i;
}

void FreeDvioutInitialize(void)
{
	struct header_list *p, *q;

	for(p = header_dviout; p != NULL; p = q){
		q = p->next;
		Free(p);
	}
	header_dviout = NULL;
}

static char *add_para[] =
{
	"TEXPK", "TEXFONTS", "TEXKNJ", "gdat"
};

void set_dviout_initialize(char *str)
{
	struct header_list *p, *q;
	char *add, *opt, *at;
	int key, i, len;
	BOOL f_page;

	while(*str == ' ')
		str++;
	if(strsubcmp(str, "`initialize"))
		return;
	if(strsubcmp(str, "page ")){
		str += 5;
		while(*str == ' ')
			str++;
		f_page = TRUE;
	}else{
		if(*str == '+'){
			add = str + 1;
			for(key = 0; key < sizeof(add_para)/sizeof(char *); key++){
				if(!strsubcmp(add, add_para[key]))
					continue;
				add += strlen(add_para[key]);
				if(*add != '=' && *add != ":")
					break;
				i = 0;
				if(*++add != ';'){
					i = strlen(add);
					while(i-- > 0 && add[i] != ';');	/* search last ; */
					if(i == 0)
						break;
					add[i+1] = 0;						/* cut spaces */
				}
				len = strlen(add)-1;
too_long:		if(len > 0x1000){
					error(WARNING, "Too long initialization %s", str);
					return;
				}
				opt = GetParaString(add_para[key]);
				if(i)
					add[i] = 0;						/* cut last ; */
				if(opt == NULL){
					SetParaString(add_para[key], add);
					return;
				}else{
					at = strstr(opt, add+(i?0:1));
					if(i)
						add[i] = ';';
					if(at != NULL){
						if(at == opt || at[-1] == ';'){
							if(at[len] == ';' || at[len] == 0)
								return;		/* already defined */
						}
					}
					str = common_work + 0x1000;
					if(!i)
						sprintf(str, "-%s=%s%s", add_para[key], opt, add );
					else
						sprintf(str, "-%s=%s%s", add_para[key], add, opt );
					if(strlen(str) > 0x2000)
						goto too_long;
					goto set;
				}
			}
			error(WARNING, "Wrong initialization %s", str);
			return;
		}
set:	f_page = FALSE;
	}
	if(dviout_initialize_id != id_dvi || dviout_initialize_do != 1)
		FreeDvioutInitialize();
	q = (struct header_list *)
		marea(sizeof(struct header_list) + strlen(str) + 10);
	sprintf(q->name, "dviout %s", str);
	q->page = f_page;
	q->next = NULL;
	if (header_dviout == NULL) {
		header_dviout = q;
	} else {
		for (p = header_dviout; p->next != NULL; p = p->next);
		p->next = q;
	}
	dviout_initialize_id = id_dvi;
	dviout_initialize_do = 1;
}
#endif

BOOL LoadInit(int mode)
{
	char *buf, *bpt;
	int i, j, skip, ch, size;

	#define	INIT_NAME	"initial.par"

	if(!mode || (size = GetAddMemory(INIT_NAME, NULL, 0), size <= 0)){
#ifdef	WIN32G
		EnableInitInfo(FALSE);
#endif
		return FALSE;
	}
#ifdef	WIN32G
	EnableInitInfo(TRUE);
#endif
	buf = (char*)marea(size+1);
	GetAddMemory(INIT_NAME, buf, size);
	buf[size] = skip = 0;
	for(bpt = buf; ; ){
		while(*bpt == 0x0d || *bpt == 0x0a || *bpt == ' ' || *bpt == '\t')
			bpt++;		/* skip null lines and top spaces */
		if(!*bpt)
			break;
		i = 0;
		if(*bpt == '-' && !skip){	/* check multi-line parameter */
			for(j = 0; bpt[++j] != '=' && bpt[j] != ':'&& bpt[j]; );
			if(bpt[j] && (ch = bpt[++j]) == '\'' || ch == '"'){
				while(bpt[++j]){
					if(bpt[j] == ch){
						i = j+1;
						break;
					}
					if(issjis1(bpt[j]) && bpt[j+1])
						j++;
				}
			}
		}
		for(; bpt[i] && bpt[i] != 0x0a && bpt[i] != 0x0d; i++);
		size = bpt[i];
		bpt[i] = 0;
		if(*bpt != '#'){
			if(!skip)
				set_dviout_initialize(bpt);
		}
		else if(!strlcmp(bpt, "#rem"))
			skip = 1;
		else if(!strlcmp(bpt, "#end"))
			skip = 0;
		*(bpt += i) = size;
		if(!size)
			break;
	}
	Free0(buf);
	return TRUE;
}

# ifndef NOPS
static BOOL em_special(char *special)
{
	int len;
	unsigned char *s, *t;
	char tmp[0x400];

	if(strncmp(special, "em: ", 4))
		return FALSE;
	for(s = special + 3; *++s && *s <= ' '; );
	if(strncmp(s, "graph ", 6) || strlen(s) > 0x300)
		return FALSE;
								/* em: graph <file_name>,<hsize>,<vsize> */
	for( s += 5; *++s <= ' '; ){
		if( !*s )
			return FALSE;
	}
	len = 0;
	if(*s == '"'){
		while(s[++len] != '"'){
			if(s[len] == 0)
				return FALSE;
		}
	}else{
		while(s[++len] > ' ' && s[len] != ',');
		if(s[len] == 0)
			return FALSE;
	}
	strcpy(tmp, "bmpfile=");		/* bmpfile=<file_name> */
	t = tmp + 8;
	while(len-- > 0)
		*t++ = *s++;
	while(*++s && *s <= ' ');
	if(*s){
		strcpy(t, " hsize=");
		t += 7;
		while(*s > ' ' && *s != ',')
			*t++ = *s++;
		if(*s){
			s++;
			while(*s && *s <= ' ')
				s++;
			strcpy(t, " vsize=");
			t += 7;
			while(*s > ' ' && *s != ',')
				*t++ = *s++;
		}
	}
	*t = 0;
	if (!(epsbox_special)(tmp))
		error(WARNING, "Cannot interpret special %s", special);
	return TRUE;
}

static BOOL pdf_special(char *special)
{
	unsigned char *s, *t, *f;
	SCALED_PT sx, sy, dsy;
	char tmp[0x400];

	if(strncmp(special, "pdf: ", 5))
		return FALSE;
	for(s = special + 4; *++s && *s <= ' '; );
	if(strncmp(s, "image width ", 12) || strlen(s) > 0x300 || 
	   (f = strstr(s, "depth")) == NULL)
		return FALSE;
			/* pdf: image width <width>pt height <height>pt depth <depth>pt(<file_name>) */
	s += 11;
	f += 5;
	while(*f && *f <= ' ')
		f++;
//	dsy = PT_TO_SP(atof(f));
	dsy = BP_TO_SP(atof(f));
	while(*f && *f++ != '(');
	strcpy(tmp, "bmpfile=");		/* bmpfile=<file_name> */
	t = tmp + 7;
	while(*f)
		*++t = *f++;
	*t++ = ' ';
	strcpy(t, " hsize=");
	t += 7;
	while(*s && *s <= ' ')
		s++;
	while(*s > ' ')
		*t++ = *s++;
	if(*s){
		s++;
		while(*s && *s <= ' ')
			s++;
		if(strncmp(s, "height ", 7))
			return FALSE;
		s += 6;
		while(*s && *s <= ' ')
			s++;
		strcpy(t, " vsize=");
		t += 7;
//		dsy -= PT_TO_SP(atof(s));
		dsy -= BP_TO_SP(atof(s));
		while(*s > ' ')
			*t++ = *s++;
	}
	*t = 0;
	get_current_xy(&sx, &sy);
	set_current_xy(sx, sy+dsy);
	if (!(epsbox_special)(tmp))
		error(WARNING, "Cannot interpret special %s", special);
	set_current_xy(sx, sy);
	return TRUE;
}
# endif

static BOOL ignore_special(char *special)
{
	char *kpt, *sp;
	
	if((kpt=isp) != NULL){
		while(*kpt){
			sp = special;
			while(*kpt++ == *sp++){
				if(*kpt == ';' || !*kpt)
					return TRUE;
			}
			while(*kpt != ';'){
				if(!*kpt++)
					return FALSE;
			}
			kpt++;
		}
	}
	return FALSE;
}

static void RectGraph(void)
{
	int x_pos, y_pos, x_size, y_size, type;
	RECT rc;

	while(GetBMPdata(StopGcount, &x_pos, &y_pos, &x_size, &y_size, &type)){
		StopGcount++;
		if(!(f_on & 2))
			continue;
		rc.right= ( (rc.left  = x_pos) + x_size);
		rc.bottom = ( (rc.top   = y_pos ) + y_size);
		if(!(f_on & 1))
			JoinBoundigBox(&StopG0Rec, &rc);
		if(!(f_on & 4))
			JoinBoundigBox(&StopG1Rec, &rc);
	}
}


static int stop_special(char *s)
{
	int num, num2, mx;

	RectGraph();
	if(!*s){
		f_stop = TRUE;
		f_on = 0;
	}else if(*s == '-' && !s[1]){
		f_stop = FALSE;
		if(stop)
			f_on = 7;
		else
			f_on = 6;
	}else{
		while(*s == ' ')
			s++;
		if(!*s || (*s != '-' && (*s < '0' || *s > '9') && *s !='M' && *s != 'm'))
			goto end;
		mx = f_on = 0;
		while(1){
			num = atoi(s);
			if(num < 0){
				num = -num;
				s++;
				if(mx < num)
					mx = num;
				if(stop >= 0 && stop <= num){	/* ex. -4 */
					f_on |= 2;
					if(stop)
						f_on |= 1;	/* former */
					if(stop < num)
						f_on |= 4;	/* next */
				}
			}
			else if(*s == 'M'){
				num = stop_max+1;
				while(*++s == 'M')
					num++;
			}else if(*s == 'm'){
				num = stop_max;
				while(*++s == 'm')
					num--;
				if(num < 0)
					num = 0;
			}
			while(*s == 'm' || *s == 'M' || (*s >= '0' && *s <= '9'))
							/* skip number */
				s++;
			if(*s == '-'){						/* ex. 1-4 */
				num2 = atoi(++s);
				if(*s < '0' || *s > '9'){
					if(*s == 'M'){
						num2 = stop_max+1;
						while(*++s == 'M')
							num2++;
					}else if(*s == 'm'){
						num2 = stop_max;
						while(*++s == 'm')
							num2--;
						if(num2 < 0)
							num2 = 0;
					}else
						num2 = 0;
				}
				if(mx < num)
					mx = num;
				if(mx < num2)
					mx = num2;
				if(num <= stop && (!num2 || stop <= num2)){
					f_on |= 2;
					if(num < stop)
						f_on |= 1;
					if(!num2 || stop < num2)
						f_on |= 4;

				}
				while(*s == 'm' || *s == 'M' || (*s >= '0' && *s <= '9'))
					s++;
			}else if(num == stop){			/* ex. 4 */
				f_on |= 2;
				if(mx < num)
					mx = num;
			}
			if(*s == ' ' || *s == ',')
				s++;
			if(*s != '-' && (*s < '0' || *s > '9') && *s != 'M' && *s != 'm')
				break;
		}
		if(stop_max < mx)
			stop_max = mx;
		if(stop >= 0)
			f_stop = f_on?FALSE:TRUE;
	}
end:
//	if( stop >= 0 ){
//		sprintf(common_work+0x1000, "%d:%d %d %d(%d:%d)%d", 
//			stop, f_on, f_stop, stop_max, num, num2, mx);
//		AskYes(common_work+0x1000, "RESULT");
//	}
	return f_stop;
}

void do_special(char *special) /* modefied by Sadayuki Iwai */
{
	static int unknown_special;

#ifdef WIN32G
	if(!strncmp(special, "dviout `+", 9)){
		if(f_dvioutspecial)
			stop_special(special + 9);
		return;
	}
	if(f_stop)
		return;
#endif
# ifdef	HYPERTEX
	if ((hyper_special)(special)) return;		/* HyperTeX */
#endif
# ifndef NOTPIC
	if ((tpic_special)(special)) return;		/* found */
# endif
	if ((pdl_special)(special)) return;        /* added by SADA.*/
# ifndef NOPS
	if ((epsbox_special)(special)) return;		/* found */
	if (em_special(special))	return;			/* some em: special */
	if (pdf_special(special))	return;
# endif
# ifndef NOPSFRAG
	if (header_special(special, 1)) return;		/* header=foo.ps */
# endif
# ifdef WIN32G
	if (dviout_special(special)) return;		/* dviout special */
	if (pause_special(special)) return;
	if (src_special(special)) return;
#endif
	if (ignore_special(special)) return;
	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 (*(*cmd128_ptr))(int) = cmd128;
static void (*(*cmd235_ptr))(int) = cmd235;

/* ptr to command tables. used for override work() */

static int work(void)
{
	int code;

	ENTER("work");

	// 0x10000 wrong minus number?
	stop = (f_killstop)?0x10000:stop_level;

	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;
#ifdef	JGAIJI
int f_gaiji;
#endif

extern char *f_out;
extern FILE *fp_out;

extern trans_jis(uint);
#endif

void d_put(uint code)
{
#ifdef	JDWN
	unsigned short int far *to;
	DJFONT *pt;
#endif
#if	0
	uint i;
#endif

//	if(font->font_type == ONDEMAND || font->font_type == ONDEMAND2)
//		resolve_font(font);
#ifdef	VIRTUALFONT
	if (font->font_type == VIRTUAL_FONT
#ifdef	USE_ETF
	  || (font->font_type == ETF_FONT && font->etf_type == VIRTUAL_FONT)
#endif
	)
		return;
#endif
#ifndef NO_NTTRPL
	if (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;
					/* Define font->font_type */
#if 0
		if (font->ext.count == 1
#ifdef	JGAIJI
		  && !f_gaiji
#endif
		 ){
			i = code;
			get_font(&i, font);
			font->char_info[(CHAR_ROOT-1)&code] = NULL;	/* add for Ver.3.0 */
		}
#endif
		font->f_goth |= ((ptex_d)?F_DTATE:F_DYOKO);
		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];pt;){
			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 *djt;

	top = 0;
	last = dj_current-1;

	while(top <= last){
		tmp = (top + last)/2;
		djt = ((DJTABLE*)djfont_top) + tmp;
		if (djt->code == code){
			if(djt->font_code < font_code) goto former;
			else if(djt->font_code > font_code) goto later;
			dj_code = djt->new_code;
			dj_font_code = djt->new_font_code;
			return(1);
		}
		if (djt->code > code)
later:		top  = tmp + 1;
		else
former:		last = tmp - 1;
	}
	return(0);
}
#endif

static uchar *dww;

void d_resume(void)
{
	BUFFER *pt;
	FONT_INFO *dfont;
	static uchar *dw;
	long maxcount;
	int i, j, k, c_max;
	uchar b;
#ifdef	JDWN
	DJFONT *dpt;
	DJFONT *dpt0;
	DJTABLE *dpt1;
	DJFONT *dpt_last;
#ifdef	JGAIJI
	char *kname;
	uchar *djw;
#endif
	unsigned int num;
/*	long lnum; */

	ptex_d = 0;

	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; ){
#ifdef JGAIJI
		if (f_gaiji) dpt->code = trans_jis(dpt->code);
#endif
		dpt0 = dpt;
		num = dpt->count;
		k = dpt->font_code;
		j = dpt0->code;
		while (dpt-- > (DJFONT*)djfont_top){
#ifdef JGAIJI
			if (f_gaiji){
				if (dpt->font_code < k) break;
				if (dpt->font_code == k && dpt->code < j) break;
				goto transpos;
			}
#endif
			if (num != 0
			  && (    (num > dpt->count)
				   || (num == dpt->count && k > dpt->font_code)
				  )
			){
transpos:		(dpt+1)->font_code = dpt->font_code;
				(dpt+1)->count = dpt->count;
				(dpt+1)->code = dpt->code;
			}
			else break;
		}
		dpt++;
		dpt->count = num;
		dpt->font_code = k;
		dpt->code = j;
		dpt = dpt0 + 1;
	}
#ifdef JGAIJI
	if (f_gaiji){
		k = -1;
		if (fp_out == NULL) fp_out = stdout;
		djw = (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, djw,
						font->font_code, num, font->k_width, font->k_height,
						font->ext.kdir->width, font->ext.kdir->height, djw);
					j = 1;
				}
				else j = 0;
			}
			if (j == 1)
				fprintf(fp_out, "%04X%5d%s", dpt->code, dpt->count + 1, djw);
		}
		Exit(0);
	}
#endif
		/* 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 (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){
		Free0(dww);
		dw = dww = (uchar *)marea(i);
	}

	for (font = first_font_info; font; font = font->next_font) {
		if (font->f_goth & F_DYOKO)		font->f_goth &= ~F_TOPT;
		else if(font->f_goth & F_DTATE)	font->f_goth |= F_TOPT;
		if ((pt = font->pk) == NULL) {		/* <- kanji font */
			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;
	}

	error(DIRECT, "\nDownloading: ");
	d_download(NULL,0);				/* intialization */
	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 && dfont->font_type != JLBP ){
			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)){
				num = (dpt1+1)->code;
				(dpt1+1)->code = dpt1->code;
				dpt1->code = num;
				
				num = (dpt1+1)->font_code;
				(dpt1+1)->font_code = dpt1->font_code;
				dpt1->font_code = num;
				
				num = (dpt1+1)->new_code;
				(dpt1+1)->new_code = dpt1->new_code;
				dpt1->new_code = num;
				
				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)
		memcpy(dj, djfont_top, 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;
	}
	error(DIRECT, " %dK byte", (int)((cur_dsize + 512) >> 10));
	f_download++;
}
#endif

#ifdef	STR_SEARCH
static int s_put(uint code, uint pos)
{
	int	i, j;
	static FONT_INFO *pre_font;
	static int max_found;
	int *tmp_found;

	if(f_s_font){
		if(f_s_font < 2 || code < 'A' || code > 'Z'){
			f_mid_word = 0;
			return 0;
		}
	}
	if(f_s_search == 3){
		if(!f_mid_word){
			pick_string[pt_pick] = '\t';
			if(++pt_pick >= MAX_PICK)
				pt_pick = 0;
			if(pick_count)
				pick_count++;
		}
		pick_string[pt_pick] = (!code)?VOID_CODE:code;
		if(++pt_pick >= MAX_PICK)
			pt_pick = 0;
		if(pick_count){
			if(++pick_count >= MAX_POST_PICK)
				f_s_search = 4;
		}
		f_mid_word = 1;
		return TRUE;
	}
	if(code <= 0x20){
		if(S_TRANS[code] == NULL)
			goto dif;
		i = j = 0;
		while(S_TRANS[code][i]){
			if(s_put(S_TRANS[code][i++], pos) == TRUE)
				j++;
		}
		return (!j)?FALSE:TRUE;
	}
	if(f_mid_word != 0 && code < 0x80 && isalpha(code)){
		if(f_mid_word < 0){		/* last one is not the whole word */
			n_found--;
			f_mid_word = 1;
			return FALSE;
		}else if(!s_str_pt)		/* top of the string */
			return FALSE;
	}
	
	if((f_s_flags & F_S_NOCASE) && code < 0x60)		/* ignore case */
		code = tolower(code);
	if(s_str[s_str_pt] != code){
		if(!s_str_pt || code == '-')		/* ignore hyphen */
			goto dif;
		for(i = 1; i < s_str_pt; i++){
			if(s_str[s_str_pt-i] != code || s_str_pos[s_str_pt-i] == 0)
nxt:			continue;
			for(j = i; j < s_str_pt; j++){
				if(s_str[j] != s_str[j-i])
					goto nxt;
			}
			s_str_pt -= i;
			for(j = 0; j < s_str_pt; j++)
				s_str_pos[j] = s_str_pos[j+i];
			goto same;
		}
dif:	if(f_s_flags & F_S_ALPHA)
			f_mid_word = (code < 0x80 && isalpha(code))?1:0;
		s_str_pt = 0;
		return FALSE;
	}
same:
	s_str_pos[s_str_pt] = (f_mid_word)?0:pos;
	if(s_str_pt){
		if(s_str[s_str_pt-1] >= 0x100){
			if(s_str[s_str_pt] >= 0x100 && font != pre_font)
				goto dif;
		}else{
			if(s_str[s_str_pt] <  0x100 && font != pre_font)
				goto dif;
		}
	}
	if(++s_str_pt >= s_str_len && s_str_len > 0){
		if(n_found >= max_found){
			tmp_found = (int *)marea((max_found += 0x100)*(sizeof(int)*2));
			if(n_found > 0){
				for(i = 0; i < 2*n_found; i++)
					tmp_found[i] = s_found[i];
				Free(s_found);
			}
			s_found = tmp_found;
		}
		s_found[2*n_found]   = s_str_pos[0];
		s_found[2*n_found+1] = pos;
		n_found++;
		s_str_pt = 0;
		if(f_s_flags & F_S_ALPHA)
			f_mid_word = -1;
		return TRUE;
	}
	pre_font = font;
	if(f_s_flags & F_S_ALPHA)
		f_mid_word = 1;
	return FALSE;
}

/*
 * 		SHIFT JIS -> EUC
 */
uint	sjtoeuc( uint code )
{
	uint	code_h;
#if	0
	uint	code_l = code & 0x00ff;

	if( (code_h  = code & 0xff00) <= 0x9f00 )
		code += code_h -(( code_l < 0x9f )?0x0e100:0x0e000);
	else
		code += code_h -(( code_l < 0x9f )?0x16100:0x16000);
	if		( code_l < 0x7f ) code -= 0x1f;
	else if	( code_l < 0x9f ) code -= 0x20;
	else					  code -= 0x7e;
	return code;
#else
	code_h = code & 0xff00;
	code += code_h - ((code_h <= 0x9fff)?0x16100:0xe100);

	if((code & 0x00ff) >= 0x9f)
		return (code + 0x102);
	return (((code & 0x00ff) >= 0x7f)? (code + 0x60):(code + 0x61));
#endif
}

BOOL IsSetSearchStr(void)
{
	return (s_str==NULL)?FALSE:TRUE;
}

void SetSearchStr(uchar *s)
{
	int code, len, flag;

//	n_found = 				// for  source special+search
	s_str_pt = flag = 0;

	if(s == NULL)
		return;
	if((len = strlen((char*)s)) > s_str_len){
		if(s_str != NULL){
			Free(s_str);
			Free(s_str_pos);
		}
		s_str = (unsigned short *)marea((len+1)*sizeof(unsigned short int));
		s_str_pos = (int *)marea((len+1)*sizeof(int));
	}
	for(s_str_len = 0; *s; ){
		if((*s & 0x80) && IsJapanese()){
			flag = 1;
			if(!s[1])
				break;
			s_str[s_str_len++] = (sjtoeuc(s[1] + (s[0] << 8)) & 0x7f7f);
			s += 2;
		}
		else if(*s == 0x20 || *s == '\t')
			s++;
		else{
			code = *s++;
			if(isalpha(code)){
				if(f_s_flags & F_S_NOCASE)
					code |= 0x20;
			}
			else if(f_s_flags & F_S_WORD)
					flag = 1;
			s_str[s_str_len++] = code;
		}
	}
	if(f_s_flags & F_S_WORD){
		if(flag)	f_s_flags &= ~F_S_ALPHA;
		else		f_s_flags |= F_S_ALPHA;
	}
}

int GetSearchLoc(int num)
{
	if(num < 0 || num >= 2*n_found)
		return 0;
	return s_found[num];
}

void clear_search_buf(void)
{
	if(s_str != NULL){
		Free(s_str);
		Free(s_str_pos);
	}
	Free0(s_found);
	Free0(dww);
}
#endif

#ifdef	HYPERTEX
static char search_h_name[MAX_TAG_LEN];;

void SetHyperSearch(char *s)
{
	if(s == NULL)
		f_hyper &= ~F_H_SEARCH;
	else{
		strncpy(search_h_name, s, MAX_TAG_LEN);
		f_hyper |= F_H_SEARCH;
	}
}

static char *skip_sp(char *s)
{
	while(*s == ' ' || *s == '\t')
		s++;
	return s;
}

static BOOL hyper_sp_pret(char *special)
{
	int	ch, tmp;

	while(*special == ' '|| *special == '\t')
		special++;
	if(strncmp(special, "html:", 5) == 0){
		if( (f_hyper & (F_H_SEARCH|F_H_SKIP)) == F_H_SKIP)
			goto dif;					/* this page is already checked */
		special += 5;
	}else
		return FALSE;
	special = skip_sp(special);
	if(*special++ != '<')
		goto dif;
	special = skip_sp(special);
	if(*special == '/'){					// </a>
		if( (f_hyper & F_H_SEARCH) != 0 || tolower(*++special) != 'a')
			goto dif;
		close_hyper_box();
	}
	if(tolower(*special) != 'a'){			//  <base href="...">
		if(strncmp(special, "base href", 9) == NULL){
			while(*++special != '"' && *special);
			for(tmp = 0; tmp < MAX_PATH && *special++ && *special != '"'; )
				base_href[tmp++] = *special;
			base_href[tmp] = 0;
		}
		goto dif;
	}
	special++;

	while(*special){
		special = skip_sp(special);
		switch(ch = tolower(*special)){
			case 'h':							//	 <a href="...">
				if(    !(f_hyper & F_H_SEARCH)
					&& tolower(*++special) == 'r'
					&& tolower(*++special) == 'e'
					&& tolower(*++special) == 'f')
						goto href;
h_skip:			while(*++special != '"' && *special);
				while(*special && *++special != '"');
				goto dif;

			case 'n':							//	<a name="...">
				if(  tolower(*++special) != 'a'
				  || tolower(*++special) != 'm'
				  || tolower(*++special) != 'e'
				) goto h_skip;
href:			while(*++special == ' '|| *special == '\t');
				if(*special++ != '=')
					goto dif;
				special = skip_sp(special);
				if(*special++ != '"')
					goto dif;
				special = skip_sp(special);
				tmp = strlen(special);
				while(tmp > 0 && special[tmp] != '"')
					tmp--;
				if( ch == 'n' || strncmp(special, "dviout:", 7) ){
					while(tmp > 0 && 
					(special[tmp-1] == ' ' || special[tmp-1] == '\t'))
						tmp--;
				}
				special[tmp] = 0;
				if(f_hyper & F_H_SEARCH){
					if(strcmp(search_h_name, special) != 0)
						return FALSE;
					f_hyper &= ~F_H_SEARCH;
					return TRUE;
				}
				store_hyper_tag(special, ch);
				count_hyper_special++;
				special += tmp + 1;
				break;
			default: 
				goto dif;
		}
	 }
dif:
	return (f_hyper & F_H_SEARCH)?FALSE:TRUE;
}

static BOOL src_special(char *special)
{
	char src_file[MAX_PATH+8];
	uint line, pos;

	if(strncmp(special, "src:", 4))
		return FALSE;
	if( (f_hyper & (F_H_SEARCH|F_H_SKIP)) == F_H_SKIP)
		return TRUE;					/* this page is already checked */
	special += 4;
	special = skip_sp(special);

	src_file[0] = (ptex_d & 1)?2:1;		/* tate or yoko */
	line = atoi(special);
	while(*special >= '0' && *special <= '9')
		special++;
	for(pos = 3; pos >= 1; pos--){			/* line number < 255*255*255 */
		src_file[pos] = line%255 + 1;
		line /= 255;
	}
	line = ftell(dvi);
	for(pos = 7; pos >= 4; pos--){			/* pos < 255^4 */
		src_file[pos] = line%255 + 1;
		line /= 255;
	}
	special = skip_sp(special);
	strncpy(src_file + 8, special, MAX_PATH);
	store_hyper_tag(src_file, 'n');
	count_src_special++;
	return TRUE;
}
#endif

#if	defined(STR_SEARCH) || defined(HYPERTEX)
/*
  return 0: usual font as cmr10 or min10
		 1: symbol font (ignore for string serach)
		 2: A-Z are usual and the others are symbols
 */
static int check_sfont(FONT_INFO *ft)
{
	char *s, *t;
	int	i, type;

	f_s_fspace = font->size_para/5;			/* 655360/5 */
	f_s_ospace = font->size_para*2/3;		/* 655360*2/3 */

	if(s_font == NULL || f_s_mode == 1)
		return 0;
	for(type = 1, s = s_font; ;){
		if(!*s)
			return 0;
		t = ft->n;
		while(*t++ == *s){
			if(!*s++)						/* match to the last one */
				goto ret;
		}
		for(i = 0; ;i++){					/* not match */
			switch(*s++){
				case 0:
					return 0;
				case ';':
					goto nxt;
				case '*':
					if(!i)
						goto ret;			/* match with * */
					goto nxt;
				case ' ':
					type = 2;
					goto nxt;
			}
		}
nxt:	;
	}
ret:return type;
}
#endif

	/*      set_char_0,	         0 SET_CHAR_0	*/
static uchar cmd128_mode[] =
{
		0x31,	/* 128 SET1			*/
		0x32,	/* 129				*/
		0x33,	/* 130				*/
		0x34,	/* 131				*/
		8,	/* 132 SET_RULE		*/
		0x31,	/* 133 PUT1			*/
		0x32,	/* 134				*/
		0x33,	/* 135				*/
		0x34,	/* 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_mode[] =
{
		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		*/
};

#ifdef	WIN32G
static void s_work(void)
{
	int code, mode, tmp;
#if 1
	char *special;
#endif

	f_spsh = 0;
	while ((code = (uchar)read_byte(dvi)) != EOP){
		if(code >= 128){
			if (code < FNT_NUM_0){
				mode = cmd128_mode[code - 128];
				goto work;
			}else if (code >= FNT1){
				mode = cmd235_mode[code - FNT1];
work:			if (mode >= 0x30)
					tmp = (long)read_n(dvi, mode & 0xf);
				switch (mode >> 4) {
				  case (0):
skip_m:				  while(mode-- > 0)
						  (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);
					  break;
/*
				  case (3):
					  break;

				  case (4):
					  break;
*/
				  case (5):
#if	1
					  if(tmp < COMMON_SIZE-1){
						special = tmp_buf + 0x400;
						while (tmp-- > 0)
							*special++ = getc(dvi);
						*special = '\0';
						special = tmp_buf + 0x400;
						while(*special && *special <= ' ')
							special++;
						if( strsubcmp(special, "sh")
							&& special[2] <= ' ')
								f_spsh++;
# ifndef NOPS
						else if(
						  (strsubcmp(special, "color")
							&& special[5] <= ' ')
						||(strsubcmp(special, "background")
							&& special[10] <= ' '))
								(epsbox_special)(special);
# endif
						break;
					  }
#endif
					  goto skip;
				}
			}
		}
	}
}
#endif

static void d_work(void)
{
	static long hh, vv;
	int code, mode;
	char *special;
	long tmp;

	hh = vv = -10000000;
	while ((code = (uchar)read_byte(dvi)) != EOP
#ifdef	STR_SEARCH
			&& f_s_search < 4
#endif
	  ) {
		if (code < 128){
#ifdef	STR_SEARCH
c_put:		if(f_s_search){
				if(f_s_search == 3){
					if(  hh - h > f_s_ospace || vv  - v > f_s_ospace )
						f_mid_word = 0;		/* backward */
					else if(!ptex_d ){
						if(v - vv > f_s_ospace || h - hh > f_s_fspace)
							f_mid_word = 0;
					}
					else{
						if(v - vv > f_s_fspace || h - hh > f_s_ospace)
						f_mid_word = 0;
					}
					s_put((uint)code, ftell(dvi));
					if (ptex_d & 1){
						vv = v += cput((uint)code);
						hh = h;
					}else{
						hh = h += cput((uint)code);
						vv = v;
					}
					if(pick_count && f_s_mode == 1){
						f_s_search = 4;
						return;
					}
				}else
					s_put((uint)code, ftell(dvi));
			}
#endif
#ifdef	FDOWN
			if(f_download)
				d_put((uint)code);
#endif
		}
		else if (code < FNT_NUM_0) {
			mode = cmd128_mode[code - 128];
			goto work;
		}
		else if (code < FNT1){
			font_change((int)(code - FNT_NUM_0));
#ifdef	STR_SEARCH
			if(f_s_search)
				f_s_font = check_sfont(font);
#endif
		}else {
			mode = cmd235_mode[code - FNT1];
work:
			if (mode >= 0x30)
				tmp = (long)read_n(dvi, mode & 0xf);
			switch (mode >> 4) {

			  case (0):
#ifdef	STR_SEARCH
				  if(f_s_search == 3 && mode <= 4){
					(cmd128_ptr[code - 128]) (code);
					break;
				  }
				  if(f_s_flags & F_S_ALPHA){
					if(code <= POP || code >= DOWN1){
						if(code == NOP)
							break;
						f_mid_word = 0;
						if(code == PUSH)
							d_push();
						else if(code == POP)
							d_pop();
						else goto skip_m;
					}else{
						if(!mode){						/* W0 or X0 */
							tmp = (code == W0)?w:x;
						}else if(code <= W0){			/* RIGHT1 - RIGHT4 */
							tmp = signed_read_n(dvi, code - (RIGHT1 - 1));
						}else if(code > X0){			/* X1 - X4 */
							x1(code);
							tmp = x;
						}else{							/* W1 - W4 */
							w1(code);
							tmp = w;
						}
						if(!tmp || tmp >= f_s_space)
							f_mid_word = 0;
					}
				  }else
#endif
skip_m:				while(mode-- > 0)
					  (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):
#ifdef STR_SEARCH
				  if(f_s_search){
					code = tmp;
					goto c_put;
				 }
#endif
#ifdef FDOWN
				  if (f_download == 1)
					  d_put((uint)tmp);
#endif
				  break;

			  case (4):
				  font_change((int)tmp);
#ifdef	STR_SEARCH
				  if(f_s_search)
					  f_s_font = check_sfont(font);
#endif
				  break;

			  case (5):
#ifdef	HYPERTEX
				  if((f_hyper & F_H_SEARCH) && tmp < COMMON_SIZE-1){
					  special = tmp_buf;
					  while (tmp-- > 0)
						  *special++ = getc(dvi);
					  *special = '\0';
					  if(hyper_sp_pret((char *)tmp_buf))	/* found tag */
						return;
					break;
				  }
#endif
				  goto skip;
			}
		}
	}
}

/* end of file : pret.c */

/* additional functions by Oh-Yeah? */

#if !defined(NOTPIC) || !defined(NOPS)

static 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);
}

pixelpoint relmi_to_abs(TPIC_MI x, TPIC_MI y)
{
#define MI_SP 4736.28672
	static pixelpoint p;

	p.x = sptopixel((SCALED_PT)(x * MI_SP) + h) - H0;
	p.y = vtopixel((SCALED_PT)(y * MI_SP)  + v) - V0;
	RETURN(p);
}

#endif /* end of ifndef NOTPIC */

#ifndef NOPSFRAG
static int save_font;
static long save_pos = -1;

void save_dvi_state(BOOL f)
{
	if (f == FALSE) {
		save_pos = -1;
	} else {
		save_font = font->font_code;
		save_pos = ftell(dvi);
	}
	return;
}

void restore_dvi_state(void)
{
	if (save_pos < 0) return;

	font_change(save_font);
	fseek(dvi, save_pos, SEEK_SET);
}

void set_current_xy(SCALED_PT x, SCALED_PT y)
{
	h = x;
	v = y;
}

void get_current_xy(SCALED_PT *x, SCALED_PT *y)
{
	*x = h;
	*y = v;
}

#endif

#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, FONT_INFO *ff)
	/* フォントの補正・回転などに関する、データの書き換え部
	 */
{
	PIXEL p_up, p_right, height, width;
	char p_rotate, p_mirror;

	p_up = p_right = p_rotate = p_mirror = 0;
	if(ff == NULL)
		ff = font;
	if (ptex_d & 1){
		if (ff->font_type == JXL && (ff->f_goth & F_TOPT)){
			p_rotate = 8;
			goto set;
		}
		if (char_code < 0x0100 || !(ff->f_goth & F_TATE))
			p_rotate = 3;
		else if (ff->font_type == UNKNOWN
#ifdef	USE_WINFONT
				|| ff->font_type == WINJTT_FONT
#endif
			) goto set;
		else if ((0x2145 < char_code) && (char_code < 0x215C))
			p_rotate = 1;
		else if(char_code < 0x2600){
			/* ptex_d == 1 なので width は漢字送り方向（すなわち縦）*/
			{
				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 0x2131:		/* ￣＿ */
			  case 0x2132:
			  case 0x213D:		/* ―…‥ */
			  case 0x2144:
			  case 0x2145:
			  case 0x2126:		/* ・‐‖｜ */
			  case 0x213E:
			  case 0x2142:
			  case 0x2143:
			  case 0x2161:		/* ＝→←↑↓〓 */
			  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;
		}
	}else if(ff->f_goth & F_TATE)
		p_rotate = 5;
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;

	if(offset < 0)
		return 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


char *find_key0(char *str, char *key)
{
	while(!isalpha(*str)){
		if(!*str++)
			return NULL;
	}
	while(*str==*key && *key){
		str++;
		key++;
	}
	if(*key || isalpha(*str))
		return NULL;
	while (*str == ' ') str++;
	if (*str == '=')
		while (*(++str) == ' ');
	return str;
}

char *find_key(char *str, char *key)
{
	char *key_str, *str_top;

	str_top = str;
	while ((key_str = strstr(str, key)) != NULL){
		str = key_str + 1;
		if ( key_str != str_top && isalpha(*(key_str-1)) )
			continue;
		key_str += strlen(key);
		if (!isalpha(*key_str)){
			while (*key_str == ' ') key_str++;
			if (*key_str == '=')
				while (*(++key_str) == ' ');
			return key_str;
		}
	}
	return NULL;
}


/*-------------------------------------------------------------------*/
/* additional functions by Sadayuki Iwai, for lips special commands. */
/*-------------------------------------------------------------------*/
#ifdef LBP
static void special_pdl(char *pdl_file, char *type_ext, int type)
{
	FILE *spf;
	int c;
	
	strncpy(common_work, pdl_file, 128);
	if (strchr(common_work, '.') == NULL){
		strcat(common_work, type_ext);
	}

	if ((spf = fopenf((char *)common_work, "rb")) == NULL){
		error(WARNING, "can't open PDLspecial file %s", common_work);
	}else{
		error(DIRECT, "PDL special file %s\n", common_work);
		if (type != PDL)
			(*(lbpf->move_cap))(get_current_y(), get_current_x());
		while ((c = fgetc(spf)) != EOF){
			pr_putc((uchar)c);
		}
		fclose(spf);
	}
}
#endif

/*-------------------------------------------------------------------*/
static BOOL pdl_sp_pret(char *str)  
{
	BOOL found = TRUE;
#ifdef LBP
	int	type;
	char *prt_name;
#endif

	/*skip blank*/
	while(*str == ' '){
		str++;
	}
	/*check lips_special*/
	switch (
#ifdef	LBP
			type = 
#endif
			check_sp(str)){
		case LP3:
#ifdef LBP
#  ifdef LIPS3
			if (dviout_dimension.prt_type == LBP_LIPS3){
				prt_name = ".lp3";
				goto pdl_prt;
			}else
#  endif
			{
				prt_name = "LIPS3";
err_prt:
# if !defined(WIN32G)||defined(RAWOUT)
		if (f_first_split
#   ifdef	RAWOUT
				  && f_dviprt
#   endif
				)
					error(WARNING, 
						"%s special commands exist, but not %s printer",
						prt_name, prt_name);
			}
# endif
#endif
			break;
		case EPG:
#ifdef LBP
#  ifdef ESCPAGE
			if (dviout_dimension.prt_type == LBP_ESCPAGE){
				prt_name = ".epg";
				goto pdl_prt;
			}else
#  endif
			{
				prt_name = "ESC/Page";
				goto err_prt;
			}
#else
			break;
#endif
		case PDL:
			prt_name = ".pdl";
pdl_prt:	if (f_first_split
# ifdef RAWOUT
			  && f_dviprt
# endif
			)
				special_pdl(pdl_fname, prt_name, type);
			break;
		case NOT_PDL :
			found = FALSE;
			break;
		}
	return found;
}
/*-------------------------------------------------------------------*/
static int check_sp(char *str)
{
	if ((pdl_fname = find_key0(str, LIPS_STR)) != NULL){
		return LP3;
	}if ((pdl_fname = find_key0(str, ESCPAGE_STR)) != NULL){
		return EPG;
	}if ((pdl_fname = find_key0(str, PDL_STR)) != NULL){
		return PDL;
	}else{
		return NOT_PDL;
	}
}

/*-------------------------------------------------------------------*/
#if 0
static unsigned char a2b_table[128] =
{
	0, 0, 0, 0, 0, 0, 0, 0,		0, 0, 0, 0, 0, 0, 0, 0
	0, 0, 0, 0, 0, 0, 0, 0,		0, 0, 0, 0, 0, 0, 0, 0

	0, 0, 0, 0, 0, 0, 0, 0,
	0, 0, 0, 0, 0x00, 0, 0x20, 0,

	0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x3b, 0x3c, 0x3d,
	0x3e, 0x3f,    0,    0,    0,    0,    0,    0,

	  0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 
	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',

	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
	'X', 'Y', 'Z',   0,   0,   0,   0,   0,

	  0, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
	'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',

	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
	'x', 'y', 'z',  0,   0,   0,   0,   0,
};

static unsigned int a2b(unsigned int aa)
{
	unsigned int bb;

	bb = a2b_table[aa & 0x7f];
	aa >>= 8;
	bb += ((unsigned int)a2b_table[aa & 0x2f]) << 6;
	aa >>= 8;
	bb += ((unsigned int)a2b_table[aa & 0x2f]) << 12;
	aa >>= 8;
	return bb + (((unsigned int)a2b_table[aa & 0x2f]) << 18);
};

void WriteFile(FILE *fp, int size, BUFFER *pt)
{
	unsigned int bb:

	for(;;pt += 4){
		bb = a2b(pt[0] + (pt[1] << 8) + (pt[2] << 16) + (pt[3] << 24));
		if(size-- > 0){
			putc(bb & 0x7f, fp);
			bb >>= 8;
		}
		if(size-- > 0){
			putc(bb & 0x7f, fp);
			bb >>= 8;
		}
		if(size-- > 0)
			putc(bb & 0x7f, fp);
		else
			break;
	}
};

void WriteBuf(BUFFER *fp, int size, BUFFER *pt)
{
	unsigned int bb:

	for(;;pt += 4){
		bb = a2b(pt[0] + (pt[1] << 8) + (pt[2] << 16) + (pt[3] << 24));
		if(size-- > 0){
			*fp ++ = bb & 0x7f;
			bb >>= 8;
		}
		if(size-- > 0){
			*fp++ = bb & 0x7f;
			bb >>= 8;
		}
		if(size-- > 0)
			*fp++ = bb & 0x7f;
		else
			break;
	}
};

#if 0
static unsigned char b2a[64] =
{
	',', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
	'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O'
	'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
	'X', 'Y', 'Z', '0', '1', '2', '3', '4',
	'.', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
	'h', 'i', 'j', 'k'. 'l', 'm', 'n', 'o',
	'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
	'x', 'y', 'z', '5', '6', '7', '8', '9'
};
#endif
#endif

/* end of all */

