/*
 * 5799-WZQ (C) COPYRIGHT IBM CORPORATION 1986,1987
 * LICENSED MATERIALS - PROPERTY OF IBM
 * REFER TO COPYRIGHT INSTRUCTIONS FORM NUMBER G120-2083
 */
/* $Header:pprint.c 12.0$ */
/* $ACIS:pprint.c 12.0$ */
/* $Source: /ibm/acis/usr/src/ibm/pprint/RCS/pprint.c,v $ */

#ifndef lint
static char *rcsid = "$Header:pprint.c 12.0$";
#endif

#include <stdio.h>
#include <ctype.h>
#include <utils.h>
#include <hash.h>
#include <environ.h>
#include <header.h>
#include <setup_txt3812.h>
#include <spooljob.h>

/***===================================================================***/

static int mn_debug;		/* debugging flag */

static	int	pg_lines=	0;	/* height of page in lines	*/
static	int	pg_cols=	0;	/* width of page in characters	*/
static	int	pg_indent=	0;	/* indent from left margin in chars */

static	char	*command=	NULL;	/* command line 		*/
static	char	*files=		NULL;	/* list of files printed	*/
static	int	hdr_fileknt=	0;	/* length of "files"		*/

static	char	*font_name=	NULL;	/* name of font to be used	*/

/***===================================================================***/

static	char	*printer=	NULL;	/* which printer?		*/
static	int	ln_wrap=	FALSE;	/* wrap lines > pg_cols?	*/
static	int	two_up=		FALSE;	/* print pages two/sheet?	*/
static	int	outline=	FALSE;	/* print border on page?	*/
static	int	ruled=		FALSE;	/* print page rules?		*/
static	int	copies=		1;	/* how many copies?		*/
static	char	*pmp_debug=	NULL;
static	char	*job_debug=	NULL;
static	char	*pg_header=	NULL;   /* name on each "pr" page 	*/
static	char	*filt_args=	NULL;	/* argument to input filter	*/
static	int	filt_arglen=	0;	/* length of 'filt_args'	*/
static	char	*hdr_layout=	NULL;	/* what kind of header page	*/
static	char	*error_out=	NULL;	/* where do we send error messages */
static	char	*error_level=	NULL;	/* which errors do we report	*/
static	char	*hdr_fields=	NULL;	/* info	for spool filter 	*/
static	int	hdr_fieldknt=	0;	/* how long is hdr_fields?	*/
static	char	*hdr_message=	NULL;	/* message on header page	*/
static	char	*job_type=	"text";	/* what are we printing?	*/

#define PORTRAIT       1
#define LANDSCAPE      2
#define UPRIGHT	       4
#define LEFT	       4
#define INVERTED       8
#define RIGHT	       8
static	int	pg_orient=	0;	/* which way does the page go?	*/

/***===================================================================***/

#define OUT_FILTER "lpr -P%s -h"

static	char	*i_filter=	"/bin/pr";/* command to filter input	*/
static	char	*o_filter=	NULL;	/* where do we send output?	*/
static	char	*w_filter=	"/usr/ucb/fold"; /* filter for -W (wrap)*/

static	FILE	*infil=		NULL;
static	FILE	*outfil=	NULL;
extern	FILE	*popen();

/***============================================================***/

_add_arg(arg,separator,strvar,lenvar)
register1 char	*arg;
register6 char	*separator;
register4 char	**strvar;
register5 int	*lenvar;
{
	register2 char	*str;
	register3 int	 len;

	D_ENTRY4(mn_debug,"add_arg(%s,%s,0x%x,0x%x)\n",
		           arg,separator,strvar,lenvar);
	str=	*strvar;
	len=	*lenvar;
	if (str) {
		if (strlen(str)+strlen(arg)+strlen(separator)+1>len) {
			len += strlen(arg)+strlen(separator)+20;
			str  = u_realloc(str,len);
		}
		strcat(str,separator);
		strcat(str,arg);
	}
	else {
		len += strlen(arg)+20;
		str  = u_malloc(len);
		strcpy(str,arg);
	}

	*lenvar = len;
	*strvar = str; 
	RETURN(TRUE);
}

