/*
 *  TEX Device Driver  ver 2.00-
 *  copyright(c) 1988,89 by TSG, 1990-93 by SHIMA
 *
 *  PRINTER DRIVER ver 1.50
 *  device.c : print out module
 *             3rd edition
 *
 *  1990, Modified by SHIMA
 *  バッファード出力、基本ルーチンのアセンブラ化、HMAX による効率アップなど
 * このモジュールは，当然device-dependentである．
 *  1992, Slightly extended for Kyocera L-880 & HP LaserJet+ by Oh-Yeah?
 *
 *  1992, *.cfgファイルにdpiの項目を追加 by sempa
 *
 *	modified for non PC-9801 machines by sempa 1992
 *
 *  *.cfgファイルを 環境変数 `TEXCFG'のパスからオープンするように変更 by sempa 1992 Apr
 *  (「dviprt -pofile」の`file'にパス指定がない場合)
 *
 *	very slightly modified against warnings by Oh-Yeah? 25 May 1992
 *
 *  modified for LIPS3 by SHIMA 30 June 1992
 *  modified for ESC/Page by H.Tomiie, 31 July 1992
 *  modified for LIPS3 + ESC/Page by H.Tomiie and OkI, 30 Sept. 1992
 *  modified for hex mode by I. Matsuda, 6 Dec. 1992
 */

#ifdef	RAWOUT
#define	PR_BUF_SIZE		0x1000
#else
#define	PR_BUF_SIZE		256
#endif
/*
  *  プリンタ出力用のバッファ・バッファサイズ（ブロック単位で出力）
  */

#define	STR_EXP_SIZE	32

#define	HWMIN		1
/*
  *  横方向の HMIN*8 ドットの範囲が、空白ならば、続く空白と合わせて、プリン
  *  タヘッドの移動命令を送る。但し、それ以降も行末までが空白ならば、何も送
  *  らない（デフォールト）。
  */

#define	HWMAX		(1440/8)
/*
  *  ESC/P　のときは (1440/8) 以下でなくてはならない。
  *  ビットイメージ、または、移動命令を１度に送る横幅のドット数の最大値
  */

#define S_CFG
#define S_CFG_BUILTIN
/*
 * 新しい プリンタ定義ファイル (S バージョン) を使えるようにするには
 * S_CFG を定義しておく。
 * バージョンナンバーを見て、新旧の CFG を使い分けるようになる。
 *
 * S_CFG_BUILTIN を定義すれば、dviprt 組込みのプリンタ定義 (ESC/P 24 pins,
 * PC-PR 24 pins, LIPS 3 など) も新 CFG の形式で保持しておくようになる。
 */
#ifndef S_CFG
#  undef S_CFG_BUILTIN
#endif

#ifdef WIN32
#include "dviout.h"
#endif

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

#ifdef	 UNIX
#include <unistd.h>
#else
#ifdef MSVC
#include "msvcdir.h"
#else
#include <dir.h>
#endif
#include <conio.h>
#include <io.h>
#endif

#define _DEF_DOS_H_
#include "dd.h"
#include "prtout.h"
#include "err.h"
#include "prtctl.h"
#include <ctype.h>
#include "s_cfg.h"
#include "dviread.h"
#include "option.h"
#include "vfont.h"

#define ESC 		0x1b
#define CR  		0x0d
#define LF  		0x0a

static int pr_buf_len;
BOOL f_pause;
int ff_flg = -1;
BOOL f_top_margin;
static BOOL f_hex_mode = FALSE;
static BOOL f_r_format;
uint slow_fact;
static char pr_buf[PR_BUF_SIZE+4];
#define	str_exp	tmp_buf

#if defined(NO_OUTP) && !defined(WIN32G)
char *f_out="";
#else
char *f_out;
#endif

static FILE *fp_out;
char *prt_initialize;

static int vert_byte_unit = V_BDIV;	/* ピン数／８ */
/* static int vert_bit_unit = V_BDIV << 3; */ /* プリンタのピン数 */
/* 下の #define を頼って lips3.c, escpage.c から exern しているので注意すること */
#define	vert_bit_unit vert_divide

static uint hwmin = HWMIN;
static uint hwmax = HWMAX;
static uint mult_const;
static int num_cr;	/* CR/LF を送るべき数 */
static long trans_byte;
static int Page;
static int f_files = -1;
static BOOL f_abort;
static int x_dpi,y_dpi,output_width,output_height,text_width,text_height,
		buf_width;
static uint x_pos=0,y_pos=0;

extern DIMENSION dviout_dimension;
extern PIXEL vert_divide;

int comp_type = -1;
extern int machine;
extern int f_init;

#ifndef UNIX
# if defined(J3100) || defined(DOSV)	
char *pr_port_str = NULL;
static int pr_port_num = 0;
# else
#  if	defined(WIN32C)|| defined(RAWOUT)
char *pr_port_str = NULL;
#  endif
# endif

# if	(defined(GCC) || defined(DOSV)) && !defined(WIN32)
static int pr_ioport;
static int pr_port_wait = 0;
# endif
#endif

#ifdef	JDWN
extern int f_gaiji;
#endif

BOOL f_rotate;

#ifdef	LBP
/* static int last_H; */
/* static int last_V; */
int f_vh_ratio;
int f_copy;
BOOL f_lbp_comp;
char *youshi;
extern int f_use_lfont;
LBP_FUNC *lbpf;

#ifdef	LIPS3
extern int f_lips4;
extern LBP_FUNC lips3_func;
#endif

#ifdef	ESCPAGE
extern LBP_FUNC escpage_func;
#endif

int k_base_l = 10000;	/* This is relative according to the
								size of Kanji in LBP.  1000 is
								corresponds the size of Kanji.
								A larger number means that Kanji
								fonts move to lower position		*/

int k_base_d = 1;	/*  Arrange of dot height of scalable
								Kanji fonts.
								A larger number means that Kanji
								fonts move to lower position	*/

int k_scale_l = 10000;	/* This is factor for Kanji width adjust-
								ment of LBP scalable font. It was used
								after multiplied by `k_scale' factor.*/

int lbp_orig_dpi = 0;	/* LIPS3本来の dpi 値．-dpiによる縮小・
								拡大印刷時にもフォントピッチ指定コマンド
								のｃｐｉ計算を正しく行なうため必要． */

static int k_width_adj = 0;	/* dot単位で計算された漢字幅にさらに
								この値を加えて補正を加える．この値は
								ESC/Pageでセットされる*/
int last_dir = -1;	/* 最後に描画したフォントの種類．LIPS3では
					 * これが異なるときには再呼びだしが必要になる
					 * 0:DownLoad Vertical 1:DL Horizontal 2:漢字 3:Bit Image.
					 * 0:DnLd l->r, 1:DnLd b->t, 2:DnLd r->l 3:DnLd t->d
					 * 4:漢字 l->r, 5:漢字 b->t, 6:漢字 r->l 7:漢字 t->d */

#endif

char *f_bmp;
static int xbit, ybit;
#ifdef	FAX
char *f_fax;
static void fax_encode_block(int, int, HUGE_BUF*, int);
static void set_FAX_ctl(void);
#endif


/* init.c prtinit.c */
extern char far *cfg_path;
extern BOOL f_lbp_prt;

/* misc.c */
#ifdef	GCC1
int KbHit(void);
int GetCh(void);
#endif

#if	!defined(NO_OUTP)||defined(RAWOUT)
void PrFlush(char *, int);
void PrBufFlush(void);
#endif

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

/* main.c */
int no_extension(char *);
void Exit(int);
extern DVIFILE_INFO dvifile;

/* bitmap.c */
extern uchar REV[];

/* gray.c */
BUFFER *make_bmp(BUFFER *s, int b_width, int s_width, int s_height, 
	int top_skip, int x_bit, int y_bit);
void gray_gamma(int,int,int,int);
int SetColor(int);

/* wmain.c */
char *GetOutPath(char *);

/* vfont.c */
V_JFM *get_vjfm(int vjfm_no);

/* p_out.c local routine (they are used in lips3.c, escpage.c, too.)*/
static void pr_putnc(char *, int);
void pr_puts(char *);
void pr_putsn(char *, int);
void pr_putc(char);

int bright = 255;

#ifdef	WIN32G
void ChangeWaitCursor(int);
extern uint f_s_dpi;
void CheckReverse(int);
#endif

#if	defined(WIN32C)||defined(RAWOUT)
/* prtw32c.c */
void Win32cPrtinterInit(int);
void Win32cPrtinterEnd(void);
#endif 

static void p_sublbp(int hmax, HUGE_BUF *ptr, int bitno, int length, int type,
	BUFFER *buf);
static void p_subbuf(int hmax, HUGE_BUF *ptr, int length, int type, BUFFER *out);

void get_prt_ctl(char *filename);

static void pr_numb_S(char *,uint,uint);
static void pr_numb_QR(char *,uint,uint);
static void (*pr_numb)(char *,uint,uint) =pr_numb_S;

static void pr_crlf(void);
static void slow(uint fact);
static void p_sub(int, HUGE_BUF *, int, int);

