/*
 * titlepage.c : title page printing program. Create a banner page
 *               for listing heading.
 *
 *       by Joel Swank 9-23-88
 *
 * This program is in the public domain, no rights reserved.
 */

#include <stdio.h>
#include <graphics/text.h>
#include <libraries/diskfont.h>
#include <functions.h>
#include <ctype.h>

#ifdef NULL
#undef NULL
#endif
#define NULL ((void *)0)

/****************************************************************/
/*         Data Area Definitions                                */
/****************************************************************/


/**** printer escape sequences ****/

char eliteon[] = "\033[2w";
char eliteoff[] = "\033[1w";
char condensedon[] = "\033[4w";
char condensedoff[] = "\033[3w";
char lpi8on[] = "\033[0z";
char lpi8off[] = "\033[1z";
char boldon[] = "\033[1m";
char boldoff[] = "\033[22m";
char nlqon[] = "\033[2\"z";
char nlqoff[] = "\033[1\"z";
char doubon[] = "\033[6w";
char douboff[] = "\033[5w";
char italon[] = "\033[3m";
char italoff[] = "\033[23m";


/****   Buffers and Pointers      ****/

unsigned char printbuf[1000];   /* buffer for output line */
unsigned char stringbuf[100];   /* buffer to hold processed output string */
unsigned char *printstring;     /* pointer to string to print */
unsigned char *pbptr;           /* pointer into printbuf  */
unsigned char hchar;            /* hold user specified print character */


/**** option mode flags ****/

int eflag = FALSE;  /* flag for elite printing */
int cflag = FALSE;  /* flag for condensed printing */
int bflag = FALSE;  /* flag for bold printing */
int uflag = FALSE;  /* flag for upper printing */
int wflag = FALSE;  /* flag for double wide printing */
int qflag = FALSE;  /* flag for NLQ printing */
int iflag = FALSE;  /* flag for italics printing */
int flag8 = FALSE;  /* flag for 8lpi printing */
int lflag = FALSE;  /* flag for linesize specified by user */
int hflag = FALSE;  /* flag for print character  specified by user */
int centerflag = FALSE;  /* flag for centering output */


/**** Things for dealing with the font data structure ****/

unsigned short *chardata;    /* pointer to array of character patterns */
unsigned short *charspace;   /* pointer to array of character widths   */

struct charDef {       /* from RKM Devices & Libraries page 207  */
	WORD charOffset;   /* bit offset to character in chardata    */
	WORD charBitWidth; /* bit width of character data            */
	};

struct charDef *charloc; /* pointer to array of chardefs */
struct TextFont *myfont = NULL; /* pointer to open font  */

char fontname[100] = "topaz.font";

struct	TextAttr myattr = {
    (STRPTR) fontname,
    8,
    0,
    FPB_DISKFONT};


/**** Things needed to do time/date ****/

long clock, time();   /* place to store time */
char *ctime(), *timebuf;

/****  Misc data ****/

struct Library *DiskfontBase = NULL;
struct GfxBase *GfxBase = NULL;
FILE *out = NULL;
int maxline;        /* max output line size */
unsigned char *rindex();


/****************************************************************/
/*         Main program starts here                             */
/****************************************************************/

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

	if (argc < 2)
		{
		usage();
		exit(1);
		}

	GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", NULL);
	if (GfxBase == NULL)
		{
		fprintf(stderr,"titlep:cannot open graphics library\n");
		exit(1);
		}

	DiskfontBase = (struct Library *)OpenLibrary("diskfont.library", NULL);
	if (DiskfontBase == NULL) {
		fprintf(stderr,"titlep:cannot open font library\n");
		done(22);
		}

	/* parse the command line and execute the parameters */

	argindex = 0;

	while(--argc > 0)
		{
		argindex++;
		do_parm(argv[argindex]);
		}


done(0);
}

/*
 * do_file : process an alternate input file
 */