/***============================================================***/

help_message(name)
register1 char	*name;
{
	D_ENTRY1(mn_debug,"help_mesage(%s)\n",name);
	information1("usage: %s [options] [files]\n",name);
	information("print text files on IBM3812 page printer\n");
	information("some options are (see pprint(1) for full list):\n");
	information("	-2		print two logical pages per sheet\n");
	information("	-c n		print 'n' copies (*not* collated)\n");
	information("	-i n		indent page 'n' spaces\n");
	information("	-J		suppress Job header page\n");
	information("	-l n		print 'n' lines per page\n");
	information("	-L		print landscape (sideways)\n");
	information("			(152 columns)\n");
	information("	-m message	print 'message' on header page\n");
	information("	-n [filter]	use 'filter' to print files\n");
	information("			('cat' if not specified)\n");
	information("	-O		print page border (Outline)\n");
	information("	-P printer	print files on 'printer'\n");
	information("	-R 		print page rules\n");
	information("	-t		send output to stdout\n");
	information("	-w n		page is 'n' columns wide\n");
	information("			(widths > 80 printed landscape)\n");
	information("	-W		wrap long lines (default truncate)\n");
	RETURN(TRUE);
}

/***============================================================***/

static char	*banner_pages[]=	{
	"banner",
	"box",
	"development",
	NULL
};

static char	*error_reports[]=	{
	"mail",
	"message",
	"trailer",
	NULL
};

static char	*error_levels[]=	{
	"all",
	"warning",
	"error",
	"none",
	NULL
};

ErrorMessages(setting)
register3 char	*setting;
{
	register1 char  *where;
	register2 char	*level;

	D_ENTRY1(mn_debug,"ErrorMessages(%s)\n",setting);
	where= level= StrDup(setting);
	while ((*level!='\0')&&(*level!=',')) {
		level++;
	}
	if (*level==',') {
		*level++= '\0';
	}
	if (*where=='\0') {
		error_out= UNSPEC_ERROR_OUT;
	}
	else if (!u_SelectStr(error_reports,where,&error_out)) {
		error1("Don't know how to report errors to \"%s\"\n",where);
		if (error_out) 
			action1("reporting to %s\n",error_out);
		else
			action("using default error report\n");
	}
	if (*level=='\0') {
		error_level= UNSPEC_ERROR_LEVEL;
	}
	else if (!u_SelectStr(error_levels,level,&error_level)) {
		error1("Illegal error level %s requested\n",level);
		if (error_level)
			action1("using error level %s\n",error_level);
		else
			action("using default error level\n");
	}
	RETURN(TRUE);
}

/***===================================================================***/