static uint pclmode1compress(BUFFER *dst,BUFFER *src,int size);
static uint pclmode2compress(BUFFER *dst,BUFFER *src,int size);
static uint (*compress_func[])(BUFFER *,BUFFER *,int) = {
	NULL,
	pclmode1compress,
	pclmode2compress,
};

/*
 * 8n×8 ドットのビットマップ・バッファのデータを 8n バイトのプリンタ用の
 * データに変えて、プリンタに送る。
 * 実際には、pr_buf_len を参照して、プリンタ出力用のバッファに直接書き込み
 * バッファが一杯になったら、Ｃの関数 pr_flush() を呼んで書き込む。
 * ビットマップの左から順に縦の列 8n ドットを、n バイトに直して、8 回送る。
 * 縦の n バイトは、上から順に送る。１バイトのうち、上の方が上位のビットに
 * なるように変換するのが p_sub() で、p_subnec() はその逆である。
 * 送るべきビットマップデータの先頭アドレスが２番目の変数、最初の変数は、１行
 * のバイト数（隣接する下のドットとのビットマップバッファでのバイト単位でのア
 * ドレス差)、n は、３番目の変数で与えられる。
 */

static void conv_bit(ulong, HUGE_BUF *);	/* convert bit pattern */

void pr_new_page(void);

#ifndef	WIN32
static void pr_esc_chk(void);
#endif

void pr_flush(void);

void device_pause(void)
{
}

void device_cont(void)
{
}

static char NUL4[4] = {0,0,0,0};

static char *line_feed = "\x02\x0d\x0a\x00";
static char *form_feed = "\x02\x0d\x0c\x00"
;static char *after_bit_image = NUL4;
static char *bit_row_header = NUL4;

static char prt_ctl[MAX_PRINTER] =
{
/* ctrl of printer
	 * lower 4 bits represents the vertical length by  bytes
	 */

	VERT_DIVIDE / 8,						/* ESC/P printer */

	(VERT_DIVIDE / 8) | TOP_IS_LOW,			/* PC-PR printer */

	(VERT_DIVIDE / 8) | TOP_IS_LOW			/*  NM   printer */

#ifdef	LIPS3
	,(8 / 8) | LEFT_IS_HIGH | NON_MOVING	/* lips3 */
#endif
#ifdef	ESCPAGE
	,(8 / 8) | LEFT_IS_HIGH					/* ESCPage */
#endif
#ifdef	FAX
	,(8 / 8) | LEFT_IS_HIGH					/* FAX */
#endif
};

static char *dot_cr[MAX_PRINTER] =
{
/* codes of start job for printer */

	"\x07"					/* ESC/P printer */
	"\x1b" "3\x18"			/* 3 byte: 24/180 inch line feed */
	"\x1b" "?Z" "\x27"		/* 4 byte: ESC Z ... -> ESC * m \x27 ... */
	"\0"
	,

	"\x06"					/* PC-PR printer */
	"\x1b" "T18"			/* 4 byte: 18/120 = 24/160 inch line feed */
	"\x1b" ">"				/* 2 byte: print in one direction */
	"\0"
	,

	"\x0a"					/* NM printer */
	"\x1a" "C"				/* 2 byte: 180 dpi for bits image */
	"\x1a" "F"				/* 2 byte:  1/120 inch pitch */
	"\x1b" "T16"			/* 4 byte: 24/180 inch line feed */
	"\x1b" ">"				/* 2 byte: print one direction */
	"\0"

#ifdef	LIPS3
	,
	NUL4					/* Use call lips3_init() */
#endif
#ifdef	ESCPAGE
	,
	NUL4					/* Use call escpage_init() */
#endif
#ifdef	FAX
	,
	"\x10"					/* Header for StarFAX (fine mode)*/
	"SF"					/* 2 byte: id */
	"\x01"					/* 1 byte: version */
	"\x00\x00\x00\x00\x00"	/* 5 byte: _[5] */
	"\x00\x40\x00\x00"		/* 4 byte: FIF[4]: fine Mode */
	"\x00\x00\x00\x00"		/* 4 byte: __[4] */
	"\0"
#endif
};

static char *nrm_cr[MAX_PRINTER] =
{
/* codes of end of job for the  printer */

	"\x04"					/* ESC/P printer */
	"\x0d\x0c"
	"\x1b" "2"				/* 2 byte: 1/6 inch line feed */
	"\0"
	,

	"\x06"					/* PC-PR printer */
	"\x0d\x0c"
	"\x1b" "A"				/* 2 byte: 1/6 inch line feed */
	"\x1b" "]"				/* 2 byte: print in both direction */
	"\0"
	,
	"\x06"					/* NM printer */
	"\x0d\x0c"
	"\x1b" "A"				/* 2 byte: 1/6 inch line feed */
	"\x1b" "]"				/* 2 byte: print in both direction */
	"\0"

#ifdef	LIPS3
	,
	"\x08"					/* LIPS3 */
	"\x0d\x0c"				/* 2 byte: CR & FF */
	"\x1b" "<"				/* 2 byte: Software reset */
	"\x90" "0J" "\x9c"		/* 4 byte: End job */
	"\0"
#endif
#ifdef	ESCPAGE
	,
	"\x06"					/* ESC/Page printer */
	"\x0d" "\x0c"
	"\x1d" "rhE"
	"\0"
#endif
#ifdef	FAX
	,
	"\x09"					/* FAX: RTC */
	"\x00\x08\x80"
	"\x00\x08\x80"
	"\x00\x08\x80"
	"\0"
#endif
};

/*			format to output string with a number 

  len[1], flag[1], pos[1], f_mode[1], data[len]

  len                  : the length of data

  flag   & 0x03        : shift left by this number (x1, x2, x4, x8)
  flag   & 0x80        : continue to the next block?

  pos                  : top of the position of the number in data

  f_mode & 0x80        : multiply by vert_byte_unit?
  f_mode & 0x40        : ISO number?
  f_mode & 0x08        : multiply by constant?
  f_mode & 0x07 =    0 : No number
					 1 : Binary Low to High
					 2 : Binary High to Low
					 3 : 3 digit decimal
					 4 : 4 digit decimal
					 5 : 5 digit decimal
					 6 : variable decimal
					 7 : not use
 */


#ifdef	LIPS3
static char dotg_lips3[] = 
	"\x01\x9b"				/* LIPS3 */
	"\xc0\x03\x80\x89\xc2"
	"\x01" ";"
	"\xc0\x03\x80\x03\xc6"
	"\x0e" ";300;;;;;;1;.r"
	"\0" "\0";
#endif

static char *dotg[MAX_PRINTER] =
{
/* printing bit image */

	"\x02" "\x1b" "Z"		/* ESC/P printer */
	"\x82\x01\x80"
	"\0"
	,

	"\x02\x1b" "J"			/* PC-PR printer */
	"\xc4\x01\x80"
	"\0"
	,

	"\x02\x1b" "J"			/* NM printer */
	"\xc4\x01\x80"
	"\0"
#ifdef	LIPS3
	,
	dotg_lips3				/* LIPS3 */
#endif
#ifdef	ESCPAGE
	,
	"\x01\x1d"				/* ESC/Page */
	"\xc0\x01\x80"
	"\x01" ";"
	"\xc0\x01\x80"
	"\x06" ";8bi{I"
	"\0"
#endif
#ifdef	FAX
	,
	NUL4					/* FAX: NULL */
#endif
};

static char *dots[MAX_PRINTER] =
{
/* dots spacing */

	"\x02\x1b\\"			/* ESC/P printer */
	"\x82\x01\x80"
	"\0"
	,

	"\x02\x1b" "U"			/* PC-PR printer */
	"\xc4\x01\x80"
	"\x03\x00\x00\x00"
	"\0"
	,

	"\x02\x1b" "U"			/* NM printer */
	"\xc4\x01\x80"
	"\x03\x00\x00\x00"
	"\0"

#ifdef	LIPS3
	,
	"\x01\x9b"				/* LIPS3 */
	"\xc0\x01\x80"
	"\x01" "a"
	"\0"
#endif
#ifdef ESCPAGE
	,
	"\x01\x1d"	  			/* ESC/Page */
	"\xc0\x01\x80"
	"\x01" "H"
	"\0"
#endif
#ifdef	FAX
	,
	NUL4					/* FAX: NULL */
#endif
};

#ifdef WIN32
int ChgGray(int dif, int end)
{
	xbit += dif;
	if(xbit <= 0)
		xbit = 1;
	if(xbit >= end)
		xbit = end;
	ybit = xbit;
	return(xbit-dif);
}
#endif

void SetXYGray(int x, int y)
{
	if(x > 0)
		xbit = x;
	if(y > 0)
		ybit = y;
	else if(y == 0)
		ybit = xbit;
}

int GetXGray(void)
{
	return xbit;
}

int GetYGray(void)
{
	return ybit;
}

static uint _get_uint(FILE * fptr)
{

	uint dl, dh;

	dl = (uchar)getc(fptr);
	dh = (uchar)getc(fptr);
	return (dl + (dh << 8));
}

