more files
diff --git a/src/cmd/postscript/common/bbox.c b/src/cmd/postscript/common/bbox.c
new file mode 100644
index 0000000..7e1f14a
--- /dev/null
+++ b/src/cmd/postscript/common/bbox.c
@@ -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 */
+
+/*****************************************************************************/
+
diff --git a/src/cmd/postscript/common/comments.h b/src/cmd/postscript/common/comments.h
new file mode 100644
index 0000000..6b409ca
--- /dev/null
+++ b/src/cmd/postscript/common/comments.h
@@ -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:"
+
diff --git a/src/cmd/postscript/common/common.c b/src/cmd/postscript/common/common.c
new file mode 100644
index 0000000..945ef6a
--- /dev/null
+++ b/src/cmd/postscript/common/common.c
@@ -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");
+}
diff --git a/src/cmd/postscript/common/common.h b/src/cmd/postscript/common/common.h
new file mode 100644
index 0000000..62eba08
--- /dev/null
+++ b/src/cmd/postscript/common/common.h
@@ -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 *);
diff --git a/src/cmd/postscript/common/ext.h b/src/cmd/postscript/common/ext.h
new file mode 100644
index 0000000..e260cee
--- /dev/null
+++ b/src/cmd/postscript/common/ext.h
@@ -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();
+ */
diff --git a/src/cmd/postscript/common/gen.h b/src/cmd/postscript/common/gen.h
new file mode 100644
index 0000000..ba8cbba
--- /dev/null
+++ b/src/cmd/postscript/common/gen.h
@@ -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))
+
diff --git a/src/cmd/postscript/common/getopt.c b/src/cmd/postscript/common/getopt.c
new file mode 100644
index 0000000..cf6619f
--- /dev/null
+++ b/src/cmd/postscript/common/getopt.c
@@ -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;
+}
diff --git a/src/cmd/postscript/common/glob.c b/src/cmd/postscript/common/glob.c
new file mode 100644
index 0000000..2826f4e
--- /dev/null
+++ b/src/cmd/postscript/common/glob.c
@@ -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 */
+
diff --git a/src/cmd/postscript/common/misc.c b/src/cmd/postscript/common/misc.c
new file mode 100644
index 0000000..25bd37a
--- /dev/null
+++ b/src/cmd/postscript/common/misc.c
@@ -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 */
+
+/*****************************************************************************/
+
diff --git a/src/cmd/postscript/common/mkfile b/src/cmd/postscript/common/mkfile
new file mode 100644
index 0000000..09d4303
--- /dev/null
+++ b/src/cmd/postscript/common/mkfile
@@ -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
diff --git a/src/cmd/postscript/common/path.h b/src/cmd/postscript/common/path.h
new file mode 100644
index 0000000..a369213
--- /dev/null
+++ b/src/cmd/postscript/common/path.h
@@ -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"
+
diff --git a/src/cmd/postscript/common/request.c b/src/cmd/postscript/common/request.c
new file mode 100644
index 0000000..d8d7dd1
--- /dev/null
+++ b/src/cmd/postscript/common/request.c
@@ -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 */
+
+/*****************************************************************************/
+
diff --git a/src/cmd/postscript/common/request.h b/src/cmd/postscript/common/request.h
new file mode 100644
index 0000000..25d94d0
--- /dev/null
+++ b/src/cmd/postscript/common/request.h
@@ -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;
+
diff --git a/src/cmd/postscript/common/rune.c b/src/cmd/postscript/common/rune.c
new file mode 100644
index 0000000..01ee6ba
--- /dev/null
+++ b/src/cmd/postscript/common/rune.c
@@ -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;
+}
diff --git a/src/cmd/postscript/common/rune.h b/src/cmd/postscript/common/rune.h
new file mode 100644
index 0000000..2df5f76
--- /dev/null
+++ b/src/cmd/postscript/common/rune.h
@@ -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
diff --git a/src/cmd/postscript/common/tempnam.c b/src/cmd/postscript/common/tempnam.c
new file mode 100644
index 0000000..529025e
--- /dev/null
+++ b/src/cmd/postscript/common/tempnam.c
@@ -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