/***************************************************
 * CNPRINT.C For CNPRINT Version 2.90 (VMS & UNIX) *
 ***************************************************
  Copyright YIDAO CAI (~{2LR@5@~}), 1992-1998
  All Rights Reserved.
  Free for non-commercial and personal use only.

  The source code, or part of it, original or modified, may not be
  included in any other software, without permission from the author.
  See "Author" section of the help file for details.

Disclaimer: Posting CNPRINT on any FTP site does not imply the author's
	endorsement of the beliefs of the organization who owns the FTP site.

CNPRINT, a utility to print Chinese/Japanese/Korean text (or convert to
	PostScript) under DOS, VMS and UNIX systems.  It works just as
	a print command on your system.  Currently GB, Hz, zW, BIG-5,
	JIS (new-, old-, NEC-), EUC, shifted-JIS, KSC, UTF8 and UTF7 are
	supported.

*** PLEASE read CNPRINT.HELP first EVEN if you have used CNPRINT before ***

YIDAO CAI  cai@neurophys.wisc.edu
JAN-10-1998
*****************************************************/

/* #define STAT
 * #define CNS_SUPPORT
 */
#define PSPRINT

#ifdef VMS
/* avoid using #ifndef */
#else
# ifdef unix
 /* */
# else
#  define unix
# endif
/*      for multi-users on unix */
# define MUSER
/**/
#endif

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

#define TIME 1
#define GBstr "_gb"
#define B5str "_b5"
#define PSstr "_ps"
#define HZstr "_hz"
#define JISstr "_jis"
#define Version "CNPRINT V2.90 (VMS & UNIX) JAN-10-1998"
#define EOL '\n'
#define CR  13
#define FF  12
#define LF  10
#define ESC 0x1B
#define IN 1
#define INb51 2
#define INb52 3
#define OUT 0
#define R 1
#define L 2
#define RMXY 11 /* rotate and move */
#define RMX  12
#define RMY  13
#define NT 0
#define EQ 0
#define T 3
#define B 4
#define RMIRROR 5

/* code types */
#define UNKNOWN 0
#define ASCII  1
#define ZW     2
#define HZ     3
#define GB     4
#define GBORB5 5
#define HZP    6        /* HZ+ */
#define B5     7
#define CNS    8
#define JIS    9        /* JIS-0208, Japanese */
#define SJIS   10
#define EUC    11
#define EUCORSJIS   12
#define KSC    13       /* KSC-5601-1987, Korean */
#define UTF    14       /* double unicode */
#define UTF7   15       /* 7-bit unicode */
#define UTF8   16       /* 8-bit unicode */

/* conversion codes */
#define HZGB 1
#define GBHZ 2
#define FIL  3
#define ZWGB 4
#define JIS8 5          /* 7-bit JIS to 8-bit JIS */
#define JISRP 6         /* repair damaged JIS file */
#define JISCVT 7        /* convert EUC etc to 7-bit JIS */
#define HZPGB 8
#define HZPB5 9
#define KSC8 10         /* 7-bit KSC to 8-bit KSC */
#define UTF7TOUNI 11    /* 7-bit unicode to double-byte */
#define UTF8TOUNI 12    /* 8-bit unicode to double-byte */
#define CNSB5 13        /* CNS planes 1/2 to Big5 */
#define GBB5  14        /* GB to B5 */
#define HZB5  15
#define B5GB  16
#define B5HZ  17
#define TOSHORTPS 18 
#define PAGEPRINT 19 

#ifdef PSPRINT
#define isbreaka(c) (c==' ' || c=='(' || c=='{') 
#define isbreakb(c) (c=='}' || c==')') 
#define MAXLENGTHA 20
#define MAXLENGTH 72
#define MAXLENGTHB 99
#endif

/* paper sizes */
#define LETTER 1
#define LEGAL  2
#define A3     3
#define A4     4

#define BUFSIZE 8192
#define MAXBUFSZ 30000
#define SBUFSIZE 256
#define ASCBUFSIZE 300
#define MAXLINES 350    /* max # of lines, affect multiple column options */
#define LBASMAX 500     /* max # of chars for sender's address */

#define isvgb(c) (c==0x21 || c==0x2c || c==0x3A || c==0x3B || c==0x3F)
#define MSBoff(c)   (c & 0x7f)
#define MSBon(c)    (c | 0x80)
#define GBPOS(a, b) (((a)-0xa1)*94 + ((b)-0xa1))
#define GBB1(n)     ((n)/94 + 0xa1)
#define GBB2(n)     ((n)%94 + 0xa1)
#define B5POS(a, b) (((a)-0xa1)*157 + (b) - ((b)>=0xa1 ?(0xa1-63):0x40))
#define B5B1(n)     (((n)/157) + 0xa1)
#define B5B2(n)     ((n)%157 + (((n)%157)<63 ? 0x40 : (0xa1-63)))
#define GBbox   85  /* index postion of 0xA1F5 */
#define B5box   27  /* 0xA1BC */

/* jis */
#define SS2         142
#define SJIS1(A)    ((A >= 129 && A <= 159) || (A >= 224 && A <= 239))
#define SJIS2(A)    (A >= 64 && A <= 252)
#define HANKATA(A)  (A >= 161 && A <= 223)
#define ISEUC(A)    (A >= 161 && A <= 254)
#define ISMARU(A)   (A >= 202 && A <= 206)
#define ISNIGORI(A) \
	((A >= 182 && A <= 196) || (A >= 202 && A <= 206) || (A == 179))

 /* margins, line space (CLP) and char spaces */
int     LM, RM, TM, BM, CSP, CLP, maxCLP, H, V;
float   XX=0.0, YY;             /* actual paper size in inch, e.g. 8.5x11 */
int     Xw, Yh, Xa, Ya;         /*  "" in dots, Xa (lm), Ya (tm) */
float   pts, defpts;            /* 1 pts = 1/72 inch */
float   ppd = -1;    /* pts per dot, default .24, assume device res 300dpi */
static float Cw=0.72;           /* char width/line space */
float   Ci, Ca, defCi, defCa;   /* space between lines, characters */
float   Casc=0.5;               /* ASC_width / CH_width */
int     nCN=2048, copies=1;     /* # of entries in CNdict */
int     nHzline=9999;           /* # of chars per Hz/JIS line, default 70 */
char    prntcmd[80];

char    PSfile[100], EPSfile[80], KWfile[80], tempfile[80];
char    DictExt[2];             /* CNdict extension for EPS */
int     pts0, ptspc;            /* pts0=INT(pts+0.5), ptspc is from PC */
int     defFont=1;
int     mx, my, MXbmp, CHsize;  /* bitmap mx by my, string length CHsize */
int     inCH=100, newpos=1;
int     filecount=1, fprntfile=1;
int     fputnpage=6;            /* page number position 1-6 */
int     pgpd=0;                 /* physical pages actually printed */
int     pgcount=1, bp=0, ep=0;  /* page numbers to begin/end printing */
int     Prntpage, odd=0;   /* page-print: 0/1/2, print all/odd/even pages */
int     twoside=0;              /* two-sided format */
int     booklet=0;              /* output booklet format */
int     frl=NT;                 /* right-left */
int     fnewline=1;
int     cnsp=0;                 /* special CH char */
unsigned int    *fstring, *fdict, nchar;
unsigned int    cspace, b1l;    /* space char, lowerest byte-1 */
unsigned char   **ptstring, *array;
float   gray=.0;                /* 0 black, .9 white */
float   Cx=1., Cy=1., defCx, defCy;
int     stdinput=0, stdoutput=0; /* use stdin/stdout */
int     code=UNKNOWN, defcode=UNKNOWN, convcode=NT;
int	codecmd, convcodecmd;
int     big5=0, lcode;  /* language code (GB, B5, JIS, KSC) */
/* int     Fps230=0;  PS format of V2.30: discontinued from V2.90 */
int     pausqm=0;       /* pause at every (pause) pages */
int     landscape=0, EPS=0, IncEPS=0;   /* generate EPS, EPS file included */
int     vertical=0, Rotate=0, vgb=0;
int     suppress=0, mute=0, keepPS=0;   /* mute menu or map .,:; to CH */
int     manualfeed=0, envelope=0;
int     adjust=1;       /* adjust spaces between punctuation marks */
int     alnumadjust=0;  /* adjust alnum from CH to English */
int     timestat=0;     /* suppress time / statistics about document */
int     charstat=1;     /* char/word statistics */
int     AdjAtEndDoc=1;  /* BM adjust at end of document if multicolumn */
int     cmdlinehbf=0;   /* hbf filename supplied in command-line */
int     cgap=0;         /* gap between columns in pts, use default if zero */
int     euro=0;         /* European chars, def: auto-detect; -1, disable */
int     tabascii=0;     /* set tab width according to CH (0) or ASCII(1)
			   default 0 (1 if ASCII file selected) */
int	addrlabel=0;	/* mode for printing address labels */
int	lbn=0, lbnx=2, lbny=5;
float	lbxp=.5, lbyp=1.0, lbxinc=4.25, lbyinc=2.0;
unsigned char *lbas;
unsigned char *buf;	/* main buffer */

/* special effect */
int     fshade=0;
struct  {int x; int f;} UDline; /* underline */

/* for central adjust; */
int     centraladj=0, spaceH;	/* spaceH: H value of 1st non-space char */
int     startline=1;            /* previous line ended with EOL */
/* ASC font */
int     nEF=2, defnEF, nEFs[40];
float   Wasc[129];       /* width of ASC char re Courier */
static char *EFname[]={"AvantGarde-Book", "", "Courier", "Helvetica", "", "",
"Palatino-Roman", "Times-Roman", "ZapfChancery-MediumItalic", "ZapfDingbats",
"AvantGarde-BookOblique", "", "Courier-Oblique", "Helvetica-Oblique",
"", "", "Palatino-Italic", "Times-Italic", "", "",
"AvantGarde-Demi", "", "Courier-Bold", "Helvetica-Bold", "", "",
"Palatino-Bold", "Times-Bold", "", "",
"AvantGarde-DemiOblique", "", "Courier-BoldOblique", "Helvetica-BoldOblique",
"", "", "Palatino-BoldItalic", "Times-BoldItalic", "", "Symbol"};

static char *codename[]={"Unknown", "ASCII", "zW", "Hz", "GB",
	"GB or BIG5", "Hz+", "BIG5", "CNS", "JIS", "Shift-JIS",
	"EUC", "EUC or Shift-JIS", "KSC", "UTF", "UTF7", "UTF8", "", ""};
		/*  for search  */
int     PCN=0, SCN=0;
int     cTM, cBM, cLM, cRM, clptmp, Ha=0;
int     pline=0, pcolumn=1;
int     sline=0, column=1, defcolumn;  /* defcolumn is the one set for doc */
int     lineclp[MAXLINES], linedif[MAXLINES];
    /* output ascii buffer: p is the total # of char, pp and Hp are the # of
	chars and H position after the last white space */
struct {unsigned char s[ASCBUFSIZE]; int p, pp, Hp;} ascbuf;

/* for HBF */
char    HBFname[80], defHBFname[80];
struct  Roots {char *s; struct Roots *p;} *root;
struct  Bytes {int l; int h; int a;} *b2;
struct  HBFrange {unsigned int l; unsigned int h; long offset;
		char bmfname[50]; FILE *fp;} *seg;
int     nb2, nseg, GR=0;        /* GL(GR=0): 7-bit form */

/* repairs */
int     ignorespace=0, fix=0, ignoreEOL=0;  /* fix/repair */
int     breakfile=0; /* break big file into small (>12k, def: 64k) ones;
	    or (when multi-input), in -fpg# start a new page for
	    each input (optional) if within # (<=9) lines to bottom,
	    or (when multi-input) multiple output (>10) */
long    fnchar=0;               /* char count in small file */
char    newshd='>';             /* initial char for news replys */
unsigned char sbuf[SBUFSIZE];
int     sbufp=0;                /* pointer to sbuf */
int     bmpshift=0, bmpshift_dir=NT;  /* shift bitmap of a char */
unsigned int bmpshift_ch, bmpshift_ch2;

/* for utf & utf7: convert to two-byte unicode */
long    utf7_getc(), utf_getc();
static unsigned char   base64[] =
	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static unsigned char   safe[] = "'(),-.:?";
static unsigned char   optional[] = "!\"#$%&*;<=>@[]^_`{|}";
static unsigned char   space[] = " \t\n\r";
#define NUMBYTES 256
#define BASE64  0x01
#define SAFE    0x02
#define OPTIONAL 0x04
#define SPACE   0x08
#define CODE_ERROR 0x80
static  char    inv_base64[128];
static  char    char_type[NUMBYTES];
static  int     utf_initzd;
static  int     in_base64;
static  unsigned long   bit_buffer;
static  int     nbits;
#define U2ESC   0x4D    /* ESCs for 2-byte unicode */
#define U2ESC2  0x21    /* 0x4D4D = 0x4D, 0x4D21(M!) = 0x00 */

/* functions */
void    newline(), endAC(), charsize(), usage(), opnfile();
void    HBFclose(), convers(), MemExit(), cleanup();
void	PSctrl();
FILE    *Rfopen();
void    shift2seven(), euc2seven(), seven2seven();
void    han2zen(), sjis2jis(), jisrepair();

struct  INfiles {char *s; char *t; FILE *fp; struct INfiles *p;}
	*Rinf, *inf, *mRinf;
struct  WordFreqstr {unsigned char *s; int *addrs; int j; int freq;
		struct WordFreqstr *p;} *WordFreq;

int     extraEOL = 0;   /* before error message */
FILE    *out, *HBF, *errout, *msgout;


#ifdef CNS_SUPPORT  /* begin CNS support */

#include "cnsb5.h"

#else  /* no CNS support */

cns2b5(in)  /* CNS to Big5 convertion */
FILE    *in;
{
	fprintf(stderr,
"No CNS subroutines, see help file for details.\n");
	return 1;
}
#endif  /* CNS support */

insertEOL() /* print an EOL, to put message between page numbers */
{
	if (extraEOL) fputc('\n', errout);
	extraEOL = 0;
	return 1;
}

int IncludeEPS(s)
char *s;
{
	char    feps[80], cst[256];
	int     llx, lly, urx, ury;
	FILE    *fp;

	if (!inCH) endAC(1);
	if (s[0]!='\0') strcpy (feps, s);
	else if (!stdinput) {
		insertEOL();
		fprintf(stderr,
"Please enter full name of EPS file to be included:\n");
		gets(feps);
	}
	if ((fp=fopen(feps, "r"))==NULL) {
		insertEOL();
		fprintf(stderr,
"Can't open EPS file -> %s\n", feps);
		bell(); return 0;
	}
	while (fgets(cst, 255, fp)!=NULL)
		if (strncmp(cst, "%%BoundingBox", 13)==0) break;
	sscanf(cst, "%*s%d%d%d%d", &llx, &lly, &urx, &ury);
	fprintf(out,
"\nBeginEPSF\ncpx cpy translate dpi 72 div dup scale %d %d translate\n\
%%%%BeginDocument: %s\n", 0-llx, 0-lly, feps);
	rewind(fp);
	while(fgets(cst, 255, fp)!=NULL) fprintf(out, "%s", cst);
	fprintf(out, "\n%%%%EndDocument\nEndEPSF\n");
	fclose(fp);
	IncEPS++;
	return 1;
}

int HBFopen()
{      /* open HBF file, set segment and byte-2-ranges, open bitmap files */
	int     j, m;
	char    cst[120];

	if ((HBF=Rfopen(HBFname, "r"))==NULL) {
		insertEOL();
		fprintf(stderr,
"Can't open HBF file -> %s\n\
Please check if the path/directory/filename is correct\n\
and see Part VI of the help file\n\
about the name convention for HBF files: cn*##.hbf\n", HBFname);
		bell();
		if (*defHBFname==0) exit(-1);
		else return 0;
	}

	GR=0;
	while (fgets(cst, 119, HBF)!=NULL)
		if (strncmp(cst, "HBF_BITMAP_BOUNDING_BOX", 23)==0) break;
	sscanf(cst, "%*s%d%d", &mx, &my);
	CHsize=my*((mx+7)/8);
	if (array!=NULL) free(array);
	array = (unsigned char *) calloc(CHsize+1, sizeof(unsigned char));
	if (array==NULL) MemExit();

	while (fgets(cst, 119, HBF)!=NULL)
		if (strncmp(cst, "HBF_START_BYTE_2_RANGES", 23)==0) break;
	sscanf(cst, "%*s%d", &nb2);
	b2 = (struct Bytes *) calloc(nb2, sizeof(struct Bytes));
	if (b2==NULL) MemExit();
	for (j=0; j<nb2; j++) {
		while (fgets(cst, 119, HBF)!=NULL)
			if (strncmp(cst, "HBF_BYTE_2_RANGE", 16)==0) break;
		sscanf(cst, "%*s%i-%i", &(b2[j].l), &(b2[j].h));
		b2[j].a = b2[j].h - b2[j].l +1;
		if (b2[j].h >= 0xa1) GR=1; /* GL: 7-bit form */
		if (b2[j].a==1) {
			fprintf(stderr,
"Your system is special, please run hbfhx2d.c on all your HBF files\n\
 (ftp: neurophys.wisc.edu:/pub/cn)\n");
			exit(0);
		}
	}

	while (fgets(cst, 119, HBF)!=NULL)
		if (strncmp(cst, "HBF_START_CODE_RANGES", 21)==0) break;
	sscanf(cst, "%*s%d", &nseg);
	seg = (struct HBFrange *) calloc(nseg, sizeof(struct HBFrange));
	if (seg==NULL) MemExit();
	for (j=0; j<nseg; j++) {
		while (fgets(cst, 119, HBF)!=NULL)
			if (strncmp(cst, "HBF_CODE_RANGE", 14)==0) break;
		sscanf(cst, "%*s%i-%i%s%li", &(seg[j].l), &(seg[j].h),
			seg[j].bmfname, &(seg[j].offset));
		if (j>0) {
		    for (m=0; m<j; m++)
			if (strcmp(seg[m].bmfname, seg[j].bmfname)==0)
				seg[j].fp=seg[m].fp;
		}
		if (seg[j].fp==NULL) {
		    if ((seg[j].fp = Rfopen(seg[j].bmfname,
				(bmpshift)? "rb+" : "rb"))==NULL) {
			insertEOL();
			fprintf(stderr,
"Can't open bitmap font file -> %s\n\
Please make sure the path/directory/filename is correct\n\
and the HBF file is properly written\n", seg[j].bmfname);
			bell();
			if (*defHBFname==0) exit(-2);
			else return 0;
		    }
		}
	}
	return 1;
}

void HBFclose()
{     /* Reset segment and byte-2-ranges, close bitmap files and HBF file */
	int j;
	for (j=0; j<nseg; j++) fclose(seg[j].fp);
	free(seg); free(b2);
	fclose(HBF);
}

int HBFgetBitmap(ch)
unsigned int ch;
{       /* according to segment and byte-2-ranges, get bitmap string,
	   or return 0 for out-of-range char */
	unsigned int i, j, k, off;
	long    addr;
	if (!GR) ch -= 0x8080;  /* if 7-bit, ch must be in GR */
	for (i=0; i<nseg; i++)
	    if (ch >= seg[i].l && ch <= seg[i].h) {
	/* treat as if segment starts at lowest byte 2, then compensate */
		off = seg[i].l%256 - b2[0].l;
		k = ch - seg[i].l + off;
		j = k%256; k /= 256;
		if (nb2==1)
		    addr = k*b2[0].a + j - off;
		else if (nb2==2) {
		    addr = k*(b2[0].a + b2[1].a) + j - off;
		    if (j > b2[0].a) addr -= (b2[1].l-b2[0].h-1);
		    if (off > b2[0].a) addr += (b2[1].l-b2[0].h-1);
		}
		else
	/* can't handle yet, but it seems enough for now */
		    return -5;
		addr = addr*CHsize + seg[i].offset;
		fseek(seg[i].fp, addr, 0);
		k = (int) fread(array, CHsize, 1, seg[i].fp);
		if (bmpshift_dir) {
		    if (bmpshift_dir != RMIRROR)
			fprintf(errout, "R%d  ", k);
		    CharBitmapShift(seg[i].fp, addr, array);
		}
		return k;
	    }
	insertEOL();
	if (!mute) fprintf(errout, "Out of Range Char: %04X\n", ch);
	for (j=0; j<CHsize; j++) array[j]=0;
	return 0;
}


int num(v, n)
char    *v[];
int     n;
{
	int     m=0;
	while (n-- && strlen(v[0])) {
		m *= 10;
		if (isdigit(*++v[0])) m += (*v[0]-'0');
		else {
			v[0]--; m /= 10; break;
		}
	}
	return m;
}

int isstr(s, v)
char    *s, *v[];
{
	int     j;
	j = strlen(s);
	if (j > strlen(v[0])) return 0;
	if (strncmp(s, v[0], j)==0) {
		v[0] += j-1;
		return 1;
	}
	else if (s[j-1]=='=' && v[0][j-1]=='/') {
		if (strncmp(s, v[0], j-1)==0) {
			v[0] += j-1;
			return 1;
		}
		else return 0;
	}
	return 0;
}

char  *readstr(v, s)
char *v[], *s;
{
	v[0]++; sscanf(*v, "%s", s);
	v[0] += (strlen(s)-1);
	return s;
}

float readfv(v, s)
char *v[], *s;
{
	float   x;
	char *readstr();
	sscanf(readstr(v, s), "%f", &x);
	return x;
}

initinputfile(cst)
char    *cst;
{
	char    *s;
#ifdef VMS
	char    s2[80], sd[70], s3[40];
	int     n, wc=0;
	FILE    *tmp;

	s = cst;
	while (*s!='\0') {
	   if (*s=='*' || *s=='?') wc++;
	   s++;
	}
	if (wc) {
	    n = strlen(cst);
	    while(n--) if (cst[n]==']') break;
	    sd[0]='\0';
	    if (n>0) {
		strcpy(sd, cst); sd[n+1]='\0';
	    }
	    strcpy(s2, "dir/output=dir.tmp ");
	    strcat(s2, cst);
	    system (s2);
	    tmp=fopen("dir.tmp", "r");
	    fgets(s2, 79, tmp);
	    while (fgets(s2, 79, tmp)!=NULL) {
		if (strncmp(s2, "Directory", 9)==0 || strlen(s2)<=2)
			continue;
		if (strncmp(s2, "Total of", 8)==0) break;
		s2[strlen(s2)-1]='\0';
		if (!mute) fprintf(errout, "%s  (Y/N)?", s2);
		if (mute || yes(1)) {
		    sscanf(s2, "%s", s3);
		    strcpy(s2, sd); strcat(s2, s3);
		    initinputfile(s2);
		}
	    }
	    system("del dir.tmp;");
	    return 1;
	}
#endif
	if (inf->fp == stdin) {
		inf->t = (char *) calloc(strlen(cst) + 2, sizeof(char));
		if (inf->t == NULL) MemExit();
		strcpy(inf->t, cst);
	}
	if (inf->s != NULL) {
inf->p = (struct INfiles *) calloc(1, sizeof(struct INfiles));
		if (inf->p == NULL) MemExit();
		inf = inf->p;
	}
	inf->s = (char *) calloc (strlen(cst) + 5, sizeof(char));
	if (inf->s == NULL) MemExit();
	strcpy(inf->s, cst);
	opnfile(IN);
	return 1;
}