static char *get_len(char *buf)
{
	uchar *temp;
	int flag;

	temp = (uchar *)buf;
	do {
		flag = temp[1];
		temp[1] |= 3 - ((temp[3] & DIVIDE_ALL) >> 4);
		temp += temp[0] + 4;
	} while (flag & 0x80);
	return ((char *)temp);
}

static void get_S_cfg(FILE *fp,char *fname)
{
  static uchar *last_buf;
  uint size;
  long int_off,str_off,code_off;
  int count;
  uchar tmpbuf[12];
  uchar *ptmp;
  uchar *cfgbuf = tmpbuf;
  int prtype = dviout_dimension.prt_type;
#ifdef FAX
  BOOL f_enc_fax = FALSE;
#endif
  
  fread(cfgbuf,4,1,fp);
  if (memcmp(CFG_MAGIC_NUMBER ,cfgbuf,2)) {
	error(FILE_FAULT,"Does not seem CFG file for dviprt:%s",fname);
  }
  size = ((uint)cfgbuf[3]<<8) | cfgbuf[2];
  if (size > CFG_VERSION || size == 0) {
	error(FILE_FAULT,"Minor version mismatch:%s",fname);
  }
  fread(cfgbuf,12,1,fp);
  int_off = long_int(cfgbuf);
  str_off = long_int(cfgbuf+4);
  code_off = long_int(cfgbuf+8);
  
  fseek(fp,int_off,0);
  if ((count = fgetc(fp)) == EOF) {
  read_error:
	error(FILE_FAULT,"Read error.");
  }
  for ( ;count;count--) {
	int v;
	fread(cfgbuf,3,1,fp);
	v = ((int)cfgbuf[2] << 8) | cfgbuf[1];
	switch (cfgbuf[0]) {
	case CFG_DPI:
	  if (dviout_dimension.dpi == 0)
		dviout_dimension.dpi = v;
	  break;
	case CFG_Y_DPI:
	  if (dviout_dimension.DPI == 0)
		dviout_dimension.DPI = v;
	  break;
	case CFG_PINS: vert_byte_unit = v; break;
	case CFG_UPPER_POS: prt_ctl[prtype] = (char)v; break;
	case CFG_MINIMAL_UNIT: hwmin = v; break;
	case CFG_MAXIMAL_UNIT: hwmax = v; break;
	case CFG_CONSTANT: mult_const = v; break;
	case CFG_ENCODE:
	  switch (v) {
	  case CFG_ENCODE_HEX:
		f_hex_mode = TRUE;
		comp_type = 0;
		break;
	  case CFG_ENCODE_PCL1:
		comp_type = COMP_PCL1;
		break;
	  case CFG_ENCODE_PCL2:
		comp_type = COMP_PCL2;
		break;
#ifdef FAX
	  case CFG_ENCODE_FAX:
		f_enc_fax = TRUE;
		break;
#endif
	  default:
		comp_type = 0;
		break;
	  }
	  break;
	}
  }
  vert_bit_unit = vert_byte_unit * 8;

  size = (int)(filelength(fileno(fp))-str_off);
  Free0(last_buf);
  cfgbuf = last_buf = (uchar *)marea(size);
  fseek(fp,str_off,0);
  if ((count = fgetc(fp)) == EOF) goto read_error;
  ptmp = cfgbuf;
  for ( ;count;count--) {
	int t,l;
	fread(ptmp,3,1,fp);
	t = ptmp[0];
	l = ptmp[1] | ((int)ptmp[2]<<8);
	fread(ptmp,l,1,fp);
	switch (t) {
	case CFG_NAME:
	  ptmp[l] = 0;
	  error(DIRECT, "%s\n", ptmp);
	  break;
	case CFG_ENCODE_INFO:
#ifdef FAX
	  if (f_enc_fax && !f_fax)
		f_fax = (char *)ptmp;
#endif
	  break;
	default: continue;
	}
	ptmp += l;
	*ptmp++ = 0;
  }
  fseek(fp,code_off,0);
  if ((count = fgetc(fp)) == EOF) goto read_error;
  for ( ;count;count--) {
	int t,l;
	fread(ptmp,3,1,fp);
	t = ptmp[0];
	l = ptmp[1] | ((int)ptmp[2]<<8);
	fread(ptmp,l,1,fp);
	switch (t) {
	case CFG_BIT_IMAGE_MODE:
	  dot_cr[prtype] = (char *)ptmp; break;
	case CFG_NORMAL_MODE:
	  nrm_cr[prtype] = (char *)ptmp; break;
	case CFG_SEND_BIT_IMAGE:
	  dotg[prtype] = (char *)ptmp; break;
	case CFG_SKIP_SPACES:
	  dots[prtype] = (char *)ptmp; break;
	case CFG_LINE_FEED:
	  line_feed = (char *)ptmp; break;
	case CFG_FORM_FEED:
	  form_feed = (char *)ptmp; break;
	case CFG_AFTER_BIT_IMAGE:
	  after_bit_image = (char *)ptmp; break;
	case CFG_BIT_ROW_HEADER:
	  bit_row_header = (char *)ptmp; break;
	default: continue;
	}
	ptmp += l;
	*ptmp++ = 0;
  }
}

static void get_QR_cfg(FILE *fptr,char *file)
	/* Read the configuration file for Printer Device
 */
{
	uint size;
	int i, ch,prtype;
	static uchar *prtctl_buf;

	prtype = dviout_dimension.prt_type;

	for (i = 16; i > 0; --i) {
		error(DIRECT, "%c", ch = (uchar)getc(fptr));
		if (ch == 0)
			while (--i > 0)
				(void)getc(fptr);
	}
	error(DIRECT, "\n");

	/* skip 16 bytes */

	if ((ch = getc(fptr)) == 'Q')
		f_r_format = FALSE;
	else if (ch == 'R')
		f_r_format = TRUE;
	else
		goto ptrcfg_err;
	prt_ctl[prtype] = (uchar)getc(fptr);
	if ((vert_byte_unit = (prt_ctl[prtype] & 0x0f)) == 0)
		goto ptrcfg_err;
	if (prt_ctl[prtype] & HEX_MODE)
		f_hex_mode = TRUE;

	if (getc(fptr) != 0xff)
		goto ptrcfg_err;
	ch = getc(fptr);
	size = (int)filelength(fileno(fptr)) - ch;
	mult_const = (uchar)getc(fptr);
	(void)getc(fptr);
	(void)getc(fptr);
	hwmin = _get_uint(fptr);
	hwmax = _get_uint(fptr);
	if (f_r_format) {
		ch = _get_uint(fptr);
		if (dviout_dimension.dpi == 0)
			dviout_dimension.dpi = ch;
	}
	if ((hwmin | hwmax) == 0) {
ptrcfg_err:
		error(FILE_FAULT, "Maybe old format:%s", file);
	}
	Free0(prtctl_buf);
	prtctl_buf = (uchar *)marea(size);
	for (i = 0; i < size; i++)
		prtctl_buf[i] = (uchar)getc(fptr);

	dot_cr[prtype] = (char *)prtctl_buf;
	nrm_cr[prtype] = get_len((char *)prtctl_buf);
	dotg[prtype] = get_len(nrm_cr[prtype]);
	dots[prtype] = get_len(dotg[prtype]);
	vert_bit_unit = (PIXEL)vert_byte_unit *8;

	line_feed = get_len(dots[prtype]);
	form_feed = get_len(line_feed);
	after_bit_image = get_len(form_feed);
	bit_row_header = get_len(after_bit_image);
	get_len(bit_row_header);
}

void get_prt_ctl(char *filename)
{
	char fname[MAXPATH];
#ifndef	GCC
	char *srcpath;
#endif
	char file[MAXPATH + 4];
	FILE *fptr;
	int	len;

	if (*filename == 0)
		strcpy(fname, prt_ctr_file);
	else {
		strncpy(fname, filename, MAXPATH);
		if (no_extension(fname))
			strcat(fname, ".cfg");
	}
	if (strpbrk(fname, "/\\:") != NULL) {	/* check path prefixed */
		strncpy(file, fname, MAXPATH);
	}
	else {
		if(cfg_path == NULL){
			strcpy(file, GetOutPath("exe"));
			len = strlen(file);
			while(--len >= 0)
				if(file[len] == '\\' || file[len] == '/' || file[len] == ':')
					break;
			file[len+1] = 0;
		}
		else
			strcpy(file, cfg_path);
		strcat(file, fname);
#ifndef	GCC
		if (access(file, 0) == -1 &&
			(srcpath = searchpath(fname)) != NULL) {
			strncpy(file, srcpath, MAXPATH);
		}
#endif
	}

	if ((fptr = fopenf(file, "rb")) == NULL) 
		error(PROGRAM_STOP, "Can't open configuration file \"%s\"", file);

	{
		int ch;
		fseek(fptr,16,0);
		ch = getc(fptr);
		fseek(fptr,0,0);

		if (ch == 'S') {
			get_S_cfg(fptr,file);
			pr_numb = pr_numb_S;
		}
		else {
			get_QR_cfg(fptr,file);
			pr_numb = pr_numb_QR;
		}
	}
	fclose(fptr);
}

