more files

This commit is contained in:
rsc 2004-05-15 23:55:53 +00:00
parent 173302913e
commit 61f5c35c94
37 changed files with 5947 additions and 1 deletions

View file

@ -5,7 +5,7 @@ SHORTLIB=sec fs mux regexp9 thread bio 9
<$PLAN9/src/mkmany <$PLAN9/src/mkmany
BUGGERED='CVS|faces|factotum|mailfs|scat|upas|vac|venti|lex|vncv|grap|eqn|troff|pic|tbl' BUGGERED='CVS|faces|factotum|mailfs|scat|upas|vac|venti|lex|vncv|grap|eqn|troff|postscript|pic|tbl'
DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"` DIRS=`ls -l |sed -n 's/^d.* //p' |egrep -v "^($BUGGERED)$"`
<$PLAN9/src/mkdirs <$PLAN9/src/mkdirs

View file

@ -0,0 +1,257 @@
/*
*
* Boundingbox code for PostScript translators. The boundingbox for each page
* is accumulated in bbox - the one for the whole document goes in docbbox. A
* call to writebbox() puts out an appropriate comment, updates docbbox, and
* resets bbox for the next page. The assumption made at the end of writebbox()
* is that we're really printing the current page only if output is now going
* to stdout - a valid assumption for all supplied translators. Needs the math
* library.
*
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <fcntl.h>
#include <math.h>
#include "comments.h" /* PostScript file structuring comments */
#include "gen.h" /* a few general purpose definitions */
#include "ext.h" /* external variable declarations */
typedef struct bbox {
int set;
double llx, lly;
double urx, ury;
} Bbox;
Bbox bbox = {FALSE, 0.0, 0.0, 0.0, 0.0};
Bbox docbbox = {FALSE, 0.0, 0.0, 0.0, 0.0};
double ctm[6] = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0};
double matrix1[6], matrix2[6];
/*****************************************************************************/
cover(x, y)
double x, y;
{
/*
*
* Adds point (x, y) to bbox. Coordinates are in user space - the transformation
* to default coordinates happens in writebbox().
*
*/
if ( bbox.set == FALSE ) {
bbox.llx = bbox.urx = x;
bbox.lly = bbox.ury = y;
bbox.set = TRUE;
} else {
if ( x < bbox.llx )
bbox.llx = x;
if ( y < bbox.lly )
bbox.lly = y;
if ( x > bbox.urx )
bbox.urx = x;
if ( y > bbox.ury )
bbox.ury = y;
} /* End else */
} /* End of cover */
/*****************************************************************************/
writebbox(fp, keyword, slop)
FILE *fp; /* the comment is written here */
char *keyword; /* the boundingbox comment string */
int slop; /* expand (or contract?) the box a bit */
{
Bbox ubbox; /* user space bounding box */
double x, y;
/*
*
* Transforms the numbers in the bbox[] using ctm[], adjusts the corners a bit
* (depending on slop) and then writes comment. If *keyword is BoundingBox use
* whatever's been saved in docbbox, otherwise assume the comment is just for
* the current page.
*
*/
if ( strcmp(keyword, BOUNDINGBOX) == 0 )
bbox = docbbox;
if ( bbox.set == TRUE ) {
ubbox = bbox;
bbox.set = FALSE; /* so cover() works properly */
x = ctm[0] * ubbox.llx + ctm[2] * ubbox.lly + ctm[4];
y = ctm[1] * ubbox.llx + ctm[3] * ubbox.lly + ctm[5];
cover(x, y);
x = ctm[0] * ubbox.llx + ctm[2] * ubbox.ury + ctm[4];
y = ctm[1] * ubbox.llx + ctm[3] * ubbox.ury + ctm[5];
cover(x, y);
x = ctm[0] * ubbox.urx + ctm[2] * ubbox.ury + ctm[4];
y = ctm[1] * ubbox.urx + ctm[3] * ubbox.ury + ctm[5];
cover(x, y);
x = ctm[0] * ubbox.urx + ctm[2] * ubbox.lly + ctm[4];
y = ctm[1] * ubbox.urx + ctm[3] * ubbox.lly + ctm[5];
cover(x, y);
bbox.llx -= slop + 0.5;
bbox.lly -= slop + 0.5;
bbox.urx += slop + 0.5;
bbox.ury += slop + 0.5;
fprintf(fp, "%s %d %d %d %d\n", keyword, (int)bbox.llx, (int)bbox.lly,(int)bbox.urx, (int)bbox.ury);
bbox = ubbox;
} /* End if */
resetbbox((fp == stdout) ? TRUE : FALSE);
} /* End of writebbox */
/*****************************************************************************/
resetbbox(output)
int output;
{
/*
*
* Adds bbox to docbbox and resets bbox for the next page. Only update docbbox
* if we really did output on the last page.
*
*/
if ( docbbox.set == TRUE ) {
cover(docbbox.llx, docbbox.lly);
cover(docbbox.urx, docbbox.ury);
} /* End if */
if ( output == TRUE ) {
docbbox = bbox;
docbbox.set = TRUE;
} /* End if */
bbox.set = FALSE;
} /* End of resetbbox */
/*****************************************************************************/
scale(sx, sy)
double sx, sy;
{
/*
*
* Scales the default matrix.
*
*/
matrix1[0] = sx;
matrix1[1] = 0;
matrix1[2] = 0;
matrix1[3] = sy;
matrix1[4] = 0;
matrix1[5] = 0;
concat(matrix1);
} /* End of scale */
/*****************************************************************************/
translate(tx, ty)
double tx, ty;
{
/*
*
* Translates the default matrix.
*
*/
matrix1[0] = 1.0;
matrix1[1] = 0.0;
matrix1[2] = 0.0;
matrix1[3] = 1.0;
matrix1[4] = tx;
matrix1[5] = ty;
concat(matrix1);
} /* End of translate */
/*****************************************************************************/
rotate(angle)
double angle;
{
/*
*
* Rotates by angle degrees.
*
*/
angle *= 3.1416 / 180;
matrix1[0] = matrix1[3] = cos(angle);
matrix1[1] = sin(angle);
matrix1[2] = -matrix1[1];
matrix1[4] = 0.0;
matrix1[5] = 0.0;
concat(matrix1);
} /* End of rotate */
/*****************************************************************************/
concat(m1)
double m1[];
{
double m2[6];
/*
*
* Replaces the ctm[] by the result of the matrix multiplication m1[] x ctm[].
*
*/
m2[0] = ctm[0];
m2[1] = ctm[1];
m2[2] = ctm[2];
m2[3] = ctm[3];
m2[4] = ctm[4];
m2[5] = ctm[5];
ctm[0] = m1[0] * m2[0] + m1[1] * m2[2];
ctm[1] = m1[0] * m2[1] + m1[1] * m2[3];
ctm[2] = m1[2] * m2[0] + m1[3] * m2[2];
ctm[3] = m1[2] * m2[1] + m1[3] * m2[3];
ctm[4] = m1[4] * m2[0] + m1[5] * m2[2] + m2[4];
ctm[5] = m1[4] * m2[1] + m1[5] * m2[3] + m2[5];
} /* End of concat */
/*****************************************************************************/

View file

@ -0,0 +1,127 @@
/*
*
* Currently defined file structuring comments from Adobe - plus a few others.
* Ones that end with a colon expect arguments, while those ending with a newline
* stand on their own. Truly overkill on Adobe's part and mine for including them
* all!
*
* All PostScript files should begin with a header that starts with one of the
* following comments.
*
*/
#define NONCONFORMING "%!PS\n"
#define MINCONFORMING "%!PS-Adobe-\n"
#define OLDCONFORMING "%!PS-Adobe-1.0\n"
#define CONFORMING "%!PS-Adobe-2.0\n"
#define CONFORMINGEPS "%!PS-Adobe-2.0 EPS\n"
#define CONFORMINGQUERY "%!PS-Adobe-2.0 Query\n"
#define CONFORMINGEXITSERVER "%!PS-Adobe-2.0 ExitServer\n"
/*
*
* Header comments - immediately follow the appropriate document classification
* comment.
*
*/
#define TITLE "%%Title:"
#define CREATOR "%%Creator:"
#define CREATIONDATE "%%CreationDate:"
#define FOR "%%For:"
#define ROUTING "%%Routing:"
#define BOUNDINGBOX "%%BoundingBox:"
#define PAGES "%%Pages:"
#define REQUIREMENTS "%%Requirements:"
#define DOCUMENTFONTS "%%DocumentFonts:"
#define DOCUMENTNEEDEDFONTS "%%DocumentNeededFonts:"
#define DOCUMENTSUPPLIEDFONTS "%%DocumentSuppliedFonts:"
#define DOCUMENTNEEDEDPROCSETS "%%DocumentNeededProcSets:"
#define DOCUMENTSUPPLIEDPROCSETS "%%DocumentSuppliedProcSets:"
#define DOCUMENTNEEDEDFILES "%%DocumentNeededFiles:"
#define DOCUMENTSUPPLIEDFILES "%%DocumentSuppliedFiles:"
#define DOCUMENTPAPERSIZES "%%DocumentPaperSizes:"
#define DOCUMENTPAPERFORMS "%%DocumentPaperForms:"
#define DOCUMENTPAPERCOLORS "%%DocumentPaperColors:"
#define DOCUMENTPAPERWEIGHTS "%%DocumentPaperWeights:"
#define DOCUMENTPRINTERREQUIRED "%%DocumentPrinterREquired:"
#define ENDCOMMENTS "%%EndComments\n"
#define ENDPROLOG "%%EndProlog\n"
/*
*
* Body comments - can appear anywhere in a document.
*
*/
#define BEGINSETUP "%%BeginSetup\n"
#define ENDSETUP "%%EndSetup\n"
#define BEGINDOCUMENT "%%BeginDocument:"
#define ENDDOCUMENT "%%EndDocument\n"
#define BEGINFILE "%%BeginFile:"
#define ENDFILE "%%EndFile\n"
#define BEGINPROCSET "%%BeginProcSet:"
#define ENDPROCSET "%%EndProcSet\n"
#define BEGINBINARY "%%BeginBinary:"
#define ENDBINARY "%%EndBinary\n"
#define BEGINPAPERSIZE "%%BeginePaperSize:"
#define ENDPAPERSIZE "%%EndPaperSize\n"
#define BEGINFEATURE "%%BeginFeature:"
#define ENDFEATURE "%%EndFeature\n"
#define BEGINEXITSERVER "%%BeginExitServer:"
#define ENDEXITSERVER "%%EndExitServer\n"
#define TRAILER "%%Trailer\n"
/*
*
* Page level comments - usually will occur once per page.
*
*/
#define PAGE "%%Page:"
#define PAGEFONTS "%%PageFonts:"
#define PAGEFILES "%%PageFiles:"
#define PAGEBOUNDINGBOX "%%PageBoundingBox:"
#define BEGINPAGESETUP "%%BeginPageSetup\n"
#define BEGINOBJECT "%%BeginObject:"
#define ENDOBJECT "%%EndObject\n"
/*
*
* Resource requirements - again can appear anywhere in a document.
*
*/
#define INCLUDEFONT "%%IncludeFont:"
#define INCLUDEPROCSET "%%IncludeProcSet:"
#define INCLUDEFILE "%%IncludeFile:"
#define EXECUTEFILE "%%ExecuteFile:"
#define CHANGEFONT "%%ChangeFont:"
#define PAPERFORM "%%PaparForm:"
#define PAPERCOLOR "%%PaperColor:"
#define PAPERWEIGHT "%%PaperWeight:"
#define PAPERSIZE "%%PaperSize:"
#define FEATURE "%%Feature:"
#define ENDOFFILE "%%EOF\n"
#define CONTINUECOMMENT "%%+"
#define ATEND "(atend)"
/*
*
* Some non-standard document comments. Global definitions are occasionally used
* in dpost and are marked by BEGINGLOBAL and ENDGLOBAL. The resulting document
* violates page independence, but can easily be converted to a conforming file
* using a utililty program.
*
*/
#define BEGINSCRIPT "%%BeginScript\n"
#define BEGINGLOBAL "%%BeginGlobal\n"
#define ENDGLOBAL "%%EndGlobal\n"
#define ENDPAGE "%%EndPage:"
#define FORMSPERPAGE "%%FormsPerPage:"
#define VERSION "%%Version:"

View file

@ -0,0 +1,264 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include "common.h"
#include "comments.h"
#include "path.h"
struct strtab charcode[FONTSIZE] = {
{4, "\\000"}, {4, "\\001"}, {4, "\\002"}, {4, "\\003"},
{4, "\\004"}, {4, "\\005"}, {4, "\\006"}, {4, "\\007"},
{4, "\\010"}, {4, "\\011"}, {4, "\\012"}, {4, "\\013"},
{4, "\\014"}, {4, "\\015"}, {4, "\\016"}, {4, "\\017"},
{4, "\\020"}, {4, "\\021"}, {4, "\\022"}, {4, "\\023"},
{4, "\\024"}, {4, "\\025"}, {4, "\\026"}, {4, "\\027"},
{4, "\\030"}, {4, "\\031"}, {4, "\\032"}, {4, "\\033"},
{4, "\\034"}, {4, "\\035"}, {4, "\\036"}, {4, "\\037"},
{1, " "}, {1, "!"}, {1, "\""}, {1, "#"},
{1, "$"}, {1, "%"}, {1, "&"}, {1, "'"},
{2, "\\("}, {2, "\\)"}, {1, "*"}, {1, "+"},
{1, ","}, {1, "-"}, {1, "."}, {1, "/"},
{1, "0"}, {1, "1"}, {1, "2"}, {1, "3"},
{1, "4"}, {1, "5"}, {1, "6"}, {1, "7"},
{1, "8"}, {1, "9"}, {1, ":"}, {1, ";"},
{1, "<"}, {1, "="}, {1, ">"}, {1, "?"},
{1, "@"}, {1, "A"}, {1, "B"}, {1, "C"},
{1, "D"}, {1, "E"}, {1, "F"}, {1, "G"},
{1, "H"}, {1, "I"}, {1, "J"}, {1, "K"},
{1, "L"}, {1, "M"}, {1, "N"}, {1, "O"},
{1, "P"}, {1, "Q"}, {1, "R"}, {1, "S"},
{1, "T"}, {1, "U"}, {1, "V"}, {1, "W"},
{1, "X"}, {1, "Y"}, {1, "Z"}, {1, "["},
{2, "\\\\"}, {1, "]"}, {1, "^"}, {1, "_"},
{1, "`"}, {1, "a"}, {1, "b"}, {1, "c"},
{1, "d"}, {1, "e"}, {1, "f"}, {1, "g"},
{1, "h"}, {1, "i"}, {1, "j"}, {1, "k"},
{1, "l"}, {1, "m"}, {1, "n"}, {1, "o"},
{1, "p"}, {1, "q"}, {1, "r"}, {1, "s"},
{1, "t"}, {1, "u"}, {1, "v"}, {1, "w"},
{1, "x"}, {1, "y"}, {1, "z"}, {1, "{"},
{1, "|"}, {1, "}"}, {1, "~"}, {4, "\\177"},
{4, "\\200"}, {4, "\\201"}, {4, "\\202"}, {4, "\\203"},
{4, "\\204"}, {4, "\\205"}, {4, "\\206"}, {4, "\\207"},
{4, "\\210"}, {4, "\\211"}, {4, "\\212"}, {4, "\\213"},
{4, "\\214"}, {4, "\\215"}, {4, "\\216"}, {4, "\\217"},
{4, "\\220"}, {4, "\\221"}, {4, "\\222"}, {4, "\\223"},
{4, "\\224"}, {4, "\\225"}, {4, "\\226"}, {4, "\\227"},
{4, "\\230"}, {4, "\\231"}, {4, "\\232"}, {4, "\\233"},
{4, "\\234"}, {4, "\\235"}, {4, "\\236"}, {4, "\\237"},
{4, "\\240"}, {4, "\\241"}, {4, "\\242"}, {4, "\\243"},
{4, "\\244"}, {4, "\\245"}, {4, "\\246"}, {4, "\\247"},
{4, "\\250"}, {4, "\\251"}, {4, "\\252"}, {4, "\\253"},
{4, "\\254"}, {4, "\\255"}, {4, "\\256"}, {4, "\\257"},
{4, "\\260"}, {4, "\\261"}, {4, "\\262"}, {4, "\\263"},
{4, "\\264"}, {4, "\\265"}, {4, "\\266"}, {4, "\\267"},
{4, "\\270"}, {4, "\\271"}, {4, "\\272"}, {4, "\\273"},
{4, "\\274"}, {4, "\\275"}, {4, "\\276"}, {4, "\\277"},
{4, "\\300"}, {4, "\\301"}, {4, "\\302"}, {4, "\\303"},
{4, "\\304"}, {4, "\\305"}, {4, "\\306"}, {4, "\\307"},
{4, "\\310"}, {4, "\\311"}, {4, "\\312"}, {4, "\\313"},
{4, "\\314"}, {4, "\\315"}, {4, "\\316"}, {4, "\\317"},
{4, "\\320"}, {4, "\\321"}, {4, "\\322"}, {4, "\\323"},
{4, "\\324"}, {4, "\\325"}, {4, "\\326"}, {4, "\\327"},
{4, "\\330"}, {4, "\\331"}, {4, "\\332"}, {4, "\\333"},
{4, "\\334"}, {4, "\\335"}, {4, "\\336"}, {4, "\\337"},
{4, "\\340"}, {4, "\\341"}, {4, "\\342"}, {4, "\\343"},
{4, "\\344"}, {4, "\\345"}, {4, "\\346"}, {4, "\\347"},
{4, "\\350"}, {4, "\\351"}, {4, "\\352"}, {4, "\\353"},
{4, "\\354"}, {4, "\\355"}, {4, "\\356"}, {4, "\\357"},
{4, "\\360"}, {4, "\\361"}, {4, "\\362"}, {4, "\\363"},
{4, "\\364"}, {4, "\\365"}, {4, "\\366"}, {4, "\\367"},
{4, "\\370"}, {4, "\\371"}, {4, "\\372"}, {4, "\\373"},
{4, "\\374"}, {4, "\\375"}, {4, "\\376"}, {4, "\\377"}
};
static BOOLEAN in_string = FALSE;
int char_no = 0;
int line_no = 0;
int page_no = 0; /* page number in a document */
int pages_printed = 0;
static int pplistmaxsize=0;
static unsigned char *pplist=0; /* bitmap list for storing pages to print */
void
pagelist(char *list) {
char c;
int n, m;
int state, start;
if (list == 0) return;
state = 1;
start = 0;
while ((c=*list) != '\0') {
n = 0;
while (isdigit(c)) {
n = n * 10 + c - '0';
c = *++list;
}
switch (state) {
case 1:
start = n;
case 2:
if (n/8+1 > pplistmaxsize) {
pplistmaxsize = n/8+1;
pplist = galloc(pplist, n/8+1, "page list");
}
for (m=start; m<=n; m++)
pplist[m/8] |= 1<<(m%8);
break;
}
switch (c) {
case '-':
state = 2;
list++;
break;
case ',':
state = 1;
list++;
break;
case '\0':
break;
}
}
}
BOOLEAN
pageon(void) {
extern BOOLEAN debug;
static BOOLEAN privdebug = FALSE;
if (pplist == 0 && page_no != 0) {
if (privdebug && !debug) {
privdebug = FALSE;
debug = TRUE;
}
return(TRUE); /* no page list, print all pages */
}
if (page_no/8 < pplistmaxsize && (pplist[page_no/8] & 1<<(page_no%8))) {
if (privdebug && !debug) {
privdebug = FALSE;
debug = TRUE;
}
return(TRUE);
} else {
if (!privdebug && debug) {
privdebug = TRUE;
debug = FALSE;
}
return(FALSE);
}
}
static int stringhpos, stringvpos;
void
startstring(void) {
if (!in_string) {
stringhpos = hpos;
stringvpos = vpos;
if (pageon()) Bprint(Bstdout, "(");
in_string = 1;
}
}
void
endstring(void) {
if (in_string) {
if (pageon()) Bprint(Bstdout, ") %d %d w\n", stringhpos, stringvpos);
in_string = 0;
}
}
BOOLEAN
isinstring(void) {
return(in_string);
}
void
startpage(void) {
++char_no;
++line_no;
++page_no;
if (pageon()) {
++pages_printed;
Bprint(Bstdout, "%s %d %d\n", PAGE, page_no, pages_printed);
Bprint(Bstdout, "/saveobj save def\n");
Bprint(Bstdout, "mark\n");
Bprint(Bstdout, "%d pagesetup\n", pages_printed);
}
}
void
endpage(void) {
endstring();
curpostfontid = -1;
line_no = 0;
char_no = 0;
if (pageon()) {
Bprint(Bstdout, "cleartomark\n");
Bprint(Bstdout, "showpage\n");
Bprint(Bstdout, "saveobj restore\n");
Bprint(Bstdout, "%s %d %d\n", ENDPAGE, page_no, pages_printed);
}
}
/* This was taken from postprint */
int
cat(char *filename) {
Biobuf *bfile;
Biobuf *Bfile;
int n;
static char buf[Bsize];
if ((bfile = Bopen(unsharp(filename), OREAD)) == 0) {
return(1);
}
Bfile = bfile;
while ((n=Bread(Bfile, buf, Bsize)) > 0) {
if (Bwrite(Bstdout, buf, n) != n)
break;
}
Bterm(Bfile);
if (n != 0) {
return(1);
}
return(0);
}
extern int debug;
void *
galloc(void *ptr, int size, char *perstr) {
void *x;
if ((x=realloc(ptr, size)) == 0) {
perror(perstr);
exits("malloc");
}
return(x);
}
static char *errorstrings[] = {
{""}, /* NONE */
{"WARNING"},
{"FATAL"}
};
char *programname;
char *inputfilename = "<stdin>";
int inputlineno;
void
error(int errtype, char *fmt, ...) {
va_list arg;
Bflush(Bstdout);
Bflush(Bstderr);
fprint(2, "%s: %s:%d :%s: ", programname, inputfilename, inputlineno, errorstrings[errtype]);
va_start(arg, fmt);
vfprint(2, fmt, arg);
va_end(arg);
if (errtype == FATAL)
exits("fatal error");
}