void init(argc, v)
int     argc;
char    *v[];
{
	char    c, cst[100], *readstr();
	int     m, j=0, ASCfile=0, HBFopen();
	float   ptscmd, Cxcmd, Cycmd, Cicmd, Cacmd, Casccmd;
	float   rmcmd, lmcmd, tmcmd, bmcmd, readfv();
	int     columncmd=0, eurocmd=0, fputnpagecmd = -2;
	int     papersize=UNKNOWN;

	if (argc==999) goto B5INIT;
	prntcmd[0]='\0'; EPSfile[0]='\0'; KWfile[0]='\0'; tempfile[0]='\0';
	*HBFname=0; *defHBFname=0; *PSfile=0;
	errout = stderr;

	ptscmd=Cxcmd=Cycmd=0.;
	Cicmd=Cacmd=Casccmd=0.;
	rmcmd=lmcmd=tmcmd=bmcmd=0.;

	Rinf = (struct INfiles *) calloc(1, sizeof(struct INfiles));
	if (Rinf == NULL) MemExit();
	inf = Rinf; inf->fp = stdin;    /* for unix pipeline */

	while (--argc>0) if (*(++v)[0] == '-') {
	    if (*(v[0]+1)=='\0') stdinput=mute=1;
	    while (c = *++v[0]) {
		switch (c) {
		    case '5': code=B5; big5++; break;
		    case 'a':
			if (isstr("aa", v)) ASCfile++;
			else if (isstr("a3", v)) papersize=A3;
			else if (isstr("a4", v)) papersize=A4;
			else alnumadjust++;
			break;
		    case 'b':
			if (isstr("b52gb", v)) convcode=B5GB;
			else if (isstr("b52hz", v)) convcode=B5HZ;
			else if (isstr("big5", v)) {
			    code=B5; big5++;
			}
			else if (isstr("bmps", v)) {
			    if ((bmpshift=num(v, 2)) > 0) {
				argc--; v++; v[0]--;
				sscanf(readstr(v, cst), "%x", &bmpshift_ch);
				v++;
				if (**v == '0') {
				    argc--; v[0]--;
				    sscanf(readstr(v, cst),
					"%x", &bmpshift_ch2);
				}
				else {
				    v--; bmpshift_ch2 = bmpshift_ch;
				}
			    }
			}
			else if (isstr("bm=", v)) bmcmd = readfv(v, cst);
			else if (isstr("bk", v)) {
				booklet = num(v, 1);
				if (booklet==0) booklet=2;
			}
			else if (bmpshift) bmpshift_dir=B;
			else {
				m=num(v, 3);
				if (*++v[0]=='e') {
					bp=m; ep=num(v, 3);
				}
				else {
					v[0]--; pgcount=m;
				}
			}
			break;
		    case 'c':
			if (isstr("cns", v)) {
			    code=CNS; break;
			}
			else if ((m=num(v, 1)) < 1) break;
			else columncmd=m;
			if ((m=num(v, 2)) >= 10) cgap=m;
			else if (m && m<10) v[0]--;
			break;
		    case 'd':
			adjust=0; Casc=0.5;
			break;
		    case 'e':
			if (isstr("euc", v)) code=EUC;
			else if (isstr("even", v)) odd += 2; 
			else if (isstr("extr", v)) convcode=PAGEPRINT;
			else if (isstr("euro", v)) eurocmd++;
			else if (isstr("env", v)) {
			    envelope = 1;
			    Casccmd = 0.6;
			    if (*++v[0]=='s') envelope++; /* small size */
			    else v[0]--;
			    m = num(v, 1) + 20; /* Is -env1? */
			    if (m!=21) break;   /* the CNLIST option is -r21 */
			    sprintf(cst, "cnlist %s -o/name.tmp -r%d ",
			       (strlen(KWfile)>0)? KWfile : "revlis.4", m);
			    argc--; v++; v[0]--;
			    strcat(cst, readstr(v, KWfile));
			    argc--; v++; v[0]--;
			    strcat(cst, " ");
			    strcat(cst, readstr(v, KWfile));
			    fprintf(errout, "%s\n", cst);
			    system(cst);
			    initinputfile("name.tmp");
			}
			else if (m=num(v, 3)) {
				Casccmd = m/10.;
				if (m>=10) Casccmd /= 10.;
			}
			else {
				isstr("eps", v); 	/* def: eps */
				EPS=1; fputnpage=0; keepPS=1;
				if (isstr("ms", v)) EPS++;
			}
			break;
		    case 'f':
			if (isstr("fpg", v)) breakfile = 1 + num(v, 1);
			else if (isstr("f=", v)) {
			    strcpy(HBFname, readstr(v, cst));
			    cmdlinehbf=1;
			}
			else twoside=1;
			break;
		    case 'g':
			if (isstr("gb2hz", v)) convcode=GBHZ;
			else if (isstr("gb2b5", v)) convcode=GBB5;
			else if (isstr("gb", v)) code=GB;
			/* else Fps230++; */
			break;
		    case 'h':
			if (isstr("hz2gb", v)) convcode=HZGB;
			else if (isstr("hz2b5", v)) convcode=HZB5;
			else if (isstr("hz", v)) code=HZ;
			else if ((m=num(v, 2)) > 0) nEF=m;
			else {
				usage(2); exit(0);
			}
			break;
		    case 'i':
			stdinput=mute=1;
			if (isstr("io", v)) stdoutput=1;
			break;
		    case 'j':
			if (isstr("jis8", v)) code=SJIS;
			else if (isstr("jis", v)) code=JIS;
			else AdjAtEndDoc=0;
			break;
		    case 'k':
			if (isstr("ksc", v)) code=KSC;
			else if ((m=num(v, 3)) > 0) breakfile=m;
			else if (isstr("k=", v))
				strcpy(KWfile, readstr(v, cst));
			else breakfile = 64;
			break;
		    case 'l':
			if (isstr("lm=", v)) lmcmd = readfv(v, cst);
			else if (isstr("letter", v)) papersize=LETTER;
			else if (isstr("legal", v)) papersize=LEGAL;
			else if (isstr("label", v)) addrlabel=1;
			else if (bmpshift) bmpshift_dir=L;
			else {
			    landscape = 1+num(v,1);
			    column = 2;
			}
			break;
		    case 'm': 
			if (isstr("mfeed", v)) manualfeed = (manualfeed)? 0:1;
			else { 
				m=num(v,3);
				if (!m) mute = (mute)? 0:1;
				else copies=m;
			}
			break;
		    case 'n':
			m=num(v, 4);
			if (m) nHzline=m;
			else if (isstr("nopage", v)) fputnpagecmd=0; 
			else if (isstr("n=", v)) {
				m=num(v, 4);
				if ( m>=0 && m<=4000) nCN=m;
			}
			break;
		    case 'o':
			if (isstr("o=", v)) {
				strcpy(PSfile, readstr(v, cst));
				keepPS++;
			}
			else if (isstr("out", v)) stdoutput++;
			else if (isstr("odd", v)) odd++; 
			else odd++;
			break;
		    case 'p': 
			pausqm=4;
			if (m=num(v,1)) pausqm=m;
			break;
		    case 'q':
			if (isstr("q=", v))
				strcpy(prntcmd, readstr(v, cst));
			break;
		    case 'r':
			if (isstr("rm=", v)) rmcmd = readfv(v, cst);
			else if ( (m=num(v, 1)) == 5) {
				bmpshift_dir = RMIRROR; v[0]--;
			}
			else if (m) { convcode=FIL; fix=m;}
			else if (!isstr("r=", v))
				bmpshift_dir = (bmpshift)? R : RMIRROR;
			else if ( (m=num(v, 4)) > 30) ppd=72./m;
			break;
		    case 's':
			if (isstr("size=", v)) ptscmd = readfv(v, cst);
			if (isstr("short", v)) convcode=TOSHORTPS;
			else suppress = (num(v, 1) > 1)? 2:1; break;
		    case 't':
			if (isstr("tab", v)) tabascii++;
			else if (isstr("tm=", v)) tmcmd = readfv(v, cst);
			else if (bmpshift) bmpshift_dir=T;
			else {
				timestat++;
				if (fix && isalnum(*(v[0]+1)))
					newshd = *++v[0];
			}
			break;
		    case 'v':
			vertical++; Rotate=1; /*adjust=0;*/ fputnpage=4;
			break;
		    case 'w': fprntfile=0; break;
		    case 'x': case 'y':
			if (m=num(v, 1)) {
				if (c=='x') Cxcmd += (m/10.);
				else Cycmd += (m/10.);
			}
			break;
		    case 'z':
			if (isstr("zw", v)) code=ZW;
			else convcode++;
			break;
		    case 'u':
			if (isstr("utf8", v)) code=UTF8;
			else if (isstr("utf7", v)) code=UTF7;
			else if (isstr("utf", v)) code=UTF;
			else {
				mute=1; errout=fopen("log.1", "w");
			}
			break;
		    default:
			fprintf(stderr, "Problem option: -%c\n", c);
			usage(11); exit(0); break;
		}
	    }
	}
	else if (argc!=999) initinputfile(*v);
/* end while-if */

	getroot();
/* get default code type, ppd, tempfile */
	if (getdata(4)==0) defcode=GB;
	if (ppd<0.) ppd=.24;
	if (strlen(tempfile)<2) strcpy(tempfile, "CNPRINT.TMP");
#ifdef MUSER
	sprintf(cst, "%d", (int) getpid());
	strcat(tempfile, cst);
#endif

	if (Rinf->fp == stdin && !bmpshift) {
#ifdef VMS
	    usage(0); exit(1);
#else
	    if (stdinput) {
		/*fprintf(errout, "CNPRINT: use standard input\n");*/
# ifdef MUSER
		sprintf(cst, "/tmp/cnpstdin%d", (int) getpid());
# else
		strcpy(cst, "cnpstdin.tmp");
# endif
		opnfile(OUT);
		while ( (c=fgetc(stdin)) != EOF) fputc(c, out);
		fclose(out); out=NULL;
		RE_name(tempfile, cst);
		initinputfile(cst);
	    }
	    else {
		usage(0); exit(1);
	    }
#endif
	}

	opnfile(OUT);
	if (!mute) fprintf(errout, "%s\n\n", Version);
/* prepare for multiple output */
	codecmd=code;
	convcodecmd=convcode;

B5INIT: if (argc==999) {
		lcode=UNKNOWN;
		HBFclose();
		if (fstring!=NULL) free(fstring);
		if (ptstring!=NULL) free(ptstring);
		fstring=NULL; ptstring=NULL;
		if (!cmdlinehbf) *HBFname=0;
	}
	if (code>=ZW && code<=GB) lcode=GB;
	else if (code==B5 || code==CNS) lcode=B5;
	else if (code>=JIS && code<=EUC) lcode=JIS;
	else if (code==KSC) lcode=KSC;
	else if (code>=UTF && code<=UTF8) lcode=UTF;
	else lcode=defcode;
	/* else use default */
	if (vertical>1 && lcode==GB) vertical=vgb=1;
	if (*HBFname==0) getdata(2);
	if (*HBFname==0) {
	    if (lcode!=GB) {
		fprintf(stderr,
"No HBF file specified for %s in either cnprint.cmd or command line\n\
Please read Part IV of the help file\n\
on how to specify HBF file for %s documents.\n",
			codename[lcode], codename[lcode]);
		bell(); exit(7);
	    }
	    else strcpy(HBFname, "cnj24.hbf");
	}
	j=strlen(HBFname);
	if (j<=3 && j<=4) {  /* if j24, k256 or alike, construct HBFname */
		strcpy(cst, HBFname);
		if (isdigit(cst[1]) && isdigit(cst[2]))
		    sprintf(HBFname, "cn%s%s.hbf",
((lcode==B5)? "5" : ((lcode==JIS) ? "j" : ( (lcode==KSC)? "k" : ""))), cst);
		    if (lcode==UTF) sprintf(HBFname, "cnu%s.hbf", cst);
	}
	if (convcode==GBHZ || convcode==GBB5 || convcode==B5GB
	    || convcode==B5HZ) return;
	if (!HBFopen()) exit(0);
	MXbmp=mx;
	strcpy(defHBFname, HBFname);
	nchar=0;
	for (j=0; j<nb2; j++) nchar += b2[j].a;
	nchar *= (seg[nseg-1].h/256 - seg[0].l/256 + 1);
	m = (lcode==B5)? 13973 : ((lcode==GB)? 8178 : 7876);
			/* 8178=94*87, 13973=(63+94)*89, 7876=94*84*/
	if (nchar<m) nchar = m;

	cspace = (lcode==B5) ? 0xA140 : 0xA1A1; /* GB, shifted JIS/KSC */
	if (lcode==UTF) cspace = 0x3000;
	b1l = cspace/256;
	fstring = (unsigned int *) calloc(nchar+1, sizeof(unsigned int));
	ptstring= (unsigned char **) calloc(nchar+1, sizeof(unsigned char *));
	if (fstring==NULL || ptstring==NULL) MemExit();
/*      if (lcode==KSC) adjust=0;   */
	if (argc==999 || bmpshift) return;

	if (papersize != UNKNOWN)
	    switch (papersize) {
		case LETTER:    XX=8.5; YY=11.; break;
		case LEGAL:     XX=8.5; YY=13.5; break;
		case A3:        XX=11.69; YY=16.54; break;
		case A4:        XX=8.27; YY=11.69; break;
		default: break;
	    }

	if (!getdata(3)) {
		XX=8.5; YY=11.;
		pts = ((landscape)? 11.6 : 13.6)/(Cx+Cy-1);
		Ca=1.; Ci=Cy+(Cx-1.)/2.;
		LM=261; RM=219; TM=252; BM=275; /* mm*10 */
		if (landscape) {
			LM=153; RM=152; TM=200; BM=220;
		}
	}
	if (prntcmd[0]=='\0') fprntfile=0;
	if (booklet) {
		column = booklet; LM=RM=100;
		landscape = 1;
	}
	if (landscape>1) {
		LM=153; RM=152; TM=200; BM=220;
		switch (landscape) {
		    case 2: Cy=1.2; Ci=1.1; pts=11.6; break;
		    case 3: pts=11.6; break;
		    case 4: Cy=1.2; Ci=1.1; pts=11.3; break;
		    case 5: pts=11.3; break;
		    default: break;
		}
	}
	if (ASCfile) {
		Ci=0.5; Casc=0.6;
		TM=180; BM=180; /* mm*10 */
		tabascii = (tabascii)? 0:1;
	}
	getEfontdata();

	ascbuf.p=ascbuf.pp=0;
/* command line values have top priority */
	if (envelope) {
		landscape=1;
		fputnpage=0;
		manualfeed++;
		Ci=.5; Casc=.6;
		if (nEF==2) nEF=3;
		TM=(XX>8.4)? 700 : 640; BM = TM - 40;
		RM=120; LM=(YY>11.2)? 823 : 648;
		if (envelope==2) LM += 750;
	}
	if (addrlabel) {
		lbas = (unsigned char *) calloc(LBASMAX, sizeof(char));
		if (lbas==NULL) MemExit(0);
		lbas[0]='\0';
		LM=RM=TM=BM=25.4;	/* 2.54 mm, 0.1 inch */
		fputnpage=0;
		manualfeed++;
		Ci=.5; Casc=.6;
		if (nEF==2) nEF=3;
	}
	else lbas=NULL;
	if (columncmd>0) column=columncmd;
	if (Cxcmd>0.01) Cx=Cxcmd; if (Cycmd>0.01) Cy=Cycmd;
	if (Cicmd>0.01) Ci=Cicmd; if (Cacmd>0.01) Ca=Cacmd;
	if (rmcmd>0.01) RM=rmcmd*10; if (lmcmd>0.01) LM=lmcmd*10;
	if (tmcmd>0.01) TM=tmcmd*10; if (bmcmd>0.01) BM=bmcmd*10;
	if (Casccmd>0.01) Casc=Casccmd;
	if (ptscmd>1.) pts=ptscmd;
	if (eurocmd) euro = (euro>=0)? -1 : 1;
	if (fputnpagecmd >= 0) fputnpage=fputnpagecmd;
}

int getdata(n)
int     n;
{
	char    t[100], *s;
	int     j, k, m[10];
	float   x1, x2, x3, x4;
	FILE    *cmd;
	if ((cmd=Rfopen("cnprint.cmd", "r"))==NULL) {
		if (n>0) fprintf(errout,
"Can't open file cnprint.cmd\n\
Please check if it exists or if the path is correct\n\
and/or read the help file for information on cnprint.cmd\n");
		return 0;
	}
	switch(n) {
	    case 1:     /* get metric data for ASCII fonts */
		if (strlen(EFname[nEF])<=1) return 0;
		while (fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(EFname[nEF], t, strlen(EFname[nEF]))==0)
			break;
		}
		k=0;
		while (fgets(t, 98, cmd)!=NULL) {
		    if (!strncmp(t, "DATA", 4)) {
			sscanf(t, "%*s%d%d%d%d%d%d%d%d%d%d",
			    &m[0], &m[1], &m[2], &m[3], &m[4], &m[5],
			    &m[6], &m[7], &m[8], &m[9]);
			j=0;
			while(k<129) {
				Wasc[k++]=m[j++]/10000.;
				if (j==10) break;
			}
		    }
		    if (k>=129) break;
		}
		if (k<129) {
		    fclose(cmd); return 0;
		}
		break;
	    case 2:     /* Default BIG5/JIS/KSC fonts */
		while(fgets(t, 98, cmd)!=NULL) {
if (strncmp(t, ((lcode==B5) ? "DEFAULT_BIG5FONT" :
	((lcode==JIS)? "DEFAULT_JIS_FONT" :
	((lcode==KSC)? "DEFAULT_KSC_FONT" :
	((lcode==UTF)? "DEFAULT_UTF_FONT" : "DEFAULT_GB_FONT:")))), 16))
		continue;
		    sscanf(t, "%*s%s", HBFname);
		    break;
		}
		break;
	    case 3:     /* PS print command, paper size, margins, etc */
		x1=x2=0.;
		if (XX < 1.0) {
		    while(fgets(t, 98, cmd)!=NULL) {
			if (strncmp(t, "DEFAULT_PAPERSIZE", 17)) continue;
			sscanf(t, "%*s%f%f", &x1, &x2);
			break;
		    }
		    if (x1<1. || x2<1.) {XX=8.5; YY=11.;}
		    else {XX=x1; YY=x2;}
		    rewind(cmd);
		}

		if (fprntfile) while(fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(t, "PS_PRINT_COMMAND", 16)) continue;
		    s = &t[j=17];
		    while(s[0]==' ') s = &t[++j];
		    j=0;
		    while(s[j]) if (s[j++]==EOL) s[j-1] = '\0';
		    if (!strlen(prntcmd)) strcpy(prntcmd, s);
		    break;
		}
		rewind(cmd);

		x1=x2=x3=x4=0.;
		while(fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(t, "PAPER_MARGINS", 13)) continue;
			/* margin: R L T B */
		    if (!landscape)
			sscanf(t, "%*s%f%f%f%f", &x1, &x2, &x3, &x4);
		    else sscanf(t,
			"%*s%*f%*f%*f%*f%f%f%f%f", &x1, &x2, &x3, &x4);
		    break;
		}
		if (x1<2.9 || x2<2.9 || x3<2.9 || x4<2.9) {
		    LM=261; RM=219; TM=252; BM=275; /* mm*10 */
		    if (landscape) {
			LM=153; RM=152; TM=200; BM=220;
		    }
		}
		else { LM = x1*10; RM = x2*10; TM = x3*10; BM = x4*10;}
		rewind(cmd);

		x1=x2=x3=x4=0.;
		while(fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(t, "SIZE_SPACE", 10)) continue;
			/* Ppts, Lpts, char & line space */
		    sscanf(t, "%*s%f%f%f%f", &x1, &x2, &x3, &x4);
		    break;
		}
		if (x1<2. || x2<2. || x3<.09 || x4<.09) {
		    pts = ((landscape)? 11.6 : 13.6)/(Cx+Cy-1);
		    Ca=1.; Ci=Cy+(Cx-1.)/2.;
		}
		else {
		    pts = (landscape)? x2 : x1; Ca=x3;
		    Ci = (x4>.99 && x4<1.01)? (Cy+(Cx-1.)/2.) : x4;
		}
		rewind(cmd);

		x1=x2=0.;
		while(fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(t, "WIDTH-HEIGHT", 12)) continue;
			/* Cx, Cy */
		    sscanf(t, "%*s%f%f", &x1, &x2);
		    break;
		}
		if (x1>=1.0) Cx=x1;
		if (x2>=1.0) Cy=x2;
		if (Cx>1.01 && Cy>1.01) Cy=1.;
		rewind(cmd);
		x1 = .5;  /* default: euro = 0 (auto detect) */
		while(fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(t, "EUROPEAN-LANGUAGE", 17)) continue;
		    sscanf(t, "%*s%f", &x1);
		    break;
		}
		if (x1 < -.2) euro = -1;        /* disable auto detect */
		else if (x1 > .8) euro = 1;
		rewind(cmd);

		k = -1; /* default page number position: H, V */
		while(fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(t, "PAGE_NUMBER_POSITION", 20)) continue;
		    sscanf(t, (vertical)? "%*s%*s%d":"%*s%d", &k);
		    if (k>=0 && k<=6) fputnpage=k;
		    break;
		}
		rewind(cmd);

		/* address label data */
		while(fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(t, "ADDRESS_LABEL", 13) != EQ) continue;
		    sscanf(t, "%*s%d%d%f%f%f%f", &j, &k, &x1, &x2, &x3, &x4);
		    lbnx=j; lbny=k;
		    lbxp=x1; lbyp=x2;
		    lbxinc=x3; lbyinc=x4;
		    break;
		}
		break;
	    case 4:     /* default encoding, tempfile & device res */
		while(fgets(t, 98, cmd)!=NULL) {
			if (strncmp(t, "DEFAULT_ENCODING", 16)) continue;
			sscanf(t, "%*s%s", tempfile);
			break;
		}
		if (strncmp(tempfile, "JIS", 3)==0) defcode=JIS;
		else if (strncmp(tempfile, "KSC", 3)==0) defcode=KSC;
		else if (strncmp(tempfile, "BIG5", 4)==0) defcode=B5;
		else if (strncmp(tempfile, "UNICODE", 7)==0) {
			defcode=UTF8; lcode=UTF;
		}
		else defcode=GB;
		if (code==UNKNOWN) lcode=defcode;
		tempfile[0]='\0';
		rewind(cmd);

		while(fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(t, "TEMPFILE", 8)) continue;
		    sscanf(t, "%*s%s", tempfile);
		    break;
		}
		rewind(cmd);
		x1=0.;
		while(fgets(t, 98, cmd)!=NULL) {
		    if (strncmp(t, "DEVICERES", 9)) continue;
		    sscanf(t, "%*s%f", &x1);
		    if (x1>30. && ppd<0.) ppd=72./x1;
		    break;
		}
		break;
	    case 5:     /* default GB<->B5 table file */
		while(fgets(t, 98, cmd)!=NULL) {
			if (strncmp(t, "DEFAULT_GBB5_TABLEFILE", 22))
				continue;
			sscanf(t, "%*s%s%s", KWfile, EPSfile);
			break;
		}
		break;
	    default: break;
	}
	fclose(cmd);
	return 1;
}

void opnfile(n)
int n;
{
	if (n==IN) {
		if ((inf->fp = fopen(inf->s, "r")) == NULL) {
		    insertEOL();
		    fprintf(errout, "Can't open input file -> %s\n", inf->s);
		    bell(); exit (-3);
		}
	}
	else if ((out=fopen(tempfile, "w"))==NULL) {
		insertEOL();
		fprintf(errout, "Can't open output file\n");
		bell(); exit (-4);
	}
}