void slow(uint fact)
{
	uint i, j;

	i = (fact<6)?5:fact;
	while(fact-- != 0){
		for(j = 0; j < 6*i; j++) slow( 0 );
	}
}

void pr_putc(char x)
	/*  １バイトプリンター出力ルーチン  */
{
	pr_buf[pr_buf_len] = x;
	if (++pr_buf_len >= PR_BUF_SIZE)
		pr_flush();
}

#ifndef	WIN32
static void pr_esc_chk(void)
	/* Check for ESC key */
{
	unsigned char c;

	do{
		if(!KbHit())	return;
	}while(GetCh() != ESC);

	error(DIRECT, "\nAbort(A) or End after flush(E) or Continue(C)? ");
	for (;;) {
		c = tolower(GetCh());
		if (c == 'a') {
			Exit(1);
		}
		else if (c == 'e'){
			f_abort = 1;
			return;
		}
		else if (c == 'c') {
			error(DIRECT, "\n");
			return;
		}
	}
}
#endif

void pr_flush(void)
	/* プリンタ出力用のバッファ・フラッシュ */
{
#ifndef	RAWOUT
	int i;
	static unsigned int num;
	static unsigned int h_num;
#endif

#ifdef	RAWOUT
	PrFlush(pr_buf, pr_buf_len);
#else
	if (xbit) goto end;
#ifndef	WIN32
	pr_esc_chk();
#endif
				 /* BMP output to file */
	if (pr_buf_len > 0) {
#ifndef NO_OUTP
			 if(f_out == NULL)
				   PrFlush(pr_buf, pr_buf_len);
			 else
#endif
		 if (*f_out == 0) {
			 for (i = 0; i < pr_buf_len;) {
				 if ((num & 0xf) == 0)
					fprintf(fp_out, "%04X: ", h_num++);
					fprintf(fp_out, (++num & 0xf) == 0 ? "%02X\n" : "%02X ",
					(uchar)(pr_buf[i++]));
				}
		  }else
				fwrite(pr_buf, pr_buf_len, 1, fp_out);
	}
done:	slow(slow_fact);
#endif
		trans_byte += pr_buf_len;
end:
		pr_buf_len = 0;
}


static void pr_putnc(char *str, int num)
	/*  n 文字をプリンターに出力する  */

{
	while (num--) {
		pr_buf[pr_buf_len] = *str++;
		if (++pr_buf_len >= PR_BUF_SIZE)
			pr_flush();
	}
}

void pr_puts(char *str)
	/*  文字列をプリンターに出力する  */
{
	while (*str != 0) {
		pr_buf[pr_buf_len] = *str++;
		if (++pr_buf_len >= PR_BUF_SIZE)
			pr_flush();
	}
}

void pr_putsn(char *str, int num)
	/* 文字列に数を代入してプリンタに出力する */
{
	sprintf((char *)str_exp, str, num);
	pr_puts((char *)str_exp);
}

static void pr_numb_S(char *str,uint defval,uint dsize)
{
  uchar *pcode = (uchar *)str;
  uint v;
  while (*pcode) {
	if (*pcode & CFG_FMT_BIT) {
	  uint stack[CFG_STACK_DEPTH];
	  int stack_p = -1;
	  uchar fmt = *pcode++;
	  int l = *pcode++;
	  while (l>0) {
		if ((*pcode & CFG_EXPR_TYPE_BIT) == CFG_OP) {
		  uint v2 = stack[stack_p--];
		  v = stack[stack_p--];
		  switch (*pcode) {
		  case CFG_OP_ADD: v += v2; break;
		  case CFG_OP_SUB: v -= v2; break;
		  case CFG_OP_MUL: v *= v2; break;
		  case CFG_OP_DIV:
			if (v2 == 0) { /* divided by zero. */
			div_by_zero:
			  error(PROGRAM_STOP,
				"Divided by zero in the CFG of printer");
			}
			v /= v2;
			break;
		  case CFG_OP_MOD:
			if (v2 == 0) goto div_by_zero;
			v %= v2;
			break;
		  case CFG_OP_SHL: v <<= v2; break;
		  case CFG_OP_SHR: v >>= v2; break;
		  case CFG_OP_AND: v &= v2; break;
		  case CFG_OP_OR : v |= v2; break;
		  case CFG_OP_XOR: v ^= v2; break;
		  default:
			;
		  }
		  stack[++stack_p] = v;
		}
		else if ((*pcode & CFG_EXPR_TYPE_BIT) == CFG_VAL) {
		  switch (*pcode) {
		  case CFG_VAL_DEFAULT: v = defval*8; break;
		  case CFG_VAL_CONSTANT: v = mult_const; break;
		  case CFG_VAL_WIDTH: v = output_width; break;
		  case CFG_VAL_HEIGHT: v = output_height; break;
		  case CFG_VAL_PAGE:
		  case CFG_VAL_PAGECOUNT: v = Page+1; break;
		  case CFG_VAL_DATASIZE: v = dsize; break;
		  case CFG_VAL_X_DPI: v = x_dpi; break;
		  case CFG_VAL_Y_DPI: v = y_dpi; break;
		  case CFG_VAL_PINS_BYTE: v = vert_byte_unit; break;
		  case CFG_VAL_X_POS: v = x_pos*8; break;
		  case CFG_VAL_Y_POS: v = y_pos; break;
		  }
		  stack[++stack_p] = v;
		}
		else {
		  stack[++stack_p] = *pcode;
		}
		l--; pcode++;
	  }
	  v = stack[stack_p];
	  if ((fmt & CFG_FMT_FORMAT_BIT) == CFG_FMT_STRINGS) {
		int l = *pcode++;
		while (v-- > 0)
		  pr_putnc((char *)pcode,l);
		pcode += l;
	  }
	  else { uchar valbuf[10];
		int cols = fmt & CFG_FMT_COLUMN_BIT;
		int i;
		
		switch (fmt & CFG_FMT_FORMAT_BIT) {
		case CFG_FMT_BIN_LTOH:
		  for (i=0;i<cols;i++) {
			valbuf[i] = v&0xff;
			v >>= 8;
		  }
		  break;
		case CFG_FMT_BIN_HTOL:
		  for (i=cols-1;i>=0;i--) {
			valbuf[i] = v&0xff;
			v >>= 8;
		  }
		  break;
		default:
		  { char *f;
			char fmtbuf[10];
			switch(fmt & CFG_FMT_FORMAT_BIT) {
			case CFG_FMT_HEX_UPPER: f = "X"; break;
			case CFG_FMT_HEX_LOWER: f = "x"; break;
			case CFG_FMT_DECIMAL: f = "u"; break;
			case CFG_FMT_OCTAL: f = "o"; break;
			}
			if (cols == 0)
			  strcpy((char *)fmtbuf,"%");
			else
			  sprintf((char *)fmtbuf,"%%0%d",cols);
			strcat((char *)fmtbuf,f);
			sprintf((char *)valbuf,fmtbuf,stack[stack_p]);
			cols = strlen((char *)valbuf);
			if (fmt & CFG_FMT_ISO_BIT)
			  valbuf[cols-1] |= 0x10;
		  }
		  break;
		}
		pr_putnc((char *)valbuf, cols);
	  }
	}
	else {
	  int l = *pcode++;
	  pr_putnc((char *)pcode,l);
	  pcode += l;
	}
  }
}

static void pr_numb_QR(char *str, uint num0, uint dummy)
	/* フォーマットつき出力 */
{
	int f_mode, mode, len, pos, num, flag;

	do {
		num = num0;
		len = (uchar)(*str++);
		flag = (uchar)(*str++);
		pos = (uchar)(*str++);
		f_mode = (uchar)(*str++);

		if (f_mode) {
			num <<= (flag & 3);
			if (f_mode & TOTAL_BYTE)
				num *= vert_byte_unit;
			if (f_mode & MULT_CONST)
				num *= mult_const;

			switch (mode = f_mode & 0x7) {

			  case (BINARY_LTOH):
				  str[pos] = num & 0xff;
				  str[pos + 1] = num >> 8;
				  break;

			  case (BINARY_HTOL):
				  str[pos] = num >> 8;
				  str[pos + 1] = num & 0xff;
				  break;

			  case (DECIMAL_3):
			  case (DECIMAL_4):
			  case (DECIMAL_5):
				  sprintf((char *)str_exp, "%05u", num);
				  mode = DECIMAL_5 - mode;
				  while (mode < 5)
					  str[pos++] = str_exp[mode++];
				  if (f_mode & ISO_NUMBER)
					  str_exp[pos - 1] += 0x10;
				  break;

			  case (DECIMAL_V):
				  sprintf((char *)str_exp, str, num);
				  mode = strlen((char *)str_exp);
				  if (f_mode & ISO_NUMBER)
					  str_exp[mode - 1] += 0x10;
				  pr_puts((char *)str_exp);
				  goto cont;

			  default:
				  break;
			}
		}
		pr_putnc(str, len);
cont:	str += len;
	} while (flag & 0x80);
}