View file

@ -0,0 +1,43 @@
#define NONE 0
#define WARNING 1
#define FATAL 2
#define RUNEGETGROUP(a) ((a>>8)&0xff)
#define RUNEGETCHAR(a) (a&0xff)
typedef int BOOLEAN;
#define TRUE 1
#define FALSE 0
#define NUMOFONTS 0x100
#define FONTSIZE 0x100
extern char *programname;
extern char *inputfilename;
extern int inputlineno;
extern int page_no;
extern int pages_printed;
extern int curpostfontid;
extern int hpos, vpos;
extern Biobuf *Bstdout, *Bstderr;
struct strtab {
int size;
char *str;
int used;
};
extern struct strtab charcode[];
BOOLEAN pageon(void);
void startstring(void);
void endstring(void);
BOOLEAN isinstring(void);
void startpage(void);
void endpage(void);
int cat(char *);
int Bgetfield(Biobuf *, int, void *, int);
void *galloc(void *, int, char *);
void pagelist(char *);

View file

@ -0,0 +1,40 @@
/*
*
* External varibles - most are in glob.c.
*
*/
extern char **argv; /* global so everyone can use them */
extern int argc;
extern int x_stat; /* program exit status */
extern int debug; /* debug flag */
extern int ignore; /* what we do with FATAL errors */
extern long lineno; /* line number */
extern long position; /* byte position */
extern char *prog_name; /* and program name - for errors */
extern char *temp_file; /* temporary file - for some programs */
extern char *fontencoding; /* text font encoding scheme */
extern int dobbox; /* enable BoundingBox stuff if TRUE */
extern double pageheight; /* only for BoundingBox calculations! */
extern double pagewidth;
extern int reading; /* input */
extern int writing; /* and output encoding */
extern char *optarg; /* for getopt() */
extern int optind;
extern void interrupt();
//extern char *tempnam(char*,char*);
/*
* extern char *malloc();
* extern char *calloc();
* extern char *strtok();
* extern long ftell();
* extern double atof();
* extern double sqrt();
* extern double atan2();
*/

View file

@ -0,0 +1,65 @@
/*
*
* A few definitions that shouldn't have to change. Used by most programs in
* this package.
*
*/
#define PROGRAMVERSION "3.3.2"
#define NON_FATAL 0
#define FATAL 1
#define USER_FATAL 2
#define OFF 0
#define ON 1
#define FALSE 0
#define TRUE 1
#define BYTE 8
#define BMASK 0377
#define POINTS 72.3
#ifndef PI
#define PI 3.141592654
#endif
#define ONEBYTE 0
#define UTFENCODING 1
#define READING ONEBYTE
#define WRITING ONEBYTE
/*
*
* DOROUND controls whether some translators include file ROUNDPAGE (path.h)
* after the prologue. Used to round page dimensions obtained from the clippath
* to know paper sizes. Enabled by setting DOROUND to TRUE (or 1).
*
*/
#define DOROUND TRUE
/*
*
* Default resolution and the height and width of a page (in case we need to get
* to upper left corner) - only used in BoundingBox calculations!!
*
*/
#define DEFAULT_RES 72
#define PAGEHEIGHT 11.0 * DEFAULT_RES
#define PAGEWIDTH 8.5 * DEFAULT_RES
/*
*
* Simple macros.
*
*/
#define ABS(A) ((A) >= 0 ? (A) : -(A))
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#define MAX(A, B) ((A) > (B) ? (A) : (B))

View file

@ -0,0 +1,56 @@
#ifndef _POSIX_SOURCE
#include <u.h>
#include <libc.h>
#endif
#include <stdio.h>
#define ERR(str, chr) if(opterr){fprintf(stderr, "%s%s%c\n", argv[0], str, chr);}
int opterr = 1;
int optind = 1;
int optopt;
char *optarg;
char *strchr();
int
getopt (argc, argv, opts)
char **argv, *opts;
{
static int sp = 1;
register c;
register char *cp;
if (sp == 1)
if (optind >= argc ||
argv[optind][0] != '-' || argv[optind][1] == '\0')
return EOF;
else if (strcmp(argv[optind], "--") == NULL) {
optind++;
return EOF;
}
optopt = c = argv[optind][sp];
if (c == ':' || (cp=strchr(opts, c)) == NULL) {
ERR (": illegal option -- ", c);
if (argv[optind][++sp] == '\0') {
optind++;
sp = 1;
}
return '?';
}
if (*++cp == ':') {
if (argv[optind][sp+1] != '\0')
optarg = &argv[optind++][sp+1];
else if (++optind >= argc) {
ERR (": option requires an argument -- ", c);
sp = 1;
return '?';
} else
optarg = argv[optind++];
sp = 1;
} else {
if (argv[optind][++sp] == '\0') {
sp = 1;
optind++;
}
optarg = NULL;
}
return c;
}

View file

@ -0,0 +1,29 @@
/*
*
* Global varibles - for PostScript translators.
*
*/
#include <stdio.h>
#include "gen.h"
char **argv; /* global so everyone can use them */
int argc;
int x_stat = 0; /* program exit status */
int debug = OFF; /* debug flag */
int ignore = OFF; /* what we do with FATAL errors */
long lineno = 0; /* line number */
long position = 0; /* byte position */
char *prog_name = ""; /* and program name - for errors */
char *temp_file = NULL; /* temporary file - for some programs */
char *fontencoding = NULL; /* text font encoding scheme */
int dobbox = FALSE; /* enable BoundingBox stuff if TRUE */
double pageheight = PAGEHEIGHT; /* only for BoundingBox calculations! */
double pagewidth = PAGEWIDTH;
int reading = UTFENCODING; /* input */
int writing = WRITING; /* and output encoding */

View file

@ -0,0 +1,230 @@
/*
*
* General purpose routines.
*
*/
#include <stdio.h>
#include <ctype.h>
#include <sys/types.h>
#include <fcntl.h>
#include "gen.h"
#include "ext.h"
#include "path.h"
int nolist = 0; /* number of specified ranges */
int olist[50]; /* processing range pairs */
/*****************************************************************************/
out_list(str)
char *str;
{
int start, stop;
/*
*
* Grab page ranges from str, save them in olist[], and update the nolist
* count. Range syntax matches nroff/troff syntax.
*
*/
while ( *str && nolist < sizeof(olist) - 2 ) {
start = stop = str_convert(&str, 0);
if ( *str == '-' && *str++ )
stop = str_convert(&str, 9999);
if ( start > stop )
error(FATAL, "illegal range %d-%d", start, stop);
olist[nolist++] = start;
olist[nolist++] = stop;
if ( *str != '\0' ) str++;
} /* End while */
olist[nolist] = 0;
} /* End of out_list */
/*****************************************************************************/
in_olist(num)
int num;
{
int i;
/*
*
* Return ON if num is in the current page range list. Print everything if
* there's no list.
*
*/
if ( nolist == 0 )
return(ON);
for ( i = 0; i < nolist; i += 2 )
if ( num >= olist[i] && num <= olist[i+1] )
return(ON);
return(OFF);
} /* End of in_olist */
/*****************************************************************************/
setencoding(name)
char *name;
{
char path[150];
/*
*
* Include the font encoding file selected by name. It's a full pathname if
* it begins with /, otherwise append suffix ".enc" and look for the file in
* ENCODINGDIR. Missing files are silently ignored.
*
*/
if ( name == NULL )
name = "Default";
if ( *name == '/' )
strcpy(path, name);
else sprintf(path, "%s/%s.enc", ENCODINGDIR, name);
if ( cat(path) == TRUE )
writing = strncmp(name, "UTF", 3) == 0;
} /* End of setencoding */
/*****************************************************************************/
cat(file)
char *file;
{
int fd_in;
int fd_out;
char buf[512];
int count;
/*
*
* Copy *file to stdout. Return FALSE is there was a problem.
*
*/
fflush(stdout);
if ( (fd_in = open(file, O_RDONLY)) == -1 )
return(FALSE);
fd_out = fileno(stdout);
while ( (count = read(fd_in, buf, sizeof(buf))) > 0 )
write(fd_out, buf, count);
close(fd_in);
return(TRUE);
} /* End of cat */
/*****************************************************************************/
str_convert(str, err)
char **str;
int err;
{
int i;
/*
*
* Grab the next integer from **str and return its value or err if *str
* isn't an integer. *str is modified after each digit is read.
*
*/
if ( ! isdigit(**str) )
return(err);
for ( i = 0; isdigit(**str); *str += 1 )
i = 10 * i + **str - '0';
return(i);
} /* End of str_convert */
/*****************************************************************************/
error(kind, mesg, a1, a2, a3)
int kind;
char *mesg;
unsigned a1, a2, a3;
{
/*
*
* Print an error message and quit if kind is FATAL.
*
*/
if ( mesg != NULL && *mesg != '\0' ) {
fprintf(stderr, "%s: ", prog_name);
fprintf(stderr, mesg, a1, a2, a3);
if ( lineno > 0 )
fprintf(stderr, " (line %d)", lineno);
if ( position > 0 )
fprintf(stderr, " (near byte %d)", position);
putc('\n', stderr);
} /* End if */
if ( kind == FATAL && ignore == OFF ) {
if ( temp_file != NULL )
unlink(temp_file);
exit(x_stat | 01);
} /* End if */
} /* End of error */
/*****************************************************************************/
void interrupt(sig)
int sig;
{
/*
*
* Signal handler for translators.
*
*/
if ( temp_file != NULL )
unlink(temp_file);
exit(1);
} /* End of interrupt */
/*****************************************************************************/

View file

@ -0,0 +1,23 @@
<$PLAN9/src/mkhdr
<../config
LIB=com.a
OFILES=bbox.$O\
glob.$O\
misc.$O\
request.$O\
rune.$O\
tempnam.$O\
getopt.$O\
HFILES=comments.h\
gen.h\
ext.h\
request.h\
path.h\
rune.h\
<$PLAN9/src/mklib
CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE

View file

@ -0,0 +1,32 @@
/*
*
* pathname definitions for important files and directories.
*
*/
#define DPOST "#9/sys/lib/postscript/prologues/dpost.ps"
#define POSTBGI "#9/sys/lib/postscript/prologues/postbgi.ps"
#define POSTDAISY "#9/sys/lib/postscript/prologues/postdaisy.ps"
#define POSTDMD "#9/sys/lib/postscript/prologues/postdmd.ps"
#define POSTMD "#9/sys/lib/postscript/prologues/postmd.ps"
#define POSTPLOT "#9/sys/lib/postscript/prologues/postplot.ps"
#define POSTPRINT "#9/sys/lib/postscript/prologues/postprint.ps"
#define POSTNPRINT "#9/sys/lib/postscript/prologues/postnprint.ps"
#define POSTTEK "#9/sys/lib/postscript/prologues/posttek.ps"
#define POSTGIF "#9/sys/lib/postscript/prologues/postgif.ps"
#define BASELINE "#9/sys/lib/postscript/prologues/baseline.ps"
#define COLOR "#9/sys/lib/postscript/prologues/color.ps"
#define DRAW "#9/sys/lib/postscript/prologues/draw.ps"
#define FORMFILE "#9/sys/lib/postscript/prologues/forms.ps"
#define SHADEFILE "#9/sys/lib/postscript/prologues/shade.ps"
#define KERNING "#9/sys/lib/postscript/prologues/kerning.ps"
#define REQUESTFILE "#9/sys/lib/postscript/prologues/ps.requests"
#define ROUNDPAGE "#9/sys/lib/postscript/prologues/roundpage.ps"
#define ENCODINGDIR "#9/sys/lib/postscript/prologues"
#define HOSTDIR "#9/sys/lib/postscript/font"
#define FONTDIR "#9/sys/lib/troff/font"
#define POSTLIBDIR "#9/sys/lib/postscript/prologues"
#define TEMPDIR "/tmp"

View file