ParseArgs(argc,argv)
register2	int	argc;
register3	char	*argv[];
{
	register1	int	ch, index;
	int		len = 0;
	extern		char	*optstring;
	extern		char	*optarg;
	extern		int	optind;
	extern		int	optional;

	D_ENTRY2(mn_debug,"ParseArgs(%d,%x)\n",argc,argv);
	optional='?';
	while( (ch=getopt(argc,argv,"25?c:D?d?e?f:F:i:h:H:Jl:L?m:n?O?p:P:R?t?vw:W")) !=EOF)
	{
		switch(ch) {
		case '2':	
			two_up=		!two_up;
			break;
		case '5':	
			job_type= 	"ascii5152";
			i_filter=	"cat";
			break;
		case 'c': 	
			copies= 	atoi(optarg);
			if (copies<=0) {
				warning1("Illegal number of copies (%d)\n",
					  copies);
				action("resetting to 1\n");
				copies= 1;
			}
			break;
		case 'D': 	
			if (optarg)	pmp_debug= 	optarg;
			else		pmp_debug= 	UNSPEC_PDEBUG;
			break;
		case 'd':	
			if (optarg) 	job_debug= 	optarg;
			else		job_debug=	UNSPEC_DEBUG;
			break;
		case 'e': 	
			if (optarg)	ErrorMessages(optarg);
			else		ErrorMessages(UNSPEC_ERROR_OUT);
			break;
		case 'f': 	
			font_name=	optarg;
			break;
		case 'F': 	
			_add_arg(optarg,",",&hdr_fields,&hdr_fieldknt);
			break;
		case 'h': 	
			pg_header=	optarg;
			break;
		case 'H':	
			if (!u_SelectStr(banner_pages,optarg,&hdr_layout)) {
				warning1("Illegal banner %s requested\n",
					  optarg);
				if (hdr_layout) {
					action1("using %s banner page\n",
						 hdr_layout);
				} 
				else { 
				    action("using default page instead\n");
				}
			}
			break;
		case 'i':	
			pg_indent=	atoi(optarg);
			if (pg_indent<0) {
				warning1("Illegal indent %d specified\n",
					  pg_indent);
				action("Resetting to 0\n");
				pg_indent= 0;
			}
			break;
		case 'J':	
			hdr_layout=	"no_header";
			break;
		case 'l':	
			pg_lines=	atoi(optarg);
			if (!pg_lines) {
				error1("illegal page length %s\n",optarg);
				action("resetting to 66 lines/page\n");
				pg_lines= 66;
			}
			break;
		case 'L':	
			if (!optarg)  {
				pg_orient= UNSPEC_ORIENT;
			}
			else {
				switch (optarg[0]) {
					break;
				case 'p':	
					pg_orient= UPRIGHT|PORTRAIT;
					break;
				case 'i':	
					pg_orient= INVERTED|PORTRAIT;
					break;
				case 'l':	
					pg_orient= LEFT|LANDSCAPE;
					break;
				case 'r':	
					pg_orient= RIGHT|LANDSCAPE;
					break;
				default:
					warning1("illegal orientation '%c'\n",
					optarg[0]);
					action("switching to landscape\n");
					pg_orient= RIGHT|LANDSCAPE;
				}
			}
			break;
		case 'm': 	
			hdr_message= 	optarg;
			break;
		case 'n': 	
			if (optarg)	i_filter=	optarg;
			else		i_filter= 	UNSPEC_IFILTER;
			break;
		case 'O': 	
			if (optarg)	outline=	atoi(optarg);
			else        	outline=	UNSPEC_BORDER;
			break;
		case 'P': 	
			printer=	optarg;
			break;
		case 'p':	
			_add_arg(optarg," ",&filt_args,&filt_arglen);
			break;
		case 'R': 	
			if (optarg)	ruled=		atoi(optarg);
			else		ruled= 		UNSPEC_RULE;
			break;
		case 't':	
			if (optarg)	o_filter= 	optarg;
			else		o_filter=	UNSPEC_OFILTER;
			break;
		case 'v':	
			job_type=	"pmp";
			i_filter=	UNSPEC_IFILTER;
			break;
		case 'w': 	
			pg_cols= 	atoi(optarg);
			if (pg_cols<=0) {
				error1("illegal page width %s\n",optarg);
				action("resetting to 80 columns\n");
				pg_cols= 80;
			}
			if (pg_cols>80) 
				pg_orient= RIGHT|LANDSCAPE;
			break;
		case 'W': 	
			ln_wrap=	!ln_wrap;
			break;
		default: 	
			help_message(argv[0]);
			exit(1);
		}
	}
	
	for ( index = 0; index < optind; index++) {
		_add_arg(argv[index]," ",&command,&len);
	}
	for ( index = optind; index < argc ; index++ ){
		_add_arg(argv[index]," ",&files,&hdr_fileknt);
	}
	RETURN(TRUE);
}
/***===================================================================***/

