ref: f231cb477ed4d7fc87702c5f4ee6d8a633a961be
dir: /ps.c/
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "post.h"
static int o_f, o_s, o_m; /* font and size */
static int o_h, o_v; /* current user position */
static int p_f, p_s, p_m; /* output postscript font */
static int o_qtype; /* queued character type */
static int o_qv, o_qh, o_qend; /* queued character position */
static int o_rh, o_rv, o_rdeg; /* previous rotation position and degree */
static int o_gname; /* use glyphshow for all glyphs */
static char o_fonts[FNLEN * NFONTS] = " ";
static void outvf(char *s, va_list ap)
{
vfprintf(stdout, s, ap);
}
static void outf(char *s, ...)
{
va_list ap;
va_start(ap, s);
outvf(s, ap);
va_end(ap);
}
static void o_flush(void)
{
if (o_qtype == 1)
outf(") %d %d w\n", o_qh, o_qv);
if (o_qtype == 2)
outf("] %d %d g\n", o_qh, o_qv);
o_qtype = 0;
}
void outgname(int g)
{
o_gname = g;
}
void outpage(void)
{
o_flush();
o_v = 0;
o_h = 0;
p_s = 0;
p_f = 0;
p_m = 0;
o_rdeg = 0;
}
static void o_queue(struct glyph *g)
{
int type = 1 + (g->pos <= 0 || o_gname);
if (o_qtype != type || o_qend != o_h || o_qv != o_v) {
o_flush();
o_qh = o_h;
o_qv = o_v;
o_qtype = type;
outf(type == 1 ? "(" : "[");
}
if (o_qtype == 1) {
if (g->pos >= ' ' && g->pos <= '~')
outf("%s%c", strchr("()\\", g->pos) ? "\\" : "", g->pos);
else
outf("\\%d%d%d", (g->pos >> 6) & 7,
(g->pos >> 3) & 7, g->pos & 7);
} else {
outf("/%s", g->id);
}
o_qend = o_h + font_wid(g->font, o_s, g->wid);
}
/* calls o_flush() if necessary */
void out(char *s, ...)
{
va_list ap;
o_flush();
va_start(ap, s);
outvf(s, ap);
va_end(ap);
}
static void out_fontup(int fid)
{
char fnname[FNLEN];
struct font *fn;
if (o_m != p_m) {
out("%d %d %d rgb\n", CLR_R(o_m), CLR_G(o_m), CLR_B(o_m));
p_m = o_m;
}
if (fid != p_f || o_s != p_s) {
fn = dev_font(fid);
out("%d /%s f\n", o_s, font_name(fn));
p_f = fid;
p_s = o_s;
sprintf(fnname, " %s ", font_name(fn));
if (!strstr(o_fonts, fnname))
sprintf(strchr(o_fonts, '\0'), "%s ", font_name(fn));
}
}
void outc(char *c)
{
struct glyph *g;
struct font *fn;
g = dev_glyph(c, o_f);
fn = g ? g->font : dev_font(o_f);
if (!g) {
outrel(*c == ' ' && fn ? font_swid(fn, o_s) : 1, 0);
return;
}
out_fontup(dev_fontid(fn));
o_queue(g);
}
void outh(int h)
{
o_h = h;
}
void outv(int v)
{
o_v = v;
}
void outrel(int h, int v)
{
o_h += h;
o_v += v;
}
void outfont(int f)
{
if (dev_font(f))
o_f = f;
}
/* a font was mounted at pos f */
void outmnt(int f)
{
if (p_f == f)
p_f = -1;
}
void outsize(int s)
{
if (s > 0)
o_s = s;
}
void outcolor(int c)
{
o_m = c;
}
void outrotate(int deg)
{
o_flush();
out_fontup(o_f);
if (o_rdeg)
outf("%d %d %d rot\n", -o_rdeg, o_rh, o_rv);
o_rdeg = deg;
o_rh = o_h;
o_rv = o_v;
outf("%d %d %d rot\n", deg, o_h, o_v);
}
static int draw_path; /* number of path segments */
static int draw_point; /* point was set for postscript newpath */
static void drawmv(void)
{
if (!draw_point)
outf("%d %d m ", o_h, o_v);
draw_point = 1;
}
/* start a multi-segment path */
void drawmbeg(char *s)
{
o_flush();
out_fontup(o_f);
draw_path = 1;
outf("gsave newpath %s\n", s);
}
/* end a multi-segment path */
void drawmend(char *s)
{
draw_path = 0;
draw_point = 0;
outf("%s grestore\n", s);
}
void drawbeg(void)
{
o_flush();
out_fontup(o_f);
if (draw_path)
return;
outf("newpath ");
}
void drawend(int close, int fill)
{
if (draw_path)
return;
draw_point = 0;
if (close)
outf("closepath ");
if (fill)
outf("fill\n");
else
outf("stroke\n");
}
void drawl(int h, int v)
{
drawmv();
outrel(h, v);
outf("%d %d drawl ", o_h, o_v);
}
void drawc(int c)
{
drawmv();
outrel(c, 0);
outf("%d %d drawe ", c, c);
}
void drawe(int h, int v)
{
drawmv();
outrel(h, 0);
outf("%d %d drawe ", h, v);
}
void drawa(int h1, int v1, int h2, int v2)
{
drawmv();
outf("%d %d %d %d drawa ", h1, v1, h2, v2);
outrel(h1 + h2, v1 + v2);
}
void draws(int h1, int v1, int h2, int v2)
{
drawmv();
outf("%d %d %d %d %d %d draws ", o_h, o_v, o_h + h1, o_v + v1,
o_h + h1 + h2, o_v + v1 + v2);
outrel(h1, v1);
}
static char *strcut(char *dst, char *src)
{
while (*src == ' ' || *src == '\n')
src++;
if (src[0] == '"') {
src++;
while (*src && (src[0] != '"' || src[1] == '"')) {
if (*src == '"')
src++;
*dst++ = *src++;
}
if (*src == '"')
src++;
} else {
while (*src && *src != ' ' && *src != '\n')
*dst++ = *src++;
}
*dst = '\0';
return src;
}
void outeps(char *spec)
{
char eps[1 << 12];
char buf[1 << 12];
int llx, lly, urx, ury;
int hwid, vwid;
FILE *filp;
int nspec, nbb;
spec = strcut(eps, spec);
if (!eps[0])
return;
nspec = sscanf(spec, "%d %d", &hwid, &vwid);
if (nspec < 1)
hwid = 0;
if (nspec < 2)
vwid = 0;
if (!(filp = fopen(eps, "r")))
return;
if (!fgets(buf, sizeof(buf), filp) ||
(strcmp(buf, "%!PS-Adobe-2.0 EPSF-1.2\n") &&
strcmp(buf, "%!PS-Adobe-2.0 EPSF-2.0\n") &&
strcmp(buf, "%!PS-Adobe-3.0 EPSF-3.0\n"))) {
fclose(filp);
return;
}
nbb = 0;
while (fgets(buf, sizeof(buf), filp))
if (!strncmp(buf, "%%BoundingBox: ", 15))
if ((nbb = sscanf(buf + 15, "%d %d %d %d",
&llx, &lly, &urx, &ury)) == 4)
break;
fclose(filp);
if (nbb < 4) /* no BoundingBox comment */
return;
if (hwid <= 0 && vwid <= 0)
hwid = (urx - llx) * dev_res / 72;
if (vwid <= 0)
vwid = (ury - lly) * hwid / (urx - llx);
if (hwid <= 0)
hwid = (urx - llx) * vwid / (ury - lly);
/* output the EPS file */
o_flush();
out_fontup(o_f);
outf("%d %d %d %d %d %d %d %d EPSFBEG\n",
llx, lly, hwid, urx - llx, vwid, ury - lly, o_h, o_v);
outf("%%%%BeginDocument: %s\n", eps);
filp = fopen(eps, "r");
while (fgets(buf, sizeof(buf), filp))
out("%s", buf);
fclose(filp);
outf("%%%%EndDocument\n");
outf("EPSFEND\n");
}
void outpdf(char *spec)
{
}
void outlink(char *spec)
{
char lnk[1 << 12];
int hwid, vwid;
int nspec;
spec = strcut(lnk, spec);
if (!lnk[0] || (nspec = sscanf(spec, "%d %d", &hwid, &vwid)) != 2)
return;
o_flush();
if (lnk[0] == '#' || isdigit((unsigned char) lnk[0])) {
outf("[ /Rect [ %d %d t %d %d t ] %s%s "
"/Subtype /Link /LNK pdfmark\n",
o_h, o_v, o_h + hwid, o_v + vwid,
lnk[0] == '#' ? "/Dest /" : "/Page ",
lnk[0] == '#' ? lnk + 1 : lnk);
} else {
outf("[ /Rect [ %d %d t %d %d t ] "
"/Action << /Subtype /URI /URI (%s) >> /Open true "
"/Subtype /Link /LNK pdfmark\n",
o_h, o_v, o_h + hwid, o_v + vwid, lnk);
}
}
void ps_pagebeg(int n)
{
out("%%%%Page: %d %d\n", n, n);
out("/saveobj save def\n");
out("mark\n");
out("%d pagesetup\n", n);
}
void ps_pageend(int n)
{
out("cleartomark\n");
out("showpage\n");
out("saveobj restore\n");
}
void ps_trailer(int pages)
{
out("%%%%Trailer\n");
out("done\n");
out("%%%%DocumentFonts: %s\n", o_fonts);
out("%%%%Pages: %d\n", pages);
out("%%%%EOF\n");
}
static char *prolog =
"/setup {\n"
" counttomark 2 idiv {def} repeat pop\n"
" /scaling 72 resolution div def\n"
" linewidth setlinewidth\n"
" 1 setlinecap\n"
" 0 pagesize 1 get translate\n"
" scaling scaling scale\n"
" 0 0 moveto\n"
"} def\n"
"\n"
"/pagesetup {\n"
" /page exch def\n"
" currentdict /pagedict known currentdict page known and {\n"
" page load pagedict exch get cvx exec\n"
" } if\n"
"} def\n"
"\n"
"/pdfmark where\n"
" { pop globaldict /?pdfmark /exec load put }\n"
" { globaldict begin\n"
" /?pdfmark /pop load def\n"
" /pdfmark /cleartomark load def\n"
" end }\n"
" ifelse\n"
"\n"
"/t {neg} bind def\n"
"/w {neg moveto show} bind def\n"
"/m {neg moveto} bind def\n"
"/g {neg moveto {glyphshow} forall} bind def\n"
"/rgb {255 div 3 1 roll 255 div 3 1 roll 255 div 3 1 roll setrgbcolor} bind def\n"
"/rot {/y exch def /x exch def x y neg translate rotate x neg y translate} bind def\n"
"/done {/lastpage where {pop lastpage} if} def\n"
"\n"
"% caching fonts, as selectfont is supposed to be doing\n"
"/fncache 16 dict def\n"
"/selectfont_append { fncache exch dup findfont put } bind def\n"
"/selectfont_cached {\n"
" exch dup fncache exch known not { dup selectfont_append } if\n"
" fncache exch get exch scalefont setfont\n"
"} bind def\n"
"/f {\n"
" exch dup 3 1 roll scaling div selectfont_cached\n"
" linewidth mul scaling 10 mul div setlinewidth\n"
"} bind def\n"
"\n"
"/savedmatrix matrix def\n"
"/drawl {\n"
" neg lineto\n"
"} bind def\n"
"/drawe {\n"
" savedmatrix currentmatrix pop scale\n"
" .5 0 rmoveto currentpoint .5 0 rmoveto .5 0 360 arc\n"
" savedmatrix setmatrix\n"
"} bind def\n"
"/drawa {\n"
" /dy2 exch def\n"
" /dx2 exch def\n"
" /dy1 exch def\n"
" /dx1 exch def\n"
" currentpoint dy1 neg add exch dx1 add exch\n"
" dx1 dx1 mul dy1 dy1 mul add sqrt\n"
" dy1 dx1 neg atan\n"
" dy2 neg dx2 atan\n"
" arc\n"
"} bind def\n"
"/draws {\n"
" /y2 exch def\n"
" /x2 exch def\n"
" /y1 exch def\n"
" /x1 exch def\n"
" /y0 exch def\n"
" /x0 exch def\n"
" x0 5 x1 mul add 6 div\n"
" y0 5 y1 mul add -6 div\n"
" x2 5 x1 mul add 6 div\n"
" y2 5 y1 mul add -6 div\n"
" x1 x2 add 2 div\n"
" y1 y2 add -2 div\n"
" curveto\n"
"} bind def\n"
"% including EPS files\n"
"/EPSFBEG {\n"
" /epsf_state save def\n"
" neg translate\n"
" div 3 1 roll div exch scale\n"
" neg exch neg exch translate\n"
" /dict_count countdictstack def\n"
" /op_count count 1 sub def\n"
" userdict begin\n"
" /showpage { } def\n"
" 0 setgray 0 setlinecap 1 setlinewidth 0 setlinejoin\n"
" 10 setmiterlimit [ ] 0 setdash newpath\n"
"} bind def\n"
"/EPSFEND {\n"
" count op_count sub {pop} repeat\n"
" countdictstack dict_count sub {end} repeat\n"
" epsf_state restore\n"
"} bind def\n";
/* pagewidth and pageheight are in tenths of a millimetre */
void ps_header(char *title, int pagewidth, int pageheight, int linewidth)
{
out("%%!PS-Adobe-2.0\n");
out("%%%%Version: 1.0\n");
if (title)
out("%%%%Title: %s\n", title);
out("%%%%Creator: Neatroff\n");
out("%%%%DocumentFonts: (atend)\n");
out("%%%%Pages: (atend)\n");
out("%%%%EndComments\n");
out("%%%%BeginProlog\n");
out("/resolution %d def\n", dev_res);
out("/pagesize [%d %d] def\n", (pagewidth * 72 + 127) / 254,
(pageheight * 72 + 127) / 254);
out("/linewidth %d.%02d def\n\n", linewidth / 100, linewidth % 100);
out("%s", prolog);
out("%%%%EndProlog\n");
out("%%%%BeginSetup\n");
out("<< /PageSize pagesize /ImagingBBox null >> setpagedevice\n");
out("mark\n");
out("setup\n");
out("%%%%EndSetup\n");
}