do_file(filename)
char *filename;
{
	FILE *in;
	unsigned char inbuf[100], *inptr, parmbuf[100], *parmptr;

	in = fopen(filename,"r");
	if (in == NULL)
		{
		fprintf(stderr,"titlep:cannot open %s\n",filename);
		done(7);
		}

	while (fgets(inbuf,100,in))
		{
		unsigned char *t;
		t = rindex(inbuf,'\n');
		if (t) *t = '\0'; /* blasted newline! */
		inptr = inbuf;
		while (*inptr != '\0')	/* do till end of line */
			{
			parmptr = parmbuf;
			/*** parse out a parm ***/
			while (*inptr != ' ' && *inptr != '\t' && *inptr != '\0')
				{
				if (*inptr == '\\' && inptr[1] == '\"')
					{	/* its an escaped quote */
					*parmptr++ = '\"';
					inptr += 2;
					continue;
					}
				if (*inptr == '\"')
					{      /*** handle a quoted string  ***/
					inptr++;
					while (*inptr != '\"' && *inptr != '\0')
						{
						if (*inptr == '\\' && inptr[1] == '\"')
							{	/* its an escaped quote */
							*parmptr++ = '\"';
							inptr += 2;
							continue;
							}
						*parmptr++ = *inptr++;
						}
					if (*inptr == '\"') inptr++;
					continue;
					}
				*parmptr++ = *inptr++;
				}
			*parmptr = '\0';
			if (parmbuf[0] != '\0') do_parm(parmbuf);
			if (*inptr++ == '\0') break;
			}	/* end while *inptr */
		}	/* end while fgets */
	fclose(in);
}


/*
 * do_parm : process one parameter
 */

do_parm(parm)
unsigned char *parm;
{
	register int i,j;

	if (parm[0] == '-')
		{
		switch (parm[1])
			{
			case 'a':	/* alternate Input file */
			  do_file(&parm[2]);
			  break;
			case 'o':	/* alternate Output file */
			  if (out != NULL)
			  	{
				fprintf(stderr,"titlep: Output file already open\n");
				done(5);
				}
			  if (parm[2] == '\0') out = stdout;
			  else open_out(&parm[2]);
			  break;
			case 'u':	/* Upper mode ON */
			  uflag = TRUE;
			  break;
			case 'b':	/* Bold mode ON */
			  do_out(boldon);
			  bflag = TRUE;
			  break;
			case 't':	/* Centering mode ON */
			  centerflag = TRUE;
			  break;
			case 'q':	/* NLQ mode ON */
			  do_out(nlqon);
			  qflag = TRUE;
			  break;
			case 'w':	/* Double Wide mode ON */
			  do_out(doubon);
			  wflag = TRUE;
			  break;
			case 'e':	/* Elite mode ON */
			  do_out(eliteon);
			  eflag = TRUE;
			  break;
			case 'i':	/* Italics mode ON */
			  do_out(italon);
			  iflag = TRUE;
			  break;
			case 'c':	/* Condensed mode ON */
			  do_out(condensedon);
			  cflag = TRUE;
			  break;
			case '8':	/* 8 LPI mode ON */
			  do_out(lpi8on);
			  flag8 = TRUE;
			  break;
			case 'h':	/* Set the print character */
			  hchar = parm[2];
			  if (hchar == '\0') hflag = FALSE;
			  else hflag = TRUE;
			  break;
			case 'l':	/* set maximum line size */
			  maxline = atoi(&parm[2]);
			  if (maxline <20 || maxline > 999)
				{
			  	fprintf(stderr,"titlep:Bad linesize: %s\n",
				   parm);
				done(6);
				}
			  lflag = TRUE;
			  break;
			case 'f':	/* Specify a font */
			  strncpy(fontname,&parm[2],95);
			  strcat(fontname,".font");
			  break;
			case 's':	/* specify a font size */
			  myattr.ta_YSize = (UWORD) atoi(&parm[2]);
			  break;
			case 'd':	/* Print date and time */
			  clock = time(NULL);
			  timebuf = ctime(&clock);
			  setmax();
			  for (j=0; j < ((maxline-strlen(timebuf))/2); j++) do_out(" ");
			  do_out(timebuf);
			  break;
			case 'n':	/* Print some newlines */
			  i = atoi(&parm[2]);
			  if (i == 0) i=1;
			  for (j=0; j<i; j++) do_out("\n");
			  break;
			case 'p':	/* Print a form feed */
			  do_out("\f");
			  break;
			default:
			  fprintf(stderr,"titlep:Bad flag: %s\n",parm);
			  usage();
			  done(21);
			}	/* end switch */
	}else if (parm[0] == '+'){
		switch (parm[1])
			{
			case 'u':	/* Upper mode OFF */
			  uflag = FALSE;
			  break;
			case 'b':	/* Bold mode OFF */
			  do_out(boldoff);
			  bflag = FALSE;
			  break;
			case 't':	/* Centering mode OFF */
			  centerflag = FALSE;
			  break;
			case 'q':	/* NLQ mode OFF */
			  do_out(nlqoff);
			  qflag = FALSE;
			  break;
			case 'w':	/* Double Wide mode OFF */
			  do_out(douboff);
			  wflag = FALSE;
			  break;
			case 'e':	/* Elite mode OFF */
			  do_out(eliteoff);
			  eflag = FALSE;
			  break;
			case 'i':	/* Italics mode OFF */
			  do_out(italoff);
			  iflag = FALSE;
			  break;
			case 'c':	/* Condensed mode OFF */
			  do_out(condensedoff);
			  cflag = FALSE;
			  break;
			case '8':	/* 8 LPI mode OFF */
			  do_out(lpi8off);
			  flag8 = FALSE;
			  break;
			case 'l':	/* Reset to default linesize */
			  lflag = FALSE;
			  break;
			case 'h':	/* Reset to default print character */
			  hflag = FALSE;
			  break;
			default:
			  fprintf(stderr,"titlep:Bad flag: %s\n",parm);
			  usage();
			  done(20);
			}   /* end switch */
	}else {
		/* not a flag, must be a string, so print it */
		printstring = parm;
		do_string();
		}
}