static void get_sheet(void)
{
	int i;

	pr_numb(dotg[dviout_dimension.prt_type], 1,0);
	for (i = vert_bit_unit; i > 0; i--) {
		if (*bit_row_header)
			pr_numb(bit_row_header, 1,0);
		pr_putc(0);
	}
	pr_numb(after_bit_image, 1,0);
	pr_putc(0x0d);
}

#ifdef LBP
/* PRT_CODE がデフォルトと異なる LBP 等のコード初期化 */
/* change_prt_ctl → get_prt_ctl の順で実行される。 */
void set_LBP_prt_ctl(int hunit, int vunit)
{
#ifdef	LIPS3
	if (dviout_dimension.prt_type == LBP_LIPS3) {
		line_feed = "\x01\x85\0";
		lbpf = &lips3_func;
#ifdef ESCPAGE
		goto to_common;
#else
		vert_bit_unit = 8;
		hwmax = 500;
		hwmin = hunit; 	/*  minimal unit */
		vert_bit_unit *= vunit;
#endif
		}
#endif
#ifdef ESCPAGE
	if (dviout_dimension.prt_type == LBP_ESCPAGE) {
		f_lbp_comp = FALSE;
		lbpf = &escpage_func;
to_common:
		vert_bit_unit = 8;
		hwmax = 500;
		hwmin = hunit; 	/*  minimal unit */
		vert_bit_unit *= vunit;
	}
#endif
}
#endif	/* LBP */

#define hex_to_dig(c)   ((c>='0'&&c<='9')?(c-'0'):(toupper(c)-('A'-10)))

#ifdef WIN32
#define gray_number g_winData.dviwin.gamma
#else
int gray_number = 800;
#endif

int SetGamma(int num)
{
	if(num < 0){
		gray_number = num;
		gray_gamma(-num, 0, bright, 16);
		f_init &= ~INIT_BRIGHT;
	}
	else if(num > 0){
		gray_number = num;
		gray_gamma(num, bright, 0, 16);
		f_init &= ~INIT_BRIGHT;
	}
	if(num)
		CheckReverse(gray_number);
	return gray_number;
}

int SetBright(void)
{
	SetGamma(gray_number);
	return bright;
}

void SetBMP(void)
{
	char *sep;

	if(*f_bmp != ':'){
		xbit = atoi(f_bmp);
		ybit = 0;
	}
	if((sep = strchr(f_bmp, ':')) != NULL){
		if(*++sep != ':')
			ybit = atoi(sep);
		if((sep = strchr(sep, ':')) != NULL)
			SetGamma(atoi(sep+1));
	}
	if(!*f_bmp || xbit < 1)
		xbit = ybit = 1;
	else if(ybit <= 0)
		ybit = xbit;
#ifndef	WIN32G
	if(xbit && f_out == NULL)
		f_out = dup_string("tmp!!!.bmp");
#endif
}


void device_init(DIMENSION *dim)
	/* プリンターの初期化 */
{
	char file[MAXPATH + 4];
	char fig[16];
#ifndef	GCC
	char *srcpath;
#endif
#if	defined(J3100) || defined(DOSV)
	char *sep;
#endif
	int ch, i, num;
	FILE *fptr;
#ifdef NO_OUTP
	static char* f_out_init = NULL;

	if( f_out_init == NULL && f_out != NULL ) f_out_init = f_out;
#endif

	ENTER("device_init");

	vert_byte_unit = vert_bit_unit/8;
	if (comp_type < 0) comp_type = 0;
#ifdef	FAX
	if (f_fax && f_files < 0)
		set_FAX_ctl();
#endif
	if (f_out != NULL){
		if( (ch = *f_out) == 0 || ch == '-' || ch == '+'){
			fp_out = stdout;
			if(!isatty(fileno(stdout))){
#ifdef NO_OUTP
				if( f_out_init != f_out ){
					Free(f_out);
					f_out_init = (char*)1; // impossible value.
				}
#else
				Free(f_out);
#endif
				f_out = dup_string((ch)?"":"+");
			}
		}else{
			if (f_files >= 0) fclose(fp_out);
			i = 0;
			for(f_files = strlen(f_out)-1; f_files >= 0; f_files--){
				if (f_out[f_files] == '!'){
					if (++i == 3) break;
				}else
					i = 0;
			}
			strncpy(file, f_out, MAXPATH);
			if (f_files >= 0 && f_files < MAXPATH){
				i = file[f_files+3];
				sprintf(fig, "%03d", Page+1);
				strncpy(f_out + f_files, fig, 3);
				file[f_files+3] = i;
			}
			if ((fp_out = fopenf(file, "wb")) == NULL)
				error(PROGRAM_STOP, "Can't open \"%s\"", f_out);
		}
	}

#ifdef JGAIJI
	if (f_gaiji) goto prf;
#endif

	x_dpi = dim->dpi;
	y_dpi = dim->DPI;
	output_width = dim->output_width;
	output_height = dim->output_height;
	text_width = dim->text_width;
	text_height = dim->text_height;
	buf_width = dim->buf_width;
	x_pos = y_pos = num_cr = Page = 0;
	if(dviout_dimension.prt_type & NO_PRN_OUT)
		return;

#if	defined(WIN32C)||defined(RAWOUT)
	Win32cPrtinterInit((pr_port_str != NULL)? atoi(pr_port_str) : 0);
#endif

#ifdef LBP
	if (f_lbp_prt){
		(*(lbpf->init)) ();
# ifdef	LIPS3
		if (dviout_dimension.prt_type == LBP_LIPS3) {
			if(lbp_orig_dpi <= 300){
				sprintf(dotg[LBP_LIPS3]+16, "%d.r", lbp_orig_dpi);
				dotg[LBP_LIPS3][14]= 6;
			}else{
				sprintf(dotg[LBP_LIPS3]+16, "%d;;;;;;1;.r", lbp_orig_dpi);
				dotg[LBP_LIPS3][14] = (lbp_orig_dpi < 1000)?14:15;
			}
		}
# endif
	}
#endif

	pr_numb(dot_cr[dviout_dimension.prt_type], 0,0);
	if (f_top_margin)
		get_sheet();
prf:
	if (prt_initialize == NULL || *prt_initialize == 0)
		goto skp;
	if (strpbrk(prt_initialize, "/\\:") != NULL) {	/* check path prefixed */
		strncpy(file, prt_initialize, MAXPATH);
	}
	else
	{
		strncpy(file, cfg_path, MAXPATH);
		strcat(file, prt_initialize);
#ifndef	GCC
		if (access(file, 0) == -1 &&
			(srcpath = searchpath(prt_initialize)) != NULL) {
			strncpy(file, srcpath, MAXPATH);
		}
#endif
	}
	if ((fptr = fopenf(file, "rb")) == NULL)
		error(PROGRAM_STOP, "Can't open %s", file);
	while ((ch = getc(fptr)) != EOF) {
		if (ch != '\\') {
			if (ch > ' ')
				pr_putc((uchar)ch);
		}
		else {
			if ((i = getc(fptr)) == '\\') {
				while ((ch = getc(fptr)) != 0x0a
					   && ch != 0x0d && ch != EOF);
				continue;
			};

			switch (i){
				case 'w':
				case 'W':
						num = dim->output_width;
pnum0:					if (i < 'a') num /= 8;
pnum:					ch = getc(fptr);

						switch (ch){
							case 'b':
								pr_putc((uchar)(num & 0xff));
								pr_putc((uchar)(num >> 8));
								break;

							case 'B':
								pr_putc((uchar)(num >> 8));
								pr_putc((uchar)(num & 0xff));
								break;

							case 'H':
								pr_putsn("%04X", num);
								break;

							default:
								ungetc(ch, fptr);
								pr_putsn("%d", num);
								break;
						}
						break;

				case 'h':
				case 'H':
						num = dim->output_height;
						goto pnum0;

				case 'r':
						num = dim->dpi;
						goto pnum;

				case 'R':
						num = dim->DPI;
						goto pnum;

				case 'p':
						num = Page+1;
						goto pnum;

				case 'f':
#ifdef	WIN32
						pr_puts(current_name);
#else
						pr_puts(dvifile.file_name);
#endif
						break;

				default:
					i = hex_to_dig(i);
					ch = getc(fptr);
					pr_putc((uchar)(i * 16 + hex_to_dig(ch)));
			}
		}
	}
	fclose(fptr);
skp:
#ifdef LBP
	if (f_lbp_prt
# ifdef JGAIJI
		&& !f_gaiji
# endif
	)
		(*(lbpf->init2)) (f_rotate, f_copy);	/****/
#endif

#if	defined(J3100) || defined(DOSV)
# ifdef	PC9801
	if(machine==M_PC98) goto skp_chk;
# endif
					/* J-3100, DOS/V */
	if (pr_port_str != NULL) {
# ifndef	GCC
		int bios_mode = 0;
# endif
		if (toupper(pr_port_str[0]) == 'B') {
			pr_port_num = (int)(pr_port_str[1]) - (int)'0';
# ifndef	GCC
			bios_mode = 1;
# endif
			if(pr_port_num < 0 || pr_port_num >= 5){
				error(ILLEGAL_ARGS,
					"Illegal Printer Port Number: %d (see -P option)\n",
					pr_port_num);
				pr_port_num = 0;
			}
			if(pr_port_num > 0)
				pr_port_num = 1 - pr_port_num;
		}
		else
# ifdef	GCC
		{
			pr_ioport = atoi(pr_port_str);
		}
# else
			pr_port_num = (int)(pr_port_str[0]) - (int)'0';
		if ((0 < pr_port_num) && (pr_port_num < 5)) {
			if (bios_mode) {
				/* チェックを入れるべきだが、ネットでだとどうするのか？ */
				if (pr_port_num >= 1)
					pr_port_num = 1 - pr_port_num;
			}
			else {
				if ((pr_ioport = peek(0x40, 6 + pr_port_num * 2)) == 0) 
					error(ILLEGAL_ARGS, "LPT%d: is Not Assigend!", 
						pr_port_num);
					pr_port_num = 0;
			}
		}
		else if (pr_port_num != 0){
			error(ILLEGAL_ARGS,
				"Illegal Printer Port Number: %d (see -P option)",
				pr_port_num);
			pr_port_num = 0;
		}
# endif
		if ( (sep = strchr(pr_port_str, ';')) != NULL){
			if ((pr_port_wait = atoi(sep+1)) < 0)
				pr_port_wait = 0;
		}
	}
#endif
skp_chk:
	END();
}