@ -0,0 +1,119 @@
/*
*
* Things used to handle special requests (eg. manual feed) globally or on a per
* page basis. Requests are passed through to the translator using the -R option.
* The argument to -R can be "request", "request:page", or "request:page:file".
* If page is omitted (as in the first form) or set to 0 request will be applied
* to the global environment. In all other cases it applies only to the selected
* page. If a file is given, page must be supplied, and the lookup is in that file
* rather than *requestfile.
*
*/
#include <stdio.h>
#include "gen.h" /* general purpose definitions */
#include "request.h" /* a few special definitions */
#include "path.h" /* for the default request file */
Request request[MAXREQUEST]; /* next page or global request */
int nextreq = 0; /* goes in request[nextreq] */
char *requestfile = REQUESTFILE; /* default lookup file */
/*****************************************************************************/
saverequest(want)
char *want; /* grab code for this stuff */
{
char *page; /* and save it for this page */
char *strtok();
/*
*
* Save the request until we get to appropriate page - don't even bother with
* the lookup right now. Format of *want string is "request", "request:page", or
* "request:page:file", and we assume we can change the string here as needed.
* If page is omitted or given as 0 the request will be done globally. If *want
* includes a file, request and page must also be given, and in that case *file
* will be used for the lookup.
*
*/
if ( nextreq < MAXREQUEST ) {
request[nextreq].want = strtok(want, ": ");
if ( (page = strtok(NULL, ": ")) == NULL )
request[nextreq].page = 0;
else request[nextreq].page = atoi(page);
if ( (request[nextreq].file = strtok(NULL, ": ")) == NULL )
request[nextreq].file = requestfile;
nextreq++;
} else error(NON_FATAL, "too many requests - ignoring %s", want);
} /* End of saverequest */
/*****************************************************************************/
writerequest(page, fp_out)
int page; /* write everything for this page */
FILE *fp_out; /* to this file */
{
int i; /* loop index */
/*
*
* Writes out all the requests that have been saved for page. Page 0 refers to
* the global environment and is done during initial setup.
*
*/
for ( i = 0; i < nextreq; i++ )
if ( request[i].page == page )
dumprequest(request[i].want, request[i].file, fp_out);
} /* End of writerequest */
/*****************************************************************************/
dumprequest(want, file, fp_out)
char *want; /* look for this string */
char *file; /* in this file */
FILE *fp_out; /* and write the value out here */
{
char buf[100]; /* line buffer for reading *file */
FILE *fp_in;
/*
*
* Looks for *want in the request file and if it's found the associated value
* is copied to the output file. Keywords (ie. the *want strings) begin an @ in
* the first column of file, while the values (ie. the stuff that's copied to
* the output file) starts on the next line and extends to the next keyword or
* to the end of file.
*
*/
if ( (fp_in = fopen(file, "r")) != NULL ) {
while ( fgets(buf, sizeof(buf), fp_in) != NULL )
if ( buf[0] == '@' && strncmp(want, &buf[1], strlen(want)) == 0 )
while ( fgets(buf, sizeof(buf), fp_in) != NULL )
if ( buf[0] == '#' || buf[0] == '%' )
continue;
else if ( buf[0] != '@' )
fprintf(fp_out, "%s", buf);
else break;
fclose(fp_in);
} /* End if */
} /* End of dumprequest */
/*****************************************************************************/

View file

@ -0,0 +1,22 @@
/*
*
* Things used to handle special PostScript requests (like manual feed) globally
* or on a per page basis. All the translators I've supplied accept the -R option
* that can be used to insert special PostScript code before the global setup is
* done, or at the start of named pages. The argument to the -R option is a string
* that can be "request", "request:page", or "request:page:file". If page isn't
* given (as in the first form) or if it's 0 in the last two, the request applies
* to the global environment, otherwise request holds only for the named page.
* If a file name is given a page number must be supplied, and in that case the
* request will be looked up in that file.
*
*/
#define MAXREQUEST 30
typedef struct {
char *want;
int page;
char *file;
} Request;

View file

@ -0,0 +1,142 @@
#include "rune.h"
enum
{
Bit1 = 7,
Bitx = 6,
Bit2 = 5,
Bit3 = 4,
Bit4 = 3,
T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
Maskx = (1<<Bitx)-1, /* 0011 1111 */
Testx = Maskx ^ 0xFF, /* 1100 0000 */
Bad = Runeerror,
};
int
chartorune(Rune *rune, char *str)
{
int c, c1, c2;
long l;
/*
* one character sequence
* 00000-0007F => T1
*/
c = *(unsigned char*)str;
if(c < Tx) {
*rune = c;
return 1;
}
/*
* two character sequence
* 0080-07FF => T2 Tx
*/
c1 = *(unsigned char*)(str+1) ^ Tx;
if(c1 & Testx)
goto bad;
if(c < T3) {
if(c < T2)
goto bad;
l = ((c << Bitx) | c1) & Rune2;
if(l <= Rune1)
goto bad;
*rune = l;
return 2;
}
/*
* three character sequence
* 0800-FFFF => T3 Tx Tx
*/
c2 = *(unsigned char*)(str+2) ^ Tx;
if(c2 & Testx)
goto bad;
if(c < T4) {
l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
if(l <= Rune2)
goto bad;
*rune = l;
return 3;
}
/*
* bad decoding
*/
bad:
*rune = Bad;
return 1;
}
int
runetochar(char *str, Rune *rune)
{
long c;
/*
* one character sequence
* 00000-0007F => 00-7F
*/
c = *rune;
if(c <= Rune1) {
str[0] = c;
return 1;
}
/*
* two character sequence
* 0080-07FF => T2 Tx
*/
if(c <= Rune2) {
str[0] = T2 | (c >> 1*Bitx);
str[1] = Tx | (c & Maskx);
return 2;
}
/*
* three character sequence
* 0800-FFFF => T3 Tx Tx
*/
str[0] = T3 | (c >> 2*Bitx);
str[1] = Tx | ((c >> 1*Bitx) & Maskx);
str[2] = Tx | (c & Maskx);
return 3;
}
int
runelen(long c)
{
Rune rune;
char str[10];
rune = c;
return runetochar(str, &rune);
}
int
fullrune(char *str, int n)
{
int c;
if(n > 0) {
c = *(unsigned char*)str;
if(c < Tx)
return 1;
if(n > 1)
if(c < T3 || n > 2)
return 1;
}
return 0;
}

View file

@ -0,0 +1,19 @@
/*
*
* Rune declarations - for supporting UTF encoding.
*
*/
#define RUNELIB 1
#ifdef RUNELIB
typedef unsigned short Rune;
enum
{
UTFmax = 3, /* maximum bytes per rune */
Runesync = 0x80, /* cannot represent part of a utf sequence (<) */
Runeself = 0x80, /* rune and utf sequences are the same (<) */
Runeerror = 0x80, /* decoding error in utf */
};
#endif

View file

@ -0,0 +1,27 @@
#include <stdio.h>
#include <errno.h>
#if defined(V9) || defined(BSD4_2) || defined(plan9)
char *tempnam(char *dir, char *pfx) {
int pid;
unsigned int len;
char *tnm, *malloc();
static int seq = 0;
pid = getpid();
len = strlen(dir) + strlen(pfx) + 10;
if ((tnm = malloc(len)) != NULL) {
sprintf(tnm, "%s", dir);
if (access(tnm, 7) == -1)
return(NULL);
do {
sprintf(tnm, "%s/%s%d%d", dir, pfx, pid, seq++);
errno = 0;
if (access(tnm, 7) == -1)
if (errno == ENOENT)
return(tnm);
} while (1);
}
return(tnm);
}
#endif

View file

@ -0,0 +1,11 @@
A simple program that scans PostScript files for %%DocumentFonts:
comments and prepends requested host resident font files to the
input. Written for Unix 4.0 lp.
Downloaded fonts are the ones named in the %%DocumentFonts: comment
and listed in a special map file (which can be selected using the
-m option). See example.map and comments in download.c for examples
of map files. By default map files and font files are in *hostfontdir.
It's initialized using HOSTDIR (file ../common/path.h).

View file

@ -0,0 +1,545 @@
/*
*
* download - host resident font downloader
*
* Prepends host resident fonts to PostScript input files. The program assumes
* the input files are part of a single PostScript job and that requested fonts
* can be downloaded at the start of each input file. Downloaded fonts are the
* ones named in a %%DocumentFonts: comment and listed in a special map table.
* Map table pathnames (supplied using the -m option) that begin with a / are
* taken as is. Otherwise the final pathname is built using *hostfontdir (-H
* option), *mapname (-m option), and *suffix.
*
* The map table consists of fontname-filename pairs, separated by white space.
* Comments are introduced by % (as in PostScript) and extend to the end of the
* current line. The only fonts that can be downloaded are the ones listed in
* the active map table that point the program to a readable Unix file. A request
* for an unlisted font or inaccessible file is ignored. All font requests are
* ignored if the map table can't be read. In that case the program simply copies
* the input files to stdout.
*
* An example (but not one to follow) of what can be in a map table is,
*
* %
* % Map requests for Bookman-Light to file *hostfontdir/KR
* %
*
* Bookman-Light KR % Keeping everything (including the map
* % table) in *hostfontdir seems like the
* % cleanest approach.
*
* %
* % Map Palatino-Roman to file *hostfontdir/palatino/Roman
* %
* Palatino-Roman palatino/Roman
*
* % Map ZapfDingbats to file /usr/lib/host/dingbats
*
* ZapfDingbats /usr/lib/host/dingbats
*
* Once again, file names that begin with a / are taken as is. All others have
* *hostfontdir/ prepended to the file string associated with a particular font.
*
* Map table can be associated with a printer model (e.g. a LaserWriter), a
* printer destination, or whatever - the choice is up to an administrator.
* By destination may be best if your spooler is running several private
* printers. Host resident fonts are usually purchased under a license that
* restricts their use to a limited number of printers. A font licensed for
* a single printer should only be used on that printer.
*
* Was written quickly, so there's much room for improvement. Undoubtedly should
* be a more general program (e.g. scan for other comments).
*
*/
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include "comments.h" /* PostScript file structuring comments */
#include "gen.h" /* general purpose definitions */
#include "path.h" /* for temporary directory */
#include "ext.h" /* external variable declarations */
#include "download.h" /* a few special definitions */
char *temp_dir = TEMPDIR; /* temp directory - for copying stdin */
char *hostfontdir = HOSTDIR; /* host resident directory */
char *mapname = "map"; /* map table - usually in *hostfontdir */
char *suffix = ""; /* appended to the map table pathname */
Map *map = NULL; /* device font map table */
char *stringspace = NULL; /* for storing font and file strings */
int next = 0; /* next free slot in map[] */
char *residentfonts = NULL; /* list of printer resident fonts */
char *printer = NULL; /* printer name - only for Unix 4.0 lp */
char buf[2048]; /* input file line buffer */
char *comment = DOCUMENTFONTS; /* look for this comment */
int atend = FALSE; /* TRUE only if a comment says so */
FILE *fp_in; /* next input file */
FILE *fp_temp = NULL; /* for copying stdin */
/*****************************************************************************/
main(agc, agv)
int agc;
char *agv[];
{
/*
*
* Host resident font downloader. The input files are assumed to be part of a
* single PostScript job.
*
*/
fp_in = stdin;
argc = agc; /* other routines may want them */
argv = agv;
prog_name = argv[0]; /* just for error messages */
init_signals(); /* sets up interrupt handling */
options(); /* first get command line options */
readmap(); /* read the font map table */
readresident(); /* and the optional resident font list */
arguments(); /* then process non-option arguments */
done(); /* and clean things up */
exit(x_stat); /* not much could be wrong */
} /* End of main */
/*****************************************************************************/
init_signals()
{
/*
*
* Makes sure we handle interrupts properly.
*
*/
if ( signal(SIGINT, interrupt) == SIG_IGN ) {
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGHUP, SIG_IGN);
} else {
signal(SIGHUP, interrupt);
signal(SIGQUIT, interrupt);
} /* End else */
signal(SIGTERM, interrupt);
} /* End of init_signals */
/*****************************************************************************/
options()
{
int ch; /* return value from getopt() */
char *optnames = "c:fm:p:r:H:T:DI";
extern char *optarg; /* used by getopt() */
extern int optind;
/*
*
* Reads and processes the command line options.
*
*/
while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
switch ( ch ) {
case 'c': /* look for this comment */
comment = optarg;
break;
case 'f': /* force a complete input file scan */
atend = TRUE;
break;
case 'm': /* printer map table name */
mapname = optarg;
break;
case 'p': /* printer name - for Unix 4.0 lp */
printer = optarg;
break;
case 'r': /* resident font list */
residentfonts = optarg;
break;
case 'H': /* host resident font directory */
hostfontdir = optarg;
break;
case 'T': /* temporary file directory */
temp_dir = optarg;
break;
case 'D': /* debug flag */
debug = ON;
break;
case 'I': /* ignore FATAL errors */
ignore = ON;
break;
case '?': /* don't understand the option */
error(FATAL, "");
break;
default: /* don't know what to do for ch */
error(FATAL, "missing case for option %c\n", ch);
break;
} /* End switch */
} /* End while */
argc -= optind; /* get ready for non-option args */
argv += optind;
} /* End of options */
/*****************************************************************************/
readmap()
{
char *path;
char *ptr;
int fd;
struct stat sbuf;
/*
*
* Initializes the map table by reading an ASCII mapping file. If mapname begins
* with a / it's the map table. Otherwise hostfontdir, mapname, and suffix are
* combined to build the final pathname. If we can open the file we read it all
* into memory, erase comments, and separate the font and file name pairs. When
* we leave next points to the next free slot in the map[] array. If it's zero
* nothing was in the file or we couldn't open it.
*
*/
if ( hostfontdir == NULL || mapname == NULL )
return;
if ( *mapname != '/' ) {
if ( (path = (char *)malloc(strlen(hostfontdir) + strlen(mapname) +
strlen(suffix) + 2)) == NULL )
error(FATAL, "no memory");
sprintf(path, "%s/%s%s", hostfontdir, mapname, suffix);
} else path = mapname;
if ( (fd = open(unsharp(path), 0)) != -1 ) {
if ( fstat(fd, &sbuf) == -1 )
error(FATAL, "can't fstat %s", path);
if ( (stringspace = (char *)malloc(sbuf.st_size + 2)) == NULL )
error(FATAL, "no memory");
if ( read(fd, stringspace, sbuf.st_size) == -1 )
error(FATAL, "can't read %s", path);
close(fd);
stringspace[sbuf.st_size] = '\n'; /* just to be safe */
stringspace[sbuf.st_size+1] = '\0';
for ( ptr = stringspace; *ptr != '\0'; ptr++ ) /* erase comments */
if ( *ptr == '%' )
for ( ; *ptr != '\n' ; ptr++ )
*ptr = ' ';
for ( ptr = stringspace; ; next++ ) {
if ( (next % 50) == 0 )
map = allocate(map, next+50);
map[next].downloaded = FALSE;
map[next].font = strtok(ptr, " \t\n");
map[next].file = strtok(ptr = NULL, " \t\n");
if ( map[next].font == NULL )
break;
if ( map[next].file == NULL )
error(FATAL, "map table format error - check %s", path);
} /* End for */
} /* End if */
} /* End of readmap */
/*****************************************************************************/
readresident()
{
FILE *fp;
char *path;
int ch;
int n;
/*
*
* Reads a file that lists the resident fonts for a particular printer and marks
* each font as already downloaded. Nothing's done if the file can't be read or
* there's no mapping file. Comments, as in the map file, begin with a % and
* extend to the end of the line. Added for Unix 4.0 lp.
*
*/
if ( next == 0 || (printer == NULL && residentfonts == NULL) )
return;
if ( printer != NULL ) { /* use Unix 4.0 lp pathnames */
sprintf(buf, "%s/printers/%s", HOSTDIR, printer);
path = buf;
} else path = residentfonts;
if ( (fp = fopen(unsharp(path), "r")) != NULL ) {
while ( fscanf(fp, "%s", buf) != EOF )
if ( buf[0] == '%' )
while ( (ch = getc(fp)) != EOF && ch != '\n' ) ;
else if ( (n = lookup(buf)) < next )
map[n].downloaded = TRUE;
fclose(fp);
} /* End if */
} /* End of readresident */
/*****************************************************************************/
arguments()
{
/*
*
* Makes sure all the non-option command line arguments are processed. If we get
* here and there aren't any arguments left, or if '-' is one of the input files
* we'll translate stdin. Assumes input files are part of a single PostScript
* job and fonts can be downloaded at the start of each file.
*
*/
if ( argc < 1 )
download();
else {
while ( argc > 0 ) {
fp_temp = NULL;
if ( strcmp(*argv, "-") == 0 )
fp_in = stdin;
else if ( (fp_in = fopen(unsharp(*argv), "r")) == NULL )
error(FATAL, "can't open %s", *argv);
download();
if ( fp_in != stdin )
fclose(fp_in);
if ( fp_temp != NULL )
fclose(fp_temp);
argc--;
argv++;
} /* End while */
} /* End else */
} /* End of arguments */
/*****************************************************************************/
done()
{
/*
*
* Clean things up before we quit.
*
*/
if ( temp_file != NULL )
unlink(temp_file);
} /* End of done */
/*****************************************************************************/
download()
{
int infontlist = FALSE;
/*
*
* If next is zero the map table is empty and all we do is copy the input file
* to stdout. Otherwise we read the input file looking for %%DocumentFonts: or
* continuation comments, add any accessible fonts to the output file, and then
* append the input file. When reading stdin we append lines to fp_temp and
* recover them when we're ready to copy the input file. fp_temp will often
* only contain part of stdin - if there's no %%DocumentFonts: (atend) comment
* we stop reading fp_in after the header.
*
*/
if ( next > 0 ) {
if ( fp_in == stdin ) {
if ( (temp_file = tempnam(temp_dir, "post")) == NULL )
error(FATAL, "can't generate temp file name");
if ( (fp_temp = fopen(temp_file, "w+r")) == NULL )
error(FATAL, "can't open %s", temp_file);
unlink(temp_file);
} /* End if */
while ( fgets(buf, sizeof(buf), fp_in) != NULL ) {
if ( fp_temp != NULL )
fprintf(fp_temp, "%s", buf);
if ( buf[0] != '%' || buf[1] != '%' ) {
if ( (buf[0] != '%' || buf[1] != '!') && atend == FALSE )
break;
infontlist = FALSE;
} else if ( strncmp(buf, comment, strlen(comment)) == 0 ) {
copyfonts(buf);
infontlist = TRUE;
} else if ( buf[2] == '+' && infontlist == TRUE )
copyfonts(buf);
else infontlist = FALSE;
} /* End while */
} /* End if */
copyinput();
} /* End of download */
/*****************************************************************************/
copyfonts(list)
char *list;
{
char *font;
char *path;
int n;
/*
*
* list points to a %%DocumentFonts: or continuation comment. What follows the
* the keyword will be a list of fonts separated by white space (or (atend)).
* Look for each font in the map table and if it's found copy the font file to
* stdout (once only).
*
*/
strtok(list, " \n"); /* skip to the font list */
while ( (font = strtok(NULL, " \t\n")) != NULL ) {
if ( strcmp(font, ATEND) == 0 ) {
atend = TRUE;
break;
} /* End if */
if ( (n = lookup(font)) < next ) {
if ( *map[n].file != '/' ) {
if ( (path = (char *)malloc(strlen(hostfontdir)+strlen(map[n].file)+2)) == NULL )
error(FATAL, "no memory");
sprintf(path, "%s/%s", hostfontdir, map[n].file);
cat(unsharp(path));
free(path);
} else cat(unsharp(map[n].file));
map[n].downloaded = TRUE;
} /* End if */
} /* End while */
} /* End of copyfonts */
/*****************************************************************************/
copyinput()
{
/*
*
* Copies the input file to stdout. If fp_temp isn't NULL seek to the start and
* add it to the output file - it's a partial (or complete) copy of stdin made
* by download(). Then copy fp_in, but only seek to the start if it's not stdin.
*
*/
if ( fp_temp != NULL ) {
fseek(fp_temp, 0L, 0);
while ( fgets(buf, sizeof(buf), fp_temp) != NULL )
printf("%s", buf);
} /* End if */
if ( fp_in != stdin )
fseek(fp_in, 0L, 0);
while ( fgets(buf, sizeof(buf), fp_in) != NULL )
printf("%s", buf);
} /* End of copyinput */
/*****************************************************************************/
lookup(font)
char *font;
{
int i;
/*
*
* Looks for *font in the map table. Return the map table index if found and
* not yet downloaded - otherwise return next.
*
*/
for ( i = 0; i < next; i++ )
if ( strcmp(font, map[i].font) == 0 ) {
if ( map[i].downloaded == TRUE )
i = next;
break;
} /* End if */
return(i);
} /* End of lookup */
/*****************************************************************************/
Map *allocate(ptr, num)
Map *ptr;
int num;
{
/*
*
* Allocates space for num Map elements. Calls malloc() if ptr is NULL and
* realloc() otherwise.
*
*/
if ( ptr == NULL )
ptr = (Map *)malloc(num * sizeof(Map));
else ptr = (Map *)realloc(ptr, num * sizeof(Map));
if ( ptr == NULL )
error(FATAL, "no map memory");
return(ptr);
} /* End of allocate */
/*****************************************************************************/