/*
 * do_string : output one string of data
 */

do_string()
{

	int i,j;

	if ((myfont = (struct TextFont *)OpenDiskFont(&myattr)) == NULL) {
		fprintf(stderr,"titlep:cannot find font: %s\n", myattr.ta_Name);
		done(2);
	}

	setmax();

	charspace = (unsigned short *) myfont->tf_CharSpace;
	charloc = (struct charDef *) myfont->tf_CharLoc;

	if (out == NULL) open_out("PRT:");

	proc_str();	/* process string for ~ */

	for (i=0; i<myfont->tf_YSize; i++)
		{
		for (j=0; j<maxline; j++) printbuf[j] =' ';
		do_row(i);
		printbuf[maxline] ='\0';
		if (centerflag)
			{
			j = (maxline - strlen(printbuf))/2;
			if (j > 0) while(j-- > 0) aputc(' ',out);
			}
		fputs(printbuf,out);
		aputc('\n',out);
		}

	if (myfont   != NULL) CloseFont( myfont );
	myfont = NULL;

}


/*
 * do_row : build one row of printdata.
 */

do_row(row)
int row;   /* which row to do */
{
	int i;
	register unsigned short next16;
	unsigned char *pstrptr;

	pbptr = printbuf;
	pstrptr = printstring;
	chardata = (unsigned short *) myfont->tf_CharData +
					(myfont->tf_Modulo * row)/2;

	if (iflag) pbptr += (myfont->tf_YSize - 1 - row);

	while (*pstrptr != '\0') /* do each charcter  */
		{
		long bitoff, wordoff, bitnum, bitcnt, charoff, bumpcnt;
		unsigned char *cptr;
		charoff = ((unsigned long) *pstrptr) - myfont->tf_LoChar;
		if (uflag) charoff += 128;
		if ((unsigned long) *pstrptr > myfont->tf_HiChar || charoff < 0)
			charoff = myfont->tf_HiChar+1 - myfont->tf_LoChar;
		bitoff = charloc[charoff].charOffset;
		bitcnt = charloc[charoff].charBitWidth;
		bumpcnt = bitcnt;
		wordoff = bitoff/16;
		bitnum = bitoff%16;

		cptr = pbptr;
		while (bitcnt > 0)    /* do up to 16 bits */
			{
			/* construct dot info in next16 */
			next16 = chardata[wordoff];
			if (bitnum != 0) next16 = (next16 << bitnum)
				| (chardata[wordoff+1] >> (16-bitnum));
			for (i=0; i<16; i++)
				{
				if (next16 & 0x08000) *cptr = (hflag) ? hchar : *pstrptr;
				if (*cptr > 128) *cptr -= 128;
				if (!isprint(*cptr)) *cptr = 'O';
				cptr++;
				if (--bitcnt < 1) break;
				next16 = next16 << 1;
				}
			wordoff++;
			}
		if (myfont->tf_Flags & FPF_PROPORTIONAL && charspace[charoff] > 0)
			pbptr += charspace[charoff]; /* bump output ptr */
		else pbptr += bumpcnt;
		pstrptr++;                   /* bump input ptr */
		if (pbptr > printbuf + maxline) break;
		}
	if (iflag) pbptr += row;
	*pbptr = '\0';
}