void pr_crlf(void)
{
	/* 行送り */
	if (f_abort){
		pr_flush();
		Exit(1);
	}
	while (num_cr) {
		num_cr--;
		pr_numb(line_feed, 0,0);
		y_pos += vert_bit_unit;
		x_pos = 0;
	}
}

void pr_new_page(void)
	/* ページ送り */
{

	if (f_abort){
		pr_flush();
		Exit(1);
	}
	if (ff_flg != -1) {
		/* LBP Printer 袋綴じ対応 */
#ifdef LBP
		if (f_lbp_prt) {
			if (!(Page & 1)) {
				(*(lbpf->move_homepoint)) (0, ff_flg);	/* 論理原点の設定 */
				num_cr = 0;
			}
			else {
				pr_numb(form_feed, 0,0);
				(*(lbpf->move_homepoint)) (0, 0);	/****/
				num_cr = 0;
				x_pos = y_pos = 0;
			}
		}
		else
#endif
		{
			if ((ff_flg|((Page+1) & 1)) == 0) goto ff;
			pr_crlf();
		}
	}
	else {
ff:		pr_numb(form_feed, 0,0);
		num_cr = 0;
		x_pos = y_pos = 0;
	}
	pr_flush();
	Page++;
	if (f_files >= 0 && Page < 999) device_init(&dviout_dimension);
#ifdef	LBP
	if (f_lbp_prt)
		(*(lbpf->move_cap)) (-1, -1);	/* CAPの初期化*/
#endif
	if (f_pause) {
		error(DIRECT, "\nPush any key to continue (or ESC -> abort).\n");

#ifndef	DBGP
#if	defined(PC9801) || defined(GCC)
		while(KbHit())
			GetCh();
		if (GetCh() == ESC)
			Exit(1);
#else
	/* J3100, AX, DOSV ,DOSC */
		regs.h.ah = 0;
		int86( 0x16, &regs, &regs );
		if ((regs.h.al & 0xFF) == ESC)
			Exit(1);
#endif
#endif
		error(DIRECT, "\x1b[1A\x1b[0K");
	}
	if (f_top_margin)
		get_sheet();
}

void device_end(void)
	/* プリンターの後始末 */
{
	ENTER("device_end");

	pr_numb(nrm_cr[dviout_dimension.prt_type], 0,0);
#ifdef LBP
	if (f_lbp_prt){
		(*(lbpf->move_homepoint)) (0, 0);	/****/
		(*(lbpf->end)) ();		/****/
	}
#endif
	ff_flg = -1;
	pr_flush();

#if	defined(WIN32C)||defined(RAWOUT)
	Win32cPrtinterEnd();
#endif
	comp_type = -1;
	if(!xbit)
		error(DIRECT, "\nSent %lu bytes.\n", trans_byte);
/*	error(14, "Sent %d byte", trans_byte); */
	trans_byte = 0;
	END();
}


void conv_bit(ulong size, HUGE_BUF * pt)
{
	while(size-- > 0){
		*pt = REV[*pt];
		pt++;
	}
}


/*　　　＃＃＃　プリンター出力ルーチン　＃＃＃
 *
 *  p_out( int hmax, int vmax, HSTR top )
 *
 *　　このルーチンを使用する前にプリンターの初期化を要する。
 *
 *   （注意）実際にプリンターに出力するのはvmaxのうち
 *  　　　　３で割り切れる最大値だけである
 */


static void p_out(int h_max, int v_max, HUGE_BUF *top)
	/*　ここでのｈｍａｘ，ｖｍａｘはバイト単位。      */
	/*ｔｏｐはビットマップの先頭を示すポインタ。      */
	/*ビットマップを８ビットのブロックに分けて、*/
	/*ブロックごとにプリンターに出力する            　*/

{

	HUGE_BUF *ptr;
	HUGE_BUF *ptr_z;
	BUFFER *ptr_f;
	BUFFER *tmpbuf;
	uint x, y, hmin, hmax, htmax, vmax, hsend;	/* ともにバイト単位 */
	uint skip, exist;
	int i, j, type, f_non_move;
	uint byte;
	int comp;
	uint total,dbytes, bsize;
#ifdef LBP
	uint old_byte, repeat;
#endif

#ifdef	FAX
	if (f_fax){
		fax_encode_block(h_max, v_max, top, 0);
		return;
	}
#endif
	vmax = v_max;
	if ((type = (prt_ctl[dviout_dimension.prt_type] & TYPE_BIT))
		== LEFT_IS_LOW)
		conv_bit(((ulong)(vmax)) * h_max * 8, top);
	f_non_move = prt_ctl[dviout_dimension.prt_type] & NON_MOVING;
	for (y = 0 ; y < vmax; y += vert_byte_unit) {
		ptr_z = top + (ulong)h_max *(y * 8);
		skip = exist = 0;
		
		for (hmin = 0; hmin < h_max ; hmin = hmax) {
			uint skip_b = 0;
			if (h_max > hmin + hwmin)
				hmax = hmin + hwmin;
			else
				hmax = h_max;
			/* support dots spaces */
			if (*dots[dviout_dimension.prt_type])	{
				for (x = hmin; x < hmax; ++x) {
					ptr_f = (BUFFER *)ptr_z + x;
					for (i = vert_bit_unit; i > 0; --i) {
						if (*ptr_f == 0)
							ptr_f += h_max;
						else 
							goto f_exist; /* exit loop */
					}
				}
				if (exist == 0){		/* spaces */
					skip += hwmin;
					continue; 	/* next block */
				}
				else skip_b = hwmin;	/* store spaces */
			}
			else {
f_exist:		exist += (hmax - hmin);
				if (hmax != h_max) /* not EOL. */
					continue;	/* next block */
				else
					hmin = hmax;
			}

			/* output */
			hmin -= exist;
			pr_crlf(); /* vertical position */
			while (exist != 0) {
				/* horizontal position. */
				while (skip != 0) {
					hsend = (skip > hwmax) ? hwmax : skip;
					pr_numb(dots[dviout_dimension.prt_type], hsend, 0);
					skip -= hsend;
					x_pos += hsend;
				}
				
				hsend = (uint)((exist > hwmax) ? hwmax : exist);
				htmax = hmin + hsend;
				comp = comp_type;
#ifdef	LBP
		if (f_lbp_prt) comp = f_lbp_comp ? COMP_LIPS3 : 0;
#endif
				if (comp == 0) {
non_comp:			dbytes = (f_hex_mode ? 2 : 1) * hsend * vert_bit_unit;
					pr_numb(dotg[dviout_dimension.prt_type], hsend,dbytes);
				}
				if (type & FLAG_LBP) {
					ptr = ptr_z + hmin;
					if (comp) {
						if (comp == COMP_PCL1) {
							bsize = hsend << 1;
						}
						else if (comp == COMP_PCL2) {
							bsize = hsend + hsend/127 + 1;
						}
#ifdef	LBP
						else if (comp == COMP_LIPS3){
							old_byte = 256;
							total = repeat = 0;
							bsize = vert_bit_unit*hsend;
						}
#endif
						else { comp = COMP_NON; goto non_comp; }
						if((tmpbuf = get_work(bsize)) == NULL)
							error(NO_MEMORY, "Working");
#ifdef LBP
						if (comp == COMP_LIPS3 && (bsize >= 16)) bsize -= 16;
#endif
					}
					if (comp > 0) {
						BUFFER *ptmp;
						dbytes = 0;
						for (i = vert_bit_unit; i > 0;ptr += h_max,i--) 
							dbytes += compress_func[comp]((BUFFER *)tmpbuf,
										(BUFFER *)ptr,hsend);
						pr_numb(dotg[dviout_dimension.prt_type], hsend,dbytes);
						ptr = ptr_z + hmin;
						for (i = vert_bit_unit; i > 0;ptr += h_max,i--) {
							ptmp = (BUFFER *)tmpbuf;
							total = compress_func[comp]((BUFFER *)tmpbuf,
										(BUFFER *)ptr,hsend);
							if (*bit_row_header)
								pr_numb(bit_row_header,hsend, total);
							while(total--) pr_putc(*ptmp++);
						}
					}
					else {
						for (i = vert_bit_unit; i > 0; ptr += h_max, i--) {
							if (*bit_row_header)
								pr_numb(bit_row_header, hsend,
									f_hex_mode ? hsend*2 : hsend);
							for (ptr_f = (BUFFER *)ptr, j = hsend; j > 0; j--) {
								byte = *ptr_f++;
#ifdef	LBP
								if (comp){ /* LIPS3 COMPRESSION */
									if (byte != old_byte){
										old_byte = byte;
										if(repeat != 0){
											tmpbuf[total++] = repeat - 1;
											repeat = 0;
										}
									}else{
										if (++repeat > 255){
											tmpbuf[total++] = repeat - 1;
											repeat = 0;
											old_byte = 256;
											continue;
										}
										else if (repeat > 1) continue;
									}
									tmpbuf[total++] = byte;
									if (total > bsize){
										comp = 0;
										goto non_comp;
									}
									continue;
								}
#endif
								if (f_hex_mode)	pr_putsn("%02X", byte);
								else			pr_putc((uchar)byte);
							}
						}
#ifdef	LBP
						if (comp < 0){
							if (repeat != 0) tmpbuf[total++] = repeat - 1;
							pr_flush();
							sprintf(pr_buf,
								"\x9b%u;%u;%u;9;%u.r",
								total, hsend, lbp_orig_dpi, vert_bit_unit);
							pr_buf_len = strlen(pr_buf);
							while(total--) pr_putc(*tmpbuf++);
						}
#endif
					}
				}
				else {
					int src_bytes = hsend*vert_bit_unit;
					BUFFER *ptmp;
					if (comp) {
						if (comp == COMP_PCL1)
							bsize = src_bytes << 1;
						else if (comp == COMP_PCL2)
							bsize = src_bytes + src_bytes/127 + 1;
						else { /* not supported. */
							comp = COMP_NON;
							goto non_comp;
						}
						bsize += src_bytes;
						if((tmpbuf = get_work(bsize)) == NULL)
							error(NO_MEMORY, "Working");
						ptmp = tmpbuf;
					}
					for (x = hmin; x < htmax; ++x) {
						ptr = ptr_z + x;
						if (comp) {
							p_subbuf(h_max, ptr, vert_byte_unit,type,ptmp);
							ptmp += vert_bit_unit;
						}
						else p_sub(h_max, ptr, vert_byte_unit, type);
					}
					if (comp) {
						dbytes = compress_func[comp]((BUFFER *)tmpbuf+src_bytes,
									(BUFFER *)tmpbuf,src_bytes);
						pr_numb(dotg[dviout_dimension.prt_type], hsend,dbytes);
						ptmp = (BUFFER *)tmpbuf+src_bytes;
						total = dbytes;
						while(total--) pr_putc(*ptmp++);
					}
				}

				if (*after_bit_image)
					pr_numb(after_bit_image,hsend,dbytes);
				exist -= hsend;
				hmin = htmax;
				if (f_non_move)
					skip += hsend;
				else
					x_pos += hsend;
			}
			skip += skip_b;
		}
		num_cr++;
	}
}

