diff options
Diffstat (limited to 'src/cmd/postscript/tr2post')
-rw-r--r-- | src/cmd/postscript/tr2post/Bgetfield.c | 156 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/chartab.c | 458 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/conv.c | 100 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/devcntl.c | 178 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/draw.c | 342 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/mkfile | 36 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/pictures.c | 295 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/ps_include.c | 191 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/ps_include.h | 66 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/readDESC.c | 139 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/shell.lib | 1238 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/tr2post.c | 218 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/tr2post.h | 103 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/utfmap | 47 | ||||
-rw-r--r-- | src/cmd/postscript/tr2post/utils.c | 264 |
15 files changed, 3831 insertions, 0 deletions
diff --git a/src/cmd/postscript/tr2post/Bgetfield.c b/src/cmd/postscript/tr2post/Bgetfield.c new file mode 100644 index 00000000..8922139d --- /dev/null +++ b/src/cmd/postscript/tr2post/Bgetfield.c @@ -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); +} diff --git a/src/cmd/postscript/tr2post/chartab.c b/src/cmd/postscript/tr2post/chartab.c new file mode 100644 index 00000000..87ab556b --- /dev/null +++ b/src/cmd/postscript/tr2post/chartab.c @@ -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', "e, 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; +} diff --git a/src/cmd/postscript/tr2post/conv.c b/src/cmd/postscript/tr2post/conv.c new file mode 100644 index 00000000..4b7d97f6 --- /dev/null +++ b/src/cmd/postscript/tr2post/conv.c @@ -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"); +} diff --git a/src/cmd/postscript/tr2post/devcntl.c b/src/cmd/postscript/tr2post/devcntl.c new file mode 100644 index 00000000..8b438f76 --- /dev/null +++ b/src/cmd/postscript/tr2post/devcntl.c @@ -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++; +} + diff --git a/src/cmd/postscript/tr2post/draw.c b/src/cmd/postscript/tr2post/draw.c new file mode 100644 index 00000000..575ec884 --- /dev/null +++ b/src/cmd/postscript/tr2post/draw.c @@ -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"); + +} diff --git a/src/cmd/postscript/tr2post/mkfile b/src/cmd/postscript/tr2post/mkfile new file mode 100644 index 00000000..e1e5aec2 --- /dev/null +++ b/src/cmd/postscript/tr2post/mkfile @@ -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 diff --git a/src/cmd/postscript/tr2post/pictures.c b/src/cmd/postscript/tr2post/pictures.c new file mode 100644 index 00000000..a20b7ade --- /dev/null +++ b/src/cmd/postscript/tr2post/pictures.c @@ -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); +} diff --git a/src/cmd/postscript/tr2post/ps_include.c b/src/cmd/postscript/tr2post/ps_include.c new file mode 100644 index 00000000..af30ff21 --- /dev/null +++ b/src/cmd/postscript/tr2post/ps_include.c @@ -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; +} diff --git a/src/cmd/postscript/tr2post/ps_include.h b/src/cmd/postscript/tr2post/ps_include.h new file mode 100644 index 00000000..cef49050 --- /dev/null +++ b/src/cmd/postscript/tr2post/ps_include.h @@ -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 +}; diff --git a/src/cmd/postscript/tr2post/readDESC.c b/src/cmd/postscript/tr2post/readDESC.c new file mode 100644 index 00000000..03b8b64d --- /dev/null +++ b/src/cmd/postscript/tr2post/readDESC.c @@ -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); +} diff --git a/src/cmd/postscript/tr2post/shell.lib b/src/cmd/postscript/tr2post/shell.lib new file mode 100644 index 00000000..d96e6565 --- /dev/null +++ b/src/cmd/postscript/tr2post/shell.lib @@ -0,0 +1,1238 @@ +# +# Shell library - for building devutf tables. +# + +RESOLUTION=720 +UNITWIDTH=10 + +OCTALESCAPES=${OCTALESCAPES:-160} # <= code means add \0ddd names +DOWNLOADVECTOR=FALSE # TRUE can mean incomplete tables + +# +# BuiltinTables returns command lines that generate PostScript programs +# for building a typesetter description file and font width tables for +# a relatively standard collection of fonts. Use awk to select a command +# line or modify an existing command to build a width table for a new +# font. +# + +BuiltinTables() { + cat <<-'//End of BuiltinTables' + Proportional R Times-Roman + Proportional I Times-Italic + Proportional B Times-Bold + Proportional BI Times-BoldItalic + Proportional AB AvantGarde-Demi + Proportional AI AvantGarde-BookOblique + Proportional AR AvantGarde-Book + Proportional AX AvantGarde-DemiOblique + Proportional H Helvetica + Proportional HB Helvetica-Bold + Proportional HI Helvetica-Oblique + Proportional HX Helvetica-BoldOblique + Proportional Hb Helvetica-Narrow-Bold + Proportional Hi Helvetica-Narrow-Oblique + Proportional Hr Helvetica-Narrow + Proportional Hx Helvetica-Narrow-BoldOblique + Proportional KB Bookman-Demi + Proportional KI Bookman-LightItalic + Proportional KR Bookman-Light + Proportional KX Bookman-DemiItalic + Proportional NB NewCenturySchlbk-Bold + Proportional NI NewCenturySchlbk-Italic + Proportional NR NewCenturySchlbk-Roman + Proportional NX NewCenturySchlbk-BoldItalic + Proportional PA Palatino-Roman + Proportional PB Palatino-Bold + Proportional PI Palatino-Italic + Proportional PX Palatino-BoldItalic + Proportional ZI ZapfChancery-MediumItalic + FixedWidth C Courier + FixedWidth CB Courier-Bold + FixedWidth CI Courier-Oblique + FixedWidth CO Courier + FixedWidth CW Courier + FixedWidth CX Courier-BoldOblique + Dingbats ZD ZapfDingbats + Greek GR Symbol + Symbol S Symbol + Special S1 Times-Roman + Description DESC --- + //End of BuiltinTables +} + +# +# AllTables prints the complete list of builtin font names. +# + +AllTables() { + BuiltinTables | awk '{print $2}' +} + +# +# Charset functions generate keyword/value pairs (as PostScript objects) +# that describe the character set available in a font. The keyword is a +# PostScript string that represents troff's name for the character. The +# value is usually the literal name (i.e. begins with a /) assigned to +# the character in the PostScript font. The value can also be an integer +# or a PostScript string. An integer value is used as an index in the +# current font's Encoding array. A string value is returned to the host +# unchanged when the entry for the character is constructed. Entries that +# have (") as their value are synonyms for the preceeding character. +# +# The 18 characters missing from ROM resident fonts on older printers are +# flagged with the PostScript comment "% missing". +# + +StandardCharset() { + cat <<-'//End of StandardCharset' + (!) /exclam + (") /quotedbl + (dq) (") % synonym + (#) /numbersign + ($) /dollar + (%) /percent + (&) /ampersand + (') /quoteright + (\() /parenleft + (\)) /parenright + (*) /asterisk + (+) /plus + (,) /comma + (-) /hyphen % changed from minus by request + (.) /period + (/) /slash + (0) /zero + (1) /one + (2) /two + (3) /three + (4) /four + (5) /five + (6) /six + (7) /seven + (8) /eight + (9) /nine + (:) /colon + (;) /semicolon + (<) /less + (=) /equal + (>) /greater + (?) /question + (@) /at + (A) /A + (B) /B + (C) /C + (D) /D + (E) /E + (F) /F + (G) /G + (H) /H + (I) /I + (J) /J + (K) /K + (L) /L + (M) /M + (N) /N + (O) /O + (P) /P + (Q) /Q + (R) /R + (S) /S + (T) /T + (U) /U + (V) /V + (W) /W + (X) /X + (Y) /Y + (Z) /Z + ([) /bracketleft + (\\) /backslash + (bs) (") % synonym + (]) /bracketright + (^) /asciicircum + (_) /underscore + (`) /quoteleft + (a) /a + (b) /b + (c) /c + (d) /d + (e) /e + (f) /f + (g) /g + (h) /h + (i) /i + (j) /j + (k) /k + (l) /l + (m) /m + (n) /n + (o) /o + (p) /p + (q) /q + (r) /r + (s) /s + (t) /t + (u) /u + (v) /v + (w) /w + (x) /x + (y) /y + (z) /z + ({) /braceleft + (|) /bar + (}) /braceright + (~) /asciitilde + (\\`) /grave % devpost character + (ga) (") % synonym + (!!) /exclamdown + (c|) /cent + (ct) (") % devpost synonym + (L-) /sterling + (ps) (") % devpost synonym + (xo) /currency + (cr) (") % devpost synonym + (Y-) /yen + (yn) (") % devpost synonym + (||) /brokenbar % missing + (so) /section + (sc) (") % devpost synonym + ("") /dieresis + (:a) (") % devpost synonym + (co) /copyright + (a_) /ordfeminine + (<<) /guillemotleft + (-,) /logicalnot + (hy) /hyphen + (--) /minus + (ro) /registered + (rg) (") % devpost synonym + (-^) /macron + (-a) (") % devpost synonym + (0^) /degree % missing + (+-) /plusminus % missing + (2^) /twosuperior % missing + (3^) /threesuperior % missing + (\\') /acute + (aa) (") % devpost synonym + (/u) /mu % missing + (P!) /paragraph + (pg) (") % devpost synonym + (.^) /periodcentered + (,,) /cedilla + (,a) (") % devpost synonym + (1^) /onesuperior % missing + (o_) /ordmasculine + (>>) /guillemotright + (14) /onequarter % missing + (12) /onehalf % missing + (34) /threequarters % missing + (??) /questiondown + (A`) /Agrave + (A') /Aacute + (A^) /Acircumflex + (A~) /Atilde + (A") /Adieresis + (A*) /Aring + (AE) /AE + (C,) /Ccedilla + (E`) /Egrave + (E') /Eacute + (E^) /Ecircumflex + (E") /Edieresis + (I`) /Igrave + (I') /Iacute + (I^) /Icircumflex + (I") /Idieresis + (D-) /Eth % missing + (N~) /Ntilde + (O`) /Ograve + (O') /Oacute + (O^) /Ocircumflex + (O~) /Otilde + (O") /Odieresis + (xx) /multiply % missing + (O/) /Oslash + (U`) /Ugrave + (U') /Uacute + (U^) /Ucircumflex + (U") /Udieresis + (Y') /Yacute % missing + (TH) /Thorn % missing + (ss) /germandbls + (a`) /agrave + (a') /aacute + (a^) /acircumflex + (a~) /atilde + (a") /adieresis + (a*) /aring + (ae) /ae + (c,) /ccedilla + (e`) /egrave + (e') /eacute + (e^) /ecircumflex + (e") /edieresis + (i`) /igrave + (i') /iacute + (i^) /icircumflex + (i") /idieresis + (d-) /eth % missing + (n~) /ntilde + (o`) /ograve + (o') /oacute + (o^) /ocircumflex + (o~) /otilde + (o") /odieresis + (-:) /divide % missing + (o/) /oslash + (u`) /ugrave + (u') /uacute + (u^) /ucircumflex + (u") /udieresis + (y') /yacute % missing + (th) /thorn % missing + (y") /ydieresis + (^a) /circumflex % devpost accent + (~a) /tilde % devpost accent + (Ua) /breve % devpost accent + (.a) /dotaccent % devpost accent + (oa) /ring % devpost accent + ("a) /hungarumlaut % devpost accent + (Ca) /ogonek % devpost accent + (va) /caron % devpost accent + //End of StandardCharset +} + +# +# DingbatsCharset guarantees changes in StandardCharset don't show up in ZD. +# + +DingbatsCharset() { + cat <<-'//End of DingbatsCharset' + (!) /exclam + (") /quotedbl + (#) /numbersign + ($) /dollar + (%) /percent + (&) /ampersand + (') /quoteright + (\() /parenleft + (\)) /parenright + (*) /asterisk + (+) /plus + (,) /comma + (-) /minus % also hyphen in devpost + (.) /period + (/) /slash + (0) /zero + (1) /one + (2) /two + (3) /three + (4) /four + (5) /five + (6) /six + (7) /seven + (8) /eight + (9) /nine + (:) /colon + (;) /semicolon + (<) /less + (=) /equal + (>) /greater + (?) /question + (@) /at + (A) /A + (B) /B + (C) /C + (D) /D + (E) /E + (F) /F + (G) /G + (H) /H + (I) /I + (J) /J + (K) /K + (L) /L + (M) /M + (N) /N + (O) /O + (P) /P + (Q) /Q + (R) /R + (S) /S + (T) /T + (U) /U + (V) /V + (W) /W + (X) /X + (Y) /Y + (Z) /Z + ([) /bracketleft + (\\) /backslash + (]) /bracketright + (^) /asciicircum + (_) /underscore + (`) /quoteleft + (a) /a + (b) /b + (c) /c + (d) /d + (e) /e + (f) /f + (g) /g + (h) /h + (i) /i + (j) /j + (k) /k + (l) /l + (m) /m + (n) /n + (o) /o + (p) /p + (q) /q + (r) /r + (s) /s + (t) /t + (u) /u + (v) /v + (w) /w + (x) /x + (y) /y + (z) /z + ({) /braceleft + (|) /bar + (}) /braceright + (~) /asciitilde + (\\`) /grave % devpost character + (!!) /exclamdown + (c|) /cent + (L-) /sterling + (xo) /currency + (Y-) /yen + (||) /brokenbar % missing + (so) /section + ("") /dieresis + (co) /copyright + (a_) /ordfeminine + (<<) /guillemotleft + (-,) /logicalnot + (hy) /hyphen + (ro) /registered + (-^) /macron + (0^) /degree % missing + (+-) /plusminus % missing + (2^) /twosuperior % missing + (3^) /threesuperior % missing + (\\') /acute + (/u) /mu % missing + (P!) /paragraph + (.^) /periodcentered + (,,) /cedilla + (1^) /onesuperior % missing + (o_) /ordmasculine + (>>) /guillemotright + (14) /onequarter % missing + (12) /onehalf % missing + (34) /threequarters % missing + (??) /questiondown + (A`) /Agrave + (A') /Aacute + (A^) /Acircumflex + (A~) /Atilde + (A") /Adieresis + (A*) /Aring + (AE) /AE + (C,) /Ccedilla + (E`) /Egrave + (E') /Eacute + (E^) /Ecircumflex + (E") /Edieresis + (I`) /Igrave + (I') /Iacute + (I^) /Icircumflex + (I") /Idieresis + (D-) /Eth % missing + (N~) /Ntilde + (O`) /Ograve + (O') /Oacute + (O^) /Ocircumflex + (O~) /Otilde + (O") /Odieresis + (xx) /multiply % missing + (O/) /Oslash + (U`) /Ugrave + (U') /Uacute + (U^) /Ucircumflex + (U") /Udieresis + (Y') /Yacute % missing + (TH) /Thorn % missing + (ss) /germandbls + (a`) /agrave + (a') /aacute + (a^) /acircumflex + (a~) /atilde + (a") /adieresis + (a*) /aring + (ae) /ae + (c,) /ccedilla + (e`) /egrave + (e') /eacute + (e^) /ecircumflex + (e") /edieresis + (i`) /igrave + (i') /iacute + (i^) /icircumflex + (i") /idieresis + (d-) /eth % missing + (n~) /ntilde + (o`) /ograve + (o') /oacute + (o^) /ocircumflex + (o~) /otilde + (o") /odieresis + (-:) /divide % missing + (o/) /oslash + (u`) /ugrave + (u') /uacute + (u^) /ucircumflex + (u") /udieresis + (y') /yacute % missing + (th) /thorn % missing + (y") /ydieresis + //End of DingbatsCharset +} + +SymbolCharset() { + cat <<-'//End of SymbolCharset' + (---) /exclam + (fa) /universal + (---) /numbersign + (te) /existential + (---) /percent + (---) /ampersand + (st) /suchthat + (---) /parenleft + (---) /parenright + (**) /asteriskmath + (pl) /plus + (---) /comma + (mi) /minus + (---) /period + (sl) /slash + (---) /zero + (---) /one + (---) /two + (---) /three + (---) /four + (---) /five + (---) /six + (---) /seven + (---) /eight + (---) /nine + (---) /colon + (---) /semicolon + (<) /less + (eq) /equal + (>) /greater + (---) /question + (cg) /congruent + (*A) /Alpha + (\244x) (") + (*B) /Beta + (\244y) (") + (*X) /Chi + (\244\257) (") + (*D) /Delta + (\244{) (") + (*E) /Epsilon + (\244|) (") + (*F) /Phi + (\244\256) (") + (*G) /Gamma + (\244z) (") + (*Y) /Eta + (\244~) (") + (*I) /Iota + (\244\241) (") + (---) /theta1 + (\244\331) (") + (*K) /Kappa + (\244\242) (") + (*L) /Lambda + (\244\243) (") + (*M) /Mu + (\244\244) (") + (*N) /Nu + (\244\245) (") + (*O) /Omicron + (\244\247) (") + (*P) /Pi + (\244\250) (") + (*H) /Theta + (\244\240) (") + (*R) /Rho + (\244\251) (") + (*S) /Sigma + (\244\253) (") + (*T) /Tau + (\244\254) (") + (*U) /Upsilon + (\244\255) (") + (ts) /sigma1 + (\244\312) (") + (*W) /Omega + (\244\261) (") + (*C) /Xi + (\244\246) (") + (*Q) /Psi + (\244\260) (") + (*Z) /Zeta + (\244}) (") + (---) /bracketleft + (tf) /therefore + (---) /bracketright + (pp) /perpendicular + (ul) /underscore + (_) (") % synonym + (rn) /radicalex + (*a) /alpha + (\244\271) (") + (*b) /beta + (\244\272) (") + (*x) /chi + (\244\317) (") + (*d) /delta + (\244\274) (") + (*e) /epsilon + (\244\275) (") + (*f) /phi + (\244\316) (") + (*g) /gamma + (\244\273) (") + (*y) /eta + (\244\277) (") + (*i) /iota + (\244\301) (") + (---) /phi1 + (\244\335) (") + (*k) /kappa + (\244\302) (") + (*l) /lambda + (\244\303) (") + (*m) /mu + (\244\304) (") + (*n) /nu + (\244\305) (") + (*o) /omicron + (\244\307) (") + (*p) /pi + (\244\310) (") + (*h) /theta + (\244\300) (") + (*r) /rho + (\244\311) (") + (*s) /sigma + (\244\313) (") + (*t) /tau + (\244\314) (") + (*u) /upsilon + (\244\315) (") + (---) /omega1 + (\244\336) (") + (*w) /omega + (\244\321) (") + (*c) /xi + (\244\306) (") + (*q) /psi + (\244\320) (") + (*z) /zeta + (\244\276) (") + (---) /braceleft + (or) /bar + (---) /braceright + (ap) /similar + (---) /Upsilon1 + (fm) /minute + (<=) /lessequal + (fr) /fraction % devpost character + (if) /infinity + (fn) /florin % devpost character + (---) /club + (---) /diamond + (---) /heart + (---) /spade + (ab) /arrowboth + (<-) /arrowleft + (ua) /arrowup + (->) /arrowright + (da) /arrowdown + (de) /degree + (+-) /plusminus + (---) /second + (>=) /greaterequal + (mu) /multiply + (pt) /proportional + (pd) /partialdiff + (bu) /bullet + (di) /divide + (!=) /notequal + (==) /equivalence + (~~) /approxequal + (el) /ellipsis + (av) /arrowvertex + (ah) /arrowhorizex + (CR) /carriagereturn + (af) /aleph + (If) /Ifraktur + (Rf) /Rfraktur + (ws) /weierstrass + (Ox) /circlemultiply + (O+) /circleplus + (es) /emptyset + (ca) /intersection + (cu) /union + (sp) /propersuperset + (ip) /reflexsuperset + (!b) /notsubset + (sb) /propersubset + (ib) /reflexsubset + (mo) /element + (!m) /notelement + (an) /angle + (gr) /gradient + (rg) /registerserif + (co) /copyrightserif + (tm) /trademarkserif + (---) /product + (sr) /radical + (c.) /dotmath + (no) /logicalnot + (l&) /logicaland + (l|) /logicalor + (---) /arrowdblboth + (---) /arrowdblleft + (---) /arrowdblup + (---) /arrowdblright + (---) /arrowdbldown + (lz) /lozenge + (b<) /angleleft + (RG) /registersans + (CO) /copyrightsans + (TM) /trademarksans + (---) /summation + (LT) /parenlefttp + (br) /parenleftex + (LX) (") % synonym + (LB) /parenleftbt + (lc) /bracketlefttp + (lx) /bracketleftex + (lf) /bracketleftbt + (lt) /bracelefttp + (lk) /braceleftmid + (lb) /braceleftbt + (bv) /braceex + (|) (") % synonym + (b>) /angleright + (is) /integral + (---) /integraltp + (---) /integralex + (---) /integralbt + (RT) /parenrighttp + (RX) /parenrightex + (RB) /parenrightbt + (rc) /bracketrighttp + (rx) /bracketrightex + (rf) /bracketrightbt + (rt) /bracerighttp + (rk) /bracerightmid + (rb) /bracerightbt + (~=) (55 0 1) % charlib + //End of SymbolCharset +} + +SpecialCharset() { + cat <<-'//End of SpecialCharset' + (ru) /underscore + ('') /quotedblright % devpost character + (``) /quotedblleft % devpost character + (dg) /dagger % devpost character + (dd) /daggerdbl % devpost character + (en) /endash % devpost character + (\\-) (") % synonym + (em) /emdash +% (ff) (60 2 1) % charlib +% (Fi) (84 2 1) % charlib +% (Fl) (84 2 1) % charlib + (14) (75 2 1) % charlib + (12) (75 2 1) % charlib + (34) (75 2 1) % charlib + (bx) (50 2 1) % charlib + (ob) (38 2 1) % charlib + (ci) (75 0 1) % charlib + (sq) (50 2 1) % charlib + (Sl) (50 2 1) % charlib + (L1) (110 1 1) % charlib + (LA) (110 1 1) % charlib + (LV) (110 3 1) % charlib + (LH) (210 1 1) % charlib + (lh) (100 0 1) % charlib + (rh) (100 0 1) % charlib + (lH) (100 0 1) % charlib + (rH) (100 0 1) % charlib + (PC) (220 2 1) % charlib + (DG) (185 2 1) % charlib + //End of SpecialCharset +} + +# +# Latin1 ensures a font uses the ISOLatin1Encoding vector, although only +# text fonts should be re-encoded. Downloading the Encoding vector doesn't +# often make sense. No ISOLatin1Encoding array likely means ROM based fonts +# on your printer are incomplete. Type 1 fonts with a full Latin1 character +# set appeared sometime after Version 50.0. +# + +Latin1() { + if [ "$DOWNLOADVECTOR" = TRUE ]; then + cat <<-'//End of ISOLatin1Encoding' + /ISOLatin1Encoding [ + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /space + /exclam + /quotedbl + /numbersign + /dollar + /percent + /ampersand + /quoteright + /parenleft + /parenright + /asterisk + /plus + /comma + /minus + /period + /slash + /zero + /one + /two + /three + /four + /five + /six + /seven + /eight + /nine + /colon + /semicolon + /less + /equal + /greater + /question + /at + /A + /B + /C + /D + /E + /F + /G + /H + /I + /J + /K + /L + /M + /N + /O + /P + /Q + /R + /S + /T + /U + /V + /W + /X + /Y + /Z + /bracketleft + /backslash + /bracketright + /asciicircum + /underscore + /quoteleft + /a + /b + /c + /d + /e + /f + /g + /h + /i + /j + /k + /l + /m + /n + /o + /p + /q + /r + /s + /t + /u + /v + /w + /x + /y + /z + /braceleft + /bar + /braceright + /asciitilde + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /.notdef + /dotlessi + /grave + /acute + /circumflex + /tilde + /macron + /breve + /dotaccent + /dieresis + /.notdef + /ring + /cedilla + /.notdef + /hungarumlaut + /ogonek + /caron + /space + /exclamdown + /cent + /sterling + /currency + /yen + /brokenbar + /section + /dieresis + /copyright + /ordfeminine + /guillemotleft + /logicalnot + /hyphen + /registered + /macron + /degree + /plusminus + /twosuperior + /threesuperior + /acute + /mu + /paragraph + /periodcentered + /cedilla + /onesuperior + /ordmasculine + /guillemotright + /onequarter + /onehalf + /threequarters + /questiondown + /Agrave + /Aacute + /Acircumflex + /Atilde + /Adieresis + /Aring + /AE + /Ccedilla + /Egrave + /Eacute + /Ecircumflex + /Edieresis + /Igrave + /Iacute + /Icircumflex + /Idieresis + /Eth + /Ntilde + /Ograve + /Oacute + /Ocircumflex + /Otilde + /Odieresis + /multiply + /Oslash + /Ugrave + /Uacute + /Ucircumflex + /Udieresis + /Yacute + /Thorn + /germandbls + /agrave + /aacute + /acircumflex + /atilde + /adieresis + /aring + /ae + /ccedilla + /egrave + /eacute + /ecircumflex + /edieresis + /igrave + /iacute + /icircumflex + /idieresis + /eth + /ntilde + /ograve + /oacute + /ocircumflex + /otilde + /odieresis + /divide + /oslash + /ugrave + /uacute + /ucircumflex + /udieresis + /yacute + /thorn + /ydieresis + ] def + //End of ISOLatin1Encoding + fi + + echo "ISOLatin1Encoding /$1 ReEncode" +} + +# +# Generating functions output PostScript programs that build font width +# tables or a typesetter description file. Send the program to a printer +# and the complete table will come back on the serial port. All write on +# stdout and assume the prologue and other required PostScript files are +# all available. +# + +Proportional() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/octalescapes $OCTALESCAPES def" + echo "/charset [" + # Get <>_ and | from S. Use accents for ascii ^ and ~. + StandardCharset | awk ' + $1 == "(<)" && $2 == "/less" {$1 = "(---)"} + $1 == "(>)" && $2 == "/greater" {$1 = "(---)"} + $1 == "(_)" && $2 == "/underscore" {$1 = "(---)"} + $1 == "(|)" && $2 == "/bar" {$1 = "(---)"} + $1 == "(^)" && $2 == "/asciicircum" { + printf "(^)\t/circumflex\n" + $1 = "(---)" + } + $1 == "(~)" && $2 == "/asciitilde" { + printf "(~)\t/tilde\n" + $1 = "(---)" + } + {printf "%s\t%s\n", $1, $2} + ' + echo "] def" + + Latin1 $2 + echo "/$2 SelectFont" + echo "(opO) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(spacewidth ) Print 32 GetWidth Print (\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +FixedWidth() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/octalescapes $OCTALESCAPES def" + echo "/charset [" + StandardCharset + echo "] def" + + Latin1 $2 + echo "/$2 SelectFont" + echo "(opO) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(spacewidth ) Print 32 GetWidth Print (\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +Dingbats() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/octalescapes $OCTALESCAPES def" + echo "/charset [" + DingbatsCharset | awk '$1 != "(---)" && $2 ~ /^\/[a-zA-Z]/ { + printf "%s\tISOLatin1Encoding %s GetCode\n", $1, $2 + }' + echo "] def" + + echo "/$2 SelectFont" + echo "( ) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +Greek() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/charset [" + SymbolCharset | awk ' + BEGIN {hit = -1} + $1 ~ /\(\*[a-zA-Z]\)/ {print; hit = NR} + $2 == "(\")" && hit == NR-1 {print; hit = NR} + ' + echo "] def" + + echo "/$2 SelectFont" + echo "(orO) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(spacewidth ) Print 32 GetWidth Print (\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +Symbol() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/charset [" + SymbolCharset + echo "] def" + + echo "ChangeMetrics" + echo "/S SelectFont" + echo "(orO) SetAscender" + + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(special\\\\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +Special() { + echo "/unitwidth $UNITWIDTH def" + echo "/resolution $RESOLUTION def" + echo "/charset [" + SpecialCharset + echo "] def" + + echo "ChangeMetrics" + echo "/S1 SelectFont" + + echo "(# Times-Roman special font\\\\n) Print" + echo "(name $1\\\\n) Print" + echo "(fontname $2\\\\n) Print" + echo "/$1 NamedInPrologue" + echo "(special\\\\n) Print" + echo "(charset\\\\n) Print" + echo "BuildFontCharset" +} + +# +# The DESC file doesn't have to be built on a printer. It's only here for +# consistency. +# + +Description() { + echo "/charset [" # awk - so the stack doesn't overflow + StandardCharset | awk '$1 !~ /\(\\[0-9]/ {print $1}' + SymbolCharset | awk '$1 !~ /\(\\[0-9]/ {print $1}' + SpecialCharset | awk '$1 !~ /\(\\[0-9]/ {print $1}' + echo "] def" + + cat <<-//DESC + (#Device Description - utf character set + + PDL PostScript + Encoding Latin1 + + fonts 10 R I B BI CW H HI HB S1 S + sizes 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 + 23 24 25 26 27 28 29 30 31 32 33 34 35 36 38 40 42 44 46 + 48 50 52 54 56 58 60 64 68 72 78 84 90 96 100 105 110 115 + 120 125 130 135 140 145 150 155 160 0 + res $RESOLUTION + hor 1 + vert 1 + unitwidth $UNITWIDTH + + ) Print + //DESC + echo "(charset\\\\n) Print" + echo "BuildDescCharset" + echo "(\\\\n) Print" +} + diff --git a/src/cmd/postscript/tr2post/tr2post.c b/src/cmd/postscript/tr2post/tr2post.c new file mode 100644 index 00000000..d60e0c7a --- /dev/null +++ b/src/cmd/postscript/tr2post/tr2post.c @@ -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(""); +} diff --git a/src/cmd/postscript/tr2post/tr2post.h b/src/cmd/postscript/tr2post/tr2post.h new file mode 100644 index 00000000..b07e0b13 --- /dev/null +++ b/src/cmd/postscript/tr2post/tr2post.h @@ -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); diff --git a/src/cmd/postscript/tr2post/utfmap b/src/cmd/postscript/tr2post/utfmap new file mode 100644 index 00000000..2f9d6dc3 --- /dev/null +++ b/src/cmd/postscript/tr2post/utfmap @@ -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 diff --git a/src/cmd/postscript/tr2post/utils.c b/src/cmd/postscript/tr2post/utils.c new file mode 100644 index 00000000..8f58ea45 --- /dev/null +++ b/src/cmd/postscript/tr2post/utils.c @@ -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); +} |