SetupInfil(argc,argv)
register2	int	argc;
register3	char	*argv[];
{
	extern		int	optind;
	register1	int	knt;
	char	*incmd=		NULL;
	int	inlen= 		0;
	int	p[2];

	D_ENTRY2(mn_debug,"SetupInfil(%d,0x%x)\n",argc,argv);
	if (pipe(p) < 0) {
		printf("Unable to set up Infil\n");
		return (NULL);
	}

	if ( fork() == 0) 
	{
		int filter_is_pr, is_stdin, index;
		char *filename, pagelen[12];

		close(p[0]);
		dup2(p[1], fileno(stdout));
		close(p[1]);
		is_stdin = ( optind == argc );  /* input is stdin */
		if (filter_is_pr = StrMatch(i_filter,"/bin/pr") )
			sprintf(pagelen,"-l%d",pg_lines);
		index = optind;
		do
		    {
			filename = is_stdin ? "" : argv[index];
			if (ln_wrap)
			{
				_add_arg(w_filter," ",&incmd,&inlen);
				_add_arg(filename," ",&incmd,&inlen);
				_add_arg("|","",&incmd,&inlen);
			}
			_add_arg(i_filter," ",&incmd,&inlen);
			if (filter_is_pr) 
			{
				_add_arg(pagelen," ",	&incmd,	&inlen);
				_add_arg("-h \""," ",	&incmd,	&inlen);
				if (pg_header) {
					_add_arg(pg_header,"", &incmd, &inlen);
				}
				else {
					_add_arg(filename, "", &incmd, &inlen);
				}
				_add_arg("\"",	  "",	&incmd,	&inlen);
			}
			if (filt_args) { 
				_add_arg(filt_args," ",	&incmd,&inlen);
			}
			if (!ln_wrap) {
				_add_arg(filename," ",&incmd,&inlen);
			}

			system(incmd);
			bzero(incmd, inlen); 
		}
		while ( ++index < argc );
		_exit(0);
	}
	close(p[1]);
	infil = fdopen(p[0], "r");
	if (!infil) {
		fatal("couldn't open input stream\n");
	}
	else {
		knt= getc(infil);
		if (knt==EOF)	{
			exit(1);
		}
		else	ungetc(knt,infil);
	}
}
/***===================================================================***/

SetupOutfil()
{
	register1	char	*outcmd=	NULL;

	D_ENTRY(mn_debug,"SetupOutfil()\n");

	if (o_filter) 
		outcmd= o_filter;
	else {
		outcmd= u_malloc(strlen(OUT_FILTER)+strlen(printer)+1);
		sprintf(outcmd,OUT_FILTER,printer);
	}
	outfil= popen(outcmd,"w");
	if (!outfil) {
		fatal("couldn't open output stream\n");
	}
	RETURN(TRUE);
}

/***===================================================================***/

SetDefaults()
{
	extern	char	*getenv();

	D_ENTRY(mn_debug,"SetDefaults()\n");
	if (!pg_lines) {
		pg_lines= 66;
	}
	if (!pg_cols) {
		if (pg_orient&LANDSCAPE)
			pg_cols= 152;
		else
			pg_cols=  80;
	}
	if (!pg_indent)
		pg_indent=	DFL_INDENT;
	if (!pg_orient)
		pg_orient=	PORTRAIT|UPRIGHT;
	if (!printer)
		printer=	DFL_PRINTER;
	if (!error_out)
		error_out=	DFL_ERRORS;

	RETURN(TRUE);
}

/***============================================================***/

CountWords(str)
register1 char *str;
{
	register2 int   words= 0;

	D_ENTRY1(mn_debug,"CountWords(%s)\n",str);
	while (isspace(*str)) {
		str++;
	}
	while (*str!='\0') {
		words++;
		while ((*str!='\0')&&(!isspace(*str))) {
			str++;
		}
		while (isspace(*str)) {
			str++;
		}
	}
	RETURN(words);
}

/***============================================================***/