static void pl_out(int h_max, int v_max, HUGE_BUF *top)
	/*　ここでのｈｍａｘ，ｖｍａｘはバイト単位。      */
	/*ｔｏｐはビットマップの先頭を示すポインタ。      */
	/*ビットマップを８ビットのブロックに分けて、*/
	/*ブロックごとにプリンターに出力する            　*/
	/* HIGH_BIT / LOW_BIT の場合は圧縮には未対応 */
{

	HUGE_BUF *ptr;
	HUGE_BUF *ptr_z;
	uint x, y, ymax, vmin, vtmax, vmax, hsend;	/* ともにバイト単位 */
	uint skip, exist;
	uchar byte;
	int i, j, type, f_non_move;
	int comp = f_lbp_prt ? 0 : comp_type;
	int dsize;

#ifdef	FAX
	if (f_fax){
		fax_encode_block(v_max, h_max, top, 1);
		return;
	}
#endif
	if ((type = (prt_ctl[dviout_dimension.prt_type] & TYPE_BIT))
		== TOP_IS_LOW)
		conv_bit(((ulong)(h_max)) * v_max * 8, top);
	f_non_move = prt_ctl[dviout_dimension.prt_type] & NON_MOVING;

	for (x = 0; x < h_max; x += vert_byte_unit) {
		ptr_z = top + (ulong)(v_max * 8 - 1) * h_max + (ulong)x;
		skip = exist = 0;

		for (vmin = 0; vmin < v_max;	vmin = vmax) {
			uint skip_b = 0;
			if (v_max > vmin + hwmin)
				vmax = vmin + hwmin;
			else
				vmax = v_max;

			/* support dots spaces */
			if (*dots[dviout_dimension.prt_type]) {
				for (y = vmin << 3, ymax = vmax << 3; y < ymax; y++) {
					ptr = ptr_z - (ulong)y *h_max;

					for (i = vert_byte_unit; i > 0; --i) {
						if (*ptr == 0)
							ptr++;
						else 
							goto f_exist; /* exit loop */
					}
				}
				if (exist == 0) {			/* spaces */
					skip += hwmin;	/* store spaces */
					continue;
				}
				else skip_b = hwmin;
			}
			else {
f_exist:		exist += (vmax - vmin);
				if (vmax != v_max)
					continue;	/* not EOL */
				else
					vmin = vmax;
			}

			vmin -= exist;

			/* output */
			pr_crlf(); /* vertical position */
			while (exist != 0) {
				/* horizontal position. */
				while (skip != 0) {
					hsend = (skip > hwmax) ? hwmax : skip;
					pr_numb(dots[dviout_dimension.prt_type], hsend, 0);
				skip -= hsend;
					x_pos += hsend;
				}

				hsend = (uint)((exist > hwmax) ? hwmax : exist);
				vtmax = vmin + hsend;
				if (comp == 0) {
non_comp:			dsize = (f_hex_mode ? 2 : 1) * hsend * vert_bit_unit;
					pr_numb(dotg[dviout_dimension.prt_type], hsend, dsize);
				}
				ptr = ptr_z - (ulong)vmin *8 * h_max;

				if (type & FLAG_LBP) {
					if (comp > 0) {
						int bsize;
						BUFFER *tmpbuf;
						HUGE_BUF *psrc;
						if (comp == COMP_PCL1) {
							bsize = hsend << 1;
						}
						else if (comp == COMP_PCL2) {
							bsize = hsend + hsend/127 + 1;
						}
						else { comp = COMP_NON; goto non_comp; }
						bsize += hsend;
						if((tmpbuf = get_work(bsize)) == NULL)
							error(NO_MEMORY, "Working");
						psrc = ptr;
						dsize = 0;
						for (i = vert_byte_unit; i > 0; psrc++, i--) {
							for (j = 7; j >= 0; j--) {
								p_sublbp(h_max, psrc, j, hsend, type, tmpbuf);
								dsize += compress_func[comp](tmpbuf + hsend,
											tmpbuf, hsend);
							}
						}
						pr_numb(dotg[dviout_dimension.prt_type], hsend, dsize);
						for (i = vert_byte_unit; i > 0; ptr++, i--) {
							for (j = 7; j >= 0; j--) {
								int s;
								BUFFER *ptmp = tmpbuf+hsend;
								p_sublbp(h_max, ptr, j, hsend, type,tmpbuf);
								s = compress_func[comp](tmpbuf+hsend,
										tmpbuf,hsend);
								if (*bit_row_header)
									pr_numb(bit_row_header, hsend,s);
								while(s--) pr_putc(*ptmp++);
							}
						}
					}
					else {
						for (i = vert_byte_unit; i > 0; ptr++, i--) {
							for (j = 7; j >= 0; j--) {
								if (*bit_row_header)
									pr_numb(bit_row_header, hsend,
										f_hex_mode ? hsend*2 : hsend);
								p_sublbp(h_max, ptr, j, hsend, type, NULL);
							}
						}
					}
				}
				else {
					/* debugged by 佐々木浩氏, size optimized by OkI */
					for (y = 0, ymax = hsend << 3; y < ymax; y++, ptr -= h_max)
						for (i = 0; i < vert_byte_unit; i++) {
							byte = (i < (h_max - x)) ? *(ptr + (ulong)i) : 0;
							if (f_hex_mode) {
								if (pr_buf_len >= PR_BUF_SIZE - 4)
									pr_flush();
								sprintf(pr_buf+pr_buf_len, "%02X", (uint)byte);
								pr_buf_len +=2;
							} else {
								pr_buf[pr_buf_len] = byte;
								if (++pr_buf_len >= PR_BUF_SIZE)
								pr_flush();
							}
					}
				}
				if (*after_bit_image)
					pr_numb(after_bit_image, hsend, dsize);
				exist -= hsend;
				vmin = vtmax;
				if (f_non_move)
					skip += hsend;
				else
					x_pos += hsend;
			}
			skip += skip_b;
		}
		num_cr++;
	}
}