/*
 * done - just clean up that which is open, and then leave.
 */
done(how)
int how;
    {
	res_pr();
    if (GfxBase) CloseLibrary(GfxBase) ;
    if (DiskfontBase) CloseLibrary(DiskfontBase) ;
	if (myfont   != NULL) CloseFont( myfont );
    exit(how) ;
    }

/*
 * do_out - put stuff to output file, open it if necessary
 */

do_out(str)
char *str;
{
	if (out == NULL) open_out("PRT:");
	fputs(str,out);
}


/*
 * open_out - open the output file
 */

open_out(filename)
char *filename;
{
	out = fopen(filename,"w");
	if (out == NULL)
		{
		fprintf(stderr,"titlep:cannot open %s\n",filename);
		done(4);
		}
}

/*
 * res_pr - reset printer to default conditions
 */

res_pr()
{
	/* restore printer to default condition */
	if (bflag) do_out(boldoff);
	if (eflag) do_out(eliteoff);
	if (cflag) do_out(condensedoff);
	if (flag8) do_out(lpi8off);
	if (wflag) do_out(douboff);
	if (qflag) do_out(nlqoff);
	if (iflag) do_out(italoff);
}

/*
 * setmax - set maxline according to print size
 */

setmax()
{
	if (!lflag)	/* if user has specified, skippit */
		{
		maxline = 80; /* 80 is default */
		if (eflag) maxline = 96; /* 96 for elite */
		if (cflag) maxline = 132; /* 132 for condensed */
		if (cflag && eflag) maxline = 160; /* 160 for both */
		if (wflag) maxline /= 2;	/* halve it for double wide */
		}
}

/*
 * usage - display syntax information
 */

usage()
{
	fprintf(stderr,"Usage: titlepage [options] [strings] . . .\n");
	fprintf(stderr,"Print a banner title page using Amiga fonts\n");
	fprintf(stderr,"[options] = -abcdefhilnopqstw, +bcehiqtw\n");
	fprintf(stderr,"[strings] = strings to print\n");
}

/*
 * proc_str - process printstring for ~ shifting
 */

proc_str()
{
	unsigned char *pstr, *nstr;
	pstr = printstring;
	nstr = stringbuf;

	while (*pstr != '\0')
		if (*pstr != '~') *nstr++ = *pstr++;
		else {
			if (*(++pstr) != '~') *nstr++ = *pstr + 128;
			else *nstr++ = '~';
			pstr++;
			}
	*nstr = '\0';
	printstring = stringbuf;
}
