[net.sources] fontbanner - generate banners from vtroff fonts

anton@ucbvax.ARPA (Jeff Anton) (10/08/85)

jeffg@tekc??? asked about this...  is that Jeff Gutow...  Oh well...

Here it is... Flames & Bugs to /dev/null.... (I don't want to look at this
code anymore.. It was written in my early days of UNIX so don't complain.)

Money to anton@INGRES.BERKELEY.EDU (anton%ucbingres@berkeley.arpa)
	 ucbvax!anton	anton@ucbvax.UUCP



FONTBANNER(PUBLIC)  UNIX Programmer's Manual   FONTBANNER(PUBLIC)



NAME
     fontbanner - print a banner using vtroff fonts

SYNOPSIS
     fontbanner {[-dchrs] [-uCHAR][-p#] [-w#] font [message]}+

DESCRIPTION
     Fontbanner(PUBLIC) outputs a message in large characters to the
     standard output.  The message may be entered on the command line
     or you will be prompted for a single line of input.  The prompt
     will be sent to the standard error to allow redirection of the
     banner output.  If you type the message on the command line you
     must quote it if it contains any spaces or special characters.
     The size of the banner is determined directly from the point of
     the selected font.  Normally, a point is 1/72 of an inch and the
     point of a font is the distaince from the lowest descender to the
     tallest character divided by 72. (A 36 point font is 1/2 an inch
     tall).  Fontbanner, however is much bigger.  If you want n column
     output, n/5.5 point would probably by a good choice.  For 132
     column output, 26 point is good; for 80 column output, 12
     point.  Not all fonts are available in all point sizes so look for
     your font in /usr/lib/vfont/* before using fontbanner.

     The -d option doubles the size of the font and the -h option
     halves it, both at the cost of ragged edges.  The -u option uses
     the character 'CHAR' instead of the default '#' for printing. The
     -s option makes each banner sized character be made up by the
     printer sized version of the same character, while the -f option
     uses the contents of a file for each character printed (useful for
     having a small message inside a bigger one). If the file ends
     before the banner is printed, the default character (or character
     specified by the -u option) will be used to complete the banner
     unless the -r option is given. The -r option causes the input file
     to be read repeated until the banner is done.  The -p option
     followed by a number specifies an offset in characters from the
     left side of a page.  The -w option followed by a number tells how
     wide your device is.  The default is 132 columns.  The -c option
     causes output to be centered.  If -p is given it becomes and
     advisory when used with the -c option.  The whole argument list
     maybe repeated to allow different fonts and page offsets in a
     banner.  Note that the toggle options, c,d,h,s and u do not reset
     but must be toggled if one want to change it when using a
     different font.

FILES
     /usr/lib/vfont/*    directory of font files to choose from

SEE ALSO
     banner(6), vfontinfo(1), vfont(5), vtroff(1)
     _T_h_e _B_e_r_k_e_l_e_y _F_o_n_t _C_a_t_a_l_o_g

AUTHOR
     Jeff Anton (anton@ucbingres)



Printed 3/30/84               local                             1



/*
 * $Header: fontbanner.c,v 1.4 84/08/06 11:56:22 anton Exp $
 *
 * $Log:	fontbanner.c,v $
 * Revision 1.4  84/08/06  11:56:22  anton
 * Lots of new stuff by Charles Spirakis
 * 
 * Revision 1.3  84/03/31  00:09:01  anton
 * Added lots of stuff - jaa
 * 
 * Revision 1.2  84/02/01  21:27:36  cc-sec
 * spaceing fixed and RCS stuff added - jaa
 * 
 */
#include <stdio.h>
#include <ctype.h>
#include <sys/file.h>
#include <vfont.h>

#define DEF '#'

struct	header	fhead;
struct	dispatch dtab[256],*dp;
long	fbase = sizeof fhead + sizeof dtab;
char	cbits[4000],*cntl(), *iname;
char	rept = DEF;
int	h,w,widthbytes,md, mu, flags;
int	pwid = 132;

#define	MAG	1
#define	CEN	2
#define HALF	4
#define INP	8
#define REDO	16

main(argc, argv)
int	argc;
char	**argv;
{
	char	line[132], chr, *cpos, *fontname, *comname;
	int	i, poff;

	poff = flags = 0;
	comname = *argv;
again:
	while (--argc && **++argv == '-') {
		while (chr = *++*argv)
			switch (chr) {
			case 'p':
				if (*++*argv) {
					poff = atoi(*argv);
					goto nxtarg;
				}
				else if (argc-- > 2) {
					poff = atoi(*++argv);
					goto nxtarg;
				 } else
					goto usage;
				break;
			case 'w':
				if (*++*argv) {
					pwid = atoi(*argv);
					goto nxtarg;
				}
				else if (argc-- > 2) {
					pwid = atoi(*++argv);
					goto nxtarg;
				} else
					goto usage;
				break;
			case 'u':
				rept = *(*argv + 1);
				if (! isprint(rept))
					rept = DEF;
				goto nxtarg;
				break;
			case 'f':
				if (*++*argv) {
					iname = *argv;
					flags |= INP;
					goto nxtarg;
				} else if (argc-- > 2) {
					iname = *++argv;
					flags |= INP;
					goto nxtarg;
				} else
					goto usage;
				break;
			case 'd':
				flags ^= MAG;
				flags &= ~HALF;
				break;
			case 'h':
				flags ^= HALF;
				flags &= ~MAG;
				break;
			case 'c':
				flags ^= CEN;
				break;
			case 'r':
				flags ^= REDO;
				break;
			default:
				fprintf(stderr, "usage: -%c flag unknown\n", chr);
			}
nxtarg:		;
	}
	cpos = NULL;
	switch (argc) {
	case 1:
		fontname = *argv;
		break;
	case 0:
usage:
		fprintf(stderr, "usage: %s {[-dchr] [-uCHAR] [-p#] [-w#] font [\"message\"]}+ (i.e. repeatable)\n", comname);
		exit(1);
	default:
		cpos = argv[1];
		fontname = *argv;
		break;
	}

	if (flags & INP)
		openinp(iname);

	printban(fontname, comname, cpos, flags, poff);

	argv++;
	if (--argc >= 2)
		goto again;
	exit(0);
}

printban(fontname, comname, cpos, flags, poff)
char	*fontname, *comname, *cpos;
int	flags, poff;
{
	int	fd, spwidth, i;
	char	line[80], *ext, chr;

	if ((fd = open(fontname, O_RDONLY)) == -1) {
		strcpy(line, "/usr/lib/vfont/");
		strcat(line, fontname);
		if ((fd = open(line, O_RDONLY)) == -1) {
			perror(fontname);
			exit(2);
		}
	}
	ext = fontname + strlen(fontname);
	if (ext[-1] == 'r') {
		fprintf(stderr,"%s: can't use rotated fonts\n",comname);
		exit(5);
	}
	while (*--ext != '.');
	spwidth = atoi(++ext);
	spwidth += spwidth >> 1;
	if (flags & MAG)
		spwidth <<= 1;
	else if (flags & HALF)
		spwidth >>= 1;

	if (read(fd, &fhead, sizeof fhead) != sizeof fhead ||
	    read(fd, dtab, sizeof dtab) != sizeof dtab) {
		fprintf(stderr, "%s: file too small\n", fontname);
		exit(3);
	}
	if (fhead.magic != 0436) {
		fprintf(stderr,"%s: magic number wrong\n",fontname);
		exit(4);
	}
	md = mu = 0;
	for (i = 0, dp = dtab; i < 256; dp++, i++) {
		if (!dp->nbytes)
			continue;
		if (md < dp->down)
			md = dp->down;
		if (mu < dp->up)
			mu = dp->up;
	}
	if (2*(poff + mu + md) > pwid)
		fprintf(stderr, "%s: Warning: %s is too tall for width %d offset %d\n", comname, fontname, pwid, poff);
	if (flags & CEN)
		poff = (pwid + poff)/2 - mu - md;
	if (cpos == NULL) {
		fprintf(stderr,"Message: ");
		gets(line);
		cpos = line;
	}
	while (chr = *cpos++) {
		dp = dtab + chr;
		if (dp->nbytes == 0) {
			if (chr == ' ')
				for (i = 0; i < spwidth; i++)
					putchar('\n');
			else
				fprintf(stderr,"%s: Warning: '%s' (0x%x) not in %s\n",comname,cntl(chr),chr,fontname);
			continue;
		}
		lseek(fd, fbase + dp->addr, 0);
		read(fd, cbits, dp->nbytes);
		h = dp->up + dp->down;
		w = dp->left + dp->right;
		widthbytes = ( w + 7 ) >> 3;
		report(poff);
	}
	close(fd);
}

report(poff)
int	poff;
{
	int	k,l,top;
	char	mstr[9], spstr[9];

	switch (flags & (MAG | HALF)) {
	   case MAG:
		strcpy(spstr, "    ");
		sprintf(mstr, "%c%c%c%c", rept, rept, rept, rept);
		break;
	   case HALF:
		strcpy(spstr, " ");
		sprintf(mstr, "%c", rept);
		break;
	   default:
		strcpy(spstr, "  ");
		sprintf(mstr, "%c%c", rept, rept);
	}

	for (l = 0; l < dp->width; l++) {
		for (k = 0; k < poff; k++)
			putchar(' ');
		for (top = - dp->up; top <= md && !fbit(top,l); top++);
		for (k = md; k >= top; k--) {
			if ((flags & INP) && fbit(k,l))
				inpstr(mstr);
			fputs(fbit(k,l)?mstr:spstr,stdout);
		}
		putchar('\n');
		if (flags & MAG) {
			for (k = md; k >= top; k--) {
				if ((flags & INP) && fbit(k,l))
					inpstr(mstr);
				fputs(fbit(k,l)?mstr:spstr,stdout);
			}
			putchar('\n');
		}
	}
}

fbit(row, col)
int	row, col;
{
	int	thisbyte,thisbit;

	row += dp->up;
	if (row < 0 || col < 0 || row >= h || col >= w)
		return(0);
	thisbyte = cbits[row * widthbytes + ( col >> 3 )];
	thisbit = 0x80 >> (col & 7);
	return((thisbyte & thisbit) != 0);
}

char	*
cntl(chr)
char	chr;
{
	static	char	ret[3];

	if (chr >= 128 || iscntrl(chr))
		ret[0] = '^', ret[1] = chr + '@', ret[2] = '\0';
	else
		ret[0] = chr, ret[1] = '\0';
	return(ret);
}

FILE *inp = NULL;

openinp(name)
char *name;
{
	if (inp != NULL)
		fclose(inp);

	if ((inp = fopen(name, "r")) == NULL) {
		fprintf(stderr, "\nCouldn't open %s.\n", name);
		exit(7);
	}
}
inpstr(str)
char *str;
{
	int i, j;
	char myget();

	switch (flags & (MAG | HALF)) {
	   case MAG:
		i = 4;
		break;
	   case HALF:
		i = 1;
		break;
	   default:
		i = 2;
	}

	for (j = 0; j < i; j++)
		*str++ = myget();
	*str = '\0';
}

char
myget()
{
	static int ch, oldchar;

	while (1) {
		if ((ch = getc(inp)) == EOF) {
			if (flags & REDO) {
				openinp(iname);
				if ((ch = getc(inp)) == EOF) {
					fprintf(stderr, "Can't use a null file for input");
					exit(8);
				}
			} else {
				return (oldchar = rept);
			}
		}
		if ((oldchar == ' ') && (isspace(ch)))
			continue;

		if (isprint(ch))
			return (oldchar = ch);

		if (isspace(ch))
			return (oldchar = ' ');
	}
}
-- 
C knows no bounds.
					Jeff Anton
					U.C.Berkeley
					Ingres Group
					ucbvax!anton
					anton@BERKELEY.EDU