void style(menu)
int menu;
{
    int     a, b, j;
    float   lm, rm, tm, bm, x, pr, pb, os=0., gap;
    float   Ck;     /* ~~~ mm/dot ~~~ */
    float   getnew();
    char    s[100], cst[100];
    static char *npagepos[]={"No Page Number", "Upper Left", "Upper Middle",
	    "Upper Right", "Lower Left", "Lower Middle", "Lower Right"};

    Ck=ppd*25.4/72;  /* mm/dot */
    Xw=XX*72/ppd; Yh=YY*72/ppd; pr=Xw*Ck; pb=Yh*Ck;
    if (landscape) {
	x=pr; pr=pb; pb=x;
    }
    lm = LM/10.; rm = RM/10.;  /* mm*10 --> mm */
    tm = TM/10.; bm = BM/10.;
    gap = (cgap)? cgap : 2.5*Cw*pts;
    gap *= 25.4/72;     /* pts --> mm */

    if (menu) do {
	charsize(pts);
	if (booklet) rm=lm=(rm+lm)/2.;
	if (fputnpage) fprintf(errout,
"    N: Page Numbering.    %s.   Starting page number: %d\n",
		npagepos[fputnpage], pgcount);
	else fprintf(errout,
"    N: Page Numbering.          No.\n");
	x = (Cx>Cy)? Cx : 1./Cy;
	fprintf(errout,
"    X: Character Width/Height. %5.2f (Y: H/W. %5.2f)\n", x, 1./x);
	fprintf(errout,
"    L: Left Margin.   %6.1f mm    S: Character Size. %6.2f mm (%4.1f pts)\n\
    R: Right Margin.  %6.1f mm    A: Character Space.%5.1f (1=standard)\n\
    T: Top Margin.    %6.1f mm    I: Line Space.     %5.1f (1=standard)\n\
    B: Bottom Margin. %6.1f mm    H: English Font.     %s.\n",
		lm, CSP*Ck, pts, rm, Ca, tm, Ci, bm, EFname[nEF]);
	fprintf(errout,
"    F: Two-Sided.        %s.\t   U: Envelope.         %s.\n",
		((twoside)? "Yes" : "No"), (envelope ? "Yes" : "No"));
	fprintf(errout,
"    V: Vertical Mode.    %s.\t   E: EPS Output.       %s.\n",
		(vertical ? "Yes" : "No"), (EPS ? "Yes" : "No"));
	fprintf(errout,
"    C: Page Column(s).   %d \t   D: EPS Page Header.  %s.\n",
		column, strlen(EPSfile)? EPSfile : "None");
	fprintf(errout,
"    M: Manual Feed.      %s.\t   O: Orientation.      %s.\n",
	    (manualfeed ? "Yes":"No"), (landscape ? "Landscape":"Portrait"));
	fprintf(errout,
"    P: Print PS file.    %s.\t   Q: Quit.\n\n", (fprntfile ? "Yes":"No"));
	a = 10.*(pb-bm-tm + (1-Cw)*CLP*Ck)/(CLP*Ck);
	if (booklet) b = 10.*(pr-rm*(column+2))/(CSP*Ck)/column;
	else {
		b = 10.*(pr-rm-lm-gap*(column-1)) / (CSP*Ck)/column;
	}
	fprintf(errout,
" There are about %d.%d lines in a page and %d.%d words in a line\n\n\
\tN, P, S, A, I, L, R, T, B, H, E, F, ..., Q\n\n\
 Type one of the above to change, or press RETURN key to continue\n",
		a/10, a%10, b/10, b%10);
	gets(cst);
	if (cst[0] != '\0') switch (toupper(cst[0])) {
	    case 'X':
		x = (Cx>Cy)? Cx : 1./Cy;
		fprintf(errout,
"\tX: Character Width/Height.    Current:   %5.2f\n", x);
		Cx=getnew(Cx, 5); Cy=1.;
		break;
	    case 'Y':
		x = (Cx>Cy)? Cx : 1./Cy;
		fprintf(errout,
"\tY: Character Height/Width.    Current:   %5.2f\n", 1./x);
		Cy=getnew(Cy, 5); Cx=1.;
		break;
	    case 'V':
		vertical = (vertical)? 0 : 1;
		if (fputnpage) fputnpage = (vertical)? 4:6;
		break;
	    case 'C':
		fprintf(errout,
"\tC: Page Column(s).    Current:   %d\n", column);
		column=getnew(column+0.1, 4);
		break;
	    case 'E':
		EPS = (EPS)? 0 : 1;
		break;
	    case 'M':
		manualfeed = (manualfeed)? 0 : 1;
		break;
	    case 'O':
		landscape=(landscape)? 0:1;
		x=pr; pr=pb; pb=x;
		break;
	    case 'U':
		envelope=1;
		if (!landscape) {
			landscape=1;
			x=pr; pr=pb; pb=x;
		}
		fputnpage=0;
		bm=tm=(XX>8.4)? 70. : 64.;
		rm=25.4; lm=(YY>11.2)? 82.3 : 64.8;
		break;
	    case 'F':
		twoside=(twoside)? 0:1;
		break;
	    case 'D':
		fprintf(errout,
"Please enter full name of the EPS file to be used as page header:\n");
		gets(EPSfile);
		fprintf(errout,
"Page header on the first page (Y/N)?\n");
		gets(s);
		if (toupper(s[0]) != 'N') IncEPS=1;
		break;
	    case 'N':
		if (fputnpage) fprintf(errout,
"\tN: Page Numbering.  Current:  %s.  Starting page number: %d\n",
			npagepos[fputnpage], pgcount);
		else fprintf(errout,
"\tN: Page Numbering.  Current:   No.\n");
		fprintf(errout,
"\nEnter any number to change/select starting page number,\n\
\tN: no page numbering\n\tP: change page number position\n\
or press RETURN to continue\n");
		gets(s);
		switch (toupper(s[0])) {
		    case 'N': fputnpage=0; break;
		    case 'P':
			for (j=0; j<7; j++)
			    fprintf(errout, "\t%d:  %s\n", j, npagepos[j]);
			fprintf(errout,
"Please select one, or press RETURN to continue\n");
			gets(s);
			if (isdigit(s[0]) && s[0] <= '6')
				fputnpage = s[0]-'0';
			break;
		    case '\0': break;
		    default:
			if (toupper(s[0])!='Y') sscanf(s,"%d", &a);
			else a=pgcount;
			if (bp && a>bp) {
			    fprintf(errout,
"Input greater than %d, the page to begin printing, OK?!\n", bp);
			    bell(); gets(s);
			}
			else {
			    pgcount=a;
			    if (!fputnpage) fputnpage = (vertical)? 4:6;
			}
			break;
		}
		break;
	    case 'P':
		fprntfile=(fprntfile)? 0:1;
		if (fprntfile && strlen(prntcmd)<=2) {
			fprintf(errout,
"Print command invalid/not found, please enter new one:\n");
			bell(); gets(s);
			sscanf(s, "%s", prntcmd);
			if (strlen(prntcmd)<=2) fprntfile=0;
		}
		break;
	    case 'S':
		fprintf(errout,
"\tCharacter Size. Current: %7.2f mm (%4.1f pts)\n\
\t\t****** 1 pts = 3.556 mm ******\n", CSP*Ck, pts);
		pts=getnew(pts,0);
		break;
	    case 'A':
		fprintf(errout,
"Standard is 8%% of the size of a Chinese character\n\
\tA: Character Space. Current: %6.1f (1=standard)\n", Ca);
		Ca=getnew(Ca,2);
		break;
	    case 'I':
		fprintf(errout,
"Standard is 50%% of the size of a Chinese character\n\
\tI: Line Space.      Current: %6.1f (1=standard)\n", Ci);
		Ci=getnew(Ci,2);
		break;
	    case 'L':
		fprintf(errout,
"\tLeft Margin.    Current: %6.1f mm\n\n", lm);
		lm=getnew(lm,1);
		if (booklet) rm=lm;
		break;
	    case 'R':
		fprintf(errout,
"\tRight Margin.   Current: %6.1f mm\n\n", rm);
		rm=getnew (rm,1);
		if (booklet) lm=rm;
		break;
	    case 'T':
		fprintf(errout,
"\tTop Margin.     Current: %6.1f mm\n\n", tm);
		tm=getnew (tm,1);
		break;
	    case 'B':
		fprintf(errout,
"\tBottom Margin.  Current: %6.1f mm\n\n", bm);
		bm=getnew (bm,1);
		break;
	    case 'H':
		fprintf(errout,
"\tH: English Font.    Current: %s\n\n", EFname[nEF]);
		for (j=0; j<10; j++) if (strlen(EFname[j]) > 1)
		    fprintf(errout, "%4d:  %s\n", j, EFname[j]);
		fprintf(errout,
"0-9: Normal  10-19: Oblique/Italic  20-29: Bold  30-39: Bold & Oblique\n");
		nEF=getnew(nEF+0.1, 3);
		getEfontdata();
		break;
	    case 'Q':
		cleanup(1);
		exit(0);
	    default: break;
	}
    } while (cst[0] != '\0');

    if ( (lm+rm) > XX*25. || (tm+bm) > YY*25.) {
	fprintf(stderr, "Supplied paper margins out of range.\n"); exit(0);
    }
    charsize(pts);
    pts0 = ptspc = (pts+0.5);
    defCa=Ca; defCi=Ci; defpts=pts; defcolumn=column;
    defCx=Cx; defCy=Cy; defnEF=nEF;
    maxCLP = clptmp = CLP;
    cgap = gap/Ck;
    if (booklet) {
	j = (pr - rm*(column+2))/Ck/CSP/column + 0.5;
	RM = j*CSP;     /* width of each "column" */
/* margins applies to all, except central one for staping, twice as wide */
	LM = (pr/Ck-column*RM)/(column+2);
	RM += LM;
	booklet = column; /* in case it is changed */
	column = 1;
    }
    else {
	LM = lm/Ck;
	RM = (pr - rm)/Ck;
/*      RM = ((RM-LM-cgap*(column-1)+CSP/2)/CSP)*CSP+LM; */
    }
    TM = (tm +(os + CSP*Ck))/Ck;        /* TM: adjust for 1st row image */
    BM = (pb - bm + (os + CLP*Ck))/Ck;
    BM = (BM-TM+CLP/2)/CLP*CLP+TM;
    j = x = (RM - LM - cgap*(column-1)) / (float) CSP / column;
    if (column>1) {     /* & not booklet */
	if (x-j > 0.65) {
	    x = (1 - x + j++) * CSP*column;
	    RM += x*0.45; LM -= x*0.15;
	}
	else if ((x=(x-j)*CSP*column) > 0.3*cgap*(column-1)) {
		RM -= x*0.45; LM += x*0.15;
	}
	cgap = (RM - LM - j*CSP*column)/(column-1);
    }
    else if (!booklet) {   /* & column = 1 */
	if (x-j > 0.50) {
	    x = (1 - x + j++) * CSP;
	    RM += x*0.651; LM -= x*0.35;
	}
	else {
	    x = (x - j) * CSP;
	    RM -= x*0.65; LM += x*0.35;
	}
    }
/* fprintf(stderr, "cgap = %d  j = %d, CSP = %d\n", cgap, j, CSP); */

    if (menu) fprintf(errout,
" There are %d lines in a page and %d words in a line\n\n", (BM-TM)/CLP, j);
    RM -= LM; BM -= TM; Xa = LM; Ya = TM; LM=TM=0;
    cRM = RM; cBM = BM; cTM=cLM=0;
    if (column>1) {
	cRM = cLM + j*CSP;
	PCN=SCN=1;
    }
    if (nEF%10 == 2) for (j=0; j<129; j++) Wasc[j] = 1.;
    nEFs[nEF]++;
    if (bp < pgcount) bp=pgcount;
    if (ep && ep<bp) ep=0;  /* error, print to file end instead */
    Prntpage = (bp==pgcount &&
	(!odd || (odd==1 && pgcount%2) || (odd>=2 && !(pgcount%2))))? 1:0;
}

	
getEfontdata()
{
	int j;

	if (strlen(EFname[nEF]) < 3) nEF=2;
	if (nEF%10 != 2) {
	    if (!getdata(1)) {
		if (!mute) {
			insertEOL(); bell(); 
			fprintf(errout,
"No data available for selected font, Courier used\n");
		}
		nEF=2;
	    }
	}
	if ((nEF%10)==2) for (j=0; j<129; j++) Wasc[j]=1.;
	return 1;
}

columnWidth()
{
	int     n;
	float   x;
	x = (cgap)? cgap :  /* (cgap/ppd) : */
		(2.*pts*(Cw*Cx + (Ca-1.)/25.)*25./24./ppd +.65);
	n = (RM-LM-x*(column-1))/column;
	return (n/CSP)*CSP;
}

void charsize(x)
float x;
{
	CSP = x*(Cw*Cx + (Ca-1.)/25.)*25./24./ppd +.65;
	pts = CSP/((Cw*Cx + (Ca-1.)/25.)*25./24./ppd);
	CLP = pts*(Cw*Cy - 1./25. + (1.0 - Cw + 1./25.)*Ci)*25./24./ppd;
}

float getnew(y, n)
float y; int n;
{
	float   x = -1.;
	char    s[40];
	fprintf(errout,
" Please enter your desired value, or press RETURN to continue\n");
	if (n==0)
fprintf(errout, " ~~~~~~ ONLY VALUE IN --pts-- IS ACCEPTABLE ~~~~~~\n");
	else if (n==1)
fprintf(errout, " ~~~~~~  inch OR mm  ~~~~~~\n");
	gets(s);
	if (s[0]=='\0') return y;
	sscanf(s,"%f",&x);
	if (x<=5. && n==1) x *= 25.4;
		/* 5mm < Margin <= 127 mm (5 in) */
	if (n==0 && x<100. && x>=1.) return x;
	else if (n==1 && x<=200. && x>=5.) return x;
	else if (n==2 && x<=20. && x>=0.1) return x;
	else if (n==3 && x<40. && x>= -0.1) return x+0.1;
	else if (n==4 && x<20. && x>= 0.9) return x+0.11;
	else if (n==5 && x<11. && x>= .1) return x;
	else {
		fprintf(errout,
"WARNING: input value out of range, ignored !\n\n");
		bell(); return y;
	}
}

void cleanup(deltempfile)
int     deltempfile;
{
	inf=Rinf;
	while (inf != NULL) {
		if (inf->fp != NULL) fclose(inf->fp);
		inf = inf->p;
	}
	HBFclose();
	if (deltempfile) {
		fclose(out); remove(tempfile);
	}
}

void newline(pr, ret)
int pr, ret;
{
	void    shade(), endpage();
	int     x;

/* if search */
	if (!pr) {
		fnewline=1; Ha=0; endAC(0); inCH=100;
		lineclp[1+(++sline)]=clptmp=CLP;
		linedif[sline] = (H<cRM && H>=0)? (cRM-H):0;
		if (ret && centraladj && startline) {
			linedif[sline] = (cRM - LM - (H-spaceH))/(-2);
		}
		H=LM; startline=ret;
		cnsp=0; spaceH = -1;
		return;
	}
/* print */
	/*ascbuf.p=0;*/
	if (fshade) shade();
	else endAC(pr);
	spaceH = -1;
	if (column==1) {
		V += CLP; H=LM;
		if (V>= BM) {
			endpage(0); V=TM;
		}
		maxCLP = clptmp = CLP;
	}
	else {
		V += lineclp[++pline]; H = cLM;
		if (V >= cBM || pline==sline) {
		    pline--;
		    x = columnWidth();
		    if (++pcolumn <= column) {
			V = cTM;
			H=cLM=LM+(x+(RM-LM-x*column)/(column-1))*(pcolumn-1);
		    }
		    else if (V >= BM) {
			endpage(0);
			V=cTM=TM; H=cLM=LM;
			PCN=SCN=1;              /* see isfs, PCN=2 */
			pline=1; sline=0;       /* force to search */
			pcolumn=1;
		    }
		    cRM = cLM + x;
		}
	}
	fnewline=1; Ha=0;
	if (fshade) ;
	if (UDline.f) UDline.x = H;
	cnsp=0;
}

void endpage(endDoc)
int endDoc;
{
	char    s[80];
	void    putnpagetime(), header(), trailer(), pagesetup();
	int     pp, j, k;
	if (Prntpage) {
		if (!pgpd++) bell();
		if (!mute) fprintf(errout,
			(pgpd%5 == 0 || endDoc)? "%5d\n" : "%5d", pgcount);
		extraEOL = 1;
		putnpagetime();
		fprintf(out, "EP SP\n");
		fprintf(out, "end  %% CN27%sDict\n", DictExt);
	}
	pgcount++;
	pp = (pausqm)? pausqm:1;
	Prntpage = (pgcount>=bp && (!ep || pgcount<=ep) &&
	  (!odd || (odd==1 && pgcount%2) || (odd>=2 && !(pgcount%2))))? 1:0;
	if (twoside) {
		j = (landscape)? Yh:Xw;
		k = Xa; Xa = j-RM-Xa;
		RM = j-Xa-k;
	}
	if (endDoc || (pausqm && !(pgpd%pp)) ) {
		insertEOL();
		trailer(0);
		if (ferror(out)) {
			fprintf(stderr,
"WARNING: PS file %s write error, possibly out of memory.\n\
Suggestion: delete PS file and run CNPRINT again, use the -p[number] option\n\
	 or select smaller number\n", tempfile);
			bell(); exit(-5);
		}
		fclose(out);
		if (!booklet) outputToDev();
		if (pausqm && !fprntfile) {
			fprintf(errout,"Please press RETURN to continue");
			bell(); gets(s);
		}
		filecount++;
		if (!endDoc) {
			opnfile(OUT); header(); pgpd=0;
		}
	}
	else if (Prntpage) pagesetup();
}

outputToStdout(fn)
char	*fn;
{
	char    s[100];
	FILE	*in;

	if ((in=fopen(fn, "r"))==NULL)
		fprintf(stderr, "CNPRINT File open error: %s", fn);
	else {
		while(fgets(s, 99, in)!=NULL) printf("%s", s);
		fclose(in);
	}
	return 1;
}

outputToDev()
{
	char    s[100], fn[100];
	void    FName();

	if (stdoutput) outputToStdout(tempfile);
	else if (fprntfile) {
		sprintf(s, "%s %s", prntcmd, tempfile);
#ifdef VMS
		if (!keepPS) sprintf(s, "%s/delete %s", prntcmd, tempfile);
#endif
		system(s); bell();
#ifdef VMS
			;
#else
                if (!mute) {
		    fprintf(errout,
"Job has been sent to the printer\n\
Please press RETURN after the print job is finished");
		    gets(s);
		}
		if (!keepPS) remove(tempfile);
#endif
	}
	if (keepPS || (!fprntfile && !stdoutput)) {
		strcpy(fn, PSfile);
		if (pausqm) {
			sprintf(s, "%d", filecount); FName(fn, s);
		}
		RE_name(tempfile, fn);
		fprintf(errout, "PS File: %s\n", fn);
	}
	return 1;
}

void trailer(Nppg)
int Nppg;       /* # of pages (booklet), use pgpd if 0 (regular) */
{
	int     j=0;
	fprintf(out, "%%%%Trailer\n");
	if (!EPS) fprintf(out, "%%%%Pages: %d\n", (Nppg==0)? pgpd : Nppg);
	while (j<40) if (nEFs[j++]>0) {
		fprintf(out,
"%%%%DocumentNeededResources: font %s\n", EFname[j-1]);
		break;
	    }
	while (j<40) if (nEFs[j++]>0)
		fprintf(out, "%%%%+: font %s\n", EFname[j-1]);
	fprintf(out,
"%%%%DocumentSuppliedResources: procset CN27%sDict\n", DictExt);
	if (nCN>0) for (j=1; j<=(1+(nCN-1)/256); j++)
		fprintf(out, "%%%%+: font CN%d%d%s\n", MXbmp, j, DictExt);
	fprintf(out, "%%%%EOF\n");
	if (Nppg) return;
	if (EPS) {
		fprintf(errout,
"Be sure to adjust the BoundingBox in the EPS file,\n\
otherwise the EPS file may be placed outside the display/print range\n");
		if (pgpd>1) {
			bell();
			fprintf(errout,
"WARNING: PS file does NOT comform to EPSF format -> more than 1 page\n");
		}
	}
	if (IncEPS) fprintf(errout,
"If the included EPS image is not printed/displayed,\n\
most likely you forgot to adjust the BoundingBox in the EPS file\n");
}

void pagesetup()
{
	if (!EPS) fprintf(out, "%%%%Page: %d %d\n", pgcount, pgpd+1);
	if (!EPS && !booklet) fprintf(out, "%%%%BeginPageSetup\n");
	fprintf(out, "CN27%sDict begin\n", DictExt);
	if (landscape) fprintf(out,
"BP -%d LRT %d %d translate\n", Xw, Xa, Xw-BM-Ya);
	else fprintf(out, "BP %d %d translate\n", Xa, Yh-BM-Ya);
	PSctrl();
	if (!EPS && !booklet) fprintf(out, "%%%%EndPageSetup\n");
	if (strlen(EPSfile)) {
		if (pgcount==1 && !IncEPS) return;
		fprintf(out, "%d 0 Q\n", BM);
		IncludeEPS(EPSfile);
	}
}

void putnpagetime()
{
	struct  tm *time_str;
	int     i=0, pnp, px, py, tx, ty;
	time_t  time_val;
	char    s[80], fmt[60];
	endAC(1);
	if (!fputnpage) return;
	pnp=fputnpage;
	if ((twoside || booklet==2) && !(pgcount%2)) {
		if (pnp==1 || pnp==4) pnp += 2;
		else if (pnp==3 || pnp==6) pnp -= 2;
	}
	if (vertical) {
		px = tx = (pnp>3)? (RM+CLP) : (LM-2*CLP);
		if (pnp==1 || pnp==4) {  /* left */
			py = BM-3*CSP; ty = TM + 3*CSP;
		}
		else if (pnp==2 || pnp==5) { /*middle */
			ty = py = (BM-TM+3*CSP)/2;
			tx = (pnp<3)? (RM+CLP) : (LM-2*CLP);
		}
		else { /*right */
			py = TM + 3*CSP;
			ty = BM - 3*CSP;
		}
	}
	else {
		py = ty = (pnp>3)? (BM+CLP) : (TM-1.5*CLP);
		if (pnp==1 || pnp==4) {  /* left */
			px = LM; tx = RM;
		}
		else if (pnp==2 || pnp==5) { /*middle */
			tx = px = (RM-LM-4*CSP)/2;
			ty = (pnp<3)? (BM+CLP) : (TM-1.5*CLP);
		}
		else { /*right */
			px = RM - 5*CSP;
			tx = LM;
		}
	}
/* use document default font/size for page number: previous whatever left */
	i = 0.8338*(defpts*Cw*defCx/ppd)*20.*Casc;
	fprintf(out,
"/%s [%d.%d 0 0 %d 0 0] SF\n", 
EFname[defnEF], i/10, i%10, (int) (defpts*0.75*defCy/ppd) );
	fprintf(out, (vertical)?
"%d %d p add Qa gctr (%5d.) S grestore\n" : 
"%d %d Qa (%5d.) S\n", BM-py, px, pgcount);
	if (!TIME || timestat==1) return;
	time(&time_val);
	time_str = localtime(&time_val);
	if (timestat==2) strcpy(fmt, ((inf==Rinf)? inf->t : inf->s));
	else strcpy(fmt, "CNPRINT");
	i=strlen(fmt);
	strcat(fmt, " %a %d-%b-%y %H:%M:%S %Z");
	strftime(s, 79, fmt, time_str);
	while ( (s[i]=toupper(s[i])) != '\0') ++i;
	i = (int) strlen(s)*3.6/ppd;
	if (pnp==2 || pnp==5) i /= 2;
	else if (pnp==3 || pnp==6) i=0;
	if (vertical) ty += i;
	else tx -= i;
	fprintf(out, (vertical)?
"/Courier %d SF %d %d p add Qa gctr (%s) S grestore\n" :
"/Courier %d SF %d %d Qa (%s) S\n", (int) (6./ppd), BM-ty, tx, s);
}

void header()
{
	int     j, n, urx, ury;
	time_t  time_val;
	void    CNdict(), pagesetup();

	if (EPS > 1) fprintf(out, "%c", 4);	/* ctrl-D: MS EPS */
	fprintf(out,
"%%!PS-Adobe-3.0 %s\n\
%%%%Creator: %s CYD UW-Madison WI USA\n\
%%%%Title: IN %s PS %s\n", (EPS)? "EPSF-3.0": "", Version, Rinf->t, PSfile);
	time(&time_val);
	DictExt[1]=DictExt[0]='\0';
	if (EPS) {
		n = (int) time_val%62;
		if (n<10) DictExt[0] = n + '0';
		else if (n<36) DictExt[0] = n - 10  + 'A';
		else DictExt[0] = n - 36  + 'a';
	}
	fprintf(out, "%%%%CreationDate: %s", ctime(&time_val));
	j=(Yh-(Ya+BM+2*CLP))*ppd; if (j<=0) j=0;
	urx = Xw-RM-Xa; n=Xa;
	if (twoside) { n=(urx<Xa)? urx : Xa; urx=n; }
	n=(n-CSP)*ppd;
	urx=(Xw-urx+3*CSP/2)*ppd;
	ury=(Yh-Ya+3*CLP/2)*ppd;
	fprintf(out,
"%%%%BoundingBox: %d %d %d %d\n", n, j, urx, ury);
	if (!EPS) fprintf(out, "%%%%Pages: (atend)\n");
	fprintf(out,
"%%%%DocumentNeededResources: (atend)\n\
%%%%DocumentSuppliedResources: (atend)\n\
%%%%Orientation: %s\n\
%%%%EndComments\n", (landscape)? "Landscape":"Portrait");
	fprintf(out,
"%%%%BeginProlog\n\
%%%%BeginResource: procset CN27%sDict 19200 6400\n", DictExt);
	fprintf(out,
"/CN27%sDict 150 dict def CN27%sDict begin\n", DictExt, DictExt);
	fprintf(out,
"/B {bind def} bind def\n\
/*SF { exch findfont exch       %% selectfont emulation\n\
  dup type /arraytype eq {makefont} {scalefont} ifelse setfont} B\n\
/*RF { gsave newpath 4 -2 roll moveto dup 0 exch rlineto exch 0 rlineto\n\
  neg 0 exch rlineto closepath fill grestore} B\n\
/languagelevel where {pop languagelevel} {1} ifelse 2 lt {/SF /*SF load def\n\
  /RF /*RF load def}{/SF /selectfont load def /RF /rectfill load def}ifelse\n\
/LRT {90 rotate 0 exch translate} B\n\
/BP {/pagelevel save def 72 dpi div dup scale} B\n\
/EP {pagelevel restore} B /SP {showpage} B\n");
	fprintf(out,
"/S {show 0 p 9 div neg rmoveto} B\n\
/Q {exch moveto} B\n\
/q {p add Q} B\n\
/Qa {exch p 9 div add moveto} B\n\
/gct {gsave currentpoint translate} B\n\
/gctr {gct 90 rotate} B\n");
	fprintf(out,
"/T {gct LL} B\n\
/t {gctr LL} B\n\
/W {show p 0 rmoveto} B\n\
/w {gctr show grestore p 0 rmoveto} B\n\
/M {imagemask grestore p 0 rmoveto} B\n\
/m /imagemask load def\n");
	fprintf(out,
"/BeginEPSF {currentpoint /cpy exch def /cpx exch def\n\
  /b4_Inc_state save def /dict_count countdictstack def\n\
  /op_count count 1 sub def userdict begin /showpage {} def\n\
  0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin 10 setmiterlimit\n\
  [] 0 setdash newpath /languagelevel where {pop languagelevel 1 ne\n\
  {false setstrokeadjust false setoverprint} if} if} B\n\
/EndEPSF {count op_count sub {pop} repeat countdictstack\n\
  dict_count sub {end} repeat b4_Inc_state restore } B\n");
	fprintf(out, "/Shade {setgray RF setgray} B\n");
	fprintf (out,           /* redefine font using ISOLatin1 */
"/ILE {findfont dup length dict begin\n\
  {1 index /FID ne {def} {pop pop} ifelse} forall\n\
  /Encoding ISOLatin1Encoding def currentdict end\n\
  /ILfont exch definefont pop /ILfont} B\n\
/UDline {gsave moveto 0 rlineto setlinewidth 1 eq\n\
  {[p 2.5 div dpi 300 div mul dup .7 mul]} {[]} ifelse\n\
  0 setdash stroke grestore} B\n");
/*
	fprintf(out,
"/code 256 array def\n  /x 0 def /str (/00) def\n\
  0 1 255 {/x exch def code x str x 15 gt {0} {1} ifelse x 16 (  )\n\
  cvrs putinterval str put} for\n");
*/
	fprintf(out, "/code 256 array def  code 0 [");
	for (j=0; j<256; j++)
		fprintf(out, (j%20==0)? "\n/%02x " : "/%02x ", j);
	fprintf(out,"] putinterval\n");
	fprintf(out, "end  %% CN27%sDict\n", DictExt);
	fprintf(out,
"%%%%EndResource\n\
%%%%EndProlog\n\
%%%%BeginSetup\n");
	fprintf(out,
"%sstatusdict begin /manualfeed true def end\n", (manualfeed)? "":"% ");
	fprintf(out, "CN27%sDict begin\n", DictExt);
	fprintf(out, "/dpi %d def\n", (j=72./ppd+.2));
	if (copies>1 && !EPS) fprintf(out, "/#copies %d def\n", copies);
	if (nCN) fprintf(out,
"/a {%d %d true [1 0 0 -1 0 %d]} B\n", mx, my, my);
	n=0;
	while (nCN > 256*n) CNdict(++n);
	if (nCN>0 && !pausqm) {
	    free(fdict); fdict=NULL;
	}
	fprintf(out, "end  %% CN27%sDict\n", DictExt);
	fprintf(out, "%%%%EndSetup\n");
	if (Prntpage) pagesetup();
}

void CNdict(n)  /* Fonts for frequently used characters with nCN entries */
int n;
{
	unsigned int i, j, k, m, ch;
	float   x;
	int     HBFgetBitmap();
	void    putBitmap();

	k = (nCN>=n*256)? 256:(nCN%256);
	j = (mx*my/24./24.)*(358./256.)*k; k = j*(344./358.);
	x = mx*25./24.;
	fprintf(out,
"%%%%BeginResource: font /CN%d%d%s %d00 %d00\n\
8 dict begin\n\
/FontType 3 def\n\
/FontMatrix [%7.5f 0 0 %7.5f 0 0] def\n\
/FontBBox [0 0 %6.3f %6.3f] def\n",
		mx, n, DictExt, j+1, k+1, 1./x, 1./x, x, x);
	fprintf(out,
"/BuildGlyph {0 0 0 0 %d %d setcachedevice	%% 0 x/y displacement\n\
  exch /CharProcs%d get exch 2 copy known not {pop /.notdef} if get exec} B\n\
/BuildChar {1 index /Encoding get exch get 1 index /BuildGlyph get exec} B\n\
%% level 1 compatibility\n", mx, my, n);
	fprintf(out,
"/Encoding 256 array def\n\
Encoding 0 code putinterval\n");
	if (nCN < n*256) fprintf(out,
"%d 1 255 {Encoding exch /.notdef put} for\n", nCN%256);
	fprintf(out,
"/CharProcs%d %d dict def\n\
CharProcs%d begin\n/.notdef {} def\n", n, (nCN>=n*256)? 257:(nCN%256+1), n);

	k = (nCN < n*256)? nCN : n*256;
	for (i=(n-1)*256; i<k; i++) {
	    m=fdict[i];
	    if (lcode==B5) {
		ch=m%157;  ch += ((ch<63)? 0x40:(0xA1-63));
		ch += (m/157+0xA1)*256;
	    }
	    else if (lcode==UTF) {      /* UTF: b1l=0x30 */
		ch = m + b1l*256; /*(m/256 + b1l)*256 + m%256 + 0; */
	    }
	    else        /* JIS, KSC & GB */
		ch = (m/94 + 0xA1)*256 + m%94 + 0xA1;
	    HBFgetBitmap(ch);
	    fprintf(out, "/%02x {a{<", i%256);
	    putBitmap(array);
	    fprintf(out, ">}m}B\n");
	    ptstring[m] = array;
	}
	fprintf(out,
"end currentdict end\n/CN%d%d%s exch definefont pop\n\
%%%%EndResource\n", mx, n, DictExt);
}

void putBitmap(a)
unsigned char *a;
{
	int j;
	for (j=0; j<CHsize; ++j)
		fprintf(out, (!((j+4)%40))? "\n%02x" : "%02x", a[j]);
}

void PSctrl() /* should not be called when in SEARCH mode */
{
	float   z, ns;
	int     j, nsx, nsy, nx, ny;

	if (ptspc <= 0 || ptspc >= 100) ptspc=pts0;
	z = (ptspc==pts0)? defpts : ptspc;

	charsize(z);
	ns = z*Cw/ppd;
	nsy = ns*Cy +.1; nsx = ns*Cx +.1;
	nx = (0.8338*CSP)*2.*Casc*10;
	ny = z*0.75*Cy/ppd;

	clearascbuf(1, 1); endAC(1); inCH=100;
	if (!Prntpage) return;
	fprintf(out,
"/p %d def\n/LL {%d %d %d %d scale true [%d 0 0 -%d 0 %d]} B\n",
CSP, mx, my, nsx, nsy, mx, my, mx);
	if (nCN>0)
	    for (j=1; j<=(nCN+255)/256; j++) {
		if (nsx!=nsy) fprintf(out,
"/z%d {/CN%d%d%s [%d 0 0 %d 0 0] SF} B\n", j, mx, j, DictExt, nsx, nsy);
		else fprintf(out,
"/z%d {/CN%d%d%s %d SF} B\n", j, mx, j, DictExt, nsx);
	    }
	fprintf(out,
"/fa {/%s %s [%d.%d 0 0 %d 0 0] SF} B\n", EFname[nEF],
		(euro>=1)? "ILE":"", nx/10, nx%10, ny);
	if (gray>0.01) fprintf(out, "%3.1f setgray\n", gray);
}

int isrlasc(c)
int c;
{              /* L=left; R=right; NT=none */
	if (!adjust) return NT;
	switch (c) {
		case 40 : case 60 : case 91 : case 123 :
			return L;
		case 33 : case 41 : case 44 : case 46 : case 58 :
		case 59 : case 62 : case 63 : case 93 : case 125 :
		case '-':
			return R;
		default: return NT;
	}
}

int isrlch(c1, c2)
unsigned char c1, c2;
{               /* L=left; R=right; NT=none */
    switch(lcode) {
	case B5:
		if (c1!=0xA1) return NT;/* A145-A149, A150-A154, a1a9-a1ac */
		if ((c2>=0x41 && c2<=0x44)||(c2>=0x4D && c2<=0x4F)) return R;
		else if (c2>=0x5D && c2<=0xA8) return (c2%2)? R : L;
		else return NT;
	case JIS:
		if (c1 > 0xA1) return NT;
		if (c2>=0xC6 && c2<=0xDB) return (c2%2)? R : L;
		else if (vertical) {
			if (c2>=0xA2 && c2<=0xA4) return R; 
			else return NT;
		}
		else { /* A1A9, A1AA ? */
			if ((c2>=0xA2 && c2<=0xA8) || (c2>=0xEB && c2<=0xED))
				 return R; 
			else return NT;
		}
	case KSC:
		if (c1==0xA3) {
		    switch (c2) {
			case 0xA8 : case 0xDB : case 0xFB : 
				return L;
			/*case 0xA1 : case 0xA7 : case 0xBF : */ 
			case 0xAE : case 0xBA : 
			case 0xBB : case 0xDF :  
				return (vertical)? NT:R;
			case 0xA9 : case 0xAC : case 0xDD : case 0xFD :
				return R;
			default: return NT;
		    }
		}
		else if (c1!=0xA1) return NT;
		/*if (c2>=0xA2 && c2<=0xA3) return R;
		else */ 
		if (c2>=0xAE && c2>=0xBD) return (c2%2)? R : L;
		else return NT;
	case GB:
	    switch (c1) {
		case 0xA1:
		    if (c2>=0xAE && c2<=0xBF) c2%=2;
		    switch (c2) {
			case 0: return L;
			case 1: case 0xA2 : case 0xA3 : /*case 0xC3 :*/
				return R;
			case 0xE3 : case 0xE4 : case 0xE5 :
				return (vertical)? NT:R;
			default: return NT;
		    }
		case 0xA3:
		    switch (c2) {
			case 0xA8 : case 0xDB : case 0xFB : 
				return L;
			case 0xE0 :
				return (vertical)? NT:L;
			case 0xA1 : case 0xA7 : case 0xAE : case 0xBA : 
			case 0xBB : case 0xBF : case 0xDF :  
				return (vertical)? NT:R;
			case 0xA9 : case 0xAC : case 0xDD : case 0xFD :
				return R;
			default: return NT;
		    }
		default: return NT;
	    }
	case UTF:      /* unicode */
		if (c1!=0x00) return NT;
		if (c2==0x01 || c2==0x02) return R;
		else if (c2>=0x08 && c2<=0x17) return (c2%2)? R : L;
		else return NT;
	    break;
	default: break;
    }
    return NT;
}

unsigned char tovhb5(c)
unsigned char c;
{ /* convert vertical big5 punctuations to horizontal ones or vice versa */
	int j;
	if (c<0x5D || c>0x7D) return c;
	j = (c-0x5D)%4;
	if (j<2 && vertical) return (c+2);
	if (j>=2 && !vertical) return (c-2);
	return c;
}

int vchange(c1, c2)  /* substitutions under vertical mode */
unsigned char *c1, *c2;
{
    switch(lcode) {
	case JIS:
	    if (*c1==0xA1) switch (*c2) {
		case 0xC6: case 0xC7: case 0xC8: case 0xC9:
			*c2 += 0x10; break;
		default: break;
	    }
	    break;
	case B5:
	    if (*c1==0xA1) switch (*c2) {
		/*case 0x43: *c1 = 0xA2; *c2 = 0x58; break;
		case 0x4D: *c2 = 0xA6; break;
		case 0x4E: *c2 = 0xAB; break;*/
		case 0xA5: *c2 = 0x77; break;
		case 0xA6: *c2 = 0x78; break;
		case 0xA7: *c2 = 0x7B; break;
		case 0xA8: *c2 = 0x7C; break;
		default: break;
	    }
	    break;
	case GB:
	    if (*c1==0xA1) switch (*c2) {      /* GB: default c1=0xA1 */
		/*case 0xA2: *c2 = 0xE4; break;
		case 0xA3: *c2 = 0xE3; break;*/
		case 0xAE: case 0xAF: case 0xB0: case 0xB1:
			*c2 += 0x0A; break;
		default: break;
	    }
/* problem: A1A3 is a comma, */
	    break;
	case KSC:
	    if (*c1==0xA1) switch (*c2) {
		case 0xAE: case 0xAF: case 0xB0: case 0xB1:
			*c2 += 0x0A; break;
		default: break;
	    }
	    break;
	case UTF:   /* unicode */
	    break;
	default: break;
    }
    return 1;
}

int rtch(c1, c2)
unsigned char c1, c2;
{               /* R=rotate */
    switch(lcode) {
	case JIS:
	    switch (c1) {
		case 0xA1: 
			if (c2>=0xA2 && c2<=0xA4) return RMXY;
			else return (c2>=0xC2)? NT : R;
		case 0xA2: return (c2<=0xEF)? NT : R;
		case 0xA3: return (c2<=0xD4)? NT : R;
		case 0xA6: return NT;
		case 0xA7: return (c2<=0xCF)? NT : R;
		default: return R;
	    }
	case B5:
	    switch (c1) {
		case 0xA1:
		    if (c2>=0x41 && c2<=0x43) return RMXY; 
		    else if (c2>=0x4D && c2<=0x4F) return RMXY;
		    else if (c2>=0x5D && c2<=0x7C) 
			return ((c2-0x5D)%4 <= 1)? R:NT;
		    else return (c2>=0x7D && c2<=0xFE && c2!=0xC0)? NT : R;
		case 0xA2:
		    if (c2>=0x40 && c2<=0x58) return NT;
		    else if (c2>=0x62 && c2<=0xC2) return NT;
		    else if (c2>=0xCF && c2<=0xFE) return NT;
		    else return R;
		case 0xA3:
		    return (c2>=0x40 && c2<=0x73)? NT : R;
		case 0xC8:
		    return (c2>=0x41 && c2<=0x78)? NT : R;
		default: return R;
	    }
	case GB:
	    switch (c1) {
		case 0xA1:
		    switch (c2) {
			case 0xA2: case 0xA3: return RMXY; 
			case 0xA9: return R;
			default: return NT;
		    }
		case 0xA3:
		    switch (c2) {
			case 0xA1: case 0xBF: case 0xBA: case 0xBB: 
				return RMX; /* ! ? : ; */
			case 0xAC: return RMXY;  /* , */
			default: return NT;
		    }
		case 0xA6: case 0xA7: case 0xA9: return NT;
		case 0xA8:
		    if (c2==0xE7) return NT;
		    else return (c2 <= 0xC4)? NT : R;
		default: return R;
	    }
	case KSC:  /* needs work */
	    switch (c1) {
		case 0xA1:
		    switch (c2) {
			default: return NT;
		    }
		case 0xA3:
		    switch (c2) {
			case 0xA1: case 0xBA: case 0xBF: return R;
			case 0xAC: return RMXY;
			default: return NT;
		    }
		default: return R;
	    }
	case UTF:
	    if (c1>=0x01) return R;
	    else if (c2==0x02 || (c2>=0x08 && c2<=0x17) ) return NT;
	    else return R;
	    break;
	default: break;
    }
    return NT;
}

int putASC(c, c2, pr)
int c, c2, pr;
{
	int     p, k, ASP, isrlasc(), rl, rr=0;
	float   x;
	static int map[] = {    /* map some European chars, 128-160 */
		0xC7, 0xFC, 0xE9, 0xE2, 0xE4, 0xE0, 0xE5, 0xE7,
		0xEA, 0xEB, 0xE8, 0xEF, 0xEE, 0xEC, 0xC4, 0xC5,
		0xC9, 0xE6, 0xC6, 0xF4, 0xF6, 0xF2, 0xFB, 0xF9,
		0xFF, 0xD6, 0xDC, 0xA2, 0xA3, 0xA5, 0xDF, 0x83, 0xE1};

	cnsp=0; frl=NT;
	if (c==LF || c==FF) {
		clearascbuf(pr, 1);
		if (c==FF) {
			V = BM; pcolumn = column;
		}
		newline(pr, 1);
		return 0;
	}
	if (c=='\t') {
		clearascbuf(pr, 1);
		endAC(pr);
		x = (H-cLM)/(CSP*((tabascii)? Casc: 0.5));
		k = x + 8.5;  k = (k/8)*8;
		H += ((k-x)*CSP*((tabascii)? Casc: 0.5));
		return 0;
	}
	k = (c>=' ' && c<=160)? (c-' ') : 0;  /* change 126 to 160 */
	ASP = CSP*Casc*Wasc[k]*10.;
	Ha += (ASP%10); ASP /= 10;
	if (c>=128 && c<=160) {
		c=map[c-128];
		if (euro==0 && pr) { /* auto detect feature: end previous line 
			with clearascbuf(1, 1) and endAC(1) in PSctrl() */
			euro=1; PSctrl();
		}
	}
	if (c!=' ') { 
		rl=isrlasc(c);
	/* left-end char */
		if (H > cRM-ASP*3/2 && rl==L && adjust) {
		    clearascbuf(pr, 1);
		    newline(pr, 0);
		    return 1;
		}
		else if (H > cRM-ASP/2) {
		    if (!adjust || H > cRM+2*CSP*Casc) {
			    clearascbuf(pr, 1);
			    newline(pr, 0);
			    return 1;
		    }
		    else if (c2==LF /*|| c2==CR*/)  /* no need for a new line */
			rr=4;
	    /*  "abc ": include space in the current line, rr=3, treat 
		as if H<<cRM; but if " a " or " I ", move them to next line */
		    else if (c2==' ') {
			rr=3;
			if ((c=='a' || c=='I') && ascbuf.p>0) {
			    if (ascbuf.s[ascbuf.p-1]==' ') {
				clearascbuf(pr, 1);
			    	newline(pr, 0);
			    	return 1;
			    }
			}
		    }
	    /*  do not break digits like 108.9, does not work if 108.92 */
		    else if (rl==R && (c!='.' || !isdigit(c2)))
			rr=2;
	    /*  c2 is ascii and not left-end, here b1l=0xa1 or 0x30(utf),
		but ascbuf.p > 40% line, or last word > 15 chars */
		    else if (c2<b1l && isrlasc(c2)!=L &&
			(ascbuf.p-ascbuf.pp>15 || H-ascbuf.Hp >(cRM-cLM)*.3)) {
			    clearascbuf(pr, 1);
			    newline(pr, 0);
			    return 1;
		    }
		    else if (ascbuf.p) {
			    p = ascbuf.p-ascbuf.pp;
			    clearascbuf(pr, 0);
			    newline(pr, 0);
			/* push un-used chars back to major buffer, safe in
			   most of cases */
			    return 1+p;
		    }
		    else newline(pr, 0);
		    if (rr<2) return 1;
			/* rr<2: do not use char c; rr=2: use c & add newline;
			   rr>2: use char c only */
		}
		if (pr) {
		    if (centraladj && spaceH == -1) {
			H -= linedif[pline];
			spaceH = 1;
		    }
		    if (inCH && Prntpage)
			fprintf(out, "%d %d Qa fa\n(", BM-V, H);
		}
		else if (centraladj && spaceH == -1) spaceH = H;
		ascbuf.s[(ascbuf.p)++]=c;
		if (ascbuf.p==1) {
			ascbuf.Hp=H; ascbuf.pp=0;
		}
		inCH=OUT;
		if (rr==2) {
			H += ASP; newline(pr, 0);
			return 0;
		}
	}
	else {
	    if (inCH) newpos = 1;
	    if (ascbuf.p) ascbuf.s[(ascbuf.p)++]=c;
	    ascbuf.pp=ascbuf.p;
	    ascbuf.Hp=H+ASP;	/* introduces error (~Ha) */
	    if (centraladj) {
		if (centraladj==2 && spaceH == -1) {
		    if (pr) {
			H -= linedif[pline]; spaceH=1;
		    }
		    else spaceH = H;
		}
		else if (pr && spaceH!=1) H -= ASP;
	    }
	}
	H += ASP;
	if (Ha>=10) { H++; Ha -= 10; }
	return 0;
}

unsigned int Addr(c1, c2)
int c1, c2;
{
	unsigned int a;
	if (lcode==UTF) a = (c1-b1l)*256 + c2;
	else a = (lcode!=B5)? ((c1-0xA1)*94+c2-0xA1) :
		( (c1-0xA1)*157 + ( (c2>=0xA1)? (63+c2-0xA1):(c2-0x40) ) );
	return (a>nchar)? nchar : a;
}

int putCH(c1, c2, pr)
unsigned char c1, c2;
int pr;
{
	int     j, rl, rt, newl=0;
	void    putBitmap();
	unsigned int ch, addr;
	unsigned char tovhb5();

	rl=rt=NT;
	if (lcode==B5)
		if ((big5>1 || vertical) && c1==0xA1) c2=tovhb5(c2);
	if (vertical) {
		vchange(&c1, &c2);
		rt = rtch(c1, c2);
		if (rt != NT) Rotate=1;
	}
	/*else rt=NT;*/
	if (c1>=0xA4) cnsp=0;
	else if (adjust) {
/* such adjustment should also be allowed for vertical printing, except
 * for some like : ;
 */
    /*      if (lcode==B5 || lcode==JIS) {
		cnsp=0; rl=isrlch(c1, c2);
		if (rl==L && H > cRM-CSP*3/2) newl=1;
	    }
	    else if (lcode==GB) {
*/              cnsp++;
		if ( (rl=isrlch(c1, c2))==NT ) cnsp=0;
		else if (rl==L) {
		    if (H > cRM-2*CSP) {
			cnsp=1; newpos=1;
			if (H < cRM-CSP*5/4) {
				H -= ((frl==R)? CSP: CSP/2);
				if (frl==R) frl=NT;
				if (H < cRM-2*CSP) H=cRM-2*CSP;
			}
			else if (H < cRM-CSP*3/4 && frl==R) {
				H -= CSP;
				if (H < cRM-2*CSP) H=cRM-2*CSP;
			}
			else newl=1;
		    }
		}
		else if (rl==R && frl==L) cnsp=1;
	   /* } */
	}
	if (!inCH) {
	    if (ascbuf.p) clearascbuf(pr, 1);
	    endAC(pr);	/* also set newpos=1, inCH=100, ascbuf.p=0 */
	}
	ch = (c1*256) + c2;
	if (ch != cspace) {
	    if (adjust) {
		if (frl==R && H > cRM-CSP && H <=cRM-CSP/4 && !cnsp) {
			newpos=1;
			H = (H > cRM-CSP/2)? (H-CSP/2):(cRM-CSP);
		}
		else if (newl || (H>cRM-CSP*2/3 && rl!=R) || H>cRM+1.5*CSP) {
			newline(pr, 0);
			return 2;
		}
		if (cnsp >= 2) {
		    if (!pr) H -= (CSP/2);
		    else {      /* take care of 'half' CN */
			if (linedif[pline] > CSP/2)
				linedif[pline] -= (CSP/2);
			else if (linedif[pline] > 0) {
				H -= (CSP/2-linedif[pline]);
				linedif[pline]=0; newpos=1;
			}
			else {
				H -= (CSP/2); newpos=1;
			}
		    }
		}
	    }
	    else if (H > cRM - CSP*2/3) {
		newline(pr, 0);
		return 2;
	    }

	    if (!pr) {
		inCH=100;
		if (centraladj && spaceH == -1) spaceH = H;
	    }
	    else {
		if (centraladj && spaceH == -1) {
			H -= linedif[pline]; spaceH=1;
		}
		addr=Addr(c1, c2);
		if (Prntpage) {
		    if ((defFont && ptstring[addr]==NULL) || !defFont) {
			HBFgetBitmap(ch);
			if (defFont) {
			 /* allocate memory for bitmap array */
ptstring[addr] = (unsigned char *) calloc(CHsize+1, sizeof(unsigned char));
			    if (ptstring[addr]!=NULL)
				for (j=0; j<CHsize; ++j)
					ptstring[addr][j]=array[j];
			    else ptstring[addr=0] = array;
			}
			else ptstring[addr=0] = array;
		    }
		    if (vertical && rt != NT && rt != R) { /* rotate & move */
			fprintf(out, "%d %d q ", 
				BM-V + CSP/ (rt==RMY ? 6:2), 
				H - CSP/ (rt==RMX ? 6:2) );
			newpos=1; /* next char must re-define position */
		    }
		    else if (newpos || (rt==NT && Rotate) ) {
			if (newpos==1 || rt==R || (rt==NT && Rotate) )
			    fprintf(out, (vertical && rt==R)?
				"%d %d q\n":"%d %d Q\n", BM-V, H);
			newpos=0;
			if (vertical && rt==NT) {Rotate=0; newpos=2;}
		    }
/* possible problem here for unicode */
		    if (defFont && fstring[addr]>=60000) {
			j = fstring[addr] - 60000;
			if (inCH != (j>>8) +1)
			    fprintf(out, "z%d ", (inCH = (j>>8) +1));
			j%=256;
fprintf(out, (j>='~' || j<' ' || j=='(' || j==')' || j==92)?
			"<%02x>%c\n" : "(%c)%c\n", j, ((rt==NT)? 'W':'w'));
		    }
		    else {
			fprintf(out, (rt==NT)? "T {<" : "t {<");
			putBitmap(ptstring[addr]);
			fprintf(out, ">}M\n");
		    }
		}
		if (fstring[addr]>0 && fstring[addr]<60000)
		    if (--fstring[addr]==100) {
			if (ptstring[addr]!=NULL) free(ptstring[addr]);
			ptstring[addr]=NULL;
		    }
	    }
	}
	else {
	    if (centraladj) {
		if (centraladj==2 && spaceH == -1) {
		    if (pr) {
			H -= linedif[pline]; spaceH=1;
		    }
		    else spaceH = H;
		}
		else if (pr && spaceH!=1) H -= CSP;
	    }
	    newpos=1;
	}
	H+=CSP;
	frl=rl;
	return 0;
}

signature()
{
	time_t  time_val;
	char    *msg[]={"\nHave a nice day !\n", "",
		"\nThank you for using CNPRINT !\n", "", "", ""};
	if (mute) return 1;
	time(&time_val);
	if (time_val%287 == 2) fprintf(errout,
"\nThis version of CNPRINT is about to expire, please contact author.\n");
	else if (time_val%131 == 2) fprintf(errout,
"\nThank you for using CNPRINT.  Please consider contribution to\n\
CNPRINT education fund, to help kids in rural China get five-\n\
years' basic education.  See \"Author\" section of the help file\n\
for details.\n");
	else fprintf(errout, "%s", msg[(int)(time_val%5)]);
	return 1;
}

void usage(n)
int n;
{
	if (n>10) bell();
	fprintf(errout, "%s\n\n", Version);
	fprintf(errout,
"USAGE: cnprint [-h] [-wvlc2x3...] [-f=font] [file1 [file2]...] \
[-o=outfile]\n\n\
	-big5(gb)(hz)(zw)(cns)(jis)(euc)(jis8)(ksc)(utf8)(utf7): \
Input is BIG5,\n\
		GB, Hz, zW, CNS, JIS, EUC, Shift-JIS, KSC, 8(7)-bit unicode.\n\
	-v(-vv): Vertical printing mode.\n\
	-c3:    Divide one page into 3 Columns.\n\
	-w:     Convert to PS Without printing.\n\
	-l:     Paper orientation Landscape.\n\
	-i(out)(io): Use standard input (output) (both).\n\
	-f=j16 (f24, k24, or full HBF name): Select font.\n");
	fprintf(errout,
"	-x2:	Character width/height 1.2 (-y3: h/w 1.3).\n\
	-e56:   ASCII width = 0.56 CJK width.\n\
	-z(-hz2gb): Hz->GB conversion only (-zz or -gb2hz: GB->Hz).\n\
	-gb2b5(-hz2b5)(-b52gb)(-b52hz): GB(HZ)<->BIG5 conversions.\n\
	-m:     Disable/enable Menu (-m5: print 5 copies).\n\
	-aa:    Special mode for pure English text file.\n\
	-b20e34: Print pages 20-34 (-odd, -even: odd or even-numbered pages).\n\
	-b18:   Set the starting page number as 18.\n");
	if (n!=2) {
		fprintf(errout,
"Use -h option for more on-line help.  See help file for details.\n");
	       /*       signature(); */
		return;
	}
	fprintf(errout, "Press RETURN key to continue\n");
	n=getchar();
	fprintf(errout,
"	-q=laserps: : System PS print command = 'laserps'.\n");
	fprintf(errout,
"	-t(-tt): Do NOT print time (-tt: print time and input filename).\n\
	-55:    BIG5 input, adjust horizontal/vertical punctuations.\n\
	-c320:  3 Columns on one page with 20 pts space between columns.\n\
	-l#:    Special landscape modes for printing HXWZ (#: 1-4) (*).\n\
	-a:     Print double-byte letters, digits as English ones.\n\
	-d:     NO special treatment of punctuation marks.\n\
	-e(-eps): EPS output (-ems or -epsms: MS format EPS).\n\
	-s:     Suppress the effects of functional sequences @[**] (*).\n\
	-k:	When multiple inputs, produce multiple outputs.\n\
	-mfeed:	Manual feed paper.\n\
	-nopage: Do not print page number and date.\n\
	-h23:	Set English font as Helvetica-Bold (def: Courier, see menu).\n\
	-size=14.5: Char size 14.5 points.\n\
	-rm(lm)(tm)(bm)=12.3: Paper margin (right, left, top, bottom) \
12.3mm\n\
	-a4(letter)(legal)(a3): Paper size A4 (Letter)(Legal)(A3).\n");

	fprintf(errout, "Press RETURN key to continue\n");
	n=getchar();
	fprintf(errout,
"	-env:	Envelope mode (-envs: small size envelope) (*).\n\
	-label: Print address label, also set manual feed (*).\n\
	-bk(4): Booklet format with 2 (4) columns.\n\
	-fpg(5): Start new page for new input file (if 5 lines to bottom).\n\
	-j:     Adjust bottom margin if more than one column (*).\n\
	-p4:    Print/convert 4 pages at a time.\n\
	-tab:   TAB mode: 4 CJKs <-> 8 ASCIIs, default CJK (ASCII if -aa)\n\
	-f:	Two-sided format (but does not print on both sides!)\n\
	-short: Convert PS file, long lines to short lines\n\
	-extr:  Extract/print selected pages in a PS file\n\
	-euro:  Disable <-> enable ability of printing European chars.\n\
	-n74:   Chars per line N 74 (Hz<->GB, JIS/KSC pre-processing *).\n\
	-bmps4 0xa1a2 (0xa1a5) -r/l/t/b: Shift bitmap to right/left/\
top/bottom\n\
		by 4 pixels for char 0xa1a2 (to 0xa1a5) (*).\n\
	-n=256: # of chars in CNdict (default 2048) (*).\n\
	-r=600: Device resolution 600 dpi (default 300).\n\
	-ttt:   Word freq statistics excluding \
(-tttt: including) symbols.\n");
	fprintf(errout, "Press RETURN key to continue\n");
	n=getchar();
	fprintf(errout,
"  Repair functions:\n\
	-zzz:   Filter out functional sequence like @[**].\n\
	-r1:    -zzz + ignore EOL when # of char per line > N and < M.\n\
	-r2:    -zzz + ignore EOL when # of char per line <= N.\n\
	-n68(-m120): set N=68 or M=120 (default: N auto-select, M 100).\n\
	-r6:    -r1 + ignore one of two consecutive EOLs (newline char).\n\
	-r7(-r8): -zzz + add (del) space before Chinese char (for CStar).\n\
	-r3:    -zzz + make # of spaces at beginning of a line to be 4.\n\
	-r4:    -r3, even there was no space there.\n\
	-s:     (when r1, r2, r6) also ignore Space\n\
	-p:     (when r1, r2, r6) match quotation marks.\n\
	-m:     (when r1, r2, r6) map .,:;?! etc to CJK ones.\n\
	-a:     Map double-byte letters, digits to English ones.\n\
	-t(-tx): (when r1, r2, r6) ignore 'x' (default: '>') in news reply.\n\
	-e:     (when r1, r2, r6) do NOT ignore EOL.\n\
	-k(-k90): (when -zzz or -r#) break big file into ~64K (90K) ones.\n\
	* See help file for details.\n");
	fprintf(errout,
"\n%s\nCopyright Yidao CAI 1992-1998, All Rights Reserved\n\
cai@neurophys.wisc.edu\n", Version);
/*      signature(); */
}

int isfs(s, pr)
unsigned char *s;
int pr;
{
	int j, k, HBFopen(), issfs();
	unsigned char c1, c2, st[6];
	void shade();

	c1=s[1]; c2=s[2];
	if (s[3]!=']' && c1!='L') {   /* not LBxx */
		if (c1!='M' || c2!='V' || s[9]!=']') return 0;
		if(suppress) return (suppress>=2)? 0 : 10;
		for (j=3; j<=8; j++) if (!isdigit(s[j])) return 0;
		j = 100*(s[3]-'0') + 10*(s[4]-'0') + (s[5]-'0');
		k = 100*(s[6]-'0') + 10*(s[7]-'0') + (s[8]-'0');
		endAC(pr);
		if (pr && k!=1) V = k/ppd;
		if (j!=1) H = j/ppd;
		return 10;
	}
	if (suppress) return (suppress>=2)? 0 : 4;
	switch(c1) {
/* line break */
	    case 'B':
		if (c2=='R') {
			clearascbuf(pr, 1);
			newline(pr, 1);
		}
		return 4;
/* C: column number */
	    case 'C':
		if (c2=='B' || c2=='b' || c2=='E') {
    /* Central adjust Begin/End */
			if (c2=='E') centraladj=0;
			else centraladj = (c2=='B')? 1:2;
			return 4;
		}
		if (!pr) return issfs(c1, c2);
		if (!isdigit(c2)) return 0;
		k = (c2=='0')? defcolumn : (c2-'0');
		PCN++;
		if (PCN==1) {
			if (column==1 && k==1) PCN=SCN=0;
			return 4;
		}
		else {
		    column = k;      /* set search mode for next one */
		    fnewline = 1;
		    sline = 0;  pline = 1;
		    if (V < cBM) V = cBM; cBM = BM;
		    H = cLM = LM;
		    if (column > 1) {
			SCN = 1; PCN = 1; cTM = V;
			cRM = LM + columnWidth();
		    }
		    else {
			SCN = 0; PCN = 0;
			cRM = RM; cTM = TM;
		    }
		}
		return 4;
/* DF: use default settings for font, size, line and char spaces... */
	    case 'D':
		if (c2 != 'F') return 0;
		strcpy((char *) st, "[F0]"); isfs(st, pr);
		strcpy((char *) st, "[00]"); isfs(st, pr);
			/* Cx, Cy: changes Ci! so XY must be before I0 */
		strcpy((char *) st, "[XY]"); isfs(st, pr); 
		strcpy((char *) st, "[I0]"); isfs(st, pr);
		strcpy((char *) st, "[A0]"); isfs(st, pr);
		return 4;

/* ASC font */
	    case 'h': case 'H': case 'q': case 'Q':
		if (!isdigit(c2)) return 0;
		k=nEF;
		nEF=c2-'0';
		if (isupper(c1)) nEF += 20;
		if (c1=='q') nEF += 10;
		getEfontdata();
		nEFs[nEF]++;
		if (pr && nEF!=k) PSctrl();
		return 4;
/* CH font */
	    case 'f': case 'F': case 'v': case 'V':
		if (!isalpha(c2) && c2 != '0') return 0;
		if (!pr) return 4;
		if (c2 == '0') {
			strcpy(HBFname, defHBFname);
			HBFclose(); HBFopen(); defFont = 1;
			PSctrl();
			return 4;
		}
		k = (isupper(c1))? 1:0;
		k += (isupper(c2))? 1:0;
		switch(k) {
			case 0: j = (toupper(c1)=='F')? 16:40; break;
			case 1: j = (toupper(c1)=='F')? 24:56; break;
			case 2: j = (toupper(c1)=='F')? 48:64; break;
			default: break;
		}
		sprintf(HBFname, "cn%s%c%d.hbf",
((lcode==B5)? "5" : ((lcode==JIS) ? "j" : ((lcode==KSC)? "k" : "")) ),
tolower(c2), j);
		if (lcode==UTF)
		    sprintf(HBFname, "cnu%c%d.hbf", tolower(c2), j);
		HBFclose();
		if (!HBFopen()) {
			strcpy(HBFname, defHBFname);
			insertEOL();
			fprintf(errout, "Default font used\n\n");
			HBFopen();
		}
		defFont= strcmp(defHBFname, HBFname)? 0:1;
		PSctrl();
		return 4;
/* shading */
	    case 'S':
		if (!isdigit(c2)) return 0;
		if (!pr) return 4;
		if (fshade) shade();
		fshade=(c2=='0')? 0:1;
		return 4;
/* gray */
	    case 'G':
		if (!isdigit(c2)) return 0;
		endAC(pr);
		if (pr && Prntpage)
			fprintf(out, "%3.1f setgray\n", gray=(c2-'0')/10.);
		return 4;
/* X, Y expansion */
	    case 'X': case 'Y':
		if (!isdigit(c2)) {
			if (c1=='X' && c2=='Y') {/* [XY], use default */
				Cx = defCx; Cy = defCy; 
			}
			else return 0;
		}
		else {
			if (c1=='X') { Cx = 1.+(c2-'0')/10.; Cy=1.;}
			else { Cy = 1.+(c2-'0')/10.; Cx=1.;}
		}
		Ci = (Cx+Cy < 2.01)? defCi: (Cy+(Cx-1.)/2.);
		if (!pr) return issfs('0'+ptspc/10, '0'+ptspc%10);
		PSctrl();
		return 4;
/* E: ASC width, line and char space; EP: EPS */
	    case 'E':
		if (!isdigit(c2) && c2!='P') return 0;
		if (c2!='P') {
			Casc = (c2=='0')? Casc : (c2-'0')/10.;
			if (!pr) return issfs('0'+ptspc/10, '0'+ptspc%10);
			PSctrl();
		}
		else {
			endAC((int) (pr && Prntpage));
			if (pr && Prntpage) {
				fprintf(out,"%d %d Q ", BM-V, H);
				IncludeEPS("");
				PSctrl();
			}
		}
		return 4;
/* line and char spaces, and envelope */
	    case 'I': case 'A':
		if (!isxdigit(c2)) {
		    if (c1=='A' && (c2=='S' || c2=='R')) {
		/* Envelope, S/R addresses of sender and receiver, move left
		   margin to right by 3.25/2 inch if AR, restore if AS */
			if (pr) return 4;
			j = ((envelope==2)? 2:3.25) * 72./ppd;
			if (c2=='R') {
			    LM += j; V = 1.25*72/ppd;
			}
			else if (LM>=j) LM -= j;
			H = cLM = LM;
			return 4;
		    }
		    else return 0;
		}
		if (c1=='I') Ci= (c2=='0')?
			defCi : (isdigit(c2)? (c2-'0')/10. : (c2-'a'+1) );
		else Ca= (c2=='0')?
			defCa : (isdigit(c2)? (c2-'0') : c2-'a'+10);
		if (!pr) return issfs('0'+ptspc/10, '0'+ptspc%10);
		PSctrl();
		return 4;
	    case 'P':
		if (!isdigit(c2)) return 0;
		if (!pr) return 4;
		j = c2-'0';
		if (!j || (BM-V)/CLP<=j) {
			V=BM; pline--; newline(1, 0);
		}
		return 4;
	    case 'L':
		if (c2!='B' || lbas==NULL) return 0;
		s += 3; j=0;
		if (strncmp((char *) s, "AS]", 3)==EQ) {
			if (!pr) return 6;
			s += 3;
			while (*s && j<LBASMAX) {
			    if (*s != '@') lbas[j++] = *s;
			    else if (strncmp((char *) s, "@[LB", 4) != EQ)
				lbas[j++] = *s;
			    else break;
			    s++;
			}
			lbas[j]='\0';
			return (6+j);
		}
		else if (pr) {  /* @[LB] or @[LBxx] */
			j=3;
			if (s[0]==']') { lbn++; j=1; }
			else lbn = (s[0]-'0')*10 + (s[1]-'0');
			if (lbn > (k=lbnx*lbny)) {
				lbn -= k;
				V=BM; pline--; newline(1, 0);  /* new page */
			}
			k = lbn-1;
			H=cLM = ((k/lbny)*lbxinc + lbxp - .1)*72/ppd;
			V = ((k%lbny)*lbyinc + lbyp - .1)*72/ppd;
			return 3+j+insert_addrAS(s+j);
		}
		return 6;
/* underline */
	    case 'U': case 'u':
		if (c2!='B' && c2!='E') return 0;
		if (!pr) return 4;
		if (c2=='B') {
			UDline.x = H; UDline.f = 1;
			if (c1=='u') UDline.f = 2;     /* broken line 10:7 */
		}
		else {
			endAC(pr);
			UDline.f = 0;
		}
		return 4;
	    default:
		if (!isdigit(c1) || !isdigit(c2)) return 0;
/* char size */
		if (!pr) return issfs(c1, c2);
		ptspc = (c1-'0')*10 + (c2-'0');
		PSctrl();
		return 4;
	}
}

insert_addrAS(s) /* insert sender's address: since this is one column
  * operation, inserting something would not confuse sline/pline */
unsigned char *s;
{
	int     j, k, n;
	n = strlen((char *) lbas);
	if (n==0) return 0;
	k = (int) (s - buf);
	if (k<n) return 0;      /* something is wrong, do not insert */
	for (j=0; j<n; j++) buf[j]=lbas[j];	/* insert */
	while (buf[j++] = *s++) ;               /* copy */
	return (-k);
}

int issfs(c1, c2)
unsigned char c1, c2;
{
	int k, span();
	float y;
	switch(c1) {
/* C: column number */
	    case 'C':
		if (!isdigit(c2)) return 0;
		k = (c2=='0')? defcolumn : (c2-'0');
		SCN++;
		if (SCN==1) {
			column = k;
			if (column==1) PCN=SCN = 0;
			cTM = V;
			cRM = LM + columnWidth();
		}
		else {
			cBM=span(1);
			cLM  = LM;
			pcolumn = 1;
		}
		return 4;
	    default:
		if (!isdigit(c1) || !isdigit(c2)) return 0;
/* char size */
		k = (c1-'0')*10 + (c2-'0');
		if (k>=100 || k<=0) { y=defpts; ptspc=pts0;}
		else y=ptspc=k;   /* ptspc for print has been saved */
		charsize(y);
		  /* size ctrl at the beginning of a line, take it */
		if (column==1) {
			if (H==LM || CLP > 1.2*clptmp) {
				V += (CLP - maxCLP);
				maxCLP = CLP;
			}
		}
		else if (H==LM || CLP > 1.2*clptmp) {
			if (sline==0) V += (CLP-lineclp[sline+1]);
			lineclp[sline+1] = CLP;
/* fprintf(errout, "SS: lineclp[%d] = %d\n", 1+sline, lineclp[1+sline]);*/
		}
		return 4;
	}
}

void shade()
{
	endAC(0); ;
}

underline()
{
	int y;

	if (vertical) {
		y = ((ptspc==pts0)? defpts : ptspc)*Cy*Cw/ppd + .1;
		y += BM-V+CLP/9;
	}
	else y = BM-V-CLP/9;
	fprintf(out, "%d %4.1f %d %d %d UDline\n",
		UDline.f-1, pts/4, H-UDline.x, UDline.x, y);
	UDline.x = H;
	return 1;
}

void endAC(pr)
int pr;
{
	if (!inCH) {
	    if (pr && Prntpage) {
		clearascbuf(1, 0);
		fprintf(out,") S\n");
	    }
	    inCH=100;
	}
	if (UDline.f && pr && Prntpage) underline();
	newpos=1; ascbuf.p=0;
}

clearascbuf(pr, clearall)
int pr, clearall;
{
	int j, k, n=0, c;
	k = clearall? ascbuf.p : ascbuf.pp;
	if (ascbuf.p<ascbuf.pp) k=0;
	if (pr && Prntpage && k>0) {
	    for (j=0; j<k; j++) {
		c=ascbuf.s[j];
		if (c<' ' || c>=128) {
		    n+=3; fprintf(out, "\\%03o", c);
		}
		if (c=='(' || c==')' || c==92) {
		    n++; fprintf(out, "\\%c", c);
		}
		else fprintf(out, "%c", c);
		n++;
		if (n>75 && c==' ' || n>78) {
		    n=0; fprintf(out, "\\\n"); /* break line */
		}
	    }
	}
	if (!clearall && ascbuf.p != ascbuf.pp && ascbuf.p)
	    for (j=ascbuf.pp; j<ascbuf.p; j++)
		ascbuf.s[j-ascbuf.pp] = ascbuf.s[j];
	ascbuf.p = 0;
	return 1;
}

void convers(convOnly)
int convOnly;
{
	void    hz2gb(), gb2hz(), zw2gb(), jis2jis8(), ksc2ksc8(), FName();
	static char *st1[]={"", "Hz --> GB", "GB --> Hz", "", "zW --> GB",
		"", "Trying to repair", "JIS Pre-Processing",
		"HZ+ --> GB", "HZ+ -->B5", "KSC7 --> KSC8",
		"UTF7 --> 2-byte unicode", "UTF8 --> 2-byte unicode",
		"CNS --> BIG5", "GB --> BIG5", "",
		"BIG5 --> GB", "", "Long lines --> short lines", 
		"Print/extract selected pages", "", ""};
	static char *st2[]={"", "GB", "Hz", "Filtered/Repaired", "GB",
		"8-bit", "Repaired", "7-bit JIS", "GB", "BIG5",
		"8-bit", "2-byte", "2-byte", "BIG5", "BIG5", "",
		"GB", "", "Short version", "Selected pages", "", ""};
	static char ki[]="$B", ko[]="(B";
	char    st[6], s[80];
	FILE    *in;

	if (convcode==FIL) {
		strcpy(st, "NEW");
		if (breakfile) sprintf(st, "%d", filecount++);
	}
/* convcode=FIL, GB/B5/JIS-->GB/B5/JIS, no action here */
	else {
	    fprintf(errout, "%s ...\n", st1[convcode]);
	    inf=Rinf; sbufp=0;
	    while ((in = inf->fp) != NULL) {
		if (inf != Rinf) fputc(EOL, out);
		switch (convcode) {
			case HZGB: case HZPGB: case HZPB5:
				hz2gb(in);
				strcpy(st, (convcode==HZPB5)? B5str : GBstr);
				break;
			case GBHZ: gb2hz(in); strcpy(st, HZstr); break;
			case ZWGB: zw2gb(in); strcpy(st, GBstr); break;
			case CNSB5: cns2b5(in); strcpy(st, B5str); break;
			case B5GB:
				gbb5conv(in, B5GB); strcpy(st, GBstr);
				break;
			case GBB5:
				gbb5conv(in, GBB5); strcpy(st, B5str);
				break;
			case JIS8: jis2jis8(in); strcpy(st, "JS8"); break;
			/*case KSC8: ksc2ksc8(in);strcpy(st, "KS8"); break;*/
			case JISRP: /*jisrepair(in);*/strcpy(st, "RP");break;
			case JISCVT:
			    switch (code) {
				case JIS:  seven2seven(in, ki, ko); break;
				case EUC:  euc2seven(in, ki, ko);   break;
				case SJIS: shift2seven(in, ki, ko); break;
				default: break;
			    }
			    strcpy(st, "JS7");
			    break;
			case UTF8TOUNI: case UTF7TOUNI:
			    to2byte_unicode(in); strcpy(st, "u2"); break;
#ifdef PSPRINT
			case TOSHORTPS:
			    toshortline(in); strcpy(st, "sht"); break;
			case PAGEPRINT:
			    pageprint(in); strcpy(st, "pps"); break;
#endif
			default: break;
		}
		fclose(in);
		if (convcode==JIS8) remove(inf->s);
		inf->fp=NULL;
		if ((inf=inf->p) == NULL) break;
	    }
	    inf=Rinf;
	}
	if (ferror(out)) {
		fprintf(stderr, "%s version write error: %s\n",
			st2[convcode], tempfile);
		bell(); exit(-5);
	}
	fclose(out);
	if (convOnly) {
	    strcpy(s, PSfile);
	    if (*PSfile==0) {
		strcpy(PSfile, Rinf->s); FName(PSfile, st);
	    }
	    else if (breakfile) FName(PSfile, st);
	    if (convOnly==10) {	/* PSPRINT functions */
		outputToDev(tempfile);
	    }
	    else {
		if (stdoutput) outputToStdout(tempfile);
		else {
			RE_name(tempfile, PSfile);
			fprintf(errout, "%s version: %s\n",
				st2[convcode], PSfile);
		}
		if (breakfile && convOnly==100) {
			opnfile(OUT); strcpy(PSfile, s);
		}
	    }
	}
	else {
		FName(Rinf->s, st);
		RE_name(tempfile, Rinf->s);
		opnfile(IN); opnfile(OUT);
	}
}

to2byte_unicode(in)
FILE *in;
{
	unsigned short  unichar;
	if (convcode==UTF7TOUNI)
	    while ((unichar=utf7_getc(in)) != (unsigned short) EOF) {
		u2byte((int) (unichar/256)); u2byte((int) (unichar%256));
	    }
	else
	    while ((unichar=utf_getc(in)) != (unsigned short) EOF) {
		u2byte((int) (unichar/256)); u2byte((int) (unichar%256));
	    }
	return 1;
}

u2byte(c1)      /* output "escaped" u2 byte */
int c1;         /*#define U2ESC 0x4D, U2ESC2 0x21, ESCs for 2-byte unicode: */
{               /*      4D4D = 4D, 4D21 = 00 */
	switch (c1) {
	    case 0x00:
		fputc(U2ESC, out); fputc(U2ESC2, out);
		break;
	    case U2ESC:
		fputc(U2ESC, out); fputc(c1, out);
		break;
	    default: fputc(c1, out); break;
	}
	return 1;
}

void jis2jis8(in)       /* 0x21-0x7E --> 0xA1-0xFE */
FILE *in;
{
	int state, c1, c2, k=0;

	state = OUT;
	sbufp=0;
	while ((c1=sgetc(in)) != EOF) {
	    if (c1 == ESC) {
		c2 = sgetc(in);
/* ESC$B <ESC$@>, ESC(B for New & old JIS */
		if (c2 == '$' || c2 == '(') {
		    c1 = sgetc(in); k+=3;
		    if (c1=='B') state = (c2=='$')? IN : OUT;
		    else {
			sungetc(c1); sungetc(c2); k-=2;
			if (state==OUT) {       /* else eat ESC */
			    fputc(ESC, out);
			}
		    }
		}
		else {  /* if IN, bad ESC, ignore */
			sungetc(c2); k++;
			if (state==OUT) fputc(ESC, out);
		}
	    }
	    else if (state==IN) {
		c2 = sgetc(in);
		fprintf(out,"%c%c", c1+128, c2+128);
		k+=2;
	    }
	    else if (k<nHzline-2 || c1!=EOL) {
		k++; fputc(c1, out);
		if (c1==EOL) k=0;
	    }
	    else k=0;
	}
}

void hz2gb(in)
FILE *in;
{
	int state, c1, c2, k=0;

	state = OUT;
	sbufp=0;
	while ( (c1=sgetc(in)) != EOF) {
	    if (c1=='~') {
		k+=2;
		if ( (c2=sgetc(in)) == '{') state = IN;
		else if (c2 == '}') state = OUT;
		else if (c2 == '~') fputc(c2, out);
		else if (c2==EOL) {
			state=OUT; k=0;
		}
		else if (state==OUT) {
			fprintf(out, "%c", c1);
			k--; sungetc(c2);
		}
		else {  /* may be more likely to be '~}' ? */
			if (!mute) fprintf(errout, 
				"Bad code : 0x%02X%02X\n", c1, c2);
			fprintf(out, "%c%c", MSBon(c1), MSBon(c2));
		}
	    }
	    else {
		if (state >= IN && c1 != EOL) {
		    c2 = sgetc(in);
		    if (c2==EOL) {	/* bad code, turn c1 to 7-bit */
			if (!mute) fprintf(errout, 
				"Bad code: 0x%02X%02X\n", c1, c2);
			fprintf(out, "%c", MSBoff(c1));
			state=OUT; k=0;
		    }
		    else if (c2=='~') {
			/* "#~{" or "#~}": since '{' or '}' is not valid
			    first byte, more likely to be "~{" or "##~{".
			    this correction is optional */
			c2=sgetc(in); sungetc(c2);
			if (c2=='{' || c2=='}') {
			    sungetc('~');
			    fprintf(out, "%c", c1);
			}
			else {
			    fprintf(out, "%c%c", MSBon(c1), MSBon('~'));
			    k+=2;
			}
		    }
		    else {
			fprintf(out, "%c%c", MSBon(c1), MSBon(c2));
			k+=2;
		    }
		}
		else if (k<nHzline-2 || c1!=EOL) {
		    /* do not set MSB off, euro or pure GB? */
			fputc(c1, out);
			k++;
			if (c1==EOL) {
			    state=OUT; k=0;
			}
		}
		else k=0;  /* eat this EOL */
	    }
	}
}

void gb2hz(in)
FILE *in;
{
	int state, c1, c2, k=0, nGB=0;

	if (nHzline>100) nHzline=76;
	state = OUT;
	while ((c1=fgetc(in))!=EOF) {
/* GB1 */   if (c1>=0xA1) {
		if ((c2=fgetc(in))==EOF) break;
/* GB2 */       else if (c2>=0xA1) {
		    nGB++;
		    if (state==OUT) {
			if (k >= nHzline-2) { fprintf(out, "~\n"); k=0; }
			fprintf(out, "~{"); state=IN; k+=2;
		    }
		    else if (k >= nHzline-4) {fprintf(out, "~}~\n~{"); k=2;}
		    fprintf(out, "%c%c", MSBoff(c1), MSBoff(c2));
		    k+=2;
		}
		else {
/* keep bad code as it is */
		    if (!mute) fprintf(errout, 
			"Probably bad code: %02X%02X\n", c1, c2);
		    if (state==IN) {
			fprintf(out, "~}"); state=OUT; k+=2;
		    }
		    if (k >= nHzline-1 && c1!=EOL && c2!=EOL)
			{ fprintf(out, "~\n"); k=0; }
		    fprintf(out, "%c%c", c1, c2);
		    k+=2;
		    if (c1==EOL) k=1;
		    if (c2==EOL) k=0;
		}
	    }
	    else {
/* ASCII */     /*  may also be euro char */
		if (c1>=0x80) fprintf(errout, "Probably bad code: %02X\n",c1);
		if (state==IN) {
			fprintf(out, "~}"); state=OUT; k+=2;
		}
		if (k >= nHzline-1 && c1!=EOL) { fprintf(out, "~\n"); k=0; }
		fputc(c1, out);
		if (c1==EOL) k=0;
		else if (c1=='\t') { k/=8; k = (k+1)*8; }
		else k++;
	    }
	}
	if (state==IN) fprintf(out, "~}");
	if (!nGB) fprintf(errout, "Input may not be a GB file\n");
}

void zw2gb(in)
FILE *in;
{
	int c1, c2, zW=0, Newline=1;

	while ((c1=fgetc(in)) != EOF)
	    if (!zW) {
		if (c1==EOL) {
		    fputc(EOL, out);
		    Newline=1;
		}
		else if (Newline && c1=='z') {
		    if ((c2=fgetc(in)) == EOF) {
			 fputc(c1, out); break;
		    }
		    else if (c2=='W') zW=1;
		    else fprintf(out, "%c%c", c1, c2);
		    Newline = 0;
		}
		else {
		    fputc(c1, out);
		    Newline = 0;
		}
	    }
	    else if (c1=='\n') {
		zW=0; Newline=1; /* soft CR */
	    }
	    else { /* zW mode */
		if ((c2=fgetc(in)) == EOF) {
		    fputc(MSBon(c1), out);
		    break;
		}
		else if (c2=='\n') {
		    zW=0; Newline=1;
		    if (c1=='#') fputc(EOL, out);
		    else fprintf(out, "%c\n", MSBon(c1)); /*invalid zW seq.*/
		}
		else if (c1=='#' && c2==' ') fputc(' ', out);
		else if (c1==' ') fputc(c2, out);
		else fprintf(out, "%c%c", MSBon(c1), MSBon(c2));
	    }
}

int span(m)
int m;
{
	int x, y, n, j, k=1;
	if (m==0) {
		x = BM-V+lineclp[0]; y=0;
		for (j=1; j<=sline; j++) {
			y += lineclp[j];
			if (y >= x) {
				y=0; j--; k++;
			}
		}
		return (k>column)? 1:0;
	}    /* end of document */
	else if (m==10 && AdjAtEndDoc) return BM;
	else {
		n=1; x=lineclp[0];
		do {
			x += lineclp[n++];
			y=0; k=1;
			for (j=1; j<=sline; j++) {
				y += lineclp[j];
				if (y >= x) {
					y=0; j--; k++;
				}
			}
			if (k<=column && y<x) return
			    ((x-lineclp[0]+cTM)>BM)? BM :(x-lineclp[0]+cTM);
		} while (k>column);
	}
}

ishz(c)
{
	if (c==EOL && nHzline>=10000) nHzline++;
	return (c=='{' || c=='}')? 1 : 0;
}

int chperline(N, Hz)  /* non-wrap, find a nHzline */
int N, Hz;
{
	int j, k, m;

	if (nHzline<9999) return nHzline;
	if (Hz && convcode==HZGB) { /* 1% lines has ~\n */
	    if ((nHzline-10000.)*200./Hz >= 2) return nHzline;
	}
	m=0;
	for (j=0; j<=150; j++) m += linedif[j];
/* long lines: # of lines < # of chars/100 or 20% lines have 150+ chars */
	if (m < N/100 || m < linedif[150]*5) return 9999;
		/* if 25% lines are N to N+3 chars long, set it */
	for (j=0; j<=40; j++)
	    for (k = -1; k<=1; k+=2) {
		N = 75 + j*k;
if ((linedif[N]+linedif[N+1]+linedif[N+2]+linedif[N+3]) > m/4)
			return N - (1-k);
	    }
	return 9999;
}

void prescan(topr)
int topr;       /* >0: print next; <0 NO print next; 0: undecided */
{
    int    c1, c2, Hz=0;
    unsigned int i, k, m=0, n=0, N;
    unsigned int Addr();
    void   FName(), Addchar();
    FILE   *in;

    if (nHzline==9999) nHzline=10000;
    for (i=0; i<nchar; i++) fstring[i]=0;
    if (!mute || convcode==FIL) fprintf(errout, "Scanning document(s) ...\n");
    inf=Rinf; sbufp=0;
    while ((in = inf->fp) != NULL) {
	if (!mute || convcode==FIL) fprintf(errout, " %s\n", inf->s);
	while ((c1=sgetc(in))!=EOF) {
	    if (lcode==UTF) {
		if (c1==U2ESC) {
			if ((c1=sgetc(in))==U2ESC2) c1=0x00;
		}
		if ((c2=sgetc(in))==EOF) break;
		else if (c2==U2ESC) {
			if ((c2=sgetc(in))==U2ESC2) c2=0x00;
		}
		if (c1>=b1l) Addchar(c1, c2);
	    }
	    else if (c1>=b1l) { /* b1l=0xa1 or 0x30 if utf */
		    m+=2;
		    if ((c2=sgetc(in))==EOF) break;
		    else if (c1==0xa3 && lcode==GB &&
			alnumadjust && isalnum(c2-128)) continue;
		    else if (c2>=cspace%256) Addchar(c1, c2);
		    else if (c2=='~' && lcode<JIS) sungetc(c2);
		    /*if (c2<=0x7E && lcode!=JIS && lcode!=KSC) b5=1;*/
	    }
	    else if (c1=='~' && lcode<JIS) {
		    c2=sgetc(in);
		    if (ishz(c2)) {Hz++; m+=2;}
		    else sungetc(c2);
	    }
	    else if (c1==EOL) { /* used to determine nHzline */
		linedif[(m<150)?m:150]++;
		n += m; m=0;
	    }
	    else m++;
	    if (vgb) if (isvgb(c1)) fstring[2*94+c1-32]++;
	}
	rewind(in);
	if (inf->p == NULL) break;
	else inf = inf->p;
    }
    inf=Rinf;
    if (convcode || (lcode==JIS && topr<=0)) nHzline=chperline(n, Hz);
    if (topr<0) return;
    if (!Hz || topr>0 || lcode>=B5) {
	fstring[0]=0; N=m=n=0;
	if (timestat==3) {
		/* Do not count symbols, Hanzi only */
		k = (lcode==B5)? Addr(0xa4, 0x40) : /* change b1l for utf */
		    ((lcode!=UTF)? Addr(0xB0, 0xA1) : Addr(b1l, 0x00));
		for (i=0; i<k; i++) fstring[i]=0;
	}
	for (i=0; i<nchar; i++)
	    if (fstring[i]) {
		m += fstring[i]; N++;
		if (fstring[i]==1) n++;
	    }
	if (!mute || convcode==FIL) fprintf(errout,
"There are %d different %s words (%d total) in the document(s)\n", N,
((lcode==JIS) ? "Japanese" : ((lcode==KSC)? "Korean" : "Chinese")), m);
	if (timestat>=3) statistics(N, m);
	if (nCN>N-n) nCN=N-n;
	m=N; n=0;
	if (N>0) {
	    if (fdict!=NULL) free(fdict);
	    fdict = (unsigned int *) calloc(N, sizeof(unsigned int));
	    if (fdict==NULL) MemExit();
	    while (++n) {
		if (m<=0) break;
		for (i=1; i<nchar; i++)
		    if (fstring[i]>0 && fstring[i]<=n) {
			fdict[--m]=i; fstring[i] += 30000;
			if (m==0) break;
		    }
	    }
	    if (nCN>0) for (m=0; m<nCN; m++) fstring[fdict[m]] = m+60000;
	    if (nCN<N) for (m=nCN; m<N; m++) fstring[fdict[m]] -= 29900;
	}
	if (*PSfile==0) {
		strcpy(PSfile, Rinf->s);
		FName(PSfile, PSstr);
	}
    }
}

int yes(n)
int n;
{
	char s[40];
	if (stdinput) return n; /* can't read from keyboard, use default */
	do {
		if (n>1) bell(); gets(s);
		if ((toupper(s[0]))=='Y') return 1;
		else if ((toupper(s[0]))=='N') return 0;
		else if (n<=1) return n;
		else s[0]='\0';
		fprintf(errout, "(Y/N) ?\n");
	} while (s[0]=='\0');
}

void Addchar(c1, c2)
int c1, c2;
{
	unsigned int ad;
	ad=Addr(c1, c2);
	fstring[ad]++;
	if (timestat<3) wordstat(ad);
	else return;
}


#ifdef STAT   /* start STAT functions */

#include "cnstat.h"

#else  /* No STAT functions */

statinit()
{
	fprintf(stderr,
"Functions supported by enhanced version only\n\
Please contact author\n");
	cleanup(1); exit(0);
	return 1;
}

wordstat(d)
unsigned int d;
{
	return 1;
}

statistics(Nchars, NcharAll)
unsigned int Nchars, NcharAll;
{
	return 1;
}

CharBMPshift()
{
	return statinit();
}

int CharBitmapShift(fp, addr, a)
FILE	*fp;
unsigned char *a;
{
	unsigned char *c, ON[8];
	int     j, k, n;

	ON[0]=128;
	for (j=1; j<8; j++) ON[j]=ON[j-1]/2;
	c = (unsigned char *) calloc(CHsize+1, sizeof(unsigned char));
	if (c==NULL) MemExit();

	for (j=0; j<CHsize; j++) c[j]=0;
	switch (bmpshift_dir) {
	    case RMIRROR:     /* rotate a mirror bitmap:
				 matrix transpose, Cij = Aji */
		for (j=0; j<CHsize; j++) {
			c[j]=0;
			for (k=0; k<8; k++) {
			    n = k*mx +j*my*8; n = n/(mx*my) + n%(mx*my);
			    if (a[n/8] & ON[n%8]) c[j] += ON[k];
			}
		}
		for (j=0; j<CHsize; j++) a[j]=c[j];
		break;
	    default: break;
	}
	free(c);
	return 0;
}

#endif  /* end STAT functions */

void putascstr(s, pr)
char *s;
int pr;
{
	if (pr) while (*s) putASC(*s++, *s, 1);
	else fprintf(out, "%s", s);
}

int gbb5convinit(dirc)
int     dirc;   /* GBB5 or B5GB */
{
	FILE    *in;
	int     j;

	nchar = (dirc==GBB5)? 8178: 13973;      /* 'standard' GB/B5 only */
	cspace = (dirc==GBB5) ? 0xA140 : 0xA1A1;
	b1l = cspace/256;

/*  fstring holds index of char mapping to, 30000 means no data;
 *  ptstring holds mapping data: "GBGB B5B5\n", maximum 7-char word/phrase,
 *  NULL means no data
 */
	if (fstring!=NULL) free(fstring);
	if (ptstring!=NULL) {
		for (j=0; j<nchar; j++) if(ptstring[j]!=NULL) free(ptstring[j]);
		free(ptstring);
	}
fstring = (unsigned int *) calloc(nchar+1, sizeof(unsigned int));
ptstring= (unsigned char **) calloc(nchar+1, sizeof(unsigned char *));
	if (fstring==NULL || ptstring==NULL) MemExit();
	for (j=0; j<nchar; j++) {
	    fstring[j] = 30000;
	    ptstring[j] = NULL;
	}

/* read in conversion table */
	j=0;
	if (strlen(KWfile)==0) getdata(5);
	if ((in=Rfopen(KWfile, "r")) == NULL) j++;
	else gbb5tableinit(dirc, in);
	if ((in=Rfopen(EPSfile, "r")) == NULL) j++;
	else gbb5tableinit(dirc, in);
	if (j==2) {
	    fprintf(errout, "Can't open GB<->B5 table file -> %s\n", KWfile);
	    exit(0);
	}
	return 1;
}

int gbb5tableinit(dirc, in)
int     dirc;   /* GBB5 or B5GB */
FILE	*in;
{
	unsigned char   *p, *t, cst[120];
	int     j, k1, k2, wordmap;

	while (fgets((char *) cst, 118, in)!=NULL) {
		/* MSB set for both GB and Big5, minimum line "GBB5\n" */
	    if (cst[0] < 0xA1 || strlen((char *) cst) < 5) continue;
	    p = &cst[0];
	    wordmap=0;  /* def: char mapping */
	    k1 = GBPOS(p[0], p[1]);
	    k2 = B5POS(p[2], p[3]);
		/* "GBGB B5B5\n", use space or tab as seperator, but change
		 * tab to space */
	    j=strlen((char *) p);
	    if (j >= 10) {
		while (*++p != '\0')
			if (*p == ' ' || *p == '\t') {
			    *p = ' ';
			    if (strlen((char *) p) >= 6) wordmap=1;
			    k2 = B5POS(p[1], p[2]);
			    break;
			}
		p = &cst[0];
	    }
	    if (k1<0 || k2<0) continue;  /* mapping line not complete */

/* word (phrase) mapping */
	    if (wordmap) {
		p[j-1] = ' '; p[j]='\0';
		if (dirc==B5GB) k1=k2;
	/* allow more than one pair  */
		if (ptstring[k1]!=NULL) j += strlen((char *)ptstring[k1]);
		t = (unsigned char *) calloc(j+1, sizeof(unsigned char));
			/* if not enough space, ignore current pair */
		if (t==NULL) continue;
		t[0]='\0';
		if (ptstring[k1]!=NULL) {
			strcpy((char *) t, (char *) ptstring[k1]);
			free(ptstring[k1]);
		}
		ptstring[k1] = t;
		strcat((char *) ptstring[k1], (char *) p);
/* fprintf(errout, "%6d :%s:\n       :%s:\n", k1, t, ptstring[k1]); */

 /*   only one pair is allowed: overwrite previous ones
		if (ptstring[k1]!=NULL) free(ptstring[k1]);
		ptstring[k1] = (unsigned char *)
				calloc(j+1, sizeof(unsigned char));
		if (ptstring[k1]==NULL) MemExit(0);
		else strcpy((char *) ptstring[k1], (char *) p);
  */
		continue;
	    }
/* else: char mapping, overwrite previous ones */
	    if (dirc==GBB5) fstring[k1]=k2;
	    else {
		fstring[k2]=k1;
		    /* multiple mapping possible */
		p += 4;
		while (strlen((char *) p) >=3) {
				/* always terminated with EOL */
			if ((k2=B5POS(p[0], p[1])) >= 0) fstring[k2]=k1;
			p += 2;
		}
	    }
	}
	fclose(in);
	return 1;
}

gbb5conv(in, dirc)
FILE    *in;
int     dirc;
{
	int     c1, c2, idx, matched;
	unsigned int ch;
	unsigned char *m, *p, *t, s1[45], s2[45];

	sbufp=0;
	while ((c1=sgetc(in)) != EOF) {
	    if (c1>=0xa1) {
		if ((c2=sgetc(in))==EOF) break;
		else if (c2>=0xa1 || (dirc==B5GB && c2>=0x40)) {
		    idx = (dirc==B5GB)? B5POS(c1, c2) : GBPOS(c1, c2);
/* consider word mapping first */
		    if ((m=ptstring[idx]) != NULL) {
			matched=0;
			while (strlen((char *)m) >= 9) {
			    p=m;
			/*  k=0; while ((s1[k] = *p++) != ' ') k++;
			    sscanf((char *) p, "%s", (char *) s2);
			    s1[k]=s2[strlen((char *) s2)+1]='\0';
			*/
			    sscanf((char *)p, "%s %s", (char *)s1, (char *)s2);
			/* advance pointer to next word pair */
			    m += strlen((char *) s1) + strlen((char *) s2) + 2;
			/* compare with current word pair */
			    p = (dirc==B5GB)? &s2[1] : &s1[1];
			    t = p+1;
			    while (*++p != '\0') {
				if ((c1=sgetc(in)) != *p) {
					sungetc(c1);
					while (--p >= t) sungetc(*p);
					break;
				}
			    }
			    if (p>t) {  /* words match, map word */
				p = (dirc==B5GB)? &s1[0] : &s2[0];
				while (*p != '\0')
				    fprintf(out, "%c", *p++);
				matched++;
				break;
			    }
			}
			if (matched) continue; /* while sgetc(in) loop */
			/* else words not match, map char */
		    }
/* one to one char mapping */
		    if (dirc==B5GB) {
			ch = (fstring[idx]==30000)? GBbox : fstring[idx];
			fprintf(out, "%c%c", GBB1(ch), GBB2(ch));
		    }
		    else {
			ch = (fstring[idx]==30000)? B5box : fstring[idx];
			fprintf(out, "%c%c", B5B1(ch), B5B2(ch));
		    }
		}
		else fprintf(errout, "Bad pair: %02X%02X\n", c1, c2);
	    }
	    else fprintf(out, "%c", c1);
	}
	return 1;
}

convertEOL(t, jmax) /* CR or CR-LF to LF, for a unified treatment */
unsigned char	*t;
int	*jmax;
{
	int	nc=0;	/* # of CR-LF converted to LF */
	unsigned char *s;

	s=t;
	while (*t = *s) {
		if (*s==CR) {
			*t = LF;
			if (*++s == LF) nc++;
			else s--;
		}  
		s++; t++;
	}
	*jmax -= nc;
}

main (argc, argv)
int     argc;
char    *argv[];
{
    int     j, jmax, c, endfile, buftoosmall;
    void    init(), style(), prescan(), header(), endpage();
    void    gbb5preproc(), jispreproc(), kscpreproc();
    unsigned char *s, *p, *doAC();
    unsigned int bufsz, bufused;
    float   Cis, Cas, Cascs, Cxs, Cys, ps;
    int     snEF, CSPs, CLPs, scnsp, sfrl, inCHs, sctradj;
    int	    conv_code;
    FILE    *in;

    mRinf=Rinf=NULL;
    buf=NULL;
    init(argc, argv);
    if (bmpshift) CharBMPshift();

    if (convcode!=FIL && breakfile>10) {
	mRinf = Rinf->p;
	Rinf->p = NULL;
    }

    if (convcode==FIL) {
	fprintf(errout, (fix)? "Repair ...\n" :
		"Filter out functional sequences ...\n");
/* prescan to find out a nHzline */
	if (nHzline==9999) prescan(-1);
	if (nHzline==9999 && fix!=2) nHzline=70;
	if (nHzline > 160 && fix==2) copies=nHzline=80;
	nchar=odd=0;
	if (copies==1) copies=100;
    }
    else if (convcode) {
	do {
	    conv_code = convcode;	/* save original convcode */
	    switch(convcode) {
	    case HZGB:
		if (nHzline==9999) prescan(0);
		break;
	    case HZB5:
		convcode=HZGB;
		if (nHzline==9999) prescan(0);
		convers(0);
		convcode=GBB5;
		gbb5convinit(GBB5);
		break;
	    case GBB5: case B5GB:
		gbb5convinit(convcode);
		break;
	    case B5HZ:
		convcode=B5GB;
		gbb5convinit(B5GB);
		convers(0);
		convcode=GBHZ;
		break;
	    case TOSHORTPS: case PAGEPRINT:  /* old PSPRINT function */
		convers(10);
		exit(0);
		break;
	    default: break;
	    }
	    convers(1);			/* 1, conversion only */
	    convcode = conv_code;	/* restore old original convcode */
	} while (OIOU((convcode==HZGB || convcode==HZB5)? 1: 0) != NT);
        if (stdinput) remove(Rinf->t);
	signature();
	exit(0);
    }
    style((convcode==FIL || mute)? 0:1);
    if (timestat>=3) statinit();

START2:
    if (!convcode) {
	if (lcode==JIS) jispreproc();
	else if (lcode==KSC) kscpreproc();
	else if (lcode==UTF) unicodepreproc();
	else gbb5preproc();
	prescan(1);
	if (!mute) fprintf(errout, "%s --> PS ...\n", codename[lcode]);
	header();
    }

    V=TM; H=LM;
    endfile=0;
    inf=Rinf; in=inf->fp;
    if (buf==NULL) {
	bufsz=BUFSIZE;
	buf = (unsigned char *) calloc(bufsz, sizeof(unsigned char));
	if (buf==NULL) MemExit();
    }
    buf[0]=fgetc(in); buf[1]='\0'; p = buf;
    while (p[0]!='\0') {
		/* reorganize buf */
	if (!endfile && strlen((char *) p) < bufsz-2048) {
	    j=0;
	    if (p != buf) while (buf[j++] = *p++) ;
	    jmax=strlen((char *) buf); j=bufsz-jmax-5;
	    while (--j) {
		if ((c=getc(in)) != EOF) {
			if (c!='\0') buf[jmax++]=c;
		}
		else {
		    fclose(in); inf->fp=NULL;
		    if (convcode==ZWGB || convcode==HZGB || convcode==JIS8)
			remove(inf->s);
		    if (inf->p == NULL) {
			endfile=1; break;
		    }
		/* else */
		    inf=inf->p;
		    if ((in = inf->fp) == NULL) {
			endfile=1; break;
		    }
		    else {
			if (breakfile && convcode!=FIL) {
			    buf[jmax++]='@'; buf[jmax++]='['; buf[jmax++]='P';
			    buf[jmax++]= '0'+(breakfile-1); buf[jmax++]=']';
			    j -= 5;
			}
			else {
			    buf[jmax++]=EOL; j--;
			}
		    }
		}
	    }
	    buf[jmax]='\0';
	    /*if (convcode!=FIL)*/ convertEOL(buf, &jmax);
	    p = buf;
	}
	s=p; H = LM;
/* save status variables that will be used and changed by search */
	Cis=Ci; Cas=Ca; Cascs=Casc; Cxs=Cx; Cys=Cy; ps=ptspc; snEF=nEF;
	CSPs = CSP; CLPs = CLP; scnsp=cnsp; sfrl=frl; inCHs=inCH;
	sctradj=centraladj;
	sline=fnewline=0;
	lineclp[0]=lineclp[1]=clptmp=CLP;
	frl=NT; cnsp=0; inCH=100; ascbuf.p=ascbuf.pp=0;
/* SEARCH */
	bufused = (unsigned int) (p - buf);
	buftoosmall = 0;
	for (;;) {
	    while (!fnewline && *s!='\0' && (s[1]!='\0' || endfile) )
		s=doAC(s, 0);
	    if (column==1 || SCN==2) break;
	    else if ( span(0) || (endfile && s[0]=='\0') ) {
		if (endfile && s[0]=='\0') {  /* see issfs  SCN=2 */
			if (s[-1]!=EOL) newline(0, 1);
			cBM=span(10);
		}
		else cBM = BM;
		cLM = LM;
		pcolumn = 1;
		break;
	    }
	    else if (!endfile && (s[0]=='\0' || (s[0]!='\0' && s[1]=='\0')) ) {
/* needs to recover all status variables */
		buftoosmall = 1;
		break;
	    }
	    fnewline = 0;
	}
	if (convcode==FIL) { p=s; continue;}
/* recover status variables */
	Ci=Cis; Ca=Cas; Casc=Cascs; Cx=Cxs; Cy=Cys; ptspc=ps;
	CSP = CSPs; CLP = CLPs; cnsp=scnsp; frl=sfrl; inCH=inCHs;
	centraladj=sctradj;
	ascbuf.p=ascbuf.pp=0;
	if (nEF != snEF) {
		nEF=snEF;
		if (!getdata(1)) for (j=0; j<129; j++) Wasc[j]=1.;
	}
	if (buftoosmall) {
		if (bufsz>MAXBUFSZ) MemExit();
		bufsz += 3072;
		buf = (unsigned char *) realloc(buf, bufsz);
		if (buf==NULL) MemExit();
		p = buf; p += bufused;
		continue;
	}
/* PRINT */
	pline=1; H=cLM;
	do {
	    fnewline=0;
	    while (!fnewline && *p!='\0' && (p[1]!='\0' || endfile) )
		p=doAC(p, 1);
	    if (column==1) break;
	} while (pline<=sline && *p!='\0');
    }
    if (convcode==FIL) {
	if (sbufp) sbufprint(EOL);
	convers(1);
    }
    else { 	/* last EOL is ignored, explicit action needed */ 
	if (ascbuf.p) { 
            clearascbuf(1, 1); endAC(1); 
	}
	endpage(1);
    }
    if (booklet) tobooklet();
    if (OIOU(1) != NT) goto START2;
    free(buf);
    cleanup(0);
    if (stdinput) remove(Rinf->t);
    signature();
    exit(0);
}

int OIOU(fstr_used) /* one input one output: multiple input, seperate output
	      Does not work for convcode=FIL because of "breakfile" */
int	fstr_used;
{
	int	j;

	if (fstr_used) {	/* re-initialize fstring and ptstring */
	    for (j=0; j<=nchar; j++)
		if (fstring[j]>0 && fstring[j]<60000) {
			if (ptstring[j]!=NULL) free(ptstring[j]);
			ptstring[j]=NULL;
		}
	}
	if (convcode!=FIL && breakfile>10 && mRinf!=NULL) {
		inf = Rinf = mRinf;
		mRinf = Rinf->p;
		Rinf->p = NULL;
	/* set to default values: there are others affected, not clean */
		init(999, NULL);
		opnfile(OUT);
		PSfile[0]='\0';
		code=codecmd;
		pgpd=0; pgcount=1;
		nCN=2048;
		return 1;
	}
	else return NT;
}

unsigned char *doAC(q, pr)
unsigned char *q;
{
	int     k, j=1;
	int     putCH(), putASC(), isfs();
	unsigned char c1, c2;

	c2=0; c1 = *q++;
	if (c1>=b1l) {  /* b1l=0xa1, or 0x30 if utf */
	    if (q[0]=='\0') ;
	    else {
		c2 = *q++;
		if (lcode==UTF) {  /* special handling for unicode */
		    if (c1=='@' && q[0]=='[') {  /* problem for unicode */
			if (k=isfs(q, pr)) { q += k; j=0; }
		    }
		    else if (c1==U2ESC) {
			c1=c2; c2=0;
			if (c1==U2ESC2) c1=0x00;
		    }
		    if (c2==0) c2 = *q++;
		    if (c2=='\0') ;
		    else {
			if (c2==U2ESC) {
			    if ((c2 = *q++) == '\0') j=0;
			    else if (c2==U2ESC2) c2=0x00;
			}
			if (c1>=b1l) j++;
			else { c1=c2; c2=0;} /* if byte 1 not 0x00, eat it */
		    }
		}
		else if (lcode!=B5 && c2>=0xa1) {
		    if (lcode==GB && alnumadjust) { /* also for JIS ? */
			if (c1==0xa3 && isalnum(c2-128)) c1=c2-128;
			else if (c1==0xa1 && c1==c2 && !inCH && *q>=c1)
				c1=0x20; /* ascii non-ascii_space ascii */
			else j = 2;
		    }
		    else j = 2;
		}
		else if (lcode==B5 && c2 >= 0x40) j = 2;
		else {q--; c2=0;}
	    }
	}
	else if (c1=='@' && q[0]=='[') {
		if (k=isfs(q, pr)) {
			q += k; j=0;
		}
	}

	if (j==2) k = putCH(c1, c2, pr);
	else if (j==1) {
	    if (c1==EOL && *q=='\0' && pr) k=0; /* Don't print the last EOL */
	    else if (!vgb || !isvgb(c1)) {
		k = putASC(c1, q[0], pr);
	    }
	    else k = putCH(0xa3, c1+128, pr);
	}
	else k=0;
	if (k==1 && c2!=0) k++;         /* (c1, c2) --> c1-128 */
	if (convcode==FIL && !k) k = filter(c1, (j==1)? q[0]:c2, q, j);
	return (q-k);
}

void MemExit()
{
	fprintf(stderr, "CNPRINT: not enough memory\n");
	exit(2);
}

FILE *Rfopen(fn, mod)
char *fn, *mod;
{
	char cst[100];
	struct Roots *rt;
	FILE *fp;

	rt=root;
	do {
		cst[0]='\0';
		if (rt!=NULL) strcpy(cst, rt->s);
		strcat(cst, fn);
/* fprintf(errout, "open: @%s@\n", cst);
*/
		if ((fp=fopen(cst, mod))!=NULL) return fp;
		if (rt!=NULL) rt = rt->p;
	} while (rt!=NULL);
	return NULL;
}

int filter(c1, c2, q, j)
unsigned char c1, c2, *q;
int     j;
{        /* filter */
/* now assumes CR or CR/LF has been converted to LF */
    int n=0, k;
    if (c1==LF && breakfile) {
	    if (fnchar >= (breakfile-2)*1024L) {
		convers(100);   /* save into small files */
		fnchar = 0;
	    }
    }
    switch(fix) {
	case 0:
		if (j==1) sbufprint(c1);
		else if (j==2) {
			sbufprint(c1); sbufprint(c2);
		}
		break;
	case 3: case 4:
	    if ((j==1 && (c1==' ' || c1=='\t')) || ((c1*256)+c2)==cspace) {
		for (k=0; k<j; k++) {
		    if (ignorespace!=nchar || (ignorespace==nchar && nchar<4))
			sbufprint(' ');
		    nchar++; ignorespace++;
		}
	    }
	    else {
		if (ignorespace==nchar && nchar<4 && (nchar>0 || fix==4) ) {
		    if (c1!=EOL)
			for (k=nchar; k<4; k++) sbufprint(' ');
		    nchar=4;
		}
		nchar++; ignorespace=0;
		sbufprint(c1);
		if (c1==LF) nchar=0;
		if (j==2) {
		    sbufprint(c2); nchar++;
		}
	    }
	    break;
	case 7: /* for CStar: in V1.3a, if HZ and non-punctuation, add
			space before CH char, should be more intelligent */
		if (j==1) sbufprint(c1);
		else if (j==2) {
if ( (c1==0xA1 && c2<=0xC3) || (c1==0xA3 && !isalnum(c2-0x80)) ) ;
		    /* else if (sbufp==0) ;
		    else if (sbuf[sbufp-1]==' ' || sbuf[sbufp-1]=='\t'); */
		    else sbufprint(' ');
		    sbufprint(c1); sbufprint(c2);
		}
	    break;
	case 8: /* for CStar: if ...HZ HZ..., delete space --> ...HZHZ... */
		if (j==1) {
		    if (c1==' ' && c2>=0xA1) {
			; /* if (sbufp==0) ;
			else if (sbuf[sbufp-1]==' ' || sbuf[sbufp-1]=='\t')
				sbufprint(c1); */
		    }
		    else sbufprint(c1);
		}
		else if (j==2) {
		    sbufprint(c1); sbufprint(c2);
		}
	    break;
	default:        /* 1 2 6 */
	if (j==1) {
	    if (nchar>=nHzline-2 && fix!=2) ignorespace=suppress; /* space */
	    switch(c1) {
		case LF: 
		/*case CR:               / * CR, LF, or CR+LF * /
		    if (c1==CR && c2==LF) n--;  / * advance buf pointer by 1 */
		    if (nchar<nHzline-2) {
			ignorespace = ( (fix==2 && nchar>0) ||
				(ignoreEOL && nchar==0) )? 1:0;
			if (ignoreEOL) ignoreEOL=0;  /* fix=6, ignore 2nd */
			else if (fix!=2 || (fix==2 && nchar==0) || EPS)
				sbufprint(EOL);         /* EPS: keep EOL */
		    }
		    else {
			if (fix==2 || EPS || nchar>copies) sbufprint(EOL);
			if (EPS || fix==2) ignorespace=0;  /* copies: nmax */
			if (fix==6) ignoreEOL=1;
		    }
		    nchar=0;
		    break;
		case ' ': case '\t':
		    if (c2==LF) break;
		    if (c1=='\t') nchar = (nchar/8 + 1) * 8;
		    else nchar++;
		    if (!ignorespace) sbufprint(c1);
		    break;
		case ',': case '.': case ':': case ';':
		case '(': case ')': case '!': case '?':
		case '"':
		    if (!mute) { /* mute = map to CH */
			nchar++; sbufprint(c1);
			break;
		    }
		    else if (c1=='.' && c2=='.') {  /* .... do not convert */
			do {
			    nchar++; sbufprint(c1); n--;
			} while (*q++ == c1);
			n++;
			break;
		    }
		    if (c2==' ') n--;  /* advance buffer pointer by 1 */
		    if (lcode==GB) {
			if (c1=='.') {
				c1=0xA1; c2=0xA3;
			}
			else if (pausqm && c1=='"') {/* quot. mark pair? */
				c2=0xB0+odd; c1=0xA1;
				odd=(odd)? 0:1;
			}
			else {
				c2=c1+0x80; c1=0xA3;
			}
		    }
		    else if (lcode==B5) {
			switch (c1) {
			    case '"':
				if (pausqm && c1=='"') {
					c2=0xA7+odd;
					odd=(odd)? 0:1;
				}
				else c2 = 0xB2;
				break;
			    case ',': c2=0x41; break;
			    case '.': c2=0x43; break;
			    case ':': c2=0x52; break;
			    case ';': c2=0x51; break;
			    case '(': c2=0x5D; break;
			    case ')': c2=0x5E; break;
			    case '?': c2=0x48; break;
			    case '!': c2=0x54; break;
			    default: break;
			}
			c1=0xA1;
		    }
		    else if (lcode==JIS) {
			switch (c1) {
			    case '"':
				if (pausqm && c1=='"') {
					c2=0xC8+odd;
					odd=(odd)? 0:1;
				}
				else c2 = 0xED;
				break;
			    case ',': c2=0xA4; break;
			    case '.': c2=0xA3; break;
			    case ':': c2=0xA7; break;
			    case ';': c2=0xA8; break;
			    case '(': c2=0xCA; break;
			    case ')': c2=0xCB; break;
			    case '?': c2=0xA9; break;
			    case '!': c2=0xAA; break;
			    default: break;
			}
			c1=0xA1;
		    }
		    nchar += (1-n);
		    sbufprint(c1); sbufprint(c2);
		    break;
		default:
		    nchar++;            /* ignore news head char '>' */
		    if (nchar==1 && c1==newshd && timestat) break;
		    if (isprint(c1)) sbufprint(c1);
		    break;
	    }
	}
	if (j==2) {
	    if (pausqm) switch((c1*256)+c2) {
		case 0xA1B0: case 0xA1B1: case 0xA1E5: case 0xA3B2:
		    c1=0xA1; c2=0xB0+odd;
		    odd=(odd)? 0:1;
		    break;
		case 0xA3AE:
		    c1=0xA1; c2=0xA3;
		    break;
		default:
		    break;
	    }
	    if (!ignorespace || ((c1*256)+c2)!=cspace) {
		sbufprint(c1); sbufprint(c2);
	    }
	    nchar+=2;
	}
/* j=0, ignore */
	break;
    }
    fnchar += (j-n);
    return n;
}

sbufprint(c)
int c;
{
	int j = -1;
	ignoreEOL=0;
	sbuf[sbufp++]=c;
	if (c==EOL) {
		j=sbufp;
		while(--j) if (sbuf[j-1] != ' ' && sbuf[j-1] != '\t') break;
		if (j != sbufp-1) {
			sbuf[j]=EOL; sbufp=j+1;
		}
	}
	if (sbufp>SBUFSIZE-1 || c==EOL) {
		for (j=0; j<sbufp; j++) fputc(sbuf[j], out);
		sbufp=0;
	}
	return 1;
}

int sgetc(in)
FILE *in;
{
	return (sbufp>0)? sbuf[--sbufp] : getc(in);
}

sungetc(c)
int c;
{
	if (sbufp>=SBUFSIZE)
		fprintf(stderr, "sungetc: too many chars\n");
	else sbuf[sbufp++]=c;
	return 1;
}

bell()
{
	fprintf(stderr, "%c", 7); return 1;
}


int SkipESCSeq(in, c, state)
FILE    *in;
int     c, *state;
{
	int temp = *state;
	if (c == '$' || c == '(') sgetc(in);
	*state = (c == 'K' || c == '$')? 1 : 0;
	return (temp == *state)? 0 : 1;
}


int DetectJPCodeType()
{
	int c = 0, dct = ASCII;  /* detected code type */
	FILE *in;

	inf=Rinf;
	while ((in = inf->fp) != NULL) {
	    while (dct==EUCORSJIS || dct==ASCII) {
		if ((c=sgetc(in)) == EOF) break;
		if (c==ESC) {
		    if ((c=sgetc(in)) == '$') {
			c=sgetc(in);
			if (c=='B' || c=='@') dct=JIS;  /* B: NEW, @: OLD */
		    }
		    else if (c=='K') dct=JIS;       /* NEC */
		}
		else if ((c>=129 && c<=141) || (c>=143 && c<=159))
		    dct=SJIS;
		else if (c==SS2) {
		    c=sgetc(in);
		    if ((c>=64 && c<=126) || (c>=128 && c<=160) ||
			(c>=224 && c<=252)) dct=SJIS;
		    else if (c>=161 && c<=223) dct=EUCORSJIS;
		}
		else if (c>=161 && c<=223) {
		    c=sgetc(in);
		    if (c>=240 && c<=254) dct=EUC;
		    else if (c >= 161 && c <= 223) dct = EUCORSJIS;
		    else if (c >= 224 && c <= 239) {
			dct = EUCORSJIS;
			while (c >= 64 && c != EOF && dct == EUCORSJIS) {
			    if (c >= 129) {
				if (c <= 141 || (c >= 143 && c <= 159))
				    dct = SJIS;
				else if (c >= 253 && c <= 254)
				    dct = EUC;
			    }
			    c = sgetc(in);
			}
		    }
		    else if (c <= 159) dct = SJIS;
		}
		else if (c >= 240 && c <= 254) dct = EUC;
		else if (c >= 224 && c <= 239) {
		    c = sgetc(in);
		    if ((c >= 64 && c <= 126) || (c >= 128 && c <= 160))
			dct = SJIS;
		    else if (c >= 253 && c <= 254) dct = EUC;
		    else if (c >= 161 && c <= 252) dct = EUCORSJIS;
		}
	    }
	    rewind(in);
	    if ((inf=inf->p) == NULL) break;
	}
	inf=Rinf;
	return dct;
}

void han2zen(in, p1, p2, codein)
FILE    *in;
int     *p1, *p2, codein;
{
	int tmp = *p1, junk, maru = 0, nigori = 0;
	static int mtable[][2] = {
    {129,66},{129,117},{129,118},{129,65},{129,69},{131,146},{131,64},
    {131,66},{131,68},{131,70},{131,72},{131,131},{131,133},{131,135},
    {131,98},{129,91},{131,65},{131,67},{131,69},{131,71},{131,73},
    {131,74},{131,76},{131,78},{131,80},{131,82},{131,84},{131,86},
    {131,88},{131,90},{131,92},{131,94},{131,96},{131,99},{131,101},
    {131,103},{131,105},{131,106},{131,107},{131,108},{131,109},
    {131,110},{131,113},{131,116},{131,119},{131,122},{131,125},
    {131,126},{131,128},{131,129},{131,130},{131,132},{131,134},
    {131,136},{131,137},{131,138},{131,139},{131,140},{131,141},
    {131,143},{131,147},{129,74},{129,75} };

	if (codein == SJIS) {
		*p2 = sgetc(in);
		if (*p2 == 222) {
			if (ISNIGORI(*p1)) nigori = 1;
			else sungetc(*p2);
		}
		else if (*p2 == 223) {
			if (ISMARU(*p1)) maru = 1;
			else sungetc(*p2);
		}
		else sungetc(*p2);
	}
	else if (codein == EUC) {
		junk = sgetc(in);
		if (junk == SS2) {
			*p2 = sgetc(in);
			if (*p2 == 222) {
			    if (ISNIGORI(*p1)) nigori = 1;
			    else {
				sungetc(*p2);
				sungetc(junk);
			    }
			}
			else if (*p2 == 223) {
			    if (ISMARU(*p1)) maru = 1;
			    else {
				sungetc(*p2);
				sungetc(junk);
			    }
			}
			else {
				sungetc(*p2);
				sungetc(junk);
			}
		}
		else sungetc(junk);
	}
	if (*p1 >= 161 && *p1 <= 223) {
		*p1 = mtable[tmp - 161][0];
		*p2 = mtable[tmp - 161][1];
	}
	if (nigori) {
		if ((*p2>=74 && *p2<=103) || (*p2>=110 && *p2<=122)) (*p2)++;
		else if (*p1 == 131 && *p2 == 69) *p2 = 148;
	}
	else if (maru && *p2 >= 110 && *p2 <= 122) *p2 += 2;
}

void sjis2jis(p1, p2)
int     *p1, *p2;
{
	unsigned char c1, c2;
	int adjust, rowOffset, cellOffset;

	c1 = *p1; c2 = *p2;
	adjust = c2 < 159;
	rowOffset = c1 < 160 ? 112 : 176;
	cellOffset = adjust ? (c2 > 127 ? 32 : 31) : 126;
	*p1 = ((c1 - rowOffset) << 1) - adjust;
	*p2 -= cellOffset;
}

void shift2seven(in, ki, ko)
FILE    *in;
char *ki, *ko;
{
	int p1, p2, state = OUT;

	while ((p1 = sgetc(in)) != EOF) {
	    if (p1 == EOL || p1 == CR) {
		if (state==IN) {
			state = OUT;
			fprintf(out, "%c%s", ESC, ko);
		}
		fprintf(out, "%c", p1);
	    }
	    else if (SJIS1(p1)) {
		p2 = sgetc(in);
		if (SJIS2(p2)) {
			sjis2jis(&p1, &p2);
			if (state==OUT) {
				state=IN;
				fprintf(out, "%c%s", ESC, ki);
			}
		}
		fprintf(out, "%c%c", p1, p2);
	    }
	    else if (HANKATA(p1)) {
		han2zen(in, &p1, &p2, SJIS);
		sjis2jis(&p1, &p2);
		if (state==OUT) {
			state=IN;
			fprintf(out, "%c%s", ESC, ki);
		}
		fprintf(out, "%c%c", p1, p2);
	    }
	    else {
		if (state==IN) {
			state = OUT;
			fprintf(out, "%c%s", ESC, ko);
		}
		fprintf(out, "%c", p1);
	    }
	}
	if (state==IN) fprintf(out, "%c%s", ESC, ko);
}

void euc2seven(in, ki, ko)
FILE    *in;
char *ki, *ko;
{
	int p1, p2, state = OUT;

	while ((p1 = sgetc(in)) != EOF) {
	    if (p1 == EOL || p1 == CR) {
		if (state==IN) {
			state = OUT;
			fprintf(out, "%c%s", ESC, ko);
		}
		fprintf(out,"%c",p1);
	    }
	    else {
		if (ISEUC(p1)) {
			p2 = sgetc(in);
			if (ISEUC(p2)) {
				p1 -= 128; p2 -= 128;
				if (state==OUT) {
					state=IN;
					fprintf(out, "%c%s", ESC, ki);
				}
			}
			fprintf(out, "%c%c", p1, p2);
		}
		else if (p1 == SS2) {
			p2 = sgetc(in);
			if (HANKATA(p2)) {
				p1 = p2;
				han2zen(in, &p1, &p2, EUC);
				sjis2jis(&p1, &p2);
				if (state==OUT) {
					state=IN;
					fprintf(out, "%c%s", ESC, ki);
				}
			}
			fprintf(out, "%c%c", p1, p2);
		}
		else {
			if (state==IN) {
				state = OUT;
				fprintf(out, "%c%s", ESC, ko);
			}
			fprintf(out, "%c", p1);
		}
	    }
	}
	if (state==IN) fprintf(out, "%c%s", ESC, ko);
}

void seven2seven(in, ki, ko)
FILE    *in;
char *ki, *ko;
{
	int temp, p1, p2, change, state = OUT;

	while ((p1 = sgetc(in)) != EOF) {
	    if (p1 == ESC) {
		temp = sgetc(in);
		change = SkipESCSeq(in, temp, &state);
		if (change) fprintf(out, "%c%s", ESC, (state==IN)? ki : ko);
	    }
	    else if (p1 == EOL || p1 == CR) {
		if (state==IN) {
			state = OUT;
			fprintf(out, "%c%s", ESC, ko);
		}
		fprintf(out, "%c", p1);
	    }
	    else {
		if (state==IN) {
			p2 = sgetc(in);
			fprintf(out, "%c%c", p1, p2);
		}
		else fprintf(out, "%c", p1);
	    }
	}
	if (state==IN) fprintf(out, "%c%s", ESC, ko);
}

void jispreproc()    /* convert to 7-bit, then to 8-bit */
{
	if (code==UNKNOWN || (code==JIS && defcode!=JIS)) {
		code = DetectJPCodeType();
		if (!mute) fprintf(errout,
			"Detected input code: %s\n", codename[code]);
	}
	switch (code) {
	    case EUCORSJIS :
		if (!mute) {
			fprintf(stderr, "Treat as Shift-JIS, OK ? (Y/N)\n");
			bell();
			if (yes(0)) code=SJIS;
			else exit(0);
		}
		else code=SJIS;
		break;
	    case ASCII :
		if (mute) {
			break;
		}
		fprintf(errout,
"Might be damaged New- or Old-JIS, repair? (Y/N)\n");
		bell();
		if (yes(1)) {
			convcode=JISRP; convers(0);
			fprintf(errout,
"Repaired version saved: %s\n", Rinf->s);
		}
		else return;
		break;
	    default: break;
	}
/* convert to 7-bit JIS according to input code type */
	convcode=JISCVT;
	convers(0);
/* convert to 8-bit for unified GB/B5/JIS/KSC processing */
	prescan(-1);
	convcode=JIS8;
	convers(0);
}

void kscpreproc()
{
/*      prescan(-1);
convert to 8-bit for unified GB/B5/JIS/KSC processing
	convcode=KSC8;
	convers(0);
*/      ;
}

void gbb5preproc()
{
	int dct=UNKNOWN;
	if (code==UNKNOWN || (code==GB && defcode!=GB)) {
		dct = DetectCNCodeType();
		if (!mute) fprintf(errout,
			"Detected input code: %s\n", codename[dct]);
	}
	else dct=code;
	switch (dct) {
	    case UNKNOWN: break;
	    case GB: break;
	    case GBORB5:
		if (dct==code) break;
		else if (mute) code=defcode;
		else if (code==GB || defcode==GB) {
			fprintf(errout, "Treat as GB\n");
			code=GB;
		}
		else {
			fprintf(stderr,
"Please supply code type at command-line.\n");
			cleanup(1); exit(0);
		}
		break;
	    case B5:
		if (defcode!=B5 && code!=B5 && !mute) {
			fprintf(stderr, "Is that right (Y/N)?\n");
			bell();
			if (yes(1)) code=dct;
			else if (code==UNKNOWN) {
				fprintf(stderr,
"Please supply code type at command-line.\n");
				cleanup(1); exit(0);
			}
		}
		else if (code==UNKNOWN) code=dct;
		break;
	    case ZW: case HZ: case CNS:
		if (mute) code=dct;
		else if (dct != code) {
			fprintf(stderr, "Is that right (Y/N)?\n");
			bell();
			if (yes(1)) code=dct;
			else fprintf(errout,
"Treat as %s\n", codename[(code==UNKNOWN)? (code=defcode) : code]);
		}
		else if (code==UNKNOWN) code=dct;
		if (code==CNS) convcode=CNSB5;
		else convcode=(code==ZW)? ZWGB : HZGB;
		break;
	    case ASCII:
		code = defcode; break;
	    default:
		exit(0); break;
	}
	switch(code) {
	    case GB: case HZ: case ZW:
		if (lcode!=GB) init(999, NULL);
		break;
	    case B5: case CNS:
		if (lcode!=B5) init(999, NULL);
		break;
	    default:
		break;
	}
	if (convcode) {
		prescan(-1); convers(0);
	}
}

int DetectCNCodeType()
{
	int c = 0, n=0, dct = ASCII;  /* detected code type */
	FILE *in;

	inf=Rinf;
	while ((in = inf->fp) != NULL) {
	    while (dct==ASCII || dct==GBORB5) {
		if ((c=fgetc(in)) == EOF) break;
		else if (c==ESC) {
		    n++;
		    if ((c=sgetc(in)) == '$') {
			n++;
			if ((c=sgetc(in)) == 'C') {
			    c=sgetc(in);
			    if (c=='G' || c=='H') dct=CNS;
			}
		    }
		}
		else if (c>=0xA1) {
		    c = fgetc(in);
		    if (c>=0x40 && c<=0x7E) dct=B5;
		    else if (c>=0xA1) dct=GBORB5;
		    else sungetc(c); /* bad codes */
		    n+=2;
		}
		else if (c == '~') {
		    c = fgetc(in);
		    if (c=='{' || c=='}') dct=HZ;
		    n+=2;
		}
		else if (c=='z' && n==0) {
		    c = fgetc(in);
		    if (c=='W') dct=ZW;
		    n+=2;
		}
		else if (c==EOL) n=0;
	    }
	    rewind(in);
	    if ((inf=inf->p) == NULL) break;
	}
	inf=Rinf;
	return dct;
}

unicodepreproc()
{
	if (code==UNKNOWN) code=lcode;
	if (code>UTF) {  /* not 2-byte unicode */
		convcode = (code==UTF8)? UTF8TOUNI : UTF7TOUNI;
		convers(0);
	}
	return 1;
}

long utf_getc(fp)       /* utf8 to 2-byte unicode */
FILE    *fp;
{
	int     c, extras;
	long    wc;
	unsigned bit;

	if ((c = getc(fp)) == EOF) return EOF;
	if ((c & 0x80) == 0)            /* ASCII character */
		return c;
	if ((c & 0xc0) == 0x80)         /* unexpected tail character */
		return CODE_ERROR;
	/* how many extra bytes? */
	extras = 1;
	for (bit = 0x20; (c & bit) != 0; bit >>= 1) extras++;
	if (extras > 5) return CODE_ERROR;
	/* put all the bits together */
	wc = c & (bit-1);
	while (extras-- > 0) {
		if ((c = getc(fp)) == EOF) return EOF;
		if ((c & 0xc0) != 0x80) { /* unexpected head character */
			ungetc(c, fp);
			return CODE_ERROR;
		}
		wc = (wc<<6) | (c&0x3f);
	}
	return wc;
}

static void invert()
{
	int     i;
	unsigned char   *s;

	utf_initzd = IN;
	for (i = 0; i < NUMBYTES; i++) char_type[i] = 0;
	for (s = base64; *s != '\0'; s++) {
		char_type[*s] |= BASE64;
		inv_base64[*s] = s - base64;
	}
	for (s = safe; *s != '\0'; s++) char_type[*s] |= SAFE;
	for (s = optional; *s != '\0'; s++) char_type[*s] |= OPTIONAL;
	for (s = space; *s != '\0'; s++) char_type[*s] |= SPACE;
}


long utf7_getc(fp)    /* utf7 to 2-byte unicode */
FILE    *fp;
{
	int     c;

	if (! utf_initzd) invert();
	for (;;) {
		if ((c = getc(fp)) == EOF) return EOF;
		if (! in_base64) {
			if (c != '+') return c;
			if ((c = getc(fp)) == EOF) return EOF;
			if (c == '-') return '+';
			in_base64 = IN;
			nbits = 0;
		}
	/* now we're in Base64 mode */
		while (char_type[c]&BASE64) {
			bit_buffer <<= 6;
			bit_buffer |= inv_base64[c];
			nbits += 6;
			if (nbits >= 16) {
				nbits -= 16;
				return ((bit_buffer >> nbits)&0xffffL);
			}
			if ((c = getc(fp)) == EOF) return EOF;
		}
		in_base64 = OUT;
		if (c != '-') return c;
	}
}

getroot()
{
	char *s, *t;
	int n, c = ':'; /* unix */
	struct Roots *rt;
	/*char defpath[50];*/

#ifdef VMS
	c = ',';
#endif
	root = (struct Roots *) calloc(1, sizeof(struct Roots));
	if (root == NULL) MemExit();
	rt = root; root->p = NULL; root->s=NULL;
	s=getenv("HBFPATH");
 /* fprintf(errout, "s=.%s.\n", s); */
/*	if (s==NULL) {
		defpath[0]='\0';
#ifdef unix
		strcpy(defpath, "/usr/local/src/cnprint");
#endif
		s=defpath;
	}
*/
	do {
		if (root->s!=NULL && rt->p==NULL) {
		    rt->p = (struct Roots *)
			calloc(1, sizeof(struct Roots));
		    if (rt->p==NULL) MemExit();
		    rt = rt->p; rt->p = NULL;
		}
		if (s!=NULL) t = strchr(s, c);
		else t = NULL;
		if (t!=NULL) n = (int) (t-s);
		else n = (s==NULL)? 0 : strlen(s);
if ( (rt->s = (char *) calloc(n+2, sizeof(char))) == NULL)
			MemExit();
		if (n) {
			strncpy (rt->s, s, n);
			s += n;
			if (t!=NULL) s++;
#ifdef unix
			if (rt->s[n-1] != '/') strcat(rt->s, "/");
#endif
		}
		else {
			(rt->s)[0] = '\0';
			s=NULL;
		}
/* fprintf(errout, "s=.%s.  .%s.\n", s, rt->s);*/
	} while (s!=NULL);

/*	rt=root;
	do {
		fprintf(errout, "rt->s: .%s.\n", rt->s);
		if (rt!=NULL) rt = rt->p;
	} while (rt!=NULL);
*/
	return 1;
}

void FName(s, t) /* compose a file name based on *s with surfix *t */
char *s, *t;
{
	int j, k;
#ifdef VMS
	j=strlen(s);
	while (s[j]!=';' && j) j--;
	if (j>1) s[j]='\0';
#endif
	strcat(s, t);
}

RE_name(old, new)
char *old, *new;
{
	char p[100];
#ifdef unix
# ifdef MUSER
	sprintf(p, "cp %s %s", old, new);
	system(p);
	remove(old);
# else
	sprintf(p, "mv %s %s", old, new);
	system(p);
# endif
#else
	if (rename(old, new)!=0) {
		sprintf(p, "copy %s %s", old, new);
		system(p);
		remove(old);
	}
#endif
	return 0;
}

tobooklet()
{
	int     j, k, xpos[17];
	int     Nppg;           /* physical pages */
	int     npg;            /* nominal page number */
	long    filepos;
	FILE    *in;

	if (!mute) fprintf(errout, "Convert PS file to booklet format...\n");
	Nppg = (pgpd+2*booklet-1)/(booklet*2);
	Nppg *= 2;
/* positions of each page on a physical page (sheet of paper) */
	for (j=1; j<=booklet/2; j++) {  /* booklet must be even number */
		xpos[j] = xpos[j+3*booklet/2] = Xa*j + RM*(j-1);
		xpos[j+booklet/2] = xpos[j+booklet] =
			Xa*(j+1+booklet/2) + RM*(j+booklet/2-1);
	}

	FName(Rinf->s, "bk");
	RE_name(tempfile, Rinf->s);
	opnfile(IN); opnfile(OUT);
	in=Rinf->fp;

	copypage(0, 0, 1, in, &filepos); /* copy header */
	for (j=1; j<=Nppg; j++) {
	    for (k=booklet; k>=1; k--) {
		if (k <= booklet/2)
		    npg = (Nppg*booklet - (j-1)*booklet/2) - (booklet/2-k);
		else npg = (j-1)*booklet/2 + (k-booklet/2);
		if (k==booklet) fprintf(out,
"\n%%%%Page: %d %d\nCN27Dict begin\n", j, npg);
		if (npg<=pgpd) copypage(npg,
			xpos[k + booklet*((j+1)%2)], 0, in, &filepos);
		if (k==1) fprintf(out, "SP end %% CN27Dict\n");
	    }
	    fprintf(errout, (j%5 == 0 || j==Nppg)? "%5d\n" : "%5d", j);
	}
	trailer(Nppg);
	remove(Rinf->s);
	if (ferror(out)) {
		fprintf(stderr,
"WARNING: PS file %s write error, possibly out of memory.\n", tempfile);
		bell(); exit(-5);
	}
	fclose(out);
	outputToDev();
	return 1;
}

copypage(npg, xp, ht, in, pfilepos)
long    *pfilepos;      /* copy selected page to output, for booklet */
int     npg, xp, ht;    /* xp: x-position; ht: -1 trailer; 1, header */
FILE    *in;
{
	int     j, k, Prntpage=0;
	char    cst[256];

	if (npg > 0) fseek(in, *pfilepos, 0);
	if (ht==1) Prntpage=2;   /* ht==1, copy header */
	while (fgets(cst, 255, in)!=NULL) {
	    if (Prntpage>=2) {
		if (strncmp(cst, "EP", 2)==0) {
		    fprintf(out, "EP\n"); break;
		}
		else fprintf(out, "%s", cst);
		if (npg<=0) {
		    if (strncmp(cst, "%%EndSetup", 10)==0) {
			*pfilepos = ftell(in);
			break;
		    }
		}
	    }
	    else if (Prntpage) {
		if (strncmp(cst, "BP", 2)==0) {
			/* BP -2550 LRT 180 186 translate */
		    sscanf(cst, "%*s%d%*s%*d%d", &j, &k);
		    fprintf(out, "BP %d LRT %d %d translate\n", j, xp, k);
		    Prntpage++;
		}
	    }
	    else if (strncmp(cst, "%%Page:", 7)==0) {
		/* Prntpage=0; */
		sscanf(cst, "%*s%d%d", &k, &j);
		if (j==npg) {
			Prntpage=1;
			fprintf(out, "%%face page: %d %d\n", k, npg);
			continue;
		}
	    }
	}
	return 1;
}


#ifdef PSPRINT
toshortline(FILE *in)
/* break long lines to short ones: some printer has problem with long lines */
{
	int	c;
	int	hexd=0;		/* # of continuous Hexidecimal digits */
	int	comment=0;	/* PS comment lines */
	int	bop=0;		/* 1: (; 0: ) */
	int	charcount=0;

	while ( (c=fgetc(in)) != EOF) {
		if (c=='(') bop=1;
		else if (c==')') bop=0;
		if (c==LF || c==CR) {
			c=getc(in);
			if (c!=LF && c!=EOF) ungetc(c, in);
			charcount=0; comment=hexd=0;
			fputc(EOL, out);
		}
		else if (c=='\\') {
			c=getc(in);
			if (charcount > MAXLENGTH-6 && c!=EOL) {
				if (bop) fputc('\\', out);
				fputc(EOL, out);
				if (comment) fputc('%', out);
				charcount=0; hexd=0;
			}
			fputc('\\', out);
			fputc(c, out);
			if (c==EOL) {
				charcount=comment=0;
				c=getc(in);
				if (c==EOL) ;
				else ungetc(c, in);
			}
		}
		else if (charcount>MAXLENGTH && (isbreaka(c) || isbreakb(c))) {
			if (isbreakb(c)) fputc(c, out);
	/* if inside a char string, add line-continuation mark */
			if (bop) fputc('\\', out);
			fputc(EOL, out);
			if (comment) fputc('%', out);
			if (isbreaka(c)) fputc(c, out);
			charcount=1; hexd=0;
		}
		else if (charcount>MAXLENGTHA && c=='/' && !bop) {
					/* not inside () */
			fputc(EOL, out);
			if (comment) fputc('%', out);
			fputc(c, out);
			charcount=1; hexd=0;
		}
		else if (charcount>MAXLENGTHB) {
			if (hexd==0 || hexd==10) {
						/* line-continuation */
				if(hexd==0) fputc('\\', out);
				fputc(EOL, out);
				if (comment) fputc('%', out);
				charcount=0; hexd=0;
			}
			if (isxdigit(c)) hexd++;
			else hexd=0;
			charcount++;
			fputc(c, out);
		}
		else {
			if (c=='%' && !bop) comment++;
			fputc(c, out);
			charcount++;
			if (isxdigit(c)) hexd++;
			else hexd=0;
			if (hexd==78) {
				fputc(EOL, out);
				if (comment) fputc('%', out);
				charcount=hexd=0;
			}
		}
	}
}

pageprint(FILE *in)
/* print selected pages, must be DSC conforming, no error checking.
 * by standard, EPS file must be bracketed with
	%%BeginDocument
	%%EndDocument
 * pair.  Ignore the "##Page: " comments in EPS file.
 * Note: it does not adjust the page numbers and # of pages.
 */
{
	int	j, npg=0, EPSlevel=0;
	char	cst[256];
	int	Prntpage=1;

	while (fgets(cst, 255, in)!=NULL) {
	    if (EPSlevel) {
		if (strncmp(cst, "%%EndDocument", 13)==0) EPSlevel--;
	    }
	    else if (strncmp(cst, "%%BeginDocument", 15)==0) {
		EPSlevel++;
	    }
	    else if (strncmp(cst, "%%Page:", 7)==0) {
		sscanf(cst, "%*s%*s%d", &j);
		if (j>npg) npg=j;
		if (npg>0) {
		    if (npg>=bp && (ep==0 || npg<=ep)) {
			if (odd==0 || ((odd%2)==(npg%2))) Prntpage=1;
			else Prntpage=0;
		    }
		    else Prntpage=0;
		}
		if (Prntpage) fprintf(stderr, "%s\tYES\n", cst);
	    }
	    else if (strncmp(cst, "%%Trailer", 9)==0) {
		Prntpage=1;
	    }
	    if (Prntpage) fprintf(out, "%s", cst);
	}
}
#endif  /* PSPRINT */