View file

@ -0,0 +1,14 @@
/*
*
* The font data for a printer is saved in an array of the following type.
*
*/
typedef struct map {
char *font; /* a request for this PostScript font */
char *file; /* means copy this unix file */
int downloaded; /* TRUE after *file is downloaded */
} Map;
Map *allocate();

View file

@ -0,0 +1,25 @@
<$PLAN9/src/mkhdr
<../config
TARG=psdownload
OFILES=download.$O
COMMONDIR=../common
HFILES=download.h\
$COMMONDIR/comments.h\
$COMMONDIR/gen.h\
$COMMONDIR/path.h\
$COMMONDIR/ext.h\
LIB=$COMMONDIR/com.a
BIN=$POSTBIN
<$PLAN9/src/mkone
CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR
$LIB:
cd $COMMONDIR
mk install
mk clean

25
src/cmd/postscript/mkfile Normal file
View file

@ -0,0 +1,25 @@
<$PLAN9/src/mkhdr
<config
DIRS=\
common\
tr2post\
download\
# cropmarks\
# grabit\
# hardcopy\
# mpictures\
# postgif\
# postprint\
# postreverse\
# posttek\
# printfont\
# psencoding\
# psfiles\
# g3p9bit\
# p9bitpost\
# tcpostio\
# text2post\
<$PLAN9/src/mkdirs

View file

@ -0,0 +1,156 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "../common/common.h"
#include "tr2post.h"
#undef isspace
#define isspace bisspace
int
isspace(Rune r)
{
return(r==' ' || r=='\t' || r=='\n' || r == '\r' || r=='\f');
}
int
Bskipws(Biobuf *bp) {
int r;
char c[UTFmax];
int sindex = 0;
/* skip over initial white space */
do {
r = Bgetrune(bp);
if (r == '\n') inputlineno++;
sindex++;
} while (r>=0 && isspace(r));
if (r<0) {
return(-1);
} else if (!isspace(r)) {
Bungetrune(bp);
--sindex;
}
return(sindex);
}
int
asc2dig(char c, int base) {
if (c >= '0' && c <= '9')
if (base == 8 && c > '7') return(-1);
else return(c - '0');
if (base == 16)
if (c >= 'a' && c <= 'f') return(10 + c - 'a');
else if (c >= 'A' && c <= 'F') return(10 + c - 'A');
return(-1);
}
/* get a string of type: "d" for decimal integer, "u" for unsigned,
* "s" for string", "c" for char,
* return the number of characters gotten for the field. If nothing
* was gotten and the end of file was reached, a negative value
* from the Bgetrune is returned.
*/
int
Bgetfield(Biobuf *bp, int type, void *thing, int size) {
int r;
Rune R;
char c[UTFmax];
int sindex = 0, i, j, n = 0;
int negate = 0;
int base = 10;
BOOLEAN bailout = FALSE;
int dig;
unsigned int u = 0;
/* skip over initial white space */
if (Bskipws(bp) < 0)
return(-1);
switch (type) {
case 'd':
while (!bailout && (r = Bgetrune(bp))>=0) {
switch (sindex++) {
case 0:
switch (r) {
case '-':
negate = 1;
continue;
case '+':
continue;
case '0':
base = 8;
continue;
default:
break;
}
break;
case 1:
if ((r == 'x' || r == 'X') && base == 8) {
base = 16;
continue;
}
}
if ((dig = asc2dig(r, base)) == -1) bailout = TRUE;
else n = dig + (n * base);
}
if (r < 0) return(-1);
*(int *)thing = (negate)?-n:n;
Bungetrune(bp);
break;
case 'u':
while (!bailout && (r = Bgetrune(bp))>=0) {
switch (sindex++) {
case 0:
if (*c == '0') {
base = 8;
continue;
}
break;
case 1:
if ((r == 'x' || r == 'X') && base == 8) {
base = 16;
continue;
}
}
if ((dig = asc2dig(r, base)) == -1) bailout = TRUE;
else u = dig + (n * base);
}
*(int *)thing = u;
if (r < 0) return(-1);
Bungetrune(bp);
break;
case 's':
j = 0;
while ((size>j+UTFmax) && (r = Bgetrune(bp))>=0 && !isspace(r)) {
R = r;
i = runetochar(&(((char *)thing)[j]), &R);
j += i;
sindex++;
}
((char *)thing)[j++] = '\0';
if (r < 0) return(-1);
Bungetrune(bp);
break;
case 'r':
if ((r = Bgetrune(bp))>=0) {
*(Rune *)thing = r;
sindex++;
return(sindex);
}
if (r <= 0) return(-1);
Bungetrune(bp);
break;
default:
return(-2);
}
if (r < 0 && sindex == 0)
return(r);
else if (bailout && sindex == 1) {
return(0);
} else
return(sindex);
}

View file

