[comp.sources.misc] v07i007: Troff C/A/T to Postscript filter

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (06/04/89)

Posting-number: Volume 7, Issue 7
Submitted-by: everson@compsci.bristol.ac.uk
Archive-name: thack

Enclosed please find thack, a Troff C/A/T to Postscript filter, written
by a colleague of mine, Gareth Waddell.

Sample usage of thack is, say:

	troff -t -man /usr/man/sh.1 | thack | lpr -Ppostscript

It does not claim to be perfect, but I personally have used it for
printing many documents in the past, especially manual pages and found
it very useful.

It was written under SunOS3.5, but has been run on a 3B2 running System V
and produces particularly nice output under SunOS4.0 or later as Sun
altered the troff font width tables to match those of Postscript at
that release.

The Postscript produced by this program has been successfully printed
on an Apple Laserwriter I and an Apple Laserwriter IINTX. It can also
be previewed under Sunview with the Rutherford Postscript Interpreter.

Phill Everson
Computer Science Dept.,
University of Bristol, UK

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 1 (of 1)."
# Contents:  COPYRIGHT MANIFEST Makefile th.h thack.1 thack.c
# Wrapped by everson@kukini on Mon May 22 12:29:59 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'COPYRIGHT' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'COPYRIGHT'\"
else
echo shar: Extracting \"'COPYRIGHT'\" \(1092 characters\)
sed "s/^X//" >'COPYRIGHT' <<'END_OF_FILE'
Copyright 1989 Gareth Waddell
X
This notice and any statement of authorship must be reproduced
on all copies.  The author does not make any warranty expressed
or implied, or assumes any liability or responsiblity for the
use of this software.
X
Any distributor of copies of this software shall grant the
recipient permission for further redistribution as permitted
by this notice.  Any distributor must distribute this software
without any fee or other monetary gains, unless expressed written
permission is granted by the author.
X
This software or its use shall not be: sold, rented, leased,
traded, or otherwise marketed without the expressed written
permission of the author.
X
If the software is modified in a manner creating derivative
copyrights, appropriate legends may be placed on derivative
work in addition to that set forth above.
X
Permission is hereby granted to copy, reproduce, redistribute or
otherwise use this software as long as the conditions above
are met.
X
All rights not granted by this notice are reserved.
X
Author: Gareth Waddell
X		Phill Everson <everson@uk.ac.bris.cs>
END_OF_FILE
if test 1092 -ne `wc -c <'COPYRIGHT'`; then
    echo shar: \"'COPYRIGHT'\" unpacked with wrong size!
fi
# end of 'COPYRIGHT'
fi
if test -f 'MANIFEST' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'MANIFEST'\"
else
echo shar: Extracting \"'MANIFEST'\" \(300 characters\)
sed "s/^X//" >'MANIFEST' <<'END_OF_FILE'
X   File Name		Archive #	Description
X-----------------------------------------------------------
X COPYRIGHT                  1	
X MANIFEST                   1	This shipping list
X Makefile                   1	
X th.h                       1	
X thack.1                    1	
X thack.c                    1	
END_OF_FILE
if test 300 -ne `wc -c <'MANIFEST'`; then
    echo shar: \"'MANIFEST'\" unpacked with wrong size!
fi
# end of 'MANIFEST'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(91 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
X.PRECIOUS: thack.c th.h
X
thack: thack.o
X	cc -o thack thack.o
X
thack.c: th.h
X	touch thack.c
END_OF_FILE
if test 91 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'th.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'th.h'\"
else
echo shar: Extracting \"'th.h'\" \(366 characters\)
sed "s/^X//" >'th.h' <<'END_OF_FILE'
X#include <stdio.h>
char *table[2][2]=
X	{ /* FONT 0,1,2,4,5,6,7 */
X	 " htnmlizsdbxfjuk p ; a_c`e'o r v-wq/.g ,&y % QTOHNMLRGIPCVEZDBSY",
X	 " FXAWJUK0123456789*       ()[]  = :+ ! ? |   $$$$$$$$$$$$$$$$$$$",
X	 /* FONT 3 */
X	 " yqnmlizsdbxhfuk p   a c e=o r t_ Y  g   w   FQW  VL-G P    D S ",
X	 " >X</ U                   {}   #  ~    *   +  $$$$$$$$$$$$$$$$$$",
X	 };
END_OF_FILE
if test 366 -ne `wc -c <'th.h'`; then
    echo shar: \"'th.h'\" unpacked with wrong size!