void device_clear(OUTPUT_INFO *out)
{
#ifdef	LBP
	if (f_lbp_prt) {
		num_cr = 0;
		(*(lbpf->move_cap)) (
								(out->split > 1) ? (out->split - 1) * dviout_dimension.buf_height : 0, 0);
		(*(lbpf->move_cap)) (-1, -1);	/*CAPの初期化*/
	}
#endif
}

#ifdef	WIN32
extern int f_2page;

char *MakeBMP(void)
{
	char *result;

	if(g_nErrorCode)
		return NULL;
#ifdef	WIN32G
	ChangeWaitCursor(1);
# ifdef	DOUBLE_PAGE
	if(IS_MPAGE){
		f_2page = 0;
		ClearKeepBMP();
		ExpandPage();
	}
# endif
#endif
	result = make_bmp((BUFFER*)(bitmap_buf_pointer->start), text_width, 
			(buf_width+7)/8,
			text_height, 0, 
#ifdef	WIN32G
			(xbit == 1 && SetColor(0) == 8 && x_dpi <= f_s_dpi)?-1:
#endif
			xbit, ybit);
#ifdef	WIN32G
	ChangeWaitCursor(0);
#endif
	return result;
}

char *GetWindowBMP(int x, int y, int width, int height, int xdiv, int ydiv,
	uchar *buf)
{
	int byte_skip, bit_skip, xset;
	char *result;

#ifdef	WIN32G
	ChangeWaitCursor(1);
#endif
	if(xdiv == 0)
		xset = xdiv = xbit;
	else if(xdiv < 0){
		xdiv = ydiv = 1;
		xset = -1;
	}else
		xset = xdiv;
	if(ydiv == 0)
		ydiv = ybit;
	else if(ydiv < 0)
		ydiv = xdiv;
	byte_skip = x/8;
	bit_skip = (x & 7)/xdiv;
	width += bit_skip*xdiv;
	if(x + width > text_width)
		width = text_width - x;
	if(y + height > text_height)
		height = text_height - y;
	if(x < 0 || y < 0 || width < xdiv || height < ydiv)
		result = NULL;
	else{
		x = (buf_width+7)/8;
		result =  make_bmp(((buf)?buf:(BUFFER*)(bitmap_buf_pointer->start))
			+ x*y + byte_skip, width, 
			x, height, bit_skip, xset, ydiv);
	}
#ifdef	WIN32G
	ChangeWaitCursor(0);
#endif
	return result;
}
#endif

BOOL device_out(OUTPUT_INFO *out)
	/* プリンターに出力 */
{
#ifndef	RAWOUT
	BUFFER *p;
#endif
	ENTER("device_out");

#ifdef LBP
	last_dir = -1;				/* ラスタイメージ送出 */
#endif
#ifndef	RAWOUT
	if(xbit){
		p = make_bmp(out->bitmap_ptr, text_width, out->byte_width,
			text_height, 0, xbit, ybit);
		fwrite(p, long_int(p+2), 1, fp_out);
		goto end;
	}

	if (f_out != NULL && *f_out == 0)
		fprintf(fp_out, "\n");
#endif
	if (out->print_direction == VERTICAL)
		pl_out(out->byte_width, out->byte_height, out->bitmap_ptr);
	else
		p_out(out->byte_width, out->byte_height, out->bitmap_ptr);
#ifdef	LBP
	if (f_lbp_prt)
		(*(lbpf->move_cap)) (-1, -1);	/*CAPの初期化*/
	pr_flush();
# ifdef	RAWOUT
	PrBufFlush();
# endif
#else
	pr_flush();
#endif
end:
	RETURN(NextPart);
}

void p_sub(int hmax, HUGE_BUF *ptr, int length, int type)
{
	HUGE_BUF *ptr_tmp;
	int j, k;
	uchar byte, mask;

	mask = 0x80;
	do{
		ptr_tmp = ptr;
		for (j = 0; j < length; j++) {
			byte = 0;
			if (type == TOP_IS_HIGH) {
				k = 0x80;
				do{
					if (*ptr_tmp & mask)
						byte |= k;
					ptr_tmp += hmax;
				}while((k >>= 1) != 0);
			} else {  /* TOP_IS_LOW  */
				k = 1;
				do{
					if (*ptr_tmp & mask)
						byte |= k;
					ptr_tmp += hmax;
				}while((k <<= 1) <= 0x80);
			}
			if(f_hex_mode){
				if (pr_buf_len >= PR_BUF_SIZE - 4)
					pr_flush();
				sprintf(pr_buf+pr_buf_len, "%02X", (uint)byte);
				pr_buf_len +=2;
			}else{
				pr_buf[pr_buf_len] = byte;
				if (++pr_buf_len >= PR_BUF_SIZE)
					pr_flush();
			}
		}
	}while((mask >>= 1) != 0);
}

void p_subbuf(int hmax, HUGE_BUF *ptr, int length, int type, BUFFER *out)
	/* p_sub の バッファ出力版 */
{
	HUGE_BUF *ptr_tmp;
	int j, k;
	uchar byte, mask;

	mask = 0x80;
	do{
		ptr_tmp = ptr;
		for (j = 0; j < length; j++) {
			byte = 0;
			if (type == TOP_IS_HIGH) {
				k = 0x80;
				do{
					if (*ptr_tmp & mask)
						byte |= k;
					ptr_tmp += hmax;
				}while((k >>= 1) != 0);
			} else { /* TOP_IS_LOW */
				k = 1;
				do{
					if (*ptr_tmp & mask)
						byte |= k;
					ptr_tmp += hmax;
				}while((k <<= 1) <= 0x80);
			}
			*out++ = byte;
		}
	}while((mask >>= 1) != 0);
}

void p_sublbp(int hmax, HUGE_BUF *ptr, int bitno, int length, int type,
	BUFFER *buf)
	/* 垂直方向の１ラインをプリンタに出力 */
{
	int k;
	uchar byte, mask;
	int pos = 0;

	mask = 0x01 << bitno;
	while (length--) {
		byte = 0;
		if (type == LEFT_IS_HIGH) {
			k = 0x80;
			do{
				if (*ptr & mask)
					byte |= k;
				ptr -= hmax;
			}while((k >>= 1) != 0);
		} else { /* LEFT_IS_LOW */
			k = 1;
			do{
				if (*ptr & mask)
					byte |= k;
				ptr -= hmax;
			}while((k <<= 1) <= 0x80);
		}
		if (buf)
			buf[pos++] = byte;
		else
		if (f_hex_mode) {
			if (pr_buf_len >= PR_BUF_SIZE - 4)
				pr_flush();
			sprintf(pr_buf+pr_buf_len, "%02X", (uint)byte);
			pr_buf_len +=2;
		} else {
			pr_buf[pr_buf_len] = byte;
			if (++pr_buf_len >= PR_BUF_SIZE)
				pr_flush();
		}
	}
}

static uint pclmode1compress(BUFFER *dst,BUFFER *src,int size)
{
	BUFFER *end = src+size;
	BUFFER *out = dst;
	uint total = 0;
	while ( src < end  ) {
		uchar test = *src++;
		BUFFER *run = src;
		while ( src < end && *src == test ) src++;
		while ( src - run > 255 ) {
			*out++ = 255;
			*out++ = test;
			total += 2;
			run += 256;
		}
		*out++ = src - run;
		*out++ = test;
		total += 2;
	}
	return total;
}

static uint
pclmode2compress(BUFFER *dst,BUFFER *src,int size)
{
	BUFFER *exam = src;
	BUFFER *cptr = dst;
	BUFFER *end = src+size;
	
	for ( ; ; ) {
		uchar test = *exam++;
		int len;
		while ((test != *exam) && (exam < end))
			test = *exam++;
		if (exam < end) exam--;
		len = exam - src;
		while (len > 0){
			int i;
			int count = len;
			if (count>127) count=127;
			*cptr++=count-1;
			for (i = 0 ; i < count ; i++) *cptr++ = *src++;
			len -= count;
		}
		if (exam >= end) break;
		exam++;
		while ((test == *exam) && (exam < end))
			exam++;
		len = exam - src;
		while (len > 0) {
			int count = len;
			if (count > 127) count = 127;
			*cptr++ = (257-count);
			*cptr++ = test;
			len -= count;
		}
		if (exam >= end) break;
		src = exam;
	}
	return (cptr-dst);
}

/* end of file : p_out.c */

#ifdef LBP
#include "lbp.c"
#endif

#ifdef	FAX
#include "p_fax.c"
#endif