GetEnvironDefaults(argc,argv)
register5 int	  *argc;
register6 char	 **argv[];
{
	register1 char	  *defaults;
	register2 char	 **default_v;
	register3 int	   knt;
	register4 int	   arg_knt;

	D_ENTRY2(mn_debug,"GetEnvironDefaults(0x%x,0x%x)\n",argc,argv);
	defaults= getenv("PPRINT_DEFAULTS");
	if (!defaults) 
		RETURN(FALSE);
	*argc+= CountWords(defaults);
	default_v= (char **)u_calloc(*argc,sizeof(char *));
	while (isspace(*defaults)) 
		defaults++;
	knt= 0;
	default_v[knt++]= *argv[0];
	while (*defaults!='\0') {
		default_v[knt++]= defaults;
		while ((*defaults!='\0')&&(!isspace(*defaults))) {
			defaults++;
		}
		if (isspace(*defaults)) {
			*defaults='\0';
			defaults++;
		}
		while (isspace(*defaults)) {
			defaults++;
		}
	}
	arg_knt= 1;
	while (knt<*argc) {
		default_v[knt++]= (*argv)[arg_knt++];
	}
	*argv= default_v;
	RETURN(TRUE);
}

/***===================================================================***/

Init(argc,argv)
int	argc;
char	*argv[];
{
	D_ENTRY(mn_debug,"Init()\n");
	GetEnvironDefaults(&argc,&argv);
	ParseArgs(argc,argv);
	SetDefaults();
	SetupInfil(argc,argv);
	SetupOutfil();
	PrintFormat();
	RETURN(TRUE);
}

/***===================================================================***/

PrintFormat()
{
	register1 char *tokens= SJ_ENVTOKENS;

	D_ENTRY(mn_debug,"PrintFormat()\n");
	env_HdrPrint(outfil,SJ_ENVNAME,tokens);
	if (hdr_layout)
		env_StrPrint(outfil,"hdr_layout",hdr_layout,tokens);
	if (hdr_message)
		env_StrPrint(outfil,"hdr_message",hdr_message,tokens);
	if (hdr_fieldknt)
		env_SetPrint(outfil,hdr_fields,tokens);
	env_IntPrint(outfil,"text_lines",pg_lines,tokens);
	env_IntPrint(outfil,"text_columns",pg_cols,tokens);
	env_IntPrint(outfil,"text_indent",pg_indent,tokens);
	if (command)
		env_StrPrint(outfil,"command",command,tokens);
	if (files)
		env_StrPrint(outfil,"files",files,tokens);
	if (outline)
		env_IntPrint(outfil,"page_border",outline,tokens);
	if (ruled)
		env_IntPrint(outfil,"page_rules",ruled,tokens);
	if (font_name)
		env_StrPrint(outfil,"text_font",font_name,tokens);
	if (copies)
		env_IntPrint(outfil,"copies",copies,tokens);
	if (error_out)
		env_StrPrint(outfil,"error_messages",error_out,tokens);
	if (error_level) 
		env_StrPrint(outfil,"error_level",error_level,tokens);
	if (pmp_debug)
		env_StrPrint(outfil,"pmp_debug",pmp_debug,tokens);
	if (job_debug)
		env_StrPrint(outfil,"job_debug",job_debug,tokens);
	env_StrPrint(outfil,"job_type",job_type,tokens);
	if (two_up)
		env_SetPrint(outfil,"two_up",tokens);
	else env_SetPrint(outfil,"one_up",tokens);
	env_SetPrint(outfil,"trunc_line",tokens);
	if (pg_orient&PORTRAIT) {
		if (pg_orient&INVERTED)
			env_SetPrint(outfil,"inverted",tokens);
		else env_SetPrint(outfil,"portrait",tokens);
	}
	else {
		if (pg_orient&LEFT)
			env_SetPrint(outfil,"left_landscape",tokens);
		else env_SetPrint(outfil,"right_landscape",tokens);
	}
	env_EndPrint(outfil,tokens);
	RETURN(TRUE);
}

/***===================================================================***/

Print()
{
	register1 int ch;

	D_ENTRY(mn_debug,"Print()\n");
	while ((ch=getc(infil))!=EOF) {
		putc(ch,outfil);
	}
	RETURN(TRUE);
}

/***===================================================================***/

main(argc,argv)
register2 int  argc;
register3 char *argv[];
{

	Init(argc,argv);
	Print();
	return(0);
}