fi
# end of 'th.h'
fi
if test -f 'thack.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'thack.1'\"
else
echo shar: Extracting \"'thack.1'\" \(1324 characters\)
sed "s/^X//" >'thack.1' <<'END_OF_FILE'
X.\" .TH name section cent-foot
X.TH THACK 1 "28 August 1987"
X.SH NAME
X.\" name \- function
thack \- hack about with TROFF output
X.SH SYNOPSIS
X.\" Bold keywords, Italic variables, [] options, | alternatives.
X.B thack
X.SH DESCRIPTION
X.\" Italic files, commands, IR manual-entry (manual-section)
X.I Thack
is a hack to
convert
X.IR troff (1)
output into 
postscript.
The postscript it
produces is not highly
efficient.
X.\".SH OPTIONS
X.\" Itemised list of options
X.\".SH FILES
X.\" List of all files used by the program
X.SH "SEE ALSO"
X.\" List of references, textual, and MAN pages.
troff(1), nroff(1), eqn(1), tbl(1)
X.br
XFormatting Documents on the Sun Workstation
X.br
Postscript Language Reference Manual
X.SH DIAGNOSTICS
X.\" List of error messages and return codes the user may expect
Cryptic Messages such as L3/16 indicate
that an uncatered for code has been
sent (24 have yet to be identified).
More interesting messages such
as 'Sequence Bell Logo is not allowed'
are also printed. There are five of these
cases. However, some illegal sequences are 
intercepted and used
as additional font information.
X.SH BUGS
X.\" Known Limitations or Desirable additions to the command
Like all hacks, there are plenty.
X.br
The code is highly inefficient.
X.br
Many Special characters are Wrong.
X.br
XEqn(1) & Tbl(1) are not 100% compatible.
END_OF_FILE
if test 1324 -ne `wc -c <'thack.1'`; then
    echo shar: \"'thack.1'\" unpacked with wrong size!
fi
# end of 'thack.1'
fi
if test -f 'thack.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'thack.c'\"
else
echo shar: Extracting \"'thack.c'\" \(10227 characters\)
sed "s/^X//" >'thack.c' <<'END_OF_FILE'
X#include "th.h"
X
int xpos, ypos, cx, cy;
int font, cfont, size, csize, tfont, tsize;
char *pstr, *cstr();
X
main()
X{
X	int c, i;
X	int sflag;
X	int hdist, vdist;
X	int esc, lead;
X	int fh;
X
X	hdist = vdist = 0;
X	cfont = csize = -1;
X	tfont = font = 0;
X	tsize = size = 12;
X	esc = lead = 1;
X	cy = ypos = 1692;
X	cx = xpos = 0;
X	sflag = 0;
X	prolog();
X	newpage();
X	while ((c = getchar()) != EOF) {
X		font = tfont;
X		size = tsize;
X		if (c & 0x80)
X			hdist += ~c & 0x7f;
X		else if ((c & 0xe0) == 0x60)
X			vdist += ~c & 0x1f;
X		if ((c & 0xc0) == 0) {
X			if ((c & 0x3f) != 0) {
X				if (hdist || vdist) {
X					xpos += esc * hdist;
X					ypos -= lead * vdist;
X					if (ypos <= 0) {
X						endpage();
X						newpage();
X						while (ypos < 0)
X							ypos += 1584;
X					}
X					hdist = 0;
X					vdist = 0;
X				}
X				sflag = 1;
X				if (table[(font % 4) == 3][fh][c & 0x3f] == ' ') {
X					if (font % 4 != 3)
X						if (fh == 0)
X							switch (c & 0x3f) {
X							case 18:
X								pstr = "\\320";
X								break;	/* \(em */
X							case 28:
X								illegal("1/4");
X								break;	/* \(14 */
X							case 30:
X								illegal("1/2");
X								break;	/* \(12 */
X							case 38:
X								illegal("3/4");
X								break;	/* \(34 */
X							default:
X								fprintf(stderr, ">>>>> L%d/%d\n", font, c & 0x3f);
X							}
X						else
X							switch (c & 0x3f) {
X							case 19:
X								pstr = "\\320";
X								break;	/* \- */
X							case 20:
X								pstr = "\\256";
X								break;	/* fi */
X							case 21:
X								pstr = "\\257";
X								break;	/* fl */
X							case 22:
X								pstr = "ff";
X								break;	/* ff */
X							case 23:
X								pstr = "\\242";
X								break;	/* cent */
X							case 24:
X								pstr = "f\\257";
X								break;	/* ffl */
X							case 25:
X								pstr = "f\\256";
X								break;	/* ffi */
X							case 30:
X								fontps(3, size, "\\260");
X								break;	/* degree */
X							case 31:
X								pstr = "\\262";
X								break;	/* dagger */
X							case 33:
X								fontps(3, size, "\\322");
X								break;	/* reg */
X							case 38:
X								pstr = "\\267";
X								break;	/* bullet */
X							case 40:
X								fontps(3, size, "\\242");
X								break;	/* footmark */
X							case 43:
X								fontps(3, size, "\\323");
X								break;	/* c'right */
X							case 44:
X								pstr = "\\250";
X								break;	/* square ? */
X							default:
X								fprintf(stderr, ">>>>> U%d/%d\n", font, c & 0x3f);
X							}
X					else if (fh == 0)
X						switch (c & 0x3f) {
X						case 18:
X							fontps(0, size, "@");
X							break;	/* @ */
X						case 19:
X							pstr = "\\257";
X							break;	/* down arrow */
X						case 22:
X							pstr = cstr('|');
X							break;	/* OR */
X						case 24:
X							fontps(0, size, "\"");
X							break;	/* " */
X						case 28:
X							pstr = "\\254";
X							break;	/* <- */
X						case 30:
X							pstr = "\\255";
X							break;	/* up arrow */
X						case 33:
X							fontps(0, size, "\\\\");
X							break;	/* Backslash ! */
X						case 35:
X							illegal("Bell Logo");
X							break;	/* Bell Logo */
X						case 36:
X							pstr = "\\245";
X							break;	/* infinity */
X						case 38:
X							pstr = "\\312";
X							break;	/* impr. super */
X						case 39:
X							pstr = "\\265";
X							break;	/* proportional */
X						case 40:
X							pstr = "\\336";
X							break;	/* right hand */
X						case 43:
X							pstr = "\\321";
X							break;	/* grad */
X						case 48:
X							pstr = "\\310";
X							break;	/* union */
X						case 49:
X							pstr = "\\140";
X							break;	/* sqrtroof */
X						case 54:
X							pstr = "\\362";
X							break;	/* integral */
X						case 56:
X							pstr = "\\314";
X							break;	/* subset */
X						case 57:
X							pstr = "\\311";
X							break;	/* superset */
X						case 58:
X							pstr = cstr('~');
X							break;	/* approximate */
X						case 59:
X							pstr = "\\256";
X							break;	/* partial */
X						case 61:
X							pstr = "\\326";
X							break;	/* sqrt */
X						case 63:
X							pstr = "\\273";
X							break;	/* ~= */
X						default:
X							fprintf(stderr, ">>>>> L%d/%d\n", font, c & 0x3f);
X						}
X					else
X						switch (c & 0x3f) {
X						case 5:
X							pstr = "\\307";
X							break;	/* intersect */
X						case 7:
X							pstr = "\\330";
X							break;	/* not */
X						case 8:
X							pstr = "\\371";
X							break;	/* righceil, sq */
X						case 9:
X							pstr = "\\354";
X							break;	/* leftop, curly */
X						case 10:
X							pstr = "\\357";
X							break;	/* bold vertical */
X						case 11:
X							pstr = "\\355";
X							break;	/* lefcent, curly */
X						case 12:
X							pstr = "\\356";
X							break;	/* leftbot, curly */
X						case 13:
X							pstr = "\\374";
X							break;	/* rightop, curly */
X						case 14:
X							pstr = "\\375";
X							break;	/* righcen, curly */
X						case 15:
X							pstr = "\\376";
X							break;	/* rightbot, curly */
X						case 16:
X							pstr = "\\373";
X							break;	/* rigfloor, sq */
X						case 17:
X							pstr = "\\353";
X							break;	/* lefloor, sq */
X						case 18:
X							pstr = "\\351";
X							break;	/* leftceil, sq */
X						case 19:
X							pstr = "\\264";
X							break;	/* times */
X						case 20:
X							pstr = "\\270";
X							break;	/* divide */
X						case 21:
X							pstr = "\\261";
X							break;	/* +- */
X						case 22:
X							pstr = "\\243";
X							break;	/* <= */
X						case 23:
X							pstr = "\\263";
X							break;	/* >= */
X						case 24:
X							pstr = "\\272";
X							break;	/* ident. equ */
X						case 25:
X							pstr = "\\271";
X							break;	/* != */
X						case 28:
X							fontps(0, size, "\\302");
X							break;	/* acute */
X						case 29:
X							fontps(0, size, "\\301");
X							break;	/* grave */
X						case 30:
X							fontps(0, size, "^");
X							break;	/* ^ */
X						case 32:
X							pstr = "\\334";
X							break;	/* left hand */
X						case 33:
X							pstr = "\\316";
X							break;	/* Member of */
X						case 35:
X							pstr = "\\306";
X							break;	/* Empty set */
X						case 37:
X							fontps(0, size, "\\263");
X							break;	/* doubdagg */
X						case 38:
X							pstr = "\\275";
X							break;	/* box vertical */
X						case 40:
X							pstr = "\\315";
X							break;	/* impr. subset */
X						case 41:
X							illegal("circle");
X							break;	/* circle */
X						case 44:
X							pstr = "\\256";
X							break;	/* -> */
X						case 45:
X							fontps(0, size, "\\247");
X							break;	/* section */
X						default:
X							fprintf(stderr, ">>>>> U%d/%d\n", font, c & 0x3f);
X						}
X				}
X				else {
X					switch (table[(font % 4) == 3][fh][c & 0x3f]) {
X					case '(':
X						pstr = "\\(";
X						break;
X					case ')':
X						pstr = "\\)";
X						break;
X					default:
X						pstr = cstr(table[(font % 4) == 3][fh][c & 0x3f]);
X						break;
X					}
X				}
X				tprint();
X			}
X		}
X		else if ((c & 0xf0) == 0x50) {
X			switch (c & 0x0f) {
X			case 0:
X				size = 7;
X				break;
X			case 1:
X				size = 8;
X				break;
X			case 2:
X				size = 10;
X				break;
X			case 3:
X				size = 11;
X				break;
X			case 4:
X				size = 12;
X				break;
X			case 5:
X				size = 14;
X				break;
X			case 6:
X				size = 18;
X				break;
X			case 7:
X				size = 9;
X				break;
X			case 8:
X				size = 6;
X				break;
X			case 9:
X				size = 16;
X				break;
X			case 10:
X				size = 20;
X				break;
X			case 11:
X				size = 22;
X				break;
X			case 12:
X				size = 24;
X				break;
X			case 13:
X				size = 28;
X				break;
X			case 14:
X				size = 36;
X				break;
X			default:
X				fprintf(stderr, "Size: %x\n", c & 0x0f);
X			}
X			crsize(csize, size);
X			tsize = size;
X		}
X		else if ((c & 0xf0) == 0x40) {
X			c &= 0xf;
X			switch (c) {
X			case 0:/* fprintf(stderr,"INIT\n"); */
X				break;
X			case 1:
X				font &= 30;
X				break;
X			case 2:
X				font |= 1;
X				break;
X			case 3:
X				font |= 2;
X				break;
X			case 4:
X				font &= 29;
X				break;
X			case 5:
X				fh = 0;
X				break;
X			case 6:
X				fh = 1;
X				break;
X			case 7:
X				esc = 1;
X				break;
X			case 8:
X				esc = -1;
X				break;
X			case 9:/* fprintf(stderr,"STOP\n"); */
X				break;
X			case 10:
X				lead = 1;
X				break;
X			case 12:
X				lead = -1;
X				break;
X			case 14:
X				font |= 4;
X				break;
X			case 15:
X				font &= 27;
X				break;
X			default:
X				fprintf(stderr, "ILLEGAL\n");
X				break;
X			}
X			tfont = font;
X		}
X	}
X	if (sflag)
X		endpage();
X}
X
tprint()
X{
X	if (font != cfont || size != csize) {
X		printf("%d ", size * 6);
X		switch (font) {
X		case 0:
X			printf("TR");
X			break;
X		case 1:
X			printf("TI");
X			break;
X		case 2:
X			printf("TB");
X			break;
X		case 3:
X			printf("S");
X			break;
X		case 8:
X			printf("H");
X			break;
X		case 9:
X			printf("HO");
X			break;
X		case 10:
X			printf("HB");
X			break;
X		case 11:
X			printf("S");
X			break;
X		case 16:
X			printf("C");
X			break;
X		case 17:
X			printf("CO");
X			break;
X		case 18:
X			printf("CB");
X			break;
X		case 19:
X			printf("S");
X			break;
X		case 24:
X			printf("TBI");
X			break;
X		case 25:
X			printf("HBO");
X			break;
X		case 26:
X			printf("CBO");
X			break;
X		case 27:
X			printf("S");
X			break;
X		default:
X			fprintf(stderr, "Illegal Font %d\n", font);
X		}
X		printf(" F\n");
X		cfont = font;
X		csize = size;
X	}
X	if (ypos == cy)
X		printf("(%s)%d X\n", pstr, xpos);
X	else
X		printf("(%s)%d %d P\n", pstr, xpos, 3 * ypos);
X	cx = xpos;
X	cy = ypos;
X}
X
fontps(f1, ps, str)
char *str;
X{
X	tfont = cfont;
X	tsize = csize;
X	pstr = str;
X	size = ps;
X	font = f1;
X}
X
illegal(s)
char *s;
X{
X	fprintf(stderr, "Sequence %s is not allowed\n", s);
X}
X
crsize(old, new)
X{
X	if ((old == 16 || old >= 20) && (new != 16 && new < 20))
X		xpos += 55;
X	else if ((new == 16 || new >= 20) && (old != 16 && old < 20))
X		xpos -= 55;
X}
X
char *
cstr(c)
char c;
X{
X	static char s[2] = " ";
X
X	*s = c;
X	return s;
X}
X
newpage()
X{
X	printf("save\n");
X}
X
prolog()
X{
X	printf("/P {moveto show} def\n");
X	printf("/X {currentpoint exch pop moveto show} def\n");
X	printf("/F {findfont exch scalefont setfont} def\n");
X	printf("/TR /Times-Roman def\n");
X	printf("/TI /Times-Italic def\n");
X	printf("/TB /Times-Bold def\n");
X	printf("/S /Symbol def\n");
X	printf("/H /Helvetica def\n");
X	printf("/HO /Helvetica-Oblique def\n");
X	printf("/HB /Helvetica-Bold def\n");
X	printf("/C /Courier def\n");
X	printf("/CO /Courier-Oblique def\n");
X	printf("/CB /Courier-Bold def\n");
X	printf("/TBI /Times-BoldItalic def\n");
X	printf("/HBO /Helvetica-BoldOblique def\n");
X	printf("/CBO /Courier-BoldOblique def\n");
X	printf("1 6 div dup scale\n");
X}
X
endpage()
X{
X	printf("showpage\n");
X	printf("restore\n");
X	cfont = csize = -1;	/* Doing this will cause a new font message */
X}
END_OF_FILE
if test 10227 -ne `wc -c <'thack.c'`; then
    echo shar: \"'thack.c'\" unpacked with wrong size!
fi
# end of 'thack.c'
fi
echo shar: End of archive 1 \(of 1\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have the archive.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0