jonnyg@umd5.umd.edu (Jon Greenblatt) (02/13/88)
Here is the epson to postscript program I promised earlier. It works
very well now but it's still a baby. I am distributing it in hopes to get
other postscript hackers interested in giving input. This program is
implemented using a finite state machine in readable format. I am not much
of a believer in comments but I strongly believe in readable code. If you
read the source carefully, you should know what's going on.
# This is a shell archive. Remove anything before this line,
# then unpack it by saving it in a file and typing "sh file".
#
# Wrapped by rover!jonnyg on Fri Feb 12 12:33:06 EST 1988
# Contents: epson.c set.h set.c crlf.c makefile
echo x - epson.c
sed 's/^@//' > "epson.c" <<'@//E*O*F epson.c//'
/*
* Version 0.5 {Supports about half of the more reasonable escapes}
*
* IBM Graphics printer to postscript translator.
*
* Copyright (c) 1988, Jonathan Greenblatt,
* <jonnyg@rover.umd.edu> (128.8.2.73)
* <jonnyg@umd5.umd.edu> (128.8.10.5)
* <pcproj@gymble.umd.edu> (128.8.128.16)
* This program may be redistributed in source form,
* provided no fee is charged and this copyright notice is preserved.
*
* DESCRIPTION:
* This program uses standard input and output to convert epson printer
* codes to Postcript. This program is an execlent ASCII listing printer.
* The crlf program is include to add PC crlf to end of lines for
* printing UNIX listings. This program was written on an IBM RT running
* 4.3. The RT does not do crlf conversions by default so some changes
* may have to be made on other systems. This is a working subset of
* what I plan to complete. I am distributing this in hopes someone else
* will take interest in this code.
*
* SUPPORTS:
* 1: ASCII text.
* 2: Underlining.
* 3: Overstrike.
* 4: Double width.
* 5: Highlighting <Esc>G
* 6: Super/Subscript
* 7: 80x66 character on a page.
*
* NEEDED:
* 1: Compressed mode.
* 2: Variable line spacing.
* 3: Option for hadling CRLF
* 4: Non ASCII characters.
* 5: Graphics escapes.
* 6: I make an assumption that the font has a 6/10 ration, there are
* better ways of doing this.
*
* BUGS:
* 1: Seems to timeout the apple laserwriter when I send large prinouts
* through the tty line using no specail line controll.
*
* PORTABILITY:
* I have not tried this anywhere else but it should be easily portable
* to the IBM PC with turbo or Microsoft C.
*
* FILES:
* crlf.c: Convert UNIX file to pc Carriage return linefeed format.
* epson.c: Main program.
* set.c: ASCII set functions, like pascal, will be used more as I write
* more.
* set.h: Include file for set handling code.
* makefile: Unix makefile.
*
*/
#include <stdio.h>
#include "set.h" /* Set functions for characters */
#define MAXX 480
#define MAXY 396
#define XSTART 0
#define YSTART point_sizey
#define YSTOP MAXY
#define XSTOP MAXX
#define BNDX (cx >= (XSTOP - point_sizex - 1))
#define BNDY (cy >= (YSTOP - 1))
#define NUM_TABS 28
int tabs[NUM_TABS+1] = {8,16,32,40,48,56,64,72,80,88,96,104,112,124,
-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
char *printables =
" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890`,./\\[]=-!@#$%^&*()_+|{}:\"<>?~;'";
char *needesc = "()\\";
typedef enum {normal,bold,doublenorm,doublebold} _font_type;
char *font_descr[] = {"Courier","Courier-Bold","Courier","Courier-Bold"};
char *font_name[] = {"normalfont","boldfont","doublefont","doublebold"};
int font_size[][2] = {{10,10},{10,10},{5,10},{5,10}};
char_set printable_set;
char_set needesc_set;
_font_type font_type;
int cx, cy;
int point_sizex, point_sizey;
int underline = 0;
int subscript = 0;
int doublewidth = 0;
int highlight = 0;
char *start_doc[] = {
"/saveobj1 save def",
"/mt {moveto} def",
"/s {show} def",
"clippath pathbbox",
"/ymax exch def /xmax exch def /ymin exch def /xmin exch def",
"xmin ymax translate",
"xmax xmin sub 480 div",
"ymin ymax sub 396 div",
"scale",
"newpath",
".5 setlinewidth",
NULL};
char *start_page[] = {
"/saveobj2 save def",
NULL};
char *end_page[] = {
"showpage",
"saveobj2 restore",
NULL};
char *end_doc[] = {
"saveobj1 restore",
"\004",
NULL};
define_font(name,font,sizex,sizey)
char *name, *font;
{
printf("/%s {/%s findfont [%d 10 6 div mul 0 0 -%d 0 0] makefont setfont} def\n",name,font,sizex,sizey);
}
new_page() {
cx = XSTART;
cy = YSTART;
plist(start_page);
set_font();
}
set_font()
{
font_type =
(doublewidth) ?
(highlight) ? doublebold : doublenorm
: (highlight) ? bold: normal;
point_sizex = get_pointx(font_size[(int)font_type][0]);
point_sizey = get_pointy(font_size[(int)font_type][1]);
printf("%s\n",font_name[(int)font_type]);
}
eject_page() {
plist(end_page);
new_page();
}
init_sets() {
clear_set(printable_set);
clear_set(needesc_set);
str_add_set(printable_set,printables);
str_add_set(needesc_set,needesc);
}
get_pointx(char_per_inch)
{
return(60/char_per_inch);
}
get_pointy(char_per_inch)
{
return(60/char_per_inch);
}
init_printer() {
point_sizex = get_pointx(font_size[(int)normal][0]);
point_sizey = get_pointy(font_size[(int)normal][1]);
plist(start_doc);
define_font(font_name[(int)normal],font_descr[(int)normal],point_sizex,point_sizey);
define_font(font_name[(int)bold],font_descr[(int)bold],point_sizex,point_sizey);
point_sizex = get_pointx(font_size[(int)doublenorm][0]);
point_sizey = get_pointy(font_size[(int)doublenorm][1]);
define_font(font_name[(int)doublenorm],font_descr[(int)doublenorm],point_sizex,point_sizey);
define_font(font_name[(int)doublebold],font_descr[(int)doublebold],point_sizex,point_sizey);
font_type = normal;
new_page();
}
plist(l)
char **l;
{
while (*l != NULL)
printf("%s\n",*l++);
}
#define LINE_SIZE 256
char pline[256];
int ptr = 0;
char outline[258];
putline()
{
char *s = pline;
int p;
int lx;
if (BNDY) eject_page();
while (*s == ' ' && ptr > 0)
{
s++;
ptr--;
if (BNDX) {cx = XSTART; newline();}
cx += point_sizex;
}
while (ptr>0) {
p = 0;
if (BNDY) eject_page();
if (BNDX) {cx = XSTART; newline();}
lx = cx;
while ((lx+point_sizex-1) < XSTOP && ptr > 0) {
if (in_set(needesc_set,*s)) outline[p++] = '\\';
outline[p++] = *s++;
ptr--;
lx += point_sizex;
}
outline[p] = 0;
if (p > 0) {
int i = strlen(outline);
/* Forward slash won't work at the end of a string */
if (outline[i-1] == '/') {
outline[i] = ' ';
outline[i+1] = '\0';
}
if (subscript)
if (subscript == 1) /* Subscript */
printf("%d %d mt gsave 1 .5 scale (%s) s grestore\n",cx,cy,outline);
else /* Superscript */
printf("%d %d mt gsave 1 .5 scale (%s) s grestore\n",cx,cy-(point_sizey>>1),outline);
else /* Normal printing */
printf("%d %d mt (%s) s\n",cx,cy,outline);
if (underline)
printf("%d %d mt %d %d lineto stroke\n",cx,cy+1,lx-1,cy+1);
}
cx = lx;
}
}
newline() {
cy += point_sizey;
if (BNDY) eject_page();
}
typedef enum {S_BASE,S_ESC,S_UNDERLINE,S_SUBSCRIPT,S_DOUBLE} states;
states state = S_BASE;
dochar(c)
{
if (ptr >= LINE_SIZE) putline();
switch (state) {
case S_UNDERLINE:
state = S_BASE;
if (c == '\0') underline = 0;
else if (c == '\1') underline = 1;
break;
case S_DOUBLE:
state = S_BASE;
if (c == '\0') doublewidth = 0;
else if (c == '\1') doublewidth = 1;
set_font();
break;
case S_SUBSCRIPT:
state = S_BASE;
if (c == '\0') subscript = 2;
else if (c == '\1') subscript = 1;
break;
case S_ESC:
state = S_BASE;
switch (c)
{
case 'G':
highlight = 1;
set_font();
break;
case 'H':
highlight = 0;
set_font();
break;
case '-':
state = S_UNDERLINE;
break;
case 'T':
subscript = 0;
break;
case 'S':
state = S_SUBSCRIPT;
break;
case 'W':
state = S_DOUBLE;
break;
}
break;
case S_BASE:
switch(c) {
case '\011': {
int i,l;
l = cx / point_sizex + ptr;
for (i = 0; i < NUM_TABS && tabs[i] <= l; i++);
if (tabs[i] == -1) break;
i = tabs[i] - l;
while (i-- > 0) dochar(' ');
}
break;
case '\033':
putline();
state = S_ESC;
break;
case '\014':
putline();
eject_page();
break;
case '\n':
putline();
newline();
break;
case '\r':
putline();
cx = XSTART;
break;
case 26: /* CTRL-Z */
break;
default:
if (in_set(printable_set,c)) pline[ptr++] = c;
else pline[ptr++] = ' ';
break;
}
break;
}
}
char istr[128];
main() {
int n;
char *p;
init_sets();
init_printer();
while ((n = read(0,p = istr,128)) > 0)
while (n--) dochar(*p++);
if (cx > XSTART || cy > YSTART)
plist(end_page);
else printf("saveobj2 restore\n");
plist(end_doc);
}
@//E*O*F epson.c//
chmod u=rw,g=r,o=r epson.c
echo x - set.h
sed 's/^@//' > "set.h" <<'@//E*O*F set.h//'
#define INTS_IN_SET 16
typedef unsigned int char_set[INTS_IN_SET];
@//E*O*F set.h//
chmod u=rw,g=r,o=r set.h
echo x - set.c
sed 's/^@//' > "set.c" <<'@//E*O*F set.c//'
#include "set.h"
clear_set(set)
char_set set;
{
int i;
for (i = 0; i < INTS_IN_SET; i++) set[i] = 0;
}
fill_set(set)
char_set set;
{
int i;
for (i = 0; i < INTS_IN_SET; i++) set[i] = 0xffff;
}
not_set(set)
char_set set;
{
int i;
for (i = 0; i < INTS_IN_SET; i++) set[i] ^= 0xffff;
}
and_set(set,set1)
char_set set, set1;
{
int i;
for (i = 0; i < INTS_IN_SET; i++) set[i] &= set1[i];
}
or_set(set,set1)
char_set set,set1;
{
int i;
for (i = 0; i < INTS_IN_SET; i++) set[i] |= set1[i];
}
add_set(set,c)
char_set set;
unsigned int c;
{
c &= 0xff;
set[c >> 4] |= 1 << (c & 15);
}
del_set(set,c)
char_set set;
unsigned int c;
{
c &= 0xff;
set[c >> 4] &= ~(1 << (c & 15));
}
in_set(set,c)
char_set set;
unsigned int c;
{
c &= 0xff;
return ((set[c >> 4] & (1 << (c & 15))) != 0);
}
str_add_set(set,s)
char_set set;
char *s;
{
unsigned int c;
while (*s) {
c = *s++;
c &= 0xff;
set[c >> 4] |= 1 << (c & 15);
}
}
str_del_set(set,s)
char_set set;
char *s;
{
unsigned int c;
while (*s) {
c = *s++;
c &= 0xff;
set[c >> 4] &= ~(1 << (c & 15));
}
}
@//E*O*F set.c//
chmod u=rw,g=r,o=r set.c
echo x - crlf.c
sed 's/^@//' > "crlf.c" <<'@//E*O*F crlf.c//'
main() {
char ibuff[512], *ip;
char obuff[1024];
int ic, oc;
while ((ic = read(0,ip = ibuff,512)) > 0) {
oc = 0;
while (ic--)
if (*ip == '\n')
{
ip++;
obuff[oc++] = '\r';
obuff[oc++] = '\n';
}
else obuff[oc++] = *ip++;
write(1,obuff,oc);
}
}
@//E*O*F crlf.c//
chmod u=rw,g=r,o=r crlf.c
echo x - makefile
sed 's/^@//' > "makefile" <<'@//E*O*F makefile//'
CC=cc
all: epson crlf
epson: epson.o set.o
$(CC) epson.o set.o -o epson
epson.o: epson.c set.h
$(CC) -O -c epson.c
set.o: set.c set.h
$(CC) -O -c set.c
crlf: crlf.c
$(CC) -O crlf.c -o crlf
@//E*O*F makefile//
chmod u=rw,g=r,o=r makefile
exit 0