/*   lprint  : 	landscape PRINT out utility for FM-TOWNS
 *
 *				Ver. 1.10     90/10/14
 *
 * 		(C) Copyright    Makoto Sakai
 * 			 	    Nifty:    ムンパッパ (MHB02550)     
 *			 	    junet:    sakai@sra.co.jp
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and that
 * both that copyright notice and this permission notice appear in
 * supporting documentation.
 */
#include <stdio.h>

#define iskanji(c) (((c>0x80)&&(c<0xa0))||((c>0xdf)&&(c<0xfd)))
#define WIDTH  112
#define HEIGHT  76
#define ANK      0
#define KANJI    1
#define KANJI2   2
#define VLINE    0xff01
#define HLINE    0xff02
#define ULLINE   0xff03
#define URLINE   0xff04
#define DLLINE   0xff05
#define DRLINE   0xff06
#define LINE     0xff00

static unsigned short	data[WIDTH][HEIGHT];
static int	lineno = 1;
static int	pageno = 1;
#ifdef NO
	static int	noflag  = 1;
#else
	static int	noflag  = 0;
#endif
#ifdef FMPR
	static int	fmflag = 1;
#else
	static int	fmflag = 0;
#endif
#ifdef B5
	static int	b5flag = 1;
#else
	static int	b5flag = 0;
#endif
#ifdef QUICK
	static int	quickflg = 1;
#else
	static int	quickflg = 0;
#endif
static int	width[] = {WIDTH,94};
static int	height[] = {HEIGHT,64};
static char	*name;
static char	*init[] =	{"\033U\000\0333\030",	"\033Q24;180 G"};
static int	initlen[] =	{6,			10};
static char	*end[] =	{"\033@",		"\033c"};
static int	endlen[] =	{2,			2};
static char	*image[] =	{"\033*\047\022\000",	"\033Q18 W"};
static int	imagelen[] =	{5,			6};
static char	*skip[] =	{"\033\\\022\000",	"\033[18a"};
static int	skiplen[] =	{4,			5};

static int	start_no = 0;
static int	end_no = 0x7fffffff;

main(argc, argv)
int	argc;
char	*argv[];
{
	
	register int	x;
	register int	y;
	static int	noteof = 1;
	FILE	*ifp;
	char	*envp;

	envp = (char *)getenv("LPRINT");
	if (envp) {
		flagset(envp);
	}
	argv++;
	while (**argv == '-') {
		(*argv)++;
		flagset(*argv);
		argc--;
		argv++;
	}
	if (argc > 2) {
		usage();
		exit(1);
	}
	if (argc != 2) {
		ifp = stdin;
		name = "";
	}
	else {
		if ((ifp = fopen(*argv,"r"))== NULL) {
			fprintf(stderr,"Can't open %s\n",*argv);
			exit(1);
		}
		name = *argv;
	}
	while(noteof && (pageno < start_no)) {
		noteof = getpage(ifp);
		pageno++;
	}
	if (!noteof) {
		exit(0);
	}
	prnnput(initlen[fmflag], init[fmflag]);
	while(noteof && (pageno <= end_no)) {
		noteof = getpage(ifp);
		for (x = 0; x < width[b5flag]; x++) {
			for (y = height[b5flag]-1; y >= 0; y--) {
				imgput(data[x][y]);
			}
			imgnl();
		}
		for (y = height[b5flag]-1; y >= 0; y--) {
			imgput(' ');
		}
		imgnl();
		pageno++;
		if (noteof && (pageno <= end_no)) {
			noteof = getpage(ifp);
			for (x = 0; x < width[b5flag]; x++) {
				for (y = height[b5flag]-1; y >= 0; y--) {
					imgput(data[x][y]);
				}
				imgnl();
			}
			pageno++;
		}
		imgflush();
		prnputc('\f');
	}
	prnnput(endlen[fmflag], end[fmflag]);
	exit(0);
}
clear(buf,size,len)
unsigned char	*buf;
int		size;
int		len;
{
	register int	cnt1;
	register int	max;

	max = size * len;
	for (cnt1 = 0; cnt1 < max; ++cnt1) {
		buf[cnt1] = 0;
	}
}
usage()
{
	fprintf(stderr,"USAGE : lprint [option] file\n");
	fprintf(stderr,"  -n  : number\n");
	fprintf(stderr,"  -p  : plain(no number)\n");
	fprintf(stderr,"  -b  : B5\n");
	fprintf(stderr,"  -a  : A4\n");
	fprintf(stderr,"  -f  : FMPR\n");
	fprintf(stderr,"  -e  : ESC/P\n");
	fprintf(stderr,"  -q  : quick\n");
	fprintf(stderr,"  -c  : case\n");
	fprintf(stderr,"  -s# : start at # page(# is decimal number)\n");
	fprintf(stderr,"  -t# : to # page(# is decimal number)\n");
}
getpage(ifp)
FILE	*ifp;
{
	register int	x,y;
	register int	colmax,lowmax;
	int	tabstop;
	int	noteof = 1;
	int	nlflag;
	register unsigned char	c;
	register unsigned short	s;
	static unsigned long	startno;
	static unsigned char lastc='\0';
	static char buffer[BUFSIZ];
	static char *bufp;

	colmax = width[b5flag] - 1;
	lowmax = height[b5flag] - 1;
	for (x = 0; (name[x] != '\0')&&(x < (colmax-1)); x++) {
		data[x+1][0] = name[x];
	}
	if (!quickflg) {
		for (x = 1; x < colmax; ++x) {
			data[x][1] = VLINE;
		}
		for (x = 1; x < colmax; ++x) {
			data[x][height[b5flag]-1] = VLINE;
		}
		for (y = 2; y < lowmax; ++y) {
			data[0][y] = HLINE;
		}
		for (y = 2; y < lowmax; ++y) {
			data[width[b5flag]-1][y] = HLINE;
		}
		data[0][1] = URLINE;
		data[0][height[b5flag]-1] = ULLINE;
		data[width[b5flag]-1][1] = DRLINE;
		data[width[b5flag]-1][height[b5flag]-1] = DLLINE;
	}
	startno = lineno;
	for (y = 2; y < lowmax; ++y) {
		if (noflag) {
			if (nlflag) {
				sprintf(buffer,"%5d: ", lineno);
				bufp = buffer;
				for (x = 1; x < 8; ++x) {
					data[x][y] = *bufp++;
				}
			}
			else {
				for (x = 1; x < 8; ++x) {
					data[x][y] = ' ';
				}
			}
		}
		else {
			x = 1;
		}
		for (; x < colmax; ++x) {
			if (noteof == 1) {
				nlflag = 0;
				if (lastc) {
					c = lastc;
					lastc = '\0';
				}
				else {
					c = getc(ifp);
					noteof = (feof(ifp))?0:1;
				}
				if (!noteof) {
					if ((noflag)&&(x == 8)) {
						for (x = 1; x < 8; ++x) {
							data[x][y] = ' ';
						}
						lineno--;
					}
					else if (x == 1) {
						lineno--;
					}
					data[x][y] = ' ';
				}
				else {
					if (iskanji(c)) {
						if (x == (colmax - 1)) {
							lastc = c;
							data[x][y] = ' ';
							continue;
						}
						noteof = (feof(ifp))?0:1;
						s = (c<<8)+ getc(ifp);
						s = s2jis(s & 0xffff);
						if (s == (unsigned short)0xffff) {
							s = 0x2222;
						}
						data[x][y] = (s | 0x8000);
						x++;
						data[x][y] = s;
					}
					else if (c == '\n') {
						for (; x < colmax; ++x) {
							data[x][y] = ' ';
						}
						x--;
						lineno++;
						nlflag = 1;
					}
					else if (c == '\r') {
						;
					}
					else if (c == '\t') {
						tabstop = (x + 8)& 0xfffffff8
								+ (noflag?0:1);
						if (tabstop > colmax) {
							tabstop = colmax;
						}
						for (; x < tabstop; ++x) {
							data[x][y] = ' ';
						}
						x--;
					}
					else if (c == '\b') {
						x -= 2;
						if (x < (noflag?7:0)) {
							x++;
						}
					}
					else if (c == '\f') {
						for (; x < colmax; ++x) {
							data[x][y] = ' ';
						}
						x--;
						lineno++;
						noteof = -1;
					}
					else if (c < 0x20) {
						data[x][y] = '.';
					}
					else {
						data[x][y] = c;
					}
				}
			}
			else {
				data[x][y] = ' ';
			}
		}
	}
	if (noflag) {
		sprintf(buffer, "Page %d", pageno);
		bufp = buffer;
		for (x = width[b5flag] - strlen(buffer) - 2; *bufp != '\0'; x++) {
			data[x][0] = *bufp++;
		}
	}
	else {
		sprintf(buffer,"%d - %d",startno,lineno-nlflag-((noteof==-1)?1:0));
		bufp = buffer;
		for (x = width[b5flag] - strlen(buffer) - 2; *bufp != '\0'; x++) {
			data[x][0] = *bufp++;
		}
	}
	return(noteof);
}

static unsigned char	pbuf[WIDTH * 18][3];
static int	dotcnt = 0;
static int	linecnt = 0;

imgput(sdata)
unsigned short	sdata;
{

	static vdata[18] = {0,0,0,0,0,0,0,0,0xff,0,0,0,0,0,0,0,0,0};
	static hdata[18] = {8,8,8,8,8,8,8,8,0x08,8,8,8,8,8,8,8,8,8};
	static uldata[18] ={0,0,0,0,0,0,0,0,0x0f,8,8,8,8,8,8,8,8,8};
	static urdata[18] ={8,8,8,8,8,8,8,8,0x0f,0,0,0,0,0,0,0,0,0};
	static dldata[18] ={0,0,0,0,0,0,0,0,0xf8,8,8,8,8,8,8,8,8,8};
	static drdata[18] ={8,8,8,8,8,8,8,8,0xf8,0,0,0,0,0,0,0,0,0};
	static int *datap[] ={vdata, hdata, uldata, urdata, dldata, drdata};
	register int	cnt;

	if ((sdata & LINE)== LINE) {
		sdata -= LINE + 1;
		for (cnt = 0; cnt < 18; ++cnt) {
			pbuf[dotcnt++][linecnt] = datap[sdata][cnt];
		}
	}
	else if (sdata == ' ') {
		for (cnt = 0; cnt < 18; ++cnt) {
			pbuf[dotcnt++][linecnt] = 0;
		}
	}
	else if (sdata <= 0xff) {
		for (cnt = 0; cnt < 16; ++cnt) {
			pbuf[dotcnt++][linecnt] = getfnt(ANK,(int)sdata,15-cnt);
		}
		for (; cnt < 18; ++cnt) {
			pbuf[dotcnt++][linecnt] = 0;
		}
	}
	else if (sdata & 0x8000) {
		sdata -= 0x8000;
		for (cnt = 0; cnt < 16; ++cnt) {
			pbuf[dotcnt++][linecnt] = 
					getfnt(KANJI,(int)sdata, (15-cnt)*2);
		}
		for (; cnt < 18; ++cnt) {
			pbuf[dotcnt++][linecnt] = 0;
		}
	}
	else {
		for (cnt = 0; cnt < 16; ++cnt) {
			pbuf[dotcnt++][linecnt] = 
					getfnt(KANJI,(int)sdata, (15-cnt)*2+1);
		}
		for (; cnt < 18; ++cnt) {
			pbuf[dotcnt++][linecnt] = 0;
		}
	}
}
imgnl()
{
	linecnt++;
	dotcnt = 0;
	if (linecnt >= 3) {
		imgflush();
	}
}
imgflush()
{
	register int	dcnt;
	register int	dotmax;

	if (dgetc() == 3) {
		prnnput(3, "\r\n\f");
		prnnput(endlen[fmflag], end[fmflag]);
		fprintf(stderr,"abort\n");
		exit(1);
	}
	if (linecnt != 0) {
		dotmax = height[b5flag] * 18;
		for (; linecnt < 3; ++linecnt) {
			for (dcnt = 0; dcnt < dotmax; ++dcnt) {
				pbuf[dcnt][linecnt] = 0;
			}
		}
		for (dcnt = 0; dcnt < dotmax; dcnt+=18) {
			if (isskip(18 * 3, &pbuf[dcnt][0])) {
				prnnput(skiplen[fmflag], skip[fmflag]);
			}
			else {
				prnnput(imagelen[fmflag], image[fmflag]);
				prnnput(18 * 3, &pbuf[dcnt][0]);
			}
		}
		prnnput(2, "\r\n");
		linecnt = 0;
		dotcnt = 0;
	}
}
isskip(n, str)
int	n;
unsigned char	*str;
{
	while (n--) {
		if (*str++) {
			return(0);
		}
	}
	return(1);
}
prnnput(n, str)
int	n;
unsigned char	*str;
{
	while (n--) {
		prnputc(*str++);
	}
}
flagset(option)
char	*option;
{
	while (*option != '\0') {
		switch (*option++) {
			case	'p':
			case	'P':
				noflag = 0;
				break;
			case	'n':
			case	'N':
				noflag = 1;
				break;
			case	'f':
			case	'F':
				fmflag = 1;
				break;
			case	'e':
			case	'E':
				fmflag = 0;
				break;
			case	'b':
			case	'B':
				b5flag = 1;
				break;
			case	'a':
			case	'A':
				b5flag = 0;
				break;
			case	'q':
			case	'Q':
				quickflg = 1;
				break;
			case	'c':
			case	'C':
				quickflg = 0;
				break;
			case	's':
			case	'S':
				sscanf(option,"%d",&start_no);
				option += strlen(option);
				break;
			case	't':
			case	'T':
				sscanf(option,"%d",&end_no);
				option += strlen(option);
				break;
			default:
				usage();
				exit(1);
		}
	}
}