@ -0,0 +1,458 @@
/* Unicode | PostScript
* start end | offset font name
* 0x0000 0x00ff 0x00 LucidaSansUnicode00
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "common.h"
#include "tr2post.h"
#include "comments.h"
#include "path.h"
/* Postscript font names, e.g., `LucidaSansUnicode00'
* names may only be added because reference to the
* names is made by indexing into this table.
*/
static struct pfnament *pfnafontmtab = 0;
static int pfnamcnt = 0;
int curpostfontid = -1;
int curfontsize = -1;
int curtrofffontid = -1;
static int curfontpos = -1;
static int fontheight = 0;
static int fontslant = 0;
/* This is troffs mounted font table. It is an anachronism resulting
* from the design of the APS typesetter. fontmnt is the
* number of positions available. fontmnt is really 11, but
* should not be limited.
*/
int fontmnt = 0;
char **fontmtab;
struct troffont *troffontab = 0;
int troffontcnt = 0;
void
mountfont(int pos, char *fontname) {
int i;
if (debug) Bprint(Bstderr, "mountfont(%d, %s)\n", pos, fontname);
if (pos < 0 || pos >= fontmnt)
error(FATAL, "cannot mount a font at position %d,\n can only mount into postions 0-%d\n",
pos, fontmnt-1);
i = strlen(fontname);
fontmtab[pos] = galloc(fontmtab[pos], i+1, "mountfont():fontmtab");
strcpy(fontmtab[pos], fontname);
if (curfontpos == pos) curfontpos = -1;
}
void
settrfont(void) {
if (curfontpos == fontpos) return;
if (fontmtab[fontpos] == 0)
error(FATAL, "Font at position %d was not initialized, botch!\n", fontpos);
curtrofffontid = findtfn(fontmtab[fontpos], 1);
if (debug) Bprint(Bstderr, "settrfont()-> curtrofffontid=%d\n", curtrofffontid);
curfontpos = fontpos;
if (curtrofffontid < 0) {
int i;
error(WARNING, "fontpos=%d\n", fontpos);
for (i=0; i<fontmnt; i++)
if (fontmtab[i] == 0)
error(WARNING, "fontmtab[%d]=0x0\n", i);
else
error(WARNING, "fontmtab[%d]=%s\n", i, fontmtab[i]);
exits("settrfont()");
}
}
void
setpsfont(int psftid, int fontsize) {
if (psftid == curpostfontid && fontsize == curfontsize) return;
if (psftid >= pfnamcnt)
error(FATAL, "Postscript font index=%d used but not defined, there are only %d fonts\n",
psftid, pfnamcnt);
endstring();
if (pageon()) {
Bprint(Bstdout, "%d /%s f\n", fontsize, pfnafontmtab[psftid].str);
if ( fontheight != 0 || fontslant != 0 )
Bprint(Bstdout, "%d %d changefont\n", fontslant, (fontheight != 0) ? fontheight : fontsize);
pfnafontmtab[psftid].used = 1;
curpostfontid = psftid;
curfontsize = fontsize;
}
}
/* find index of PostScript font name in table
* returns -1 if name is not in table
* If insflg is not zero
* and the name is not found in the table, insert it.
*/
int
findpfn(char *fontname, int insflg) {
char *tp;
int i;
for (i=0; i<pfnamcnt; i++) {
if (strcmp(pfnafontmtab[i].str, fontname) == 0)
return(i);
}
if (insflg) {
tp = galloc(pfnafontmtab, sizeof(struct pfnament)*(pfnamcnt+1), "findpfn():pfnafontmtab");
if (tp == 0)
return(-2);
pfnafontmtab = (struct pfnament *)tp;
i = strlen(fontname);
pfnafontmtab[pfnamcnt].str = galloc(0, i+1, "findpfn():pfnafontmtab[].str");
strncpy(pfnafontmtab[pfnamcnt].str, fontname, i);
pfnafontmtab[pfnamcnt].str[i] = '\0';
pfnafontmtab[pfnamcnt].used = 0;
return(pfnamcnt++);
}
return(-1);
}
char postroffdirname[] = "#9/sys/lib/postscript/troff"; /* "/sys/lib/postscript/troff/"; */
char troffmetricdirname[] = "#9/sys/lib/troff/font"; /* "/sys/lib/troff/font/devutf/"; */
int
readpsfontdesc(char *fontname, int trindex) {
static char *filename = 0;
Biobuf *bfd;
Biobuf *Bfd;
int warn = 0, errorflg = 0, line =1, rv;
int start, end, offset;
int startfont, endfont, startchar, endchar, i, pfid;
char psfontnam[128];
struct troffont *tp;
if (debug) Bprint(Bstderr, "readpsfontdesc(%s,%d)\n", fontname, trindex);
filename=galloc(filename, strlen(postroffdirname)+1+strlen(fontname)+1, "readpsfontdesc: cannot allocate memory\n");
sprint(filename, "%s/%s", postroffdirname, fontname);
bfd = Bopen(unsharp(filename), OREAD);
if (bfd == 0) {
error(WARNING, "cannot open file %s\n", filename);
return(0);
}
Bfd = bfd;
do {
offset = 0;
if ((rv=Bgetfield(Bfd, 'd', &start, 0)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal start value\n", filename, line);
} else if (rv < 0) break;
if ((rv=Bgetfield(Bfd, 'd', &end, 0)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal end value\n", filename, line);
} else if (rv < 0) break;
if ((rv=Bgetfield(Bfd, 'd', &offset, 0)) < 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal offset value\n", filename, line);
}
if ((rv=Bgetfield(Bfd, 's', psfontnam, 128)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal fontname value\n", filename, line);
} else if (rv < 0) break;
Brdline(Bfd, '\n');
if (!errorflg) {
struct psfent *psfentp;
startfont = RUNEGETGROUP(start);
startchar = RUNEGETCHAR(start);
endfont = RUNEGETGROUP(end);
endchar = RUNEGETCHAR(end);
pfid = findpfn(psfontnam, 1);
if (startfont != endfont) {
error(WARNING, "font descriptions must not cross 256 glyph block boundary\n");
errorflg = 1;
break;
}
tp = &(troffontab[trindex]);
tp->psfmap = galloc(tp->psfmap, ++(tp->psfmapsize)*sizeof(struct psfent), "readpsfontdesc():psfmap");
psfentp = &(tp->psfmap[tp->psfmapsize-1]);
psfentp->start = start;
psfentp->end = end;
psfentp->offset = offset;
psfentp->psftid = pfid;
if (debug) {
Bprint(Bstderr, "\tpsfmap->start=0x%x\n", start);
Bprint(Bstderr, "\tpsfmap->end=0x%x\n", end);
Bprint(Bstderr, "\tpsfmap->offset=0x%x\n", offset);
Bprint(Bstderr, "\tpsfmap->pfid=0x%x\n", pfid);
}
/*
for (i=startchar; i<=endchar; i++) {
tp->charent[startfont][i].postfontid = pfid;
tp->charent[startfont][i].postcharid = i + offset - startchar;
}
*/
if (debug) {
Bprint(Bstderr, "%x %x ", start, end);
if (offset) Bprint(Bstderr, "%x ", offset);
Bprint(Bstderr, "%s\n", psfontnam);
}
line++;
}
} while(errorflg != 1);
Bterm(Bfd);
return(1);
}
int
readtroffmetric(char *fontname, int trindex) {
static char *filename = 0;
Biobuf *bfd;
Biobuf *Bfd;
int warn = 0, errorflg = 0, line =1, rv;
struct troffont *tp;
struct charent **cp;
char stoken[128], *str;
int ntoken;
Rune troffchar, quote;
int width, flag, charnum, thisfont, thischar;
BOOLEAN specharflag;
if (debug) Bprint(Bstderr, "readtroffmetric(%s,%d)\n", fontname, trindex);
filename=galloc(filename, strlen(troffmetricdirname)+4+strlen(devname)+1+strlen(fontname)+1, "readtroffmetric():filename");
sprint(filename, "%s/dev%s/%s", troffmetricdirname, devname, fontname);
bfd = Bopen(unsharp(filename), OREAD);
if (bfd == 0) {
error(WARNING, "cannot open file %s\n", filename);
return(0);
}
Bfd = bfd;
do {
/* deal with the few lines at the beginning of the
* troff font metric files.
*/
if ((rv=Bgetfield(Bfd, 's', stoken, 128)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal token\n", filename, line);
} else if (rv < 0) break;
if (debug) {
Bprint(Bstderr, "%s\n", stoken);
}
if (strcmp(stoken, "name") == 0) {
if ((rv=Bgetfield(Bfd, 's', stoken, 128)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal token\n", filename, line);
} else if (rv < 0) break;
} else if (strcmp(stoken, "named") == 0) {
Brdline(Bfd, '\n');
} else if (strcmp(stoken, "fontname") == 0) {
if ((rv=Bgetfield(Bfd, 's', stoken, 128)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal token\n", filename, line);
} else if (rv < 0) break;
} else if (strcmp(stoken, "spacewidth") == 0) {
if ((rv=Bgetfield(Bfd, 'd', &ntoken, 0)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal token\n", filename, line);
} else if (rv < 0) break;
troffontab[trindex].spacewidth = ntoken;
thisfont = RUNEGETGROUP(' ');
thischar = RUNEGETCHAR(' ');
for (cp = &(troffontab[trindex].charent[thisfont][thischar]); *cp != 0; cp = &((*cp)->next))
if ((*cp)->name)
if (strcmp((*cp)->name, " ") == 0)
break;
if (*cp == 0) *cp = galloc(0, sizeof(struct charent), "readtroffmetric:charent");
(*cp)->postfontid = thisfont;
(*cp)->postcharid = thischar;
(*cp)->troffcharwidth = ntoken;
(*cp)->name = galloc(0, 2, "readtroffmetric: char name");
(*cp)->next = 0;
strcpy((*cp)->name, " ");
} else if (strcmp(stoken, "special") == 0) {
troffontab[trindex].special = TRUE;
} else if (strcmp(stoken, "charset") == 0) {
line++;
break;
}
if (!errorflg) {
line++;
}
} while(!errorflg && rv>=0);
while(!errorflg && rv>=0) {
if ((rv=Bgetfield(Bfd, 's', stoken, 128)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal rune token <0x%x> rv=%d\n", filename, line, troffchar, rv);
} else if (rv < 0) break;
if (utflen(stoken) > 1) specharflag = TRUE;
else specharflag = FALSE;
/* if this character is a quote we have to use the previous characters info */
if ((rv=Bgetfield(Bfd, 'r', &quote, 0)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal width or quote token <0x%x> rv=%d\n", filename, line, quote, rv);
} else if (rv < 0) break;
if (quote == '"') {
/* need some code here */
goto flush;
} else {
Bungetrune(Bfd);
}
if ((rv=Bgetfield(Bfd, 'd', &width, 0)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal width token <0x%x> rv=%d\n", filename, line, troffchar, rv);
} else if (rv < 0) break;
if ((rv=Bgetfield(Bfd, 'd', &flag, 0)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal flag token <0x%x> rv=%d\n", filename, line, troffchar, rv);
} else if (rv < 0) break;
if ((rv=Bgetfield(Bfd, 'd', &charnum, 0)) == 0) {
errorflg = 1;
error(WARNING, "file %s:%d illegal character number token <0x%x> rv=%d\n", filename, line, troffchar, rv);
} else if (rv < 0) break;
flush:
str = Brdline(Bfd, '\n');
/* stash the crap from the end of the line for debugging */
if (debug) {
if (str == 0) {
Bprint(Bstderr, "premature EOF\n");
return(0);
}
str[Blinelen(Bfd)-1] = '\0';
}
line++;
chartorune(&troffchar, stoken);
if (specharflag) {
if (debug)
Bprint(Bstderr, "%s %d %d 0x%x %s # special\n",stoken, width, flag, charnum, str);
}
if (strcmp(stoken, "---") == 0) {
thisfont = RUNEGETGROUP(charnum);
thischar = RUNEGETCHAR(charnum);
stoken[0] = '\0';
} else {
thisfont = RUNEGETGROUP(troffchar);
thischar = RUNEGETCHAR(troffchar);
}
for (cp = &(troffontab[trindex].charent[thisfont][thischar]); *cp != 0; cp = &((*cp)->next))
if ((*cp)->name) {
if (debug) Bprint(Bstderr, "installing <%s>, found <%s>\n", stoken, (*cp)->name);
if (strcmp((*cp)->name, stoken) == 0)
break;
}
if (*cp == 0) *cp = galloc(0, sizeof(struct charent), "readtroffmetric:charent");
(*cp)->postfontid = RUNEGETGROUP(charnum);
(*cp)->postcharid = RUNEGETCHAR(charnum);
(*cp)->troffcharwidth = width;
(*cp)->name = galloc(0, strlen(stoken)+1, "readtroffmetric: char name");
(*cp)->next = 0;
strcpy((*cp)->name, stoken);
if (debug) {
if (specharflag)
Bprint(Bstderr, "%s", stoken);
else
Bputrune(Bstderr, troffchar);
Bprint(Bstderr, " %d %d 0x%x %s # psfontid=0x%x pscharid=0x%x thisfont=0x%x thischar=0x%x\n",
width, flag, charnum, str,
(*cp)->postfontid,
(*cp)->postcharid,
thisfont, thischar);
}
}
Bterm(Bfd);
Bflush(Bstderr);
return(1);
}
/* find index of troff font name in table
* returns -1 if name is not in table
* returns -2 if it cannot allocate memory
* returns -3 if there is a font mapping problem
* If insflg is not zero
* and the name is not found in the table, insert it.
*/
int
findtfn(char *fontname, BOOLEAN insflg) {
struct troffont *tp;
int i, j;
if (debug) {
if (fontname==0) fprint(2, "findtfn(0x%x,%d)\n", fontname, insflg);
else fprint(2, "findtfn(%s,%d)\n", fontname, insflg);
}
for (i=0; i<troffontcnt; i++) {
if (troffontab[i].trfontid==0) {
error(WARNING, "findtfn:troffontab[%d].trfontid=0x%x, botch!\n",
i, troffontab[i].trfontid);
continue;
}
if (strcmp(troffontab[i].trfontid, fontname) == 0)
return(i);
}
if (insflg) {
tp = (struct troffont *)galloc(troffontab, sizeof(struct troffont)*(troffontcnt+1), "findtfn: struct troffont:");
if (tp == 0)
return(-2);
troffontab = tp;
tp = &(troffontab[troffontcnt]);
i = strlen(fontname);
tp->trfontid = galloc(0, i+1, "findtfn: trfontid:");
/* initialize new troff font entry with name and numeric fields to 0 */
strncpy(tp->trfontid, fontname, i);
tp->trfontid[i] = '\0';
tp->special = FALSE;
tp->spacewidth = 0;
tp->psfmapsize = 0;
tp->psfmap = 0;
for (i=0; i<NUMOFONTS; i++)
for (j=0; j<FONTSIZE; j++)
tp->charent[i][j] = 0;
troffontcnt++;
if (!readtroffmetric(fontname, troffontcnt-1))
return(-3);
if (!readpsfontdesc(fontname, troffontcnt-1))
return(-3);
return(troffontcnt-1);
}
return(-1);
}
void
finish(void) {
int i;
Bprint(Bstdout, "%s", TRAILER);
Bprint(Bstdout, "done\n");
Bprint(Bstdout, "%s", DOCUMENTFONTS);
for (i=0; i<pfnamcnt; i++)
if (pfnafontmtab[i].used)
Bprint(Bstdout, " %s", pfnafontmtab[i].str);
Bprint(Bstdout, "\n");
Bprint(Bstdout, "%s %d\n", PAGES, pages_printed);
}
/* Set slant to n degrees. Disable slanting if n is 0. */
void
t_slant(int n) {
fontslant = n;
curpostfontid = -1;
}
/* Set character height to n points. Disabled if n is 0 or the current size. */
void
t_charht(int n) {
fontheight = (n == fontsize) ? 0 : n;
curpostfontid = -1;
}

View file

@ -0,0 +1,100 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "../common/common.h"
#include "tr2post.h"
void
conv(Biobuf *Bp) {
long c, n;
int r;
char special[10];
int save;
inputlineno = 1;
if (debug) Bprint(Bstderr, "conv(Biobuf *Bp=0x%x)\n", Bp);
while ((r = Bgetrune(Bp)) >= 0) {
/* Bprint(Bstderr, "r=<%c>,0x%x\n", r, r); */
/* Bflush(Bstderr); */
switch (r) {
case 's': /* set point size */
Bgetfield(Bp, 'd', &fontsize, 0);
break;
case 'f': /* set font to postion */
Bgetfield(Bp, 'd', &fontpos, 0);
save = inputlineno;
settrfont();
inputlineno = save; /* ugh */
break;
case 'c': /* print rune */
r = Bgetrune(Bp);
runeout(r);
break;
case 'C': /* print special character */
Bgetfield(Bp, 's', special, 10);
specialout(special);
break;
case 'N': /* print character with numeric value from current font */
Bgetfield(Bp, 'd', &n, 0);
break;
case 'H': /* go to absolute horizontal position */
Bgetfield(Bp, 'd', &n, 0);
hgoto(n);
break;
case 'V': /* go to absolute vertical position */
Bgetfield(Bp, 'd', &n, 0);
vgoto(n);
break;
case 'h': /* go to relative horizontal position */
Bgetfield(Bp, 'd', &n, 0);
hmot(n);
break;
case 'v': /* go to relative vertical position */
Bgetfield(Bp, 'd', &n, 0);
vmot(n);
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/* move right nn units, then print character c */
n = (r - '0') * 10;
r = Bgetrune(Bp);
if (r < 0)
error(FATAL, "EOF or error reading input\n");
else if (r < '0' || r > '9')
error(FATAL, "integer expected\n");
n += r - '0';
r = Bgetrune(Bp);
hmot(n);
runeout(r);
break;
case 'p': /* begin page */
Bgetfield(Bp, 'd', &n, 0);
endpage();
startpage();
break;
case 'n': /* end of line (information only 'b a' follows) */
Brdline(Bp, '\n'); /* toss rest of line */
inputlineno++;
break;
case 'w': /* paddable word space (information only) */
break;
case 'D': /* graphics function */
draw(Bp);
break;
case 'x': /* device control functions */
devcntl(Bp);
break;
case '#': /* comment */
Brdline(Bp, '\n'); /* toss rest of line */
case '\n':
inputlineno++;
break;
default:
error(WARNING, "unknown troff function <%c>\n", r);
break;
}
}
endpage();
if (debug) Bprint(Bstderr, "r=0x%x\n", r);
if (debug) Bprint(Bstderr, "leaving conv\n");
}

View file

@ -0,0 +1,178 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <stdio.h>
#include "../common/common.h"
#include "tr2post.h"
char devname[20] = { 'u', 't', 'f', '\0' };
int resolution;
int minx, miny;
struct sjt {
char *str;
void (*func)(void *);
};
/* I won't need this if getfields can replace sscanf
extern void picture(Biobuf *);
extern void notavail(char *);
void
PSInclude(Biobuf *inp) {
char buf[256];
Bgetfield(inp, 's', buf, 256);
if(pageon()) {
endstring();
Bprint(Bstdout, "%s\n", buf);
}
}
struct sjt specialjumptable[] = {
{"PI", picture},
{"PictureInclusion", picture},
{"InlinePicture", NULL},
{"BeginPath", NULL},
{"DrawPath", NULL},
{"BeginObject", NULL},
{"EndObject", NULL},
{"NewBaseline", NULL},
{"DrawText", NULL},
{"SetText", NULL},
{"SetColor", NULL},
{"INFO", NULL},
{"PS", PSInclude},
{"Postscript", PSInclude},
{"ExportPS", notavail("ExportPS")},
{NULL, NULL}
};
*/
void
devcntl(Biobuf *inp) {
char cmd[50], buf[256], str[MAXTOKENSIZE], *line;
int c, n, linelen;
/*
*
* Interpret device control commands, ignoring any we don't recognize. The
* "x X ..." commands are a device dependent collection generated by troff's
* \X'...' request.
*
*/
Bgetfield(inp, 's', cmd, 50);
if (debug) Bprint(Bstderr, "devcntl(cmd=%s)\n", cmd);
switch (cmd[0]) {
case 'f': /* mount font in a position */
Bgetfield(inp, 'd', &n, 0);
Bgetfield(inp, 's', str, 100);
mountfont(n, str);
break;
case 'i': /* initialize */
initialize();
break;
case 'p': /* pause */
break;
case 'r': /* resolution assumed when prepared */
Bgetfield(inp, 'd', &resolution, 0);
Bgetfield(inp, 'd', &minx, 0);
Bgetfield(inp, 'd', &miny, 0);
break;
case 's': /* stop */
case 't': /* trailer */
/* flushtext(); */
break;
case 'H': /* char height */
Bgetfield(inp, 'd', &n, 0);
t_charht(n);
break;
case 'S': /* slant */
Bgetfield(inp, 'd', &n, 0);
t_slant(n);
break;
case 'T': /* device name */
Bgetfield(inp, 's', &devname, 16);
if (debug) Bprint(Bstderr, "devname=%s\n", devname);
break;
case 'E': /* input encoding - not in troff yet */
Bgetfield(inp, 's', &str, 100);
/* if ( strcmp(str, "UTF") == 0 )
reading = UTFENCODING;
else reading = ONEBYTE;
*/
break;
case 'X': /* copy through - from troff */
if (Bgetfield(inp, 's', str, MAXTOKENSIZE-1) <= 0)
error(FATAL, "incomplete devcntl line\n");
if ((line = Brdline(inp, '\n')) == 0)
error(FATAL, "incomplete devcntl line\n");
strncpy(buf, line, Blinelen(inp)-1);
buf[Blinelen(inp)-1] = '\0';
Bungetc(inp);
if (strncmp(str, "PI", sizeof("PI")-1) == 0 || strncmp(str, "PictureInclusion", sizeof("PictureInclusion")-1) == 0) {
picture(inp, str);
} else if (strncmp(str, "InlinePicture", sizeof("InlinePicture")-1) == 0) {
error(FATAL, "InlinePicture not implemented yet.\n");
/* inlinepic(inp, buf); */
} else if (strncmp(str, "BeginPath", sizeof("BeginPath")-1) == 0) {
beginpath(buf, FALSE);
} else if (strncmp(str, "DrawPath", sizeof("DrawPath")-1) == 0) {
drawpath(buf, FALSE);
} else if (strncmp(str, "BeginObject", sizeof("BeginObject")-1) == 0) {
beginpath(buf, TRUE);
} else if (strncmp(str, "EndObject", sizeof("EndObject")-1) == 0) {
drawpath(buf, TRUE);
} else if (strncmp(str, "NewBaseline", sizeof("NewBaseline")-1) == 0) {
error(FATAL, "NewBaseline not implemented yet.\n");
/* newbaseline(buf); */
} else if (strncmp(str, "DrawText", sizeof("DrawText")-1) == 0) {
error(FATAL, "DrawText not implemented yet.\n");
/* drawtext(buf); */
} else if (strncmp(str, "SetText", sizeof("SetText")-1) == 0) {
error(FATAL, "SetText not implemented yet.\n");
/* settext(buf); */
} else if (strncmp(str, "SetColor", sizeof("SetColor")-1) == 0) {
error(FATAL, "SetColor not implemented yet.\n");
/* newcolor(buf); */
/* setcolor(); */
} else if (strncmp(str, "INFO", sizeof("INFO")-1) == 0) {
error(FATAL, "INFO not implemented yet.\n");
/* flushtext(); */
/* Bprint(outp, "%%INFO%s", buf); */
} else if (strncmp(str, "PS", sizeof("PS")-1) == 0 || strncmp(str, "PostScript", sizeof("PostScript")-1) == 0) {
if(pageon()) {
endstring();
Bprint(Bstdout, "%s\n", buf);
}
} else if (strncmp(str, "ExportPS", sizeof("ExportPS")-1) == 0) { /* dangerous!! */
error(FATAL, "ExportPS not implemented yet.\n");
/* if (Bfildes(outp) == 1) { */
/* restore(); */
/* Bprint(outp, "%s", buf); */
/* save(); */
/* } */
}
/* else
error(WARNING, "Unknown string <%s %s> after x X\n", str, buf);
*/
break;
}
while ((c = Bgetc(inp)) != '\n' && c != Beof);
inputlineno++;
}

View file

@ -0,0 +1,342 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include "../common/common.h"
#include "tr2post.h"
BOOLEAN drawflag = FALSE;
BOOLEAN inpath = FALSE; /* TRUE if we're putting pieces together */
void
cover(double x, double y) {
}
void
drawspline(Biobuf *Bp, int flag) { /* flag!=1 connect end points */
int x[100], y[100];
int i, N;
/*
*
* Spline drawing routine for Postscript printers. The complicated stuff is
* handled by procedure Ds, which should be defined in the library file. I've
* seen wrong implementations of troff's spline drawing, so fo the record I'll
* write down the parametric equations and the necessary conversions to Bezier
* cubic splines (as used in Postscript).
*
*
* Parametric equation (x coordinate only):
*
*
* (x2 - 2 * x1 + x0) 2 (x0 + x1)
* x = ------------------ * t + (x1 - x0) * t + ---------
* 2 2
*
*
* The coefficients in the Bezier cubic are,
*
*
* A = 0
* B = (x2 - 2 * x1 + x0) / 2
* C = x1 - x0
*
*
* while the current point is,
*
* current-point = (x0 + x1) / 2
*
* Using the relationships given in the Postscript manual (page 121) it's easy to
* see that the control points are given by,
*
*
* x0' = (x0 + 5 * x1) / 6
* x1' = (x2 + 5 * x1) / 6
* x2' = (x1 + x2) / 2
*
*
* where the primed variables are the ones used by curveto. The calculations
* shown above are done in procedure Ds using the coordinates set up in both
* the x[] and y[] arrays.
*
* A simple test of whether your spline drawing is correct would be to use cip
* to draw a spline and some tangent lines at appropriate points and then print
* the file.
*
*/
for (N=2; N<sizeof(x)/sizeof(x[0]); N++)
if (Bgetfield(Bp, 'd', &x[N], 0)<=0 || Bgetfield(Bp, 'd', &y[N], 0)<=0)
break;
x[0] = x[1] = hpos;
y[0] = y[1] = vpos;
for (i = 1; i < N; i++) {
x[i+1] += x[i];
y[i+1] += y[i];
}
x[N] = x[N-1];
y[N] = y[N-1];
for (i = ((flag!=1)?0:1); i < ((flag!=1)?N-1:N-2); i++) {
endstring();
if (pageon())
Bprint(Bstdout, "%d %d %d %d %d %d Ds\n", x[i], y[i], x[i+1], y[i+1], x[i+2], y[i+2]);
/* if (dobbox == TRUE) { /* could be better */
/* cover((double)(x[i] + x[i+1])/2,(double)-(y[i] + y[i+1])/2);
/* cover((double)x[i+1], (double)-y[i+1]);
/* cover((double)(x[i+1] + x[i+2])/2, (double)-(y[i+1] + y[i+2])/2);
/* }
*/
}
hpos = x[N]; /* where troff expects to be */
vpos = y[N];
}
void
draw(Biobuf *Bp) {
int r, x1, y1, x2, y2, i;
int d1, d2;
drawflag = TRUE;
r = Bgetrune(Bp);
switch(r) {
case 'l':
if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'r', &i, 0)<=0)
error(FATAL, "draw line function, destination coordinates not found.\n");
endstring();
if (pageon())
Bprint(Bstdout, "%d %d %d %d Dl\n", hpos, vpos, hpos+x1, vpos+y1);
hpos += x1;
vpos += y1;
break;
case 'c':
if (Bgetfield(Bp, 'd', &d1, 0)<=0)
error(FATAL, "draw circle function, diameter coordinates not found.\n");
endstring();
if (pageon())
Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d1);
hpos += d1;
break;
case 'e':
if (Bgetfield(Bp, 'd', &d1, 0)<=0 || Bgetfield(Bp, 'd', &d2, 0)<=0)
error(FATAL, "draw ellipse function, diameter coordinates not found.\n");
endstring();
if (pageon())
Bprint(Bstdout, "%d %d %d %d De\n", hpos, vpos, d1, d2);
hpos += d1;
break;
case 'a':
if (Bgetfield(Bp, 'd', &x1, 0)<=0 || Bgetfield(Bp, 'd', &y1, 0)<=0 || Bgetfield(Bp, 'd', &x2, 0)<=0 || Bgetfield(Bp, 'd', &y2, 0)<=0)
error(FATAL, "draw arc function, coordinates not found.\n");
endstring();
if (pageon())
Bprint(Bstdout, "%d %d %d %d %d %d Da\n", hpos, vpos, x1, y1, x2, y2);
hpos += x1 + x2;
vpos += y1 + y2;
break;
case 'q':
drawspline(Bp, 1);
break;
case '~':
drawspline(Bp, 2);
break;
default:
error(FATAL, "unknown draw function <%c>\n", r);
break;
}
}
void
beginpath(char *buf, int copy) {
/*
* Called from devcntrl() whenever an "x X BeginPath" command is read. It's used
* to mark the start of a sequence of drawing commands that should be grouped
* together and treated as a single path. By default the drawing procedures in
* *drawfile treat each drawing command as a separate object, and usually start
* with a newpath (just as a precaution) and end with a stroke. The newpath and
* stroke isolate individual drawing commands and make it impossible to deal with
* composite objects. "x X BeginPath" can be used to mark the start of drawing
* commands that should be grouped together and treated as a single object, and
* part of what's done here ensures that the PostScript drawing commands defined
* in *drawfile skip the newpath and stroke, until after the next "x X DrawPath"
* command. At that point the path that's been built up can be manipulated in
* various ways (eg. filled and/or stroked with a different line width).
*
* Color selection is one of the options that's available in parsebuf(),
* so if we get here we add *colorfile to the output file before doing
* anything important.
*
*/
if (inpath == FALSE) {
endstring();
/* getdraw(); */
/* getcolor(); */
Bprint(Bstdout, "gsave\n");
Bprint(Bstdout, "newpath\n");
Bprint(Bstdout, "%d %d m\n", hpos, vpos);
Bprint(Bstdout, "/inpath true def\n");
if ( copy == TRUE )
Bprint(Bstdout, "%s\n", buf);
inpath = TRUE;
}
}
static void parsebuf(char*);
void
drawpath(char *buf, int copy) {
/*
*
* Called from devcntrl() whenever an "x X DrawPath" command is read. It marks the
* end of the path started by the last "x X BeginPath" command and uses whatever
* has been passed along in *buf to manipulate the path (eg. fill and/or stroke
* the path). Once that's been done the drawing procedures are restored to their
* default behavior in which each drawing command is treated as an isolated path.
* The new version (called after "x X DrawPath") has copy set to FALSE, and calls
* parsebuf() to figure out what goes in the output file. It's a feeble attempt
* to free users and preprocessors (like pic) from having to know PostScript. The
* comments in parsebuf() describe what's handled.
*
* In the early version a path was started with "x X BeginObject" and ended with
* "x X EndObject". In both cases *buf was just copied to the output file, and
* was expected to be legitimate PostScript that manipulated the current path.
* The old escape sequence will be supported for a while (for Ravi), and always
* call this routine with copy set to TRUE.
*
*
*/
if ( inpath == TRUE ) {
if ( copy == TRUE )
Bprint(Bstdout, "%s\n", buf);
else
parsebuf(buf);
Bprint(Bstdout, "grestore\n");
Bprint(Bstdout, "/inpath false def\n");
/* reset(); */
inpath = FALSE;
}
}
/*****************************************************************************/
static void
parsebuf(char *buf)
{
char *p; /* usually the next token */
char *q;
int gsavelevel = 0; /* non-zero if we've done a gsave */
/*
*
* Simple minded attempt at parsing the string that followed an "x X DrawPath"
* command. Everything not recognized here is simply ignored - there's absolutely
* no error checking and what was originally in buf is clobbered by strtok().
* A typical *buf might look like,
*
* gray .9 fill stroke
*
* to fill the current path with a gray level of .9 and follow that by stroking the
* outline of the path. Since unrecognized tokens are ignored the last example
* could also be written as,
*
* with gray .9 fill then stroke
*
* The "with" and "then" strings aren't recognized tokens and are simply discarded.
* The "stroke", "fill", and "wfill" force out appropriate PostScript code and are
* followed by a grestore. In otherwords changes to the grahics state (eg. a gray
* level or color) are reset to default values immediately after the stroke, fill,
* or wfill tokens. For now "fill" gets invokes PostScript's eofill operator and
* "wfill" calls fill (ie. the operator that uses the non-zero winding rule).
*
* The tokens that cause temporary changes to the graphics state are "gray" (for
* setting the gray level), "color" (for selecting a known color from the colordict
* dictionary defined in *colorfile), and "line" (for setting the line width). All
* three tokens can be extended since strncmp() makes the comparison. For example
* the strings "line" and "linewidth" accomplish the same thing. Colors are named
* (eg. "red"), but must be appropriately defined in *colorfile. For now all three
* tokens must be followed immediately by their single argument. The gray level
* (ie. the argument that follows "gray") should be a number between 0 and 1, with
* 0 for black and 1 for white.
*
* To pass straight PostScript through enclose the appropriate commands in double
* quotes. Straight PostScript is only bracketed by the outermost gsave/grestore
* pair (ie. the one from the initial "x X BeginPath") although that's probably
* a mistake. Suspect I may have to change the double quote delimiters.
*
*/
for( ; p != nil ; p = q ) {
if( q = strchr(p, ' ') ) {
*q++ = '\0';
}
if ( gsavelevel == 0 ) {
Bprint(Bstdout, "gsave\n");
gsavelevel++;
}
if ( strcmp(p, "stroke") == 0 ) {
Bprint(Bstdout, "closepath stroke\ngrestore\n");
gsavelevel--;
} else if ( strcmp(p, "openstroke") == 0 ) {
Bprint(Bstdout, "stroke\ngrestore\n");
gsavelevel--;
} else if ( strcmp(p, "fill") == 0 ) {
Bprint(Bstdout, "eofill\ngrestore\n");
gsavelevel--;
} else if ( strcmp(p, "wfill") == 0 ) {
Bprint(Bstdout, "fill\ngrestore\n");
gsavelevel--;
} else if ( strcmp(p, "sfill") == 0 ) {
Bprint(Bstdout, "eofill\ngrestore\ngsave\nstroke\ngrestore\n");
gsavelevel--;
} else if ( strncmp(p, "gray", strlen("gray")) == 0 ) {
if( q ) {
p = q;
if ( q = strchr(p, ' ') )
*q++ = '\0';
Bprint(Bstdout, "%s setgray\n", p);
}
} else if ( strncmp(p, "color", strlen("color")) == 0 ) {
if( q ) {
p = q;
if ( q = strchr(p, ' ') )
*q++ = '\0';
Bprint(Bstdout, "/%s setcolor\n", p);
}
} else if ( strncmp(p, "line", strlen("line")) == 0 ) {
if( q ) {
p = q;
if ( q = strchr(p, ' ') )
*q++ = '\0';
Bprint(Bstdout, "%s resolution mul 2 div setlinewidth\n", p);
}
} else if ( strncmp(p, "reverse", strlen("reverse")) == 0 )
Bprint(Bstdout, "reversepath\n");
else if ( *p == '"' ) {
for ( ; gsavelevel > 0; gsavelevel-- )
Bprint(Bstdout, "grestore\n");
if ( q != nil )
*--q = ' ';
if ( (q = strchr(p, '"')) != nil ) {
*q++ = '\0';
Bprint(Bstdout, "%s\n", p);
}
}
}
for ( ; gsavelevel > 0; gsavelevel-- )
Bprint(Bstdout, "grestore\n");
}

View file

@ -0,0 +1,36 @@
<$PLAN9/src/mkhdr
<../config
COMMONDIR=../common
SHORTLIB=bio 9
TARG=tr2post
OFILES=tr2post.$O\
chartab.$O\
Bgetfield.$O\
conv.$O\
utils.$O\
devcntl.$O\
draw.$O\
readDESC.$O\
ps_include.$O\
pictures.$O\
common.$O\
HFILES=tr2post.h\
ps_include.h\
$COMMONDIR/common.h\
$COMMONDIR/comments.h\
$COMMONDIR/path.h\
$COMMONDIR/ext.h\
BIN=$POSTBIN
<$PLAN9/src/mkone
CFLAGS=$CFLAGS -c -D'PROGRAMVERSION="0.1"' -D'DOROUND=1' -I$COMMONDIR
%.$O: $COMMONDIR/%.c
$CC $CFLAGS $COMMONDIR/$stem.c

View file

@ -0,0 +1,295 @@
/*
*
* PostScript picture inclusion routines. Support for managing in-line pictures
* has been added, and works in combination with the simple picpack pre-processor
* that's supplied with this package. An in-line picture begins with a special
* device control command that looks like,
*
* x X InlinPicture name size
*
* where name is the pathname of the original picture file and size is the number
* of bytes in the picture, which begins immediately on the next line. When dpost
* encounters the InlinePicture device control command inlinepic() is called and
* that routine appends the string name and the integer size to a temporary file
* (fp_pic) and then adds the next size bytes read from the current input file to
* file fp_pic. All in-line pictures are saved in fp_pic and located later using
* the name string and picture file size that separate pictures saved in fp_pic.
*
* When a picture request (ie. an "x X PI" command) is encountered picopen() is
* called and it first looks for the picture file in fp_pic. If it's found there
* the entire picture (ie. size bytes) is copied from fp_pic to a new temp file
* and that temp file is used as the picture file. If there's nothing in fp_pic
* or if the lookup failed the original route is taken.
*
* Support for in-line pictures is an attempt to address requirements, expressed
* by several organizations, of being able to store a document as a single file
* (usually troff input) that can then be sent through dpost and ultimately to
* a PostScript printer. The mechanism may help some users, but the are obvious
* disadvantages to this approach, and the original mechanism is the recommended
* approach! Perhaps the most important problem is that troff output, with in-line
* pictures included, doesn't fit the device independent language accepted by
* important post-processors (like proff) and that means you won't be able to
* reliably preview a packed file on your 5620 (or whatever).
*
*/
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <stdio.h>
#include "ext.h"
#include "common.h"
#include "tr2post.h"
/* PostScript file structuring comments */
#include "comments.h"
/* general purpose definitions */
/* #include "gen.h" */
/* just for TEMPDIR definition */
#include "path.h"
/* external variable declarations */
/* #include "ext.h" */
Biobuf *bfp_pic = NULL;
Biobuf *Bfp_pic;
Biobuf *picopen(char *);
#define MAXGETFIELDS 16
char *fields[MAXGETFIELDS];
int nfields;
extern int devres, hpos, vpos;
extern int picflag;
/*****************************************************************************/
void
picture(Biobuf *inp, char *buf) {
int poffset; /* page offset */
int indent; /* indent */
int length; /* line length */
int totrap; /* distance to next trap */
char name[100]; /* picture file and page string */
char hwo[40], *p; /* height, width and offset strings */
char flags[20]; /* miscellaneous stuff */
int page = 1; /* page number pulled from name[] */
double frame[4]; /* height, width, y, and x offsets from hwo[] */
char units; /* scale indicator for frame dimensions */
int whiteout = 0; /* white out the box? */
int outline = 0; /* draw a box around the picture? */
int scaleboth = 0; /* scale both dimensions? */
double adjx = 0.5; /* left-right adjustment */
double adjy = 0.5; /* top-bottom adjustment */
double rot = 0; /* rotation in clockwise degrees */
Biobuf *fp_in; /* for *name */
int i; /* loop index */
/*
*
* Called from devcntrl() after an 'x X PI' command is found. The syntax of that
* command is:
*
* x X PI:args
*
* with args separated by colons and given by:
*
* poffset
* indent
* length
* totrap
* file[(page)]
* height[,width[,yoffset[,xoffset]]]
* [flags]
*
* poffset, indent, length, and totrap are given in machine units. height, width,
* and offset refer to the picture frame in inches, unless they're followed by
* the u scale indicator. flags is a string that provides a little bit of control
* over the placement of the picture in the frame. Rotation of the picture, in
* clockwise degrees, is set by the a flag. If it's not followed by an angle
* the current rotation angle is incremented by 90 degrees, otherwise the angle
* is set by the number that immediately follows the a.
*
*/
if (!picflag) /* skip it */
return;
endstring();
flags[0] = '\0'; /* just to be safe */
nfields = getfields(buf, fields, MAXGETFIELDS, 0, ":\n");
if (nfields < 6) {
error(WARNING, "too few arguments to specify picture");
return;
}
poffset = atoi(fields[1]);
indent = atoi(fields[2]);
length = atoi(fields[3]);
totrap = atoi(fields[4]);
strncpy(name, fields[5], sizeof(name));
strncpy(hwo, fields[6], sizeof(hwo));
if (nfields >= 6)
strncpy(flags, fields[7], sizeof(flags));
nfields = getfields(buf, fields, MAXGETFIELDS, 0, "()");
if (nfields == 2) {
strncpy(name, fields[0], sizeof(name));
page = atoi(fields[1]);
}
if ((fp_in = picopen(name)) == NULL) {
error(WARNING, "can't open picture file %s\n", name);
return;
}
frame[0] = frame[1] = -1; /* default frame height, width */
frame[2] = frame[3] = 0; /* and y and x offsets */
for (i = 0, p = hwo-1; i < 4 && p != NULL; i++, p = strchr(p, ','))
if (sscanf(++p, "%lf%c", &frame[i], &units) == 2)
if (units == 'i' || units == ',' || units == '\0')
frame[i] *= devres;
if (frame[0] <= 0) /* check what we got for height */
frame[0] = totrap;
if (frame[1] <= 0) /* and width - check too big?? */
frame[1] = length - indent;
frame[3] += poffset + indent; /* real x offset */
for (i = 0; flags[i]; i++)
switch (flags[i]) {
case 'c': adjx = adjy = 0.5; break; /* move to the center */
case 'l': adjx = 0; break; /* left */
case 'r': adjx = 1; break; /* right */
case 't': adjy = 1; break; /* top */
case 'b': adjy = 0; break; /* or bottom justify */
case 'o': outline = 1; break; /* outline the picture */
case 'w': whiteout = 1; break; /* white out the box */
case 's': scaleboth = 1; break; /* scale both dimensions */
case 'a': if ( sscanf(&flags[i+1], "%lf", &rot) != 1 )
rot += 90;
}
/* restore(); */
endstring();
Bprint(Bstdout, "cleartomark\n");
Bprint(Bstdout, "saveobj restore\n");
ps_include(fp_in, Bstdout, page, whiteout, outline, scaleboth,
frame[3]+frame[1]/2, -vpos-frame[2]-frame[0]/2, frame[1], frame[0], adjx, adjy, -rot);
/* save(); */
Bprint(Bstdout, "/saveobj save def\n");
Bprint(Bstdout, "mark\n");
Bterm(fp_in);
}
/*
*
* Responsible for finding and opening the next picture file. If we've accumulated
* any in-line pictures fp_pic won't be NULL and we'll look there first. If *path
* is found in *fp_pic we create another temp file, open it for update, unlink it,
* copy in the picture, seek back to the start of the new temp file, and return
* the file pointer to the caller. If fp_pic is NULL or the lookup fails we just
* open file *path and return the resulting file pointer to the caller.
*
*/
Biobuf *
picopen(char *path) {
/* char name[100]; /* pathnames */
/* long pos; /* current position */
/* long total; /* and sizes - from *fp_pic */
Biobuf *bfp;
Biobuf *Bfp; /* and pointer for the new temp file */
if ((bfp = Bopen(path, OREAD)) == 0)
error(FATAL, "can't open %s\n", path);
Bfp = bfp;
return(Bfp);
#ifdef UNDEF
if (Bfp_pic != NULL) {
Bseek(Bfp_pic, 0L, 0);
while (Bgetfield(Bfp_pic, 's', name, 99)>0
&& Bgetfield(Bfp_pic, 'd', &total, 0)>0) {
pos = Bseek(Bfp_pic, 0L, 1);
if (strcmp(path, name) == 0) {
if (tmpnam(pictmpname) == NULL)
error(FATAL, "can't generate temp file name");
if ( (bfp = Bopen(pictmpname, ORDWR)) == NULL )
error(FATAL, "can't open %s", pictmpname);
Bfp = bfp;
piccopy(Bfp_pic, Bfp, total);
Bseek(Bfp, 0L, 0);
return(Bfp);
}
Bseek(Bfp_pic, total+pos, 0);
}
}
if ((bfp = Bopen(path, OREAD)) == 0)
Bfp = 0;
else
Bfp = bfp;
return(Bfp);
#endif
}
/*
*
* Adds an in-line picture file to the end of temporary file *Bfp_pic. All pictures
* grabbed from the input file are saved in the same temp file. Each is preceeded
* by a one line header that includes the original picture file pathname and the
* size of the picture in bytes. The in-line picture file is opened for update,
* left open, and unlinked so it disappears when we do.
*
*/
/* *fp; /* current input file */
/* *buf; /* whatever followed "x X InlinePicture" */
#ifdef UNDEF
void
inlinepic(Biobuf *Bfp, char *buf) {
char name[100]; /* picture file pathname */
long total; /* and size - both from *buf */
if (Bfp_pic == NULL ) {
tmpnam(pictmpname);
if ((bfp_pic = Bopen(pictmpname, ORDWR)) == 0)
error(FATAL, "can't open in-line picture file %s", ipictmpname);
unlink(pictmpname);
}
if ( sscanf(buf, "%s %ld", name, &total) != 2 )
error(FATAL, "in-line picture error");
fseek(Bfp_pic, 0L, 2);
fprintf(Bfp_pic, "%s %ld\n", name, total);
getc(fp);
fflush(fp_pic);
piccopy(fp, fp_pic, total);
ungetc('\n', fp);
}
#endif
/*
*
* Copies total bytes from file fp_in to fp_out. Used to append picture files to
* *fp_pic and then copy them to yet another temporary file immediately before
* they're used (in picture()).
*
*/
/* *fp_in; input */
/* *fp_out; and output file pointers */
/* total; number of bytes to be copied */
void
piccopy(Biobuf *Bfp_in, Biobuf *Bfp_out, long total) {
long i;
for (i = 0; i < total; i++)
if (Bputc(Bfp_out, Bgetc(Bfp_in)) < 0)
error(FATAL, "error copying in-line picture file");
Bflush(Bfp_out);
}

View file

@ -0,0 +1,191 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <stdio.h>
#include "../common/common.h"
#include "ps_include.h"
extern int curpostfontid;
extern int curfontsize;
typedef struct {long start, end;} Section;
static char *buf;
static void
copy(Biobuf *fin, Biobuf *fout, Section *s) {
int cond;
if (s->end <= s->start)
return;
Bseek(fin, s->start, 0);
while (Bseek(fin, 0L, 1) < s->end && (buf=Brdline(fin, '\n')) != NULL){
/*
* We have to be careful here, because % can legitimately appear
* in Ascii85 encodings, and must not be elided.
* The goal here is to make any DSC comments impotent without
* actually changing the behavior of the Postscript.
* Since stripping ``comments'' breaks Ascii85, we can instead just
* indent comments a space, which turns DSC comments into non-DSC comments
* and has no effect on binary encodings, which are whitespace-blind.
*/
if(buf[0] == '%')
Bputc(fout, ' ');
Bwrite(fout, buf, Blinelen(fin));
}
}
/*
*
* Reads a PostScript file (*fin), and uses structuring comments to locate the
* prologue, trailer, global definitions, and the requested page. After the whole
* file is scanned, the special ps_include PostScript definitions are copied to
* *fout, followed by the prologue, global definitions, the requested page, and
* the trailer. Before returning the initial environment (saved in PS_head) is
* restored.
*
* By default we assume the picture is 8.5 by 11 inches, but the BoundingBox
* comment, if found, takes precedence.
*
*/
/* *fin, *fout; /* input and output files */
/* page_no; /* physical page number from *fin */
/* whiteout; /* erase picture area */
/* outline; /* draw a box around it and */
/* scaleboth; /* scale both dimensions - if not zero */
/* cx, cy; /* center of the picture and */
/* sx, sy; /* its size - in current coordinates */
/* ax, ay; /* left-right, up-down adjustment */
/* rot; /* rotation - in clockwise degrees */
void
ps_include(Biobuf *fin, Biobuf *fout, int page_no, int whiteout,
int outline, int scaleboth, double cx, double cy, double sx, double sy,
double ax, double ay, double rot) {
char **strp;
int foundpage = 0; /* found the page when non zero */
int foundpbox = 0; /* found the page bounding box */
int nglobal = 0; /* number of global defs so far */
int maxglobal = 0; /* and the number we've got room for */
Section prolog, page, trailer; /* prologue, page, and trailer offsets */
Section *global; /* offsets for all global definitions */
double llx, lly; /* lower left and */
double urx, ury; /* upper right corners - default coords */
double w = whiteout != 0; /* mostly for the var() macro */
double o = outline != 0;
double s = scaleboth != 0;
int i; /* loop index */
#define has(word) (strncmp(buf, word, strlen(word)) == 0)
#define grab(n) ((Section *)(nglobal \
? realloc((char *)global, n*sizeof(Section)) \
: calloc(n, sizeof(Section))))
llx = lly = 0; /* default BoundingBox - 8.5x11 inches */
urx = 72 * 8.5;
ury = 72 * 11.0;
/* section boundaries and bounding box */
prolog.start = prolog.end = 0;
page.start = page.end = 0;
trailer.start = 0;
Bseek(fin, 0L, 0);
while ((buf=Brdline(fin, '\n')) != NULL) {
buf[Blinelen(fin)-1] = '\0';
if (!has("%%"))
continue;
else if (has("%%Page: ")) {
if (!foundpage)
page.start = Bseek(fin, 0L, 1);
sscanf(buf, "%*s %*s %d", &i);
if (i == page_no)
foundpage = 1;
else if (foundpage && page.end <= page.start)
page.end = Bseek(fin, 0L, 1);
} else if (has("%%EndPage: ")) {
sscanf(buf, "%*s %*s %d", &i);
if (i == page_no) {
foundpage = 1;
page.end = Bseek(fin, 0L, 1);
}
if (!foundpage)
page.start = Bseek(fin, 0L, 1);
} else if (has("%%PageBoundingBox: ")) {
if (i == page_no) {
foundpbox = 1;
sscanf(buf, "%*s %lf %lf %lf %lf",
&llx, &lly, &urx, &ury);
}
} else if (has("%%BoundingBox: ")) {
if (!foundpbox)
sscanf(buf,"%*s %lf %lf %lf %lf",
&llx, &lly, &urx, &ury);
} else if (has("%%EndProlog") || has("%%EndSetup") || has("%%EndDocumentSetup"))
prolog.end = page.start = Bseek(fin, 0L, 1);
else if (has("%%Trailer"))
trailer.start = Bseek(fin, 0L, 1);
else if (has("%%BeginGlobal")) {
if (page.end <= page.start) {
if (nglobal >= maxglobal) {
maxglobal += 20;
global = grab(maxglobal);
}
global[nglobal].start = Bseek(fin, 0L, 1);
}
} else if (has("%%EndGlobal"))
if (page.end <= page.start)
global[nglobal++].end = Bseek(fin, 0L, 1);
}
Bseek(fin, 0L, 2);
if (trailer.start == 0)
trailer.start = Bseek(fin, 0L, 1);
trailer.end = Bseek(fin, 0L, 1);
if (page.end <= page.start)
page.end = trailer.start;
/*
fprint(2, "prolog=(%d,%d)\n", prolog.start, prolog.end);
fprint(2, "page=(%d,%d)\n", page.start, page.end);
for(i = 0; i < nglobal; i++)
fprint(2, "global[%d]=(%d,%d)\n", i, global[i].start, global[i].end);
fprint(2, "trailer=(%d,%d)\n", trailer.start, trailer.end);
*/
/* all output here */
for (strp = PS_head; *strp != NULL; strp++)
Bwrite(fout, *strp, strlen(*strp));
Bprint(fout, "/llx %g def\n", llx);
Bprint(fout, "/lly %g def\n", lly);
Bprint(fout, "/urx %g def\n", urx);
Bprint(fout, "/ury %g def\n", ury);
Bprint(fout, "/w %g def\n", w);
Bprint(fout, "/o %g def\n", o);
Bprint(fout, "/s %g def\n", s);
Bprint(fout, "/cx %g def\n", cx);
Bprint(fout, "/cy %g def\n", cy);
Bprint(fout, "/sx %g def\n", sx);
Bprint(fout, "/sy %g def\n", sy);
Bprint(fout, "/ax %g def\n", ax);
Bprint(fout, "/ay %g def\n", ay);
Bprint(fout, "/rot %g def\n", rot);
for (strp = PS_setup; *strp != NULL; strp++)
Bwrite(fout, *strp, strlen(*strp));
copy(fin, fout, &prolog);
for(i = 0; i < nglobal; i++)
copy(fin, fout, &global[i]);
copy(fin, fout, &page);
copy(fin, fout, &trailer);
for (strp = PS_tail; *strp != NULL; strp++)
Bwrite(fout, *strp, strlen(*strp));
if(nglobal)
free(global);
/* force the program to reestablish its state */
curpostfontid = -1;
curfontsize = -1;
}

View file

@ -0,0 +1,66 @@
static char *PS_head[] = {
"%ps_include: begin\n",
"save\n",
"/ed {exch def} def\n",
"{} /showpage ed\n",
"{} /copypage ed\n",
"{} /erasepage ed\n",
"{} /letter ed\n",
"currentdict /findfont known systemdict /findfont known and {\n",
" /findfont systemdict /findfont get def\n",
"} if\n",
"36 dict dup /PS-include-dict-dw ed begin\n",
"/context ed\n",
"count array astore /o-stack ed\n",
"%ps_include: variables begin\n",
0
};
static char *PS_setup[] = {
"%ps_include: variables end\n",
"{llx lly urx ury} /bbox ed\n",
"{newpath 2 index exch 2 index exch dup 6 index exch\n",
" moveto 3 {lineto} repeat closepath} /boxpath ed\n",
"{dup mul exch dup mul add sqrt} /len ed\n",
"{2 copy gt {exch} if pop} /min ed\n",
"{2 copy lt {exch} if pop} /max ed\n",
"{transform round exch round exch A itransform} /nice ed\n",
"{6 array} /n ed\n",
"n defaultmatrix n currentmatrix n invertmatrix n concatmatrix /A ed\n",
"urx llx sub 0 A dtransform len /Sx ed\n",
"0 ury lly sub A dtransform len /Sy ed\n",
"llx urx add 2 div lly ury add 2 div A transform /Cy ed /Cx ed\n",
"rot dup sin abs /S ed cos abs /C ed\n",
"Sx S mul Sy C mul add /H ed\n",
"Sx C mul Sy S mul add /W ed\n",
"sy H div /Scaley ed\n",
"sx W div /Scalex ed\n",
"s 0 eq {Scalex Scaley min dup /Scalex ed /Scaley ed} if\n",
"sx Scalex W mul sub 0 max ax 0.5 sub mul cx add /cx ed\n",
"sy Scaley H mul sub 0 max ay 0.5 sub mul cy add /cy ed\n",
"urx llx sub 0 A dtransform exch atan rot exch sub /rot ed\n",
"n currentmatrix initgraphics setmatrix\n",
"cx cy translate\n",
"Scalex Scaley scale\n",
"rot rotate\n",
"Cx neg Cy neg translate\n",
"A concat\n",
"bbox boxpath clip newpath\n",
"w 0 ne {gsave bbox boxpath 1 setgray fill grestore} if\n",
"end\n",
"gsave\n",
"%ps_include: inclusion begin\n",
0
};
static char *PS_tail[] = {
"%ps_include: inclusion end\n",
"grestore\n",
"PS-include-dict-dw begin\n",
"o 0 ne {gsave A defaultmatrix /A ed llx lly nice urx ury nice\n",
" initgraphics 0.1 setlinewidth boxpath stroke grestore} if\n",
"clear o-stack aload pop\n",
"context end restore\n",
"%ps_include: end\n",
0
};

View file

@ -0,0 +1,139 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include "common.h"
#include "tr2post.h"
#include "comments.h"
#include "path.h"
char *printdesclang = 0;
char *encoding = 0;
int devres;
int unitwidth;
int nspechars = 0;
struct charent spechars[MAXSPECHARS];
#define NDESCTOKS 9
static char *desctoks[NDESCTOKS] = {
"PDL",
"Encoding",
"fonts",
"sizes",
"res",
"hor",
"vert",
"unitwidth",
"charset"
};
char *spechar[MAXSPECHARS];
int
hash(char *s, int l) {
unsigned i;
for (i=0; *s; s++)
i = i*10 + *s;
return(i % l);
}
BOOLEAN
readDESC(void) {
char token[MAXTOKENSIZE];
char *descnameformat = "%s/dev%s/DESC";
char *descfilename = 0;
Biobuf *bfd;
Biobuf *Bfd;
int i, state = -1;
int fontindex = 0;
if (debug) Bprint(Bstderr, "readDESC()\n");
descfilename = galloc(descfilename, strlen(descnameformat)+strlen(FONTDIR)
+strlen(devname)+1, "readdesc");
sprint(descfilename, descnameformat, FONTDIR, devname);
if ((bfd = Bopen(unsharp(descfilename), OREAD)) == 0) {
error(WARNING, "cannot open file %s\n", descfilename);
return(0);
}
Bfd = bfd;
while (Bgetfield(Bfd, 's', token, MAXTOKENSIZE) > 0) {
for (i=0; i<NDESCTOKS; i++) {
if (strcmp(desctoks[i], token) == 0) {
state = i;
break;
}
}
if (i<NDESCTOKS) continue;
switch (state) {
case 0:
printdesclang=galloc(printdesclang, strlen(token)+1, "readdesc:");
strcpy(printdesclang, token);
if (debug) Bprint(Bstderr, "PDL %s\n", token);
break;
case 1:
encoding=galloc(encoding, strlen(token)+1, "readdesc:");
strcpy(encoding, token);
if (debug) Bprint(Bstderr, "encoding %s\n", token);
break;
case 2:
if (fontmnt <=0) {
if (!isdigit(*token)) {
error(WARNING, "readdesc: expecting number of fonts in mount table.\n");
return(FALSE);
}
fontmnt = atoi(token) + 1;
fontmtab = galloc(fontmtab, fontmnt*sizeof(char *), "readdesc:");
for (i=0; i<fontmnt; i++)
fontmtab[i] = 0;
fontindex = 0;
} else {
mountfont(++fontindex, token);
findtfn(token, TRUE);
}
break;
case 3:
/* I don't really care about sizes */
break;
case 4:
/* device resolution in dots per inch */
if (!isdigit(*token)) {
error(WARNING, "readdesc: expecting device resolution.\n");
return(FALSE);
}
devres = atoi(token);
if (debug) Bprint(Bstderr, "res %d\n", devres);
break;
case 5:
/* I don't really care about horizontal motion resolution */
if (debug) Bprint(Bstderr, "ignoring horizontal resolution\n");
break;
case 6:
/* I don't really care about vertical motion resolution */
if (debug) Bprint(Bstderr, "ignoring vertical resolution\n");
break;
case 7:
/* unitwidth is the font size at which the character widths are 1:1 */
if (!isdigit(*token)) {
error(WARNING, "readdesc: expecting unitwidth.\n");
return(FALSE);
}
unitwidth = atoi(token);
if (debug) Bprint(Bstderr, "unitwidth %d\n", unitwidth);
break;
case 8:
/* I don't really care about this list of special characters */
if (debug) Bprint(Bstderr, "ignoring special character <%s>\n", token);
break;
default:
if (*token == '#')
Brdline(Bfd, '\n');
else
error(WARNING, "unknown token %s in DESC file.\n", token);
break;
}
}
Bterm(Bfd);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,218 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include <stdio.h>
#include "common.h"
#include "tr2post.h"
#include "comments.h"
#include "path.h"
int formsperpage = 1;
int picflag = 1;
double aspectratio = 1.0;
int copies = 1;
int landscape = 0;
double magnification = 1.0;
int linesperpage = 66;
int pointsize = 10;
double xoffset = .25;
double yoffset = .25;
char *passthrough = 0;
Biobuf binp, *bstdout, bstderr;
Biobuf *Bstdin, *Bstdout, *Bstderr;
int debug = 0;
char tmpfilename[MAXTOKENSIZE];
char copybuf[BUFSIZ];
struct charent **build_char_list = 0;
int build_char_cnt = 0;
void
prologues(void) {
int i;
char charlibname[MAXTOKENSIZE];
Bprint(Bstdout, "%s", CONFORMING);
Bprint(Bstdout, "%s %s\n", VERSION, PROGRAMVERSION);
Bprint(Bstdout, "%s %s\n", DOCUMENTFONTS, ATEND);
Bprint(Bstdout, "%s %s\n", PAGES, ATEND);
Bprint(Bstdout, "%s", ENDCOMMENTS);
if (cat(unsharp(DPOST))) {
Bprint(Bstderr, "can't read %s\n", DPOST);
exits("dpost prologue");
}
if (drawflag) {
if (cat(unsharp(DRAW))) {
Bprint(Bstderr, "can't read %s\n", DRAW);
exits("draw prologue");
}
}
if (DOROUND)
cat(unsharp(ROUNDPAGE));
Bprint(Bstdout, "%s", ENDPROLOG);
Bprint(Bstdout, "%s", BEGINSETUP);
Bprint(Bstdout, "mark\n");
if (formsperpage > 1) {
Bprint(Bstdout, "%s %d\n", FORMSPERPAGE, formsperpage);
Bprint(Bstdout, "/formsperpage %d def\n", formsperpage);
}
if (aspectratio != 1) Bprint(Bstdout, "/aspectratio %g def\n", aspectratio);
if (copies != 1) Bprint(Bstdout, "/#copies %d store\n", copies);
if (landscape) Bprint(Bstdout, "/landscape true def\n");
if (magnification != 1) Bprint(Bstdout, "/magnification %g def\n", magnification);
if (pointsize != 10) Bprint(Bstdout, "/pointsize %d def\n", pointsize);
if (xoffset != .25) Bprint(Bstdout, "/xoffset %g def\n", xoffset);
if (yoffset != .25) Bprint(Bstdout, "/yoffset %g def\n", yoffset);
cat(unsharp(ENCODINGDIR"/Latin1.enc"));
if (passthrough != 0) Bprint(Bstdout, "%s\n", passthrough);
Bprint(Bstdout, "setup\n");
if (formsperpage > 1) {
cat(unsharp(FORMFILE));
Bprint(Bstdout, "%d setupforms \n", formsperpage);
}
/* output Build character info from charlib if necessary. */
for (i=0; i<build_char_cnt; i++) {
sprint(charlibname, "%s/%s", CHARLIB, build_char_list[i]->name);
if (cat(unsharp(charlibname)))
Bprint(Bstderr, "cannot open %s\n", charlibname);
}
Bprint(Bstdout, "%s", ENDSETUP);
}
void
cleanup(void) {
remove(tmpfilename);
}
main(int argc, char *argv[]) {
Biobuf *binp;
Biobuf *Binp;
int i, tot, ifd;
char *t;
programname = argv[0];
if (Binit(&bstderr, 2, OWRITE) == Beof) {
exits("Binit");
}
Bstderr = &bstderr;
tmpnam(tmpfilename);
if ((bstdout=Bopen(tmpfilename, OWRITE)) == 0) {
Bprint(Bstderr, "cannot open temporary file %s\n", tmpfilename);
exits("Bopen");
}
atexit(cleanup);
Bstdout = bstdout;
ARGBEGIN{
case 'a': /* aspect ratio */
aspectratio = atof(ARGF());
break;
case 'c': /* copies */
copies = atoi(ARGF());
break;
case 'd':
debug = 1;
break;
case 'm': /* magnification */
magnification = atof(ARGF());
break;
case 'n': /* forms per page */
formsperpage = atoi(ARGF());
break;
case 'o': /* output page list */
pagelist(ARGF());
break;
case 'p': /* landscape or portrait mode */
if ( ARGF()[0] == 'l' )
landscape = 1;
else
landscape = 0;
break;
case 'x': /* shift things horizontally */
xoffset = atof(ARGF());
break;
case 'y': /* and vertically on the page */
yoffset = atof(ARGF());
break;
case 'P': /* PostScript pass through */
t = ARGF();
i = strlen(t) + 1;
passthrough = malloc(i);
if (passthrough == 0) {
Bprint(Bstderr, "cannot allocate memory for argument string\n");
exits("malloc");
}
strncpy(passthrough, t, i);
break;
default: /* don't know what to do for ch */
Bprint(Bstderr, "unknown option %C\n", ARGC());
break;
}ARGEND;
readDESC();
if (argc == 0) {
if ((binp = (Biobuf *)malloc(sizeof(Biobuf))) < (Biobuf *)0) {
Bprint(Bstderr, "malloc failed.\n");
exits("malloc");
}
if (Binit(binp, 0, OREAD) == Beof) {
Bprint(Bstderr, "Binit of <stdin> failed.\n");
exits("Binit");
}
Binp = binp;
if (debug) Bprint(Bstderr, "using standard input\n");
conv(Binp);
Bterm(Binp);
}
for (i=0; i<argc; i++) {
if ((binp=Bopen(argv[i], OREAD)) == 0) {
Bprint(Bstderr, "cannot open file %s\n", argv[i]);
continue;
}
Binp = binp;
inputfilename = argv[i];
conv(Binp);
Bterm(Binp);
}
Bterm(Bstdout);
if ((ifd=open(tmpfilename, OREAD)) < 0) {
Bprint(Bstderr, "open of %s failed.\n", tmpfilename);
exits("open");
}
bstdout = galloc(0, sizeof(Biobuf), "bstdout");
if (Binit(bstdout, 1, OWRITE) == Beof) {
Bprint(Bstderr, "Binit of <stdout> failed.\n");
exits("Binit");
}
Bstdout = bstdout;
prologues();
Bflush(Bstdout);
tot = 0; i = 0;
while ((i=read(ifd, copybuf, BUFSIZ)) > 0) {
if (write(1, copybuf, i) != i) {
Bprint(Bstderr, "write error on copying from temp file.\n");
exits("write");
}
tot += i;
}
if (debug) Bprint(Bstderr, "copied %d bytes to final output i=%d\n", tot, i);
if (i < 0) {
Bprint(Bstderr, "read error on copying from temp file.\n");
exits("read");
}
finish();
exits("");
}

View file

@ -0,0 +1,103 @@
#define MAXSPECHARS 512
#define MAXTOKENSIZE 128
#define CHARLIB "#9/sys/lib/troff/font/devutf/charlib"
extern int debug;
extern int fontsize;
extern int fontpos;
extern int resolution; /* device resolution, goobies per inch */
extern int minx; /* minimum x motion */
extern int miny; /* minimum y motion */
extern char devname[];
extern int devres;
extern int unitwidth;
extern char *printdesclang;
extern char *encoding;
extern int fontmnt;
extern char **fontmtab;
extern int curtrofffontid; /* index into trofftab of current troff font */
extern int troffontcnt;
extern BOOLEAN drawflag;
struct specname {
char *str;
struct specname *next;
};
/* character entries for special characters (those pointed
* to by multiple character names, e.g. \(mu for multiply.
*/
struct charent {
char postfontid; /* index into pfnamtab */
char postcharid; /* e.g., 0x00 */
short troffcharwidth;
char *name;
struct charent *next;
};
extern struct charent **build_char_list;
extern int build_char_cnt;
struct pfnament {
char *str;
int used;
};
/* these entries map troff character code ranges to
* postscript font and character ranges.
*/
struct psfent {
int start;
int end;
int offset;
int psftid;
};
struct troffont {
char *trfontid; /* the common troff font name e.g., `R' */
BOOLEAN special; /* flag says this is a special font. */
int spacewidth;
int psfmapsize;
struct psfent *psfmap;
struct charent *charent[NUMOFONTS][FONTSIZE];
};
extern struct troffont *troffontab;
extern struct charent spechars[];
/** prototypes **/
void initialize(void);
void mountfont(int, char*);
int findtfn(char *, int);
void runeout(Rune);
void specialout(char *);
long nametorune(char *);
void conv(Biobuf *);
void hgoto(int);
void vgoto(int);
void hmot(int);
void vmot(int);
void draw(Biobuf *);
void devcntl(Biobuf *);
void notavail(char *);
void error(int, char *, ...);
void loadfont(int, char *);
void flushtext(void);
void t_charht(int);
void t_slant(int);
void startstring(void);
void endstring(void);
BOOLEAN pageon(void);
void setpsfont(int, int);
void settrfont(void);
int hash(char *, int);
BOOLEAN readDESC(void);
void finish(void);
void ps_include(Biobuf *, Biobuf *, int, int,
int, int, double, double, double, double,
double, double, double);
void picture(Biobuf *, char *);
void beginpath(char*, int);
void drawpath(char*, int);

View file

@ -0,0 +1,47 @@
¡ !! ¢ c$ £ l$ ¤ g$
¥ y$ ¦ || § SS ¨ ""
© cO ª sa « << ¬ no
­ -- ® rO ¯ __ ° de
± +- ² s2 ³ s3 ´ ''
µ mi ¶ pg · .. ¸ ,,
¹ s1 º s0 » >> ¼ 14
½ 12 ¾ 34 ¿ ?? À `A
Á 'A Â ^A Ã ~A Ä "A
Å oA Æ AE Ç ,C È `E
É 'E Ê ^E Ë "E Ì `I
Í 'I Î ^I Ï "I Ð D-
Ñ ~N Ò `O Ó 'O Ô ^O
Õ ~O Ö "O × mu Ø /O
Ù `U Ú 'U Û ^U Ü "U
Ý 'Y Þ |P ß ss à `a
á 'a â ^a ã ~a ä "a
å oa æ ae ç ,c è `e
é 'e ê ^e ë "e ì `i
í 'i î ^i ï "i ð d-
ñ ~n ò `o ó 'o ô ^o
õ ~o ö "o ÷ -: ø /o
ù `u ú 'u û ^u ü "u
ý 'y þ |p ÿ "y α *a
β *b γ *g δ *d ε *e
ζ *z η *y θ *h ι *i
κ *k λ *l *m μ ν *n
ξ *c ο *o π *p ρ *r
ς ts σ *s τ *t υ *u
φ *f χ *x ψ *q ω *w
Α *A Β *B Γ *G Δ *D
Ε *E Ζ *Z Η *Y Θ *H
Ι *I Κ *K Λ *L Μ *M
Ν *N Ξ *C Ο *O Π *P
Ρ *R Σ *S Τ *T Υ *U
Φ *F Χ *X Ψ *Q Ω *W
← <- ↑ ua → -> ↓ da
↔ ab ∀ fa ∃ te ∂ pd
∅ es ∆ *D ∇ gr ∉ !m
∍ st ** ∙ bu √ sr
∝ pt ∞ if ∠ an ∧ l&
l| ∩ ca cu ∫ is
∴ tf ≃ ~= ≅ cg ≈ ~~
≠ != ≡ == ≦ <= ≧ >=
⊂ sb ⊃ sp ⊄ !b ⊆ ib
⊇ ip ⊕ O+ ⊖ O- ⊗ Ox
⊢ tu ⊨ Tu ⋄ lz ⋯ el

View file

@ -0,0 +1,264 @@
#include <u.h>
#include <libc.h>
#include <bio.h>
#include "../common/common.h"
#include "tr2post.h"
int hpos = 0, vpos = 0;
int fontsize, fontpos;
#define MAXSTR 128
int trindex; /* index into trofftab of current troff font */
static int expecthmot = 0;
void
initialize(void) {
}
void
hgoto(int x) {
hpos = x;
if (pageon()) {
endstring();
/* Bprint(Bstdout, "%d %d m\n", hpos, vpos); */
}
}
void
vgoto(int y) {
vpos = y;
if (pageon()) {
endstring();
/* Bprint(Bstdout, "%d %d m\n", hpos, vpos); */
}
}
void
hmot(int x) {
int delta;
if ((x<expecthmot-1) || (x>expecthmot+1)) {
delta = x - expecthmot;
if (curtrofffontid <0 || curtrofffontid >= troffontcnt) {
Bprint(Bstderr, "troffontcnt=%d curtrofffontid=%d\n", troffontcnt, curtrofffontid);
Bflush(Bstderr);
exits("");
}
if (delta == troffontab[curtrofffontid].spacewidth*fontsize/10 && isinstring()) {
if (pageon()) runeout(' ');
} else {
if (pageon()) {
endstring();
/* Bprint(Bstdout, " %d 0 rmoveto ", delta); */
/* Bprint(Bstdout, " %d %d m ", hpos+x, vpos); */
if (debug) Bprint(Bstderr, "x=%d expecthmot=%d\n", x, expecthmot);
}
}
}
hpos += x;
expecthmot = 0;
}
void
vmot(int y) {
endstring();
/* Bprint(Bstdout, " 0 %d rmoveto ", -y); */
vpos += y;
}
struct charent **
findglyph(int trfid, Rune rune, char *stoken) {
struct charent **cp;
for (cp = &(troffontab[trfid].charent[RUNEGETGROUP(rune)][RUNEGETCHAR(rune)]); *cp != 0; cp = &((*cp)->next)) {
if ((*cp)->name) {
if (debug) Bprint(Bstderr, "looking for <%s>, have <%s> in font %s\n", stoken, (*cp)->name, troffontab[trfid].trfontid);
if (strcmp((*cp)->name, stoken) == 0)
break;
}
}
return(cp);
}
/* output glyph. Use first rune to look up character (hash)
* then use stoken UTF string to find correct glyph in linked
* list of glyphs in bucket.
*/
void
glyphout(Rune rune, char *stoken, BOOLEAN specialflag) {
struct charent **cp;
struct troffont *tfp;
struct psfent *psfp;
int i, t;
int fontid; /* this is the troff font table index, not the mounted font table index */
int mi, fi, wid;
Rune r;
settrfont();
/* check current font for the character, special or not */
fontid = curtrofffontid;
if (debug) fprint(2, " looking through current font: trying %s\n", troffontab[fontid].trfontid);
cp = findglyph(fontid, rune, stoken);
if (*cp != 0) goto foundit;
if (specialflag) {
if (expecthmot) hmot(0);
/* check special fonts for the special character */
/* cycle through the (troff) mounted fonts starting at the next font */
for (mi=0; mi<fontmnt; mi++) {
if (troffontab[fontid].trfontid==0) error(WARNING, "glyphout:troffontab[%d].trfontid=0x%x, botch!\n",
fontid, troffontab[fontid].trfontid);
if (fontmtab[mi]==0) {
if (debug) fprint(2, "fontmtab[%d]=0x%x, fontmnt=%d\n", mi, fontmtab[mi], fontmnt);
continue;
}
if (strcmp(troffontab[fontid].trfontid, fontmtab[mi])==0) break;
}
if (mi==fontmnt) error(FATAL, "current troff font is not mounted, botch!\n");
for (i=(mi+1)%fontmnt; i!=mi; i=(i+1)%fontmnt) {
if (fontmtab[i]==0) {
if (debug) fprint(2, "fontmtab[%d]=0x%x, fontmnt=%d\n", i, fontmtab[i], fontmnt);
continue;
}
fontid = findtfn(fontmtab[i], TRUE);
if (debug) fprint(2, " looking through special fonts: trying %s\n", troffontab[fontid].trfontid);
if (troffontab[fontid].special) {
cp = findglyph(fontid, rune, stoken);
if (*cp != 0) goto foundit;
}
}
/* check font 1 (if current font is not font 1) for the special character */
if (mi != 1) {
fontid = findtfn(fontmtab[1], TRUE);;
if (debug) fprint(2, " looking through font at position 1: trying %s\n", troffontab[fontid].trfontid);
cp = findglyph(fontid, rune, stoken);
if (*cp != 0) goto foundit;
}
}
if (*cp == 0) {
error(WARNING, "cannot find glyph, rune=0x%x stoken=<%s> troff font %s\n", rune, stoken,
troffontab[curtrofffontid].trfontid);
expecthmot = 0;
}
/* use the peter face in lieu of the character that we couldn't find */
rune = 'p'; stoken = "pw";
for (i=(mi+1)%fontmnt; i!=mi; i=(i+1)%fontmnt) {
if (fontmtab[i]==0) {
if (debug) fprint(2, "fontmtab[%d]=0x%x\n", i, fontmtab[i]);
continue;
}
fontid = findtfn(fontmtab[i], TRUE);
if (debug) fprint(2, " looking through special fonts: trying %s\n", troffontab[fontid].trfontid);
if (troffontab[fontid].special) {
cp = findglyph(fontid, rune, stoken);
if (*cp != 0) goto foundit;
}
}
if (*cp == 0) {
error(WARNING, "cannot find glyph, rune=0x%x stoken=<%s> troff font %s\n", rune, stoken,
troffontab[curtrofffontid].trfontid);
expecthmot = 0;
return;
}
foundit:
t = (((*cp)->postfontid&0xff)<<8) | ((*cp)->postcharid&0xff);
if (debug) {
Bprint(Bstderr, "runeout(0x%x)<%C> postfontid=0x%x postcharid=0x%x troffcharwidth=%d\n",
rune, rune, (*cp)->postfontid, (*cp)->postcharid, (*cp)->troffcharwidth);
}
tfp = &(troffontab[fontid]);
for (i=0; i<tfp->psfmapsize; i++) {
psfp = &(tfp->psfmap[i]);
if(t>=psfp->start && t<=psfp->end) break;
}
if (i >= tfp->psfmapsize)
error(FATAL, "character <0x%x> does not have a Postscript font defined.\n", rune);
setpsfont(psfp->psftid, fontsize);
if (t == 0x0001) { /* character is in charlib */
endstring();
if (pageon()) {
struct charent *tcp;
Bprint(Bstdout, "%d %d m ", hpos, vpos);
/* if char is unicode character rather than name, clean up for postscript */
wid = chartorune(&r, (*cp)->name);
if(' '<r && r<0x7F)
Bprint(Bstdout, "%d build_%s\n", (*cp)->troffcharwidth, (*cp)->name);
else{
if((*cp)->name[wid] != 0)
error(FATAL, "character <%s> badly named\n", (*cp)->name);
Bprint(Bstdout, "%d build_X%.4x\n", (*cp)->troffcharwidth, r);
}
/* stash charent pointer in a list so that we can print these character definitions
* in the prologue.
*/
for (i=0; i<build_char_cnt; i++)
if (*cp == build_char_list[i]) break;
if (i == build_char_cnt) {
build_char_list = galloc(build_char_list, sizeof(struct charent *) * ++build_char_cnt,
"build_char_list");
build_char_list[build_char_cnt-1] = *cp;
}
}
expecthmot = (*cp)->troffcharwidth * fontsize / unitwidth;
} else if (isinstring() || rune != ' ') {
startstring();
if (pageon()) {
if (rune == ' ')
Bprint(Bstdout, " ");
else
Bprint(Bstdout, "%s", charcode[RUNEGETCHAR(t)].str);
}
expecthmot = (*cp)->troffcharwidth * fontsize / unitwidth;
}
}
/* runeout puts a symbol into a string (queue) to be output.
* It also has to keep track of the current and last symbol
* output to check that the spacing is correct by default
* or needs to be adjusted with a spacing operation.
*/
void
runeout(Rune rune) {
char stoken[UTFmax+1];
int i;
i = runetochar(stoken, &rune);
stoken[i] = '\0';
glyphout(rune, stoken, TRUE);
}
void
specialout(char *stoken) {
Rune rune;
int i;
i = chartorune(&rune, stoken);
glyphout(rune, stoken, TRUE);
}
void
graphfunc(Biobuf *bp) {
}
long
nametorune(char *name) {
return(0);
}
void
notavail(char *msg) {
Bprint(Bstderr, "%s is not available at this time.\n", msg);
}