summaryrefslogtreecommitdiff
path: root/sys/src/cmd/postscript/postdaisy
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/postscript/postdaisy
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/postscript/postdaisy')
-rwxr-xr-xsys/src/cmd/postscript/postdaisy/Opostdaisy.c1222
-rwxr-xr-xsys/src/cmd/postscript/postdaisy/README4
-rwxr-xr-xsys/src/cmd/postscript/postdaisy/mkfile62
-rwxr-xr-xsys/src/cmd/postscript/postdaisy/postdaisy.1217
-rwxr-xr-xsys/src/cmd/postscript/postdaisy/postdaisy.c1225
-rwxr-xr-xsys/src/cmd/postscript/postdaisy/postdaisy.h88
-rwxr-xr-xsys/src/cmd/postscript/postdaisy/postdaisy.mk93
-rwxr-xr-xsys/src/cmd/postscript/postdaisy/postdaisy.ps74
8 files changed, 2985 insertions, 0 deletions
diff --git a/sys/src/cmd/postscript/postdaisy/Opostdaisy.c b/sys/src/cmd/postscript/postdaisy/Opostdaisy.c
new file mode 100755
index 000000000..a440fd604
--- /dev/null
+++ b/sys/src/cmd/postscript/postdaisy/Opostdaisy.c
@@ -0,0 +1,1222 @@
+/*
+ *
+ * postdaisy - PostScript translator for Diablo 1640 files.
+ *
+ * A program that translates Diablo 1640 files into PostScript. Absolutely nothing
+ * is guaranteed. Quite a few things haven't been implemented, and what's been
+ * done isn't well tested. Most of the documentation used to write this program
+ * was taken from the 'Diablo Emulator' section of a recent Imagen manual.
+ *
+ * Some of document comments that are generated may not be right. Most of the test
+ * files I used produced a trailing blank page. I've put a check in formfeed() that
+ * won't print the last page if it doesn't contain any text, but PAGES comments may
+ * not be right. The DOCUMENTFONTS comment will also be wrong if auto underline or
+ * bold printing have been turned on by escape commands.
+ *
+ * The brute force approach used to implement horizontal and vertical tabs leaves
+ * much to be desired, and may not work for very small initial hmi and vmi values.
+ * At the very least I should have used malloc() to get space for the two tabstop
+ * arrays after hmi and vmi are known!
+ *
+ * Reverse printing mode hasn't been tested at all, but what's here should be
+ * close even though it's not efficient.
+ *
+ * The PostScript prologue is copied from *prologue before any of the input files
+ * are translated. The program expects that the following PostScript procedures
+ * are defined in that file:
+ *
+ * setup
+ *
+ * mark ... setup -
+ *
+ * Handles special initialization stuff that depends on how this program
+ * was called. Expects to find a mark followed by key/value pairs on the
+ * stack. The def operator is applied to each pair up to the mark, then
+ * the default state is set up.
+ *
+ * pagesetup
+ *
+ * page pagesetup -
+ *
+ * Does whatever is needed to set things up for the next page. Expects to
+ * find the current page number on the stack.
+ *
+ * t
+ *
+ * mark str1 x1 str2 x2 ... strn xn y hmi t mark
+ *
+ * Handles all the text on the stack. Characters in the strings are
+ * printed using hmi as the character advance, and all strings are at
+ * vertical position y. Each string is begins at the horizontal position
+ * that preceeds it.
+ *
+ * f
+ *
+ * font f -
+ *
+ * Use font f, where f is the full PostScript font name. Only used when
+ * we switch to auto underline (Courier-Italic) or bold (Courier-Bold)
+ * printing.
+ *
+ * done
+ *
+ * done
+ *
+ * Makes sure the last page is printed. Only needed when we're printing
+ * more than one page on each sheet of paper.
+ *
+ * Many default values, like the magnification and orientation, are defined in
+ * the prologue, which is where they belong. If they're changed (by options), an
+ * appropriate definition is made after the prologue is added to the output file.
+ * The -P option passes arbitrary PostScript through to the output file. Among
+ * other things it can be used to set (or change) values that can't be accessed by
+ * other options.
+ *
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include "comments.h" /* PostScript file structuring comments */
+#include "gen.h" /* general purpose definitions */
+#include "path.h" /* for the prologue */
+#include "ext.h" /* external variable declarations */
+#include "postdaisy.h" /* a few special definitions */
+
+char *optnames = "a:c:f:h:l:m:n:o:p:r:s:v:x:y:A:C:E:J:L:P:DI";
+
+char *prologue = POSTDAISY; /* default PostScript prologue */
+char *formfile = FORMFILE; /* stuff for multiple pages per sheet */
+
+int formsperpage = 1; /* page images on each piece of paper */
+int copies = 1; /* and this many copies of each sheet */
+
+char htabstops[COLUMNS]; /* horizontal */
+char vtabstops[ROWS]; /* and vertical tabs */
+
+int res = RES; /* input file resolution - sort of */
+
+int hmi = HMI; /* horizontal motion index - 1/120 inch */
+int vmi = VMI; /* vertical motion index - 1/48 inch */
+int ohmi = HMI; /* original hmi */
+int ovmi = VMI; /* and vmi - for tabs and char size */
+
+int hpos = 0; /* current horizontal */
+int vpos = 0; /* and vertical position */
+
+int lastx = -1; /* printer's last horizontal */
+int lasty = -1; /* and vertical position */
+int lasthmi = -1; /* hmi for current text strings */
+
+int lastc = -1; /* last printed character */
+int prevx = -1; /* at this position */
+
+int leftmargin = LEFTMARGIN; /* page margins */
+int rightmargin = RIGHTMARGIN;
+int topmargin = TOPMARGIN;
+int bottommargin = BOTTOMMARGIN;
+
+int stringcount = 0; /* number of strings on the stack */
+int stringstart = 1; /* column where current one starts */
+int advance = 1; /* -1 if in backward print mode */
+
+int lfiscr = OFF; /* line feed implies carriage return */
+int crislf = OFF; /* carriage return implies line feed */
+
+int linespp = 0; /* lines per page if it's positive */
+int markedpage = FALSE; /* helps prevent trailing blank page */
+int page = 0; /* page we're working on */
+int printed = 0; /* printed this many pages */
+
+Fontmap fontmap[] = FONTMAP; /* for translating font names */
+char *fontname = "Courier"; /* use this PostScript font */
+int shadowprint = OFF; /* automatic bold printing if ON */
+
+FILE *fp_in; /* read from this file */
+FILE *fp_out = stdout; /* and write stuff here */
+FILE *fp_acct = NULL; /* for accounting data */
+
+/*****************************************************************************/
+
+main(agc, agv)
+
+ int agc;
+ char *agv[];
+
+{
+
+/*
+ *
+ * A simple program that translates Diablo 1640 files into PostScript. Nothing
+ * is guaranteed - the program not well tested and doesn't implement everything.
+ *
+ */
+
+ argc = agc; /* other routines may want them */
+ argv = agv;
+
+ prog_name = argv[0]; /* really just for error messages */
+
+ init_signals(); /* sets up interrupt handling */
+ header(); /* PostScript header comments */
+ options(); /* handle the command line options */
+ setup(); /* for PostScript */
+ arguments(); /* followed by each input file */
+ done(); /* print the last page etc. */
+ account(); /* job accounting data */
+
+ exit(x_stat); /* not much could be wrong */
+
+} /* End of main */
+
+/*****************************************************************************/
+
+init_signals()
+
+{
+
+ int interrupt(); /* signal handler */
+
+/*
+ *
+ * Makes sure we handle interrupts.
+ *
+ */
+
+ if ( signal(SIGINT, interrupt) == SIG_IGN ) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ } else {
+ signal(SIGHUP, interrupt);
+ signal(SIGQUIT, interrupt);
+ } /* End else */
+
+ signal(SIGTERM, interrupt);
+
+} /* End of init_signals */
+
+/*****************************************************************************/
+
+header()
+
+{
+
+ int ch; /* return value from getopt() */
+ int old_optind = optind; /* for restoring optind - should be 1 */
+
+/*
+ *
+ * Scans the option list looking for things, like the prologue file, that we need
+ * right away but could be changed from the default. Doing things this way is an
+ * attempt to conform to Adobe's latest file structuring conventions. In particular
+ * they now say there should be nothing executed in the prologue, and they have
+ * added two new comments that delimit global initialization calls. Once we know
+ * where things really are we write out the job header, follow it by the prologue,
+ * and then add the ENDPROLOG and BEGINSETUP comments.
+ *
+ */
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF )
+ if ( ch == 'L' )
+ prologue = optarg;
+ else if ( ch == '?' )
+ error(FATAL, "");
+
+ optind = old_optind; /* get ready for option scanning */
+
+ fprintf(stdout, "%s", CONFORMING);
+ fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
+ fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
+ fprintf(stdout, "%s %s\n", PAGES, ATEND);
+ fprintf(stdout, "%s", ENDCOMMENTS);
+
+ if ( cat(prologue) == FALSE )
+ error(FATAL, "can't read %s", prologue);
+
+ if ( DOROUND )
+ cat(ROUNDPAGE);
+
+ fprintf(stdout, "%s", ENDPROLOG);
+ fprintf(stdout, "%s", BEGINSETUP);
+ fprintf(stdout, "mark\n");
+
+} /* End of header */
+
+/*****************************************************************************/
+
+options()
+
+{
+
+ int ch; /* return value from getopt() */
+ int n; /* for CR and LF modes */
+
+/*
+ *
+ * Reads and processes the command line options. Added the -P option so arbitrary
+ * PostScript code can be passed through. Expect it could be useful for changing
+ * definitions in the prologue for which options have not been defined.
+ *
+ * Although any PostScript font can be used, things will only work for constant
+ * width fonts.
+ *
+ */
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
+ switch ( ch ) {
+ case 'a': /* aspect ratio */
+ fprintf(stdout, "/aspectratio %s def\n", optarg);
+ break;
+
+ case 'c': /* copies */
+ copies = atoi(optarg);
+ fprintf(stdout, "/#copies %s store\n", optarg);
+ break;
+
+ case 'f': /* use this PostScript font */
+ fontname = get_font(optarg);
+ fprintf(stdout, "/font /%s def\n", fontname);
+ break;
+
+ case 'h': /* default character spacing */
+ ohmi = hmi = atoi(optarg) * HSCALE;
+ fprintf(stdout, "/hmi %s def\n", optarg);
+ break;
+
+ case 'l': /* lines per page */
+ linespp = atoi(optarg);
+ break;
+
+ case 'm': /* magnification */
+ fprintf(stdout, "/magnification %s def\n", optarg);
+ break;
+
+ case 'n': /* forms per page */
+ formsperpage = atoi(optarg);
+ fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
+ fprintf(stdout, "/formsperpage %s def\n", optarg);
+ break;
+
+ case 'o': /* output page list */
+ out_list(optarg);
+ break;
+
+ case 'p': /* landscape or portrait mode */
+ if ( *optarg == 'l' )
+ fprintf(stdout, "/landscape true def\n");
+ else fprintf(stdout, "/landscape false def\n");
+ break;
+
+ case 'r': /* set CR and LF modes */
+ n = atoi(optarg);
+ if ( n & 01 )
+ lfiscr = ON;
+ else lfiscr = OFF;
+ if ( n & 02 )
+ crislf = ON;
+ else crislf = OFF;
+ break;
+
+ case 's': /* point size */
+ fprintf(stdout, "/pointsize %s def\n", optarg);
+ break;
+
+ case 'v': /* default line spacing */
+ ovmi = vmi = atoi(optarg) * VSCALE;
+ break;
+
+ case 'x': /* shift things horizontally */
+ fprintf(stdout, "/xoffset %s def\n", optarg);
+ break;
+
+ case 'y': /* and vertically on the page */
+ fprintf(stdout, "/yoffset %s def\n", optarg);
+ break;
+
+ case 'A': /* force job accounting */
+ case 'J':
+ if ( (fp_acct = fopen(optarg, "a")) == NULL )
+ error(FATAL, "can't open accounting file %s", optarg);
+ break;
+
+ case 'C': /* copy file straight to output */
+ if ( cat(optarg) == FALSE )
+ error(FATAL, "can't read %s", optarg);
+ break;
+
+ case 'E': /* text font encoding */
+ fontencoding = optarg;
+ break;
+
+ case 'L': /* PostScript prologue file */
+ prologue = optarg;
+ break;
+
+ case 'P': /* PostScript pass through */
+ fprintf(stdout, "%s\n", optarg);
+ break;
+
+ case 'R': /* special global or page level request */
+ saverequest(optarg);
+ break;
+
+ case 'D': /* debug flag */
+ debug = ON;
+ break;
+
+ case 'I': /* ignore FATAL errors */
+ ignore = ON;
+ break;
+
+ case '?': /* don't understand the option */
+ error(FATAL, "");
+ break;
+
+ default: /* don't know what to do for ch */
+ error(FATAL, "missing case for option %c\n", ch);
+ break;
+ } /* End switch */
+ } /* End while */
+
+ argc -= optind; /* get ready for non-option args */
+ argv += optind;
+
+} /* End of options */
+
+/*****************************************************************************/
+
+char *get_font(name)
+
+ char *name; /* name the user asked for */
+
+{
+
+ int i; /* for looking through fontmap[] */
+
+/*
+ *
+ * Called from options() to map a user's font name into a legal PostScript name.
+ * If the lookup fails *name is returned to the caller. That should let you choose
+ * any PostScript font, although things will only work well for constant width
+ * fonts.
+ *
+ */
+
+ for ( i = 0; fontmap[i].name != NULL; i++ )
+ if ( strcmp(name, fontmap[i].name) == 0 )
+ return(fontmap[i].val);
+
+ return(name);
+
+} /* End of get_font */
+
+/*****************************************************************************/
+
+setup()
+
+{
+
+/*
+ *
+ * Handles things that must be done after the options are read but before the
+ * input files are processed.
+ *
+ */
+
+ writerequest(0, stdout); /* global requests eg. manual feed */
+ setencoding(fontencoding);
+ fprintf(stdout, "setup\n");
+
+ if ( formsperpage > 1 ) {
+ if ( cat(formfile) == FALSE )
+ error(FATAL, "can't read %s", formfile);
+ fprintf(stdout, "%d setupforms\n", formsperpage);
+ } /* End if */
+
+ fprintf(stdout, "%s", ENDSETUP);
+
+} /* End of setup */
+
+/*****************************************************************************/
+
+arguments()
+
+{
+
+/*
+ *
+ * Makes sure all the non-option command line arguments are processed. If we get
+ * here and there aren't any arguments left, or if '-' is one of the input files
+ * we'll process stdin.
+ *
+ */
+
+ fp_in = stdin;
+
+ if ( argc < 1 )
+ text();
+ else { /* at least one argument is left */
+ while ( argc > 0 ) {
+ if ( strcmp(*argv, "-") == 0 )
+ fp_in = stdin;
+ else if ( (fp_in = fopen(*argv, "r")) == NULL )
+ error(FATAL, "can't open %s", *argv);
+ text();
+ if ( fp_in != stdin )
+ fclose(fp_in);
+ argc--;
+ argv++;
+ } /* End while */
+ } /* End else */
+
+} /* End of arguments */
+
+/*****************************************************************************/
+
+done()
+
+{
+
+/*
+ *
+ * Finished with all the input files, so mark the end of the pages, make sure the
+ * last page is printed, and restore the initial environment.
+ *
+ */
+
+ fprintf(stdout, "%s", TRAILER);
+ fprintf(stdout, "done\n");
+ fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
+ fprintf(stdout, "%s %d\n", PAGES, printed);
+
+} /* End of done */
+
+/*****************************************************************************/
+
+account()
+
+{
+
+/*
+ *
+ * Writes an accounting record to *fp_acct provided it's not NULL. Accounting
+ * is requested using the -A or -J options.
+ *
+ */
+
+ if ( fp_acct != NULL )
+ fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
+
+} /* End of account */
+
+/*****************************************************************************/
+
+text()
+
+{
+
+ int ch; /* next input character */
+
+/*
+ *
+ * Translates the next input file into PostScript. The redirect(-1) call forces
+ * the initial output to go to /dev/null - so the stuff formfeed() does at the
+ * end of each page doesn't go to stdout.
+ *
+ */
+
+ redirect(-1); /* get ready for the first page */
+ formfeed(); /* force PAGE comment etc. */
+ inittabs();
+
+ while ( (ch = getc(fp_in)) != EOF )
+ switch ( ch ) {
+ case '\010': /* backspace */
+ backspace();
+ break;
+
+ case '\011': /* horizontal tab */
+ htab();
+ break;
+
+ case '\012': /* new line */
+ linefeed();
+ break;
+
+ case '\013': /* vertical tab */
+ vtab();
+ break;
+
+ case '\014': /* form feed */
+ formfeed();
+ break;
+
+ case '\015': /* carriage return */
+ carriage();
+ break;
+
+ case '\016': /* extended character set - SO */
+ break;
+
+ case '\017': /* extended character set - SI */
+ break;
+
+ case '\031': /* next char from supplementary set */
+ break;
+
+ case '\033': /* 2 or 3 byte escape sequence */
+ escape();
+ break;
+
+ default:
+ if ( isascii(ch) && isprint(ch) )
+ oput(ch);
+ break;
+ } /* End switch */
+
+ formfeed(); /* next file starts on a new page? */
+
+} /* End of text */
+
+/*****************************************************************************/
+
+inittabs()
+
+{
+
+ int i; /* loop index */
+
+/*
+ *
+ * Initializes the horizontal and vertical tab arrays. The way tabs are handled is
+ * quite inefficient and may not work for all initial hmi or vmi values.
+ *
+ */
+
+ for ( i = 0; i < COLUMNS; i++ )
+ htabstops[i] = ((i % 8) == 0) ? ON : OFF;
+
+ for ( i = 0; i < ROWS; i++ )
+ vtabstops[i] = ((i * ovmi) > BOTTOMMARGIN) ? ON : OFF;
+
+} /* End of inittabs */
+
+/*****************************************************************************/
+
+cleartabs()
+
+{
+
+ int i; /* loop index */
+
+/*
+ *
+ * Clears all horizontal and vertical tab stops.
+ *
+ */
+
+ for ( i = 0; i < ROWS; i++ )
+ htabstops[i] = OFF;
+
+ for ( i = 0; i < COLUMNS; i++ )
+ vtabstops[i] = OFF;
+
+} /* End of cleartabs */
+
+/*****************************************************************************/
+
+formfeed()
+
+{
+
+/*
+ *
+ * Called whenever we've finished with the last page and want to get ready for the
+ * next one. Also used at the beginning and end of each input file, so we have to
+ * be careful about what's done. I've added a simple test before the showpage that
+ * should eliminate the extra blank page that was put out at the end of many jobs,
+ * but the PAGES comments may be wrong.
+ *
+ */
+
+ if ( fp_out == stdout ) /* count the last page */
+ printed++;
+
+ endline(); /* print the last line */
+
+ fprintf(fp_out, "cleartomark\n");
+ if ( feof(fp_in) == 0 || markedpage == TRUE )
+ fprintf(fp_out, "showpage\n");
+ fprintf(fp_out, "saveobj restore\n");
+ fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
+
+ if ( ungetc(getc(fp_in), fp_in) == EOF )
+ redirect(-1);
+ else redirect(++page);
+
+ fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
+ fprintf(fp_out, "/saveobj save def\n");
+ fprintf(fp_out, "mark\n");
+ writerequest(printed+1, fp_out);
+ fprintf(fp_out, "%d pagesetup\n", printed+1);
+
+ vgoto(topmargin);
+ hgoto(leftmargin);
+
+ markedpage = FALSE;
+
+} /* End of formfeed */
+
+/*****************************************************************************/
+
+linefeed()
+
+{
+
+ int line = 0; /* current line - based on ovmi */
+
+/*
+ *
+ * Adjust our current vertical position. If we've passed the bottom of the page
+ * or exceeded the number of lines per page, print it and go to the upper left
+ * corner of the next page. This routine is also called from carriage() if crislf
+ * is ON.
+ *
+ */
+
+ vmot(vmi);
+
+ if ( lfiscr == ON )
+ hgoto(leftmargin);
+
+ if ( linespp > 0 ) /* means something so see where we are */
+ line = vpos / ovmi + 1;
+
+ if ( vpos > bottommargin || line > linespp )
+ formfeed();
+
+} /* End of linefeed */
+
+/*****************************************************************************/
+
+carriage()
+
+{
+
+/*
+ *
+ * Handles carriage return character. If crislf is ON we'll generate a line feed
+ * every time we get a carriage return character.
+ *
+ */
+
+ if ( shadowprint == ON ) /* back to normal mode */
+ changefont(fontname);
+
+ advance = 1;
+ shadowprint = OFF;
+
+ hgoto(leftmargin);
+
+ if ( crislf == ON )
+ linefeed();
+
+} /* End of carriage */
+
+/*****************************************************************************/
+
+htab()
+
+{
+
+ int col; /* 'column' we'll be at next */
+ int i; /* loop index */
+
+/*
+ *
+ * Tries to figure out where the next tab stop is. Wasn't positive about this
+ * one, since hmi can change. I'll assume columns are determined by the original
+ * value of hmi. That fixes them on the page, which seems to make more sense than
+ * letting them float all over the place.
+ *
+ */
+
+ endline();
+
+ col = hpos/ohmi + 1;
+ for ( i = col; i < ROWS; i++ )
+ if ( htabstops[i] == ON ) {
+ col = i;
+ break;
+ } /* End if */
+
+ hgoto(col * ohmi);
+ lastx = hpos;
+
+} /* End of htab */
+
+/*****************************************************************************/
+
+vtab()
+
+{
+
+ int line; /* line we'll be at next */
+ int i; /* loop index */
+
+/*
+ *
+ * Looks for the next vertical tab stop in the vtabstops[] array and moves to that
+ * line. If we don't find a tab we'll just move down one line - shouldn't happen.
+ *
+ */
+
+ endline();
+
+ line = vpos/ovmi + 1;
+ for ( i = line; i < COLUMNS; i++ )
+ if ( vtabstops[i] == ON ) {
+ line = i;
+ break;
+ } /* End if */
+
+ vgoto(line * ovmi);
+
+} /* End of vtab */
+
+/*****************************************************************************/
+
+backspace()
+
+{
+
+/*
+ *
+ * Moves backwards a distance equal to the current value of hmi, but don't go
+ * past the left margin.
+ *
+ */
+
+ endline();
+
+ if ( hpos - leftmargin >= hmi )
+ hmot(-hmi);
+ else hgoto(leftmargin); /* maybe just ignore the backspace?? */
+
+ lastx = hpos;
+
+} /* End of backspace */
+
+/*****************************************************************************/
+
+escape()
+
+{
+
+ int ch; /* control character */
+
+/*
+ *
+ * Handles special codes that are expected to follow an escape character. The
+ * initial escape character is followed by one or two bytes.
+ *
+ */
+
+ switch ( ch = getc(fp_in) ) {
+ case 'T': /* top margin */
+ topmargin = vpos;
+ break;
+
+ case 'L': /* bottom margin */
+ bottommargin = vpos;
+ break;
+
+ case 'C': /* clear top and bottom margins */
+ bottommargin = BOTTOMMARGIN;
+ topmargin = TOPMARGIN;
+ break;
+
+ case '9': /* left margin */
+ leftmargin = hpos;
+ break;
+
+ case '0': /* right margin */
+ rightmargin = hpos;
+ break;
+
+ case '1': /* set horizontal tab */
+ htabstops[hpos/ohmi] = ON;
+ break;
+
+ case '8': /* clear horizontal tab at hpos */
+ htabstops[hpos/ohmi] = OFF;
+ break;
+
+ case '-': /* set vertical tab */
+ vtabstops[vpos/ovmi] = ON;
+ break;
+
+ case '2': /* clear all tabs */
+ cleartabs();
+ break;
+
+ case '\014': /* set lines per page */
+ linespp = getc(fp_in);
+ break;
+
+ case '\037': /* set hmi to next byte minus 1 */
+ hmi = HSCALE * (getc(fp_in) - 1);
+ break;
+
+ case 'S': /* reset hmi to default */
+ hmi = ohmi;
+ break;
+
+ case '\011': /* move to column given by next byte */
+ hgoto((getc(fp_in)-1) * ohmi);
+ break;
+
+ case '?': /* do carriage return after line feed */
+ lfiscr = ON;
+ break;
+
+ case '!': /* don't generate carriage return */
+ lfiscr = OFF;
+ break;
+
+ case '5': /* forward print mode */
+ advance = 1;
+ break;
+
+ case '6': /* backward print mode */
+ advance = -1;
+ break;
+
+ case '\036': /* set vmi to next byte minus 1 */
+ vmi = VSCALE * (getc(fp_in) - 1);
+ break;
+
+ case '\013': /* move to line given by next byte */
+ vgoto((getc(fp_in)-1) * ovmi);
+ break;
+
+ case 'U': /* positive half line feed */
+ vmot(vmi/2);
+ break;
+
+ case 'D': /* negative half line feed */
+ vmot(-vmi/2);
+ break;
+
+ case '\012': /* negative line feed */
+ vmot(-vmi);
+ break;
+
+ case '\015': /* clear all margins */
+ bottommargin = BOTTOMMARGIN;
+ topmargin = TOPMARGIN;
+ leftmargin = BOTTOMMARGIN;
+ rightmargin = RIGHTMARGIN;
+ break;
+
+ case 'E': /* auto underscore - use italic font */
+ changefont("/Courier-Oblique");
+ break;
+
+ case 'R': /* disable auto underscore */
+ changefont(fontname);
+ break;
+
+ case 'O': /* bold/shadow printing */
+ case 'W':
+ changefont("/Courier-Bold");
+ shadowprint = ON;
+ break;
+
+ case '&': /* disable bold printing */
+ changefont(fontname);
+ shadowprint = OFF;
+ break;
+
+ case '/': /* ignored 2 byte escapes */
+ case '\\':
+ case '<':
+ case '>':
+ case '%':
+ case '=':
+ case '.':
+ case '4':
+ case 'A':
+ case 'B':
+ case 'M':
+ case 'N':
+ case 'P':
+ case 'Q':
+ case 'X':
+ case '\010':
+ break;
+
+ case ',': /* ignored 3 byte escapes */
+ case '\016':
+ case '\021':
+ getc(fp_in);
+ break;
+
+ case '3': /* graphics mode - should quit! */
+ case '7':
+ case 'G':
+ case 'V':
+ case 'Y':
+ case 'Z':
+ error(FATAL, "graphics mode is not implemented");
+ break;
+
+ default:
+ error(FATAL, "missing case for escape o%o\n", ch);
+ break;
+ } /* End switch */
+
+} /* End of escape */
+
+/*****************************************************************************/
+
+vmot(n)
+
+ int n; /* move this far vertically */
+
+{
+
+/*
+ *
+ * Move vertically n units from where we are.
+ *
+ */
+
+ vpos += n;
+
+} /* End of vmot */
+
+/*****************************************************************************/
+
+vgoto(n)
+
+ int n; /* new vertical position */
+
+{
+
+/*
+ *
+ * Moves to absolute vertical position n.
+ *
+ */
+
+ vpos = n;
+
+} /* End of vgoto */
+
+/*****************************************************************************/
+
+hmot(n)
+
+ int n; /* move this horizontally */
+
+{
+
+/*
+ *
+ * Moves horizontally n units from our current position.
+ *
+ */
+
+ hpos += n * advance;
+
+ if ( hpos < leftmargin )
+ hpos = leftmargin;
+
+} /* End of hmot */
+
+/*****************************************************************************/
+
+hgoto(n)
+
+ int n; /* go to this horizontal position */
+
+{
+
+/*
+ *
+ * Moves to absolute horizontal position n.
+ *
+ */
+
+ hpos = n;
+
+} /* End of hgoto */
+
+/*****************************************************************************/
+
+changefont(name)
+
+ char *name;
+
+{
+
+/*
+ *
+ * Changes the current font. Used to get in and out of auto underscore and bold
+ * printing.
+ *
+ */
+
+ endline();
+ fprintf(fp_out, "%s f\n", name);
+
+} /* End of changefont */
+
+/*****************************************************************************/
+
+startline()
+
+{
+
+/*
+ *
+ * Called whenever we want to be certain we're ready to start pushing characters
+ * into an open string on the stack. If stringcount is positive we've already
+ * started, so there's nothing to do. The first string starts in column 1.
+ *
+ */
+
+ if ( stringcount < 1 ) {
+ putc('(', fp_out);
+ stringstart = lastx = hpos;
+ lasty = vpos;
+ lasthmi = hmi;
+ lastc = -1;
+ prevx = -1;
+ stringcount = 1;
+ } /* End if */
+
+} /* End of startline */
+
+/*****************************************************************************/
+
+endline()
+
+{
+
+/*
+ *
+ * Generates a call to the PostScript procedure that processes the text on the
+ * the stack - provided stringcount is positive.
+ *
+ */
+
+ if ( stringcount > 0 )
+ fprintf(fp_out, ")%d %d %d t\n", stringstart, lasty, lasthmi);
+
+ stringcount = 0;
+
+} /* End of endline */
+
+/*****************************************************************************/
+
+endstring()
+
+{
+
+/*
+ *
+ * Takes the string we've been working on and adds it to the output file. Called
+ * when we need to adjust our horizontal position before starting a new string.
+ * Also called from endline() when we're done with the current line.
+ *
+ */
+
+ if ( stringcount > 0 ) {
+ fprintf(fp_out, ")%d(", stringstart);
+ lastx = stringstart = hpos;
+ stringcount++;
+ } /* End if */
+
+} /* End of endstring */
+
+/*****************************************************************************/
+
+oput(ch)
+
+ int ch; /* next output character */
+
+{
+
+/*
+ *
+ * Responsible for adding all printing characters from the input file to the
+ * open string on top of the stack. The only other characters that end up in
+ * that string are the quotes required for special characters. Reverse printing
+ * mode hasn't been tested but it should be close. hpos and lastx should disagree
+ * each time (except after startline() does something), and that should force a
+ * call to endstring() for every character.
+ *
+ */
+
+ if ( stringcount > 100 ) /* don't put too much on the stack */
+ endline();
+
+ if ( vpos != lasty )
+ endline();
+
+ if ( advance == -1 ) /* for reverse printing - move first */
+ hmot(hmi);
+
+ startline();
+
+ if ( lastc != ch || hpos != prevx ) {
+ if ( lastx != hpos )
+ endstring();
+
+ if ( ch == '\\' || ch == '(' || ch == ')' )
+ putc('\\', fp_out);
+ putc(ch, fp_out);
+
+ lastc = ch;
+ prevx = hpos;
+ lastx += lasthmi;
+ } /* End if */
+
+ if ( advance != -1 )
+ hmot(hmi);
+
+ markedpage = TRUE;
+
+} /* End of oput */
+
+/*****************************************************************************/
+
+redirect(pg)
+
+ int pg; /* next page we're printing */
+
+{
+
+ static FILE *fp_null = NULL; /* if output is turned off */
+
+/*
+ *
+ * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
+ * otherwise output goes to stdout.
+ *
+ */
+
+ if ( pg >= 0 && in_olist(pg) == ON )
+ fp_out = stdout;
+ else if ( (fp_out = fp_null) == NULL )
+ fp_out = fp_null = fopen("/dev/null", "w");
+
+} /* End of redirect */
+
+/*****************************************************************************/
+
diff --git a/sys/src/cmd/postscript/postdaisy/README b/sys/src/cmd/postscript/postdaisy/README
new file mode 100755
index 000000000..53c0485cc
--- /dev/null
+++ b/sys/src/cmd/postscript/postdaisy/README
@@ -0,0 +1,4 @@
+
+Diablo 630 to PostScript translator. Not terribly useful, and much has
+been omitted.
+
diff --git a/sys/src/cmd/postscript/postdaisy/mkfile b/sys/src/cmd/postscript/postdaisy/mkfile
new file mode 100755
index 000000000..e596ef0a6
--- /dev/null
+++ b/sys/src/cmd/postscript/postdaisy/mkfile
@@ -0,0 +1,62 @@
+BUILTINS=
+</$objtype/mkfile
+MAKE=mk
+
+SYSTEM=plan9
+VERSION=3.3.1
+
+ROOT=
+MAN1DIR=$ROOT/tmp
+POSTBIN=$ROOT/rc/bin/postscript/
+POSTLIB=$ROOT/sys/lib/postscript/prologues
+
+COMMONDIR=../common
+
+CC=pcc
+LD=pcc
+
+CFLAGS=-c -D$SYSTEM -D_POSIX_SOURCE -I$COMMONDIR -B
+LDFLAGS=
+
+all :V: $O.out
+
+install :V: $POSTBIN/$objtype/postdaisy $POSTLIB/postdaisy.ps $MAN1DIR/postdaisy.1
+
+installall :V:
+ for(objtype in $CPUS) { \
+ $MAKE 'MAKE=$MAKE' \
+ 'SYSTEM=$SYSTEM' 'VERSION=$VERSION' \
+ 'FONTDIR=$FONTDIR' 'HOSTDIR=$HOSTDIR' 'MAN1DIR=$MAN1DIR' \
+ 'POSTBIN=$POSTBIN' 'POSTLIB=$POSTLIB' 'TMACDIR=$TMACDIR' \
+ 'DKHOST=$DKHOST' 'DKSTREAMS=$DKSTREAMS' \
+ 'ROUNDPAGE=$ROUNDPAGE' \
+ 'CC=$CC' 'LD=$LD' 'CFLAGS=$CFLAGS' 'LDFLAGS=$LDFLAGS' \
+ install \
+ }
+
+clean :V:
+ rm -f *.$O
+
+clobber :V: clean
+ rm -f $O.out
+
+$POSTBIN/$objtype/postdaisy : $O.out
+ cp $prereq $target
+
+$POSTLIB/postdaisy.ps : postdaisy.ps
+ cp $prereq $target
+
+$MAN1DIR/postdaisy.1 : postdaisy.1
+ cp $prereq $target
+
+$O.out : postdaisy.$O $COMMONDIR/glob.$O $COMMONDIR/misc.$O $COMMONDIR/request.$O $COMMONDIR/getopt.$O
+ $LD $LDFLAGS $prereq
+
+%.$O: %.c
+ $CC $CFLAGS $stem.c
+
+postdaisy.$O : postdaisy.c postdaisy.h $COMMONDIR/comments.h $COMMONDIR/ext.h $COMMONDIR/gen.h $COMMONDIR/path.h
+
+
+common :V:
+ cd $COMMONDIR; $MAKE
diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.1 b/sys/src/cmd/postscript/postdaisy/postdaisy.1
new file mode 100755
index 000000000..a8716aa2e
--- /dev/null
+++ b/sys/src/cmd/postscript/postdaisy/postdaisy.1
@@ -0,0 +1,217 @@
+.ds dQ /usr/lib/postscript
+.TH POSTDAISY 1 "DWB 3.2"
+.SH NAME
+.B postdaisy
+\- PostScript translator for Diablo 630 files
+.SH SYNOPSIS
+\*(mBpostdaisy\f1
+.OP "" options []
+.OP "" files []
+.SH DESCRIPTION
+.B postdaisy
+translates Diablo 630 daisy-wheel
+.I files
+into PostScript and writes the results on the
+standard output.
+If no
+.I files
+are specified, or if
+.OP \-
+is one of the input
+.IR files ,
+the standard input is read.
+The following
+.I options
+are understood:
+.TP 0.75i
+.OP \-c num
+Print
+.I num
+copies of each page.
+By default only one copy is printed.
+.TP
+.OP \-f name
+Print
+.I files
+using font
+.IR name .
+Any PostScript font can be used,
+although the best results will only be
+obtained with constant width fonts.
+The default font is Courier.
+.TP
+.OP \-h num
+Set the initial horizontal motion index to
+.IR num .
+Determines the character advance and the default
+point size, unless the
+.OP \-s
+option is used.
+The default is 12.
+.TP
+.OP \-m num
+Magnify each logical page by the factor
+.IR num .
+Pages are scaled uniformly about the origin,
+which is located near the upper left corner of
+each page.
+The default magnification is 1.0.
+.TP
+.OP \-n num
+Print
+.I num
+logical pages on each piece of paper,
+where
+.I num
+can be any positive integer.
+By default
+.I num
+is set to 1.
+.TP
+.OP \-o list
+Print pages whose numbers are given in the comma-separated
+.IR list .
+The list contains single numbers
+.I N
+and ranges
+.IR N1\-\|N2 .
+A missing
+.I N1
+means the lowest numbered page, a missing
+.I N2
+means the highest.
+.TP
+.OP \-p mode
+Print
+.I files
+in either \*(mBportrait\fP or \*(mBlandscape\fP
+.IR mode .
+Only the first character of
+.I mode
+is significant.
+The default
+.I mode
+is \*(mBportrait\fP.
+.TP
+.OP \-r num
+Selects carriage return and line feed behavior.
+If
+.I num
+is 1 a line feed generates a carriage return.
+If
+.I num
+is 2 a carriage return generates a line feed.
+Setting
+.I num
+to 3 enables both modes.
+.TP
+.OP \-s num
+Use point size
+.I num
+instead of the default value set by the
+initial horizontal motion index.
+.TP
+.OP \-v num
+Set the initial vertical motion index to
+.IR num .
+The default is 8.
+.TP
+.OP \-x num
+Translate the origin
+.I num
+inches along the positive x axis.
+The default
+coordinate system has the origin fixed near the
+upper left corner of the page, with positive
+x to the right and positive y down the page.
+Positive
+.I num
+moves everything right.
+The default offset is 0.25 inches.
+.TP
+.OP \-y num
+Translate the origin
+.I num
+inches along the positive y axis.
+Positive
+.I num
+moves text down the page.
+The default offset is 0.25 inches.
+.TP
+.OP \-E name
+Set the character encoding for text fonts to
+.IR name .
+Requesting
+.I name
+means include file
+.MI \*(dQ/ name .enc \f1.
+A nonexistent encoding file is silently ignored.
+The default selects file
+.MR \*(dQ/Default.enc .
+.TP
+.OP \-L file
+Use
+.I file
+as the PostScript prologue.
+.br
+The default is
+.MR \*(dQ/postdaisy.ps .
+.PP
+Three options allow insertion of arbitrary PostScript
+at controlled points in the translation process:
+.TP 0.75i
+.OP \-C file
+Copy
+.I file
+to the output file;
+.I file
+must contain legitimate PostScript.
+.TP
+.OP \-P string
+Include
+.I string
+in output file;
+.I string
+must be legitimate PostScript.
+.TP
+.OP \-R action
+Requests special
+.I action
+(e.g.,
+.MR manualfeed )
+on a per page or global basis.
+The
+.I action
+string can be given as
+.IR request ,
+.IM request : page\f1\|,
+or
+.IM request : page : file\f1\|.
+If
+.I page
+is omitted or given as 0, the request
+applies to all pages.
+If
+.I file
+is omitted, the request
+lookup is done in
+.MR \*(dQ/ps.requests .
+.SH DIAGNOSTICS
+A 0 exit status is returned if
+.I files
+were successfully processed.
+.SH FILES
+.MW \*(dQ/postdaisy.ps
+.br
+.MW \*(dQ/forms.ps
+.br
+.MW \*(dQ/ps.requests
+.SH SEE ALSO
+.BR dpost (1),
+.BR postdmd (1),
+.BR postio (1),
+.BR postmd (1),
+.BR postprint (1),
+.BR postreverse (1),
+.BR posttek (1),
+.BR psencoding (1)
diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.c b/sys/src/cmd/postscript/postdaisy/postdaisy.c
new file mode 100755
index 000000000..8588cf9af
--- /dev/null
+++ b/sys/src/cmd/postscript/postdaisy/postdaisy.c
@@ -0,0 +1,1225 @@
+/*
+ *
+ * postdaisy - PostScript translator for Diablo 1640 files.
+ *
+ * A program that translates Diablo 1640 files into PostScript. Absolutely nothing
+ * is guaranteed. Quite a few things haven't been implemented, and what's been
+ * done isn't well tested. Most of the documentation used to write this program
+ * was taken from the 'Diablo Emulator' section of a recent Imagen manual.
+ *
+ * Some of document comments that are generated may not be right. Most of the test
+ * files I used produced a trailing blank page. I've put a check in formfeed() that
+ * won't print the last page if it doesn't contain any text, but PAGES comments may
+ * not be right. The DOCUMENTFONTS comment will also be wrong if auto underline or
+ * bold printing have been turned on by escape commands.
+ *
+ * The brute force approach used to implement horizontal and vertical tabs leaves
+ * much to be desired, and may not work for very small initial hmi and vmi values.
+ * At the very least I should have used malloc() to get space for the two tabstop
+ * arrays after hmi and vmi are known!
+ *
+ * Reverse printing mode hasn't been tested at all, but what's here should be
+ * close even though it's not efficient.
+ *
+ * The PostScript prologue is copied from *prologue before any of the input files
+ * are translated. The program expects that the following PostScript procedures
+ * are defined in that file:
+ *
+ * setup
+ *
+ * mark ... setup -
+ *
+ * Handles special initialization stuff that depends on how this program
+ * was called. Expects to find a mark followed by key/value pairs on the
+ * stack. The def operator is applied to each pair up to the mark, then
+ * the default state is set up.
+ *
+ * pagesetup
+ *
+ * page pagesetup -
+ *
+ * Does whatever is needed to set things up for the next page. Expects to
+ * find the current page number on the stack.
+ *
+ * t
+ *
+ * mark str1 x1 str2 x2 ... strn xn y hmi t mark
+ *
+ * Handles all the text on the stack. Characters in the strings are
+ * printed using hmi as the character advance, and all strings are at
+ * vertical position y. Each string is begins at the horizontal position
+ * that preceeds it.
+ *
+ * f
+ *
+ * font f -
+ *
+ * Use font f, where f is the full PostScript font name. Only used when
+ * we switch to auto underline (Courier-Italic) or bold (Courier-Bold)
+ * printing.
+ *
+ * done
+ *
+ * done
+ *
+ * Makes sure the last page is printed. Only needed when we're printing
+ * more than one page on each sheet of paper.
+ *
+ * Many default values, like the magnification and orientation, are defined in
+ * the prologue, which is where they belong. If they're changed (by options), an
+ * appropriate definition is made after the prologue is added to the output file.
+ * The -P option passes arbitrary PostScript through to the output file. Among
+ * other things it can be used to set (or change) values that can't be accessed by
+ * other options.
+ *
+ */
+
+#include <stdio.h>
+#include <signal.h>
+#include <ctype.h>
+#ifdef plan9
+#define isascii(c) ((unsigned char)(c)<=0177)
+#endif
+#include <sys/types.h>
+#include <fcntl.h>
+
+#include "comments.h" /* PostScript file structuring comments */
+#include "gen.h" /* general purpose definitions */
+#include "path.h" /* for the prologue */
+#include "ext.h" /* external variable declarations */
+#include "postdaisy.h" /* a few special definitions */
+
+char *optnames = "a:c:f:h:l:m:n:o:p:r:s:v:x:y:A:C:E:J:L:P:DI";
+
+char *prologue = POSTDAISY; /* default PostScript prologue */
+char *formfile = FORMFILE; /* stuff for multiple pages per sheet */
+
+int formsperpage = 1; /* page images on each piece of paper */
+int copies = 1; /* and this many copies of each sheet */
+
+char htabstops[COLUMNS]; /* horizontal */
+char vtabstops[ROWS]; /* and vertical tabs */
+
+int res = RES; /* input file resolution - sort of */
+
+int hmi = HMI; /* horizontal motion index - 1/120 inch */
+int vmi = VMI; /* vertical motion index - 1/48 inch */
+int ohmi = HMI; /* original hmi */
+int ovmi = VMI; /* and vmi - for tabs and char size */
+
+int hpos = 0; /* current horizontal */
+int vpos = 0; /* and vertical position */
+
+int lastx = -1; /* printer's last horizontal */
+int lasty = -1; /* and vertical position */
+int lasthmi = -1; /* hmi for current text strings */
+
+int lastc = -1; /* last printed character */
+int prevx = -1; /* at this position */
+
+int leftmargin = LEFTMARGIN; /* page margins */
+int rightmargin = RIGHTMARGIN;
+int topmargin = TOPMARGIN;
+int bottommargin = BOTTOMMARGIN;
+
+int stringcount = 0; /* number of strings on the stack */
+int stringstart = 1; /* column where current one starts */
+int advance = 1; /* -1 if in backward print mode */
+
+int lfiscr = OFF; /* line feed implies carriage return */
+int crislf = OFF; /* carriage return implies line feed */
+
+int linespp = 0; /* lines per page if it's positive */
+int markedpage = FALSE; /* helps prevent trailing blank page */
+int page = 0; /* page we're working on */
+int printed = 0; /* printed this many pages */
+
+Fontmap fontmap[] = FONTMAP; /* for translating font names */
+char *fontname = "Courier"; /* use this PostScript font */
+int shadowprint = OFF; /* automatic bold printing if ON */
+
+FILE *fp_in; /* read from this file */
+FILE *fp_out = stdout; /* and write stuff here */
+FILE *fp_acct = NULL; /* for accounting data */
+
+/*****************************************************************************/
+
+main(agc, agv)
+
+ int agc;
+ char *agv[];
+
+{
+
+/*
+ *
+ * A simple program that translates Diablo 1640 files into PostScript. Nothing
+ * is guaranteed - the program not well tested and doesn't implement everything.
+ *
+ */
+
+ argc = agc; /* other routines may want them */
+ argv = agv;
+
+ prog_name = argv[0]; /* really just for error messages */
+
+ init_signals(); /* sets up interrupt handling */
+ header(); /* PostScript header comments */
+ options(); /* handle the command line options */
+ setup(); /* for PostScript */
+ arguments(); /* followed by each input file */
+ done(); /* print the last page etc. */
+ account(); /* job accounting data */
+
+ exit(x_stat); /* not much could be wrong */
+
+} /* End of main */
+
+/*****************************************************************************/
+
+init_signals()
+
+{
+
+/*
+ *
+ * Makes sure we handle interrupts.
+ *
+ */
+
+ if ( signal(SIGINT, interrupt) == SIG_IGN ) {
+ signal(SIGINT, SIG_IGN);
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ } else {
+ signal(SIGHUP, interrupt);
+ signal(SIGQUIT, interrupt);
+ } /* End else */
+
+ signal(SIGTERM, interrupt);
+
+} /* End of init_signals */
+
+/*****************************************************************************/
+
+header()
+
+{
+
+ int ch; /* return value from getopt() */
+ int old_optind = optind; /* for restoring optind - should be 1 */
+
+/*
+ *
+ * Scans the option list looking for things, like the prologue file, that we need
+ * right away but could be changed from the default. Doing things this way is an
+ * attempt to conform to Adobe's latest file structuring conventions. In particular
+ * they now say there should be nothing executed in the prologue, and they have
+ * added two new comments that delimit global initialization calls. Once we know
+ * where things really are we write out the job header, follow it by the prologue,
+ * and then add the ENDPROLOG and BEGINSETUP comments.
+ *
+ */
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF )
+ if ( ch == 'L' )
+ prologue = optarg;
+ else if ( ch == '?' )
+ error(FATAL, "");
+
+ optind = old_optind; /* get ready for option scanning */
+
+ fprintf(stdout, "%s", CONFORMING);
+ fprintf(stdout, "%s %s\n", VERSION, PROGRAMVERSION);
+ fprintf(stdout, "%s %s\n", DOCUMENTFONTS, ATEND);
+ fprintf(stdout, "%s %s\n", PAGES, ATEND);
+ fprintf(stdout, "%s", ENDCOMMENTS);
+
+ if ( cat(prologue) == FALSE )
+ error(FATAL, "can't read %s", prologue);
+
+ if ( DOROUND )
+ cat(ROUNDPAGE);
+
+ fprintf(stdout, "%s", ENDPROLOG);
+ fprintf(stdout, "%s", BEGINSETUP);
+ fprintf(stdout, "mark\n");
+
+} /* End of header */
+
+/*****************************************************************************/
+
+options()
+
+{
+
+ int ch; /* return value from getopt() */
+ int n; /* for CR and LF modes */
+
+/*
+ *
+ * Reads and processes the command line options. Added the -P option so arbitrary
+ * PostScript code can be passed through. Expect it could be useful for changing
+ * definitions in the prologue for which options have not been defined.
+ *
+ * Although any PostScript font can be used, things will only work for constant
+ * width fonts.
+ *
+ */
+
+ while ( (ch = getopt(argc, argv, optnames)) != EOF ) {
+ switch ( ch ) {
+ case 'a': /* aspect ratio */
+ fprintf(stdout, "/aspectratio %s def\n", optarg);
+ break;
+
+ case 'c': /* copies */
+ copies = atoi(optarg);
+ fprintf(stdout, "/#copies %s store\n", optarg);
+ break;
+
+ case 'f': /* use this PostScript font */
+ fontname = get_font(optarg);
+ fprintf(stdout, "/font /%s def\n", fontname);
+ break;
+
+ case 'h': /* default character spacing */
+ ohmi = hmi = atoi(optarg) * HSCALE;
+ fprintf(stdout, "/hmi %s def\n", optarg);
+ break;
+
+ case 'l': /* lines per page */
+ linespp = atoi(optarg);
+ break;
+
+ case 'm': /* magnification */
+ fprintf(stdout, "/magnification %s def\n", optarg);
+ break;
+
+ case 'n': /* forms per page */
+ formsperpage = atoi(optarg);
+ fprintf(stdout, "%s %s\n", FORMSPERPAGE, optarg);
+ fprintf(stdout, "/formsperpage %s def\n", optarg);
+ break;
+
+ case 'o': /* output page list */
+ out_list(optarg);
+ break;
+
+ case 'p': /* landscape or portrait mode */
+ if ( *optarg == 'l' )
+ fprintf(stdout, "/landscape true def\n");
+ else fprintf(stdout, "/landscape false def\n");
+ break;
+
+ case 'r': /* set CR and LF modes */
+ n = atoi(optarg);
+ if ( n & 01 )
+ lfiscr = ON;
+ else lfiscr = OFF;
+ if ( n & 02 )
+ crislf = ON;
+ else crislf = OFF;
+ break;
+
+ case 's': /* point size */
+ fprintf(stdout, "/pointsize %s def\n", optarg);
+ break;
+
+ case 'v': /* default line spacing */
+ ovmi = vmi = atoi(optarg) * VSCALE;
+ break;
+
+ case 'x': /* shift things horizontally */
+ fprintf(stdout, "/xoffset %s def\n", optarg);
+ break;
+
+ case 'y': /* and vertically on the page */
+ fprintf(stdout, "/yoffset %s def\n", optarg);
+ break;
+
+ case 'A': /* force job accounting */
+ case 'J':
+ if ( (fp_acct = fopen(optarg, "a")) == NULL )
+ error(FATAL, "can't open accounting file %s", optarg);
+ break;
+
+ case 'C': /* copy file straight to output */
+ if ( cat(optarg) == FALSE )
+ error(FATAL, "can't read %s", optarg);
+ break;
+
+ case 'E': /* text font encoding */
+ fontencoding = optarg;
+ break;
+
+ case 'L': /* PostScript prologue file */
+ prologue = optarg;
+ break;
+
+ case 'P': /* PostScript pass through */
+ fprintf(stdout, "%s\n", optarg);
+ break;
+
+ case 'R': /* special global or page level request */
+ saverequest(optarg);
+ break;
+
+ case 'D': /* debug flag */
+ debug = ON;
+ break;
+
+ case 'I': /* ignore FATAL errors */
+ ignore = ON;
+ break;
+
+ case '?': /* don't understand the option */
+ error(FATAL, "");
+ break;
+
+ default: /* don't know what to do for ch */
+ error(FATAL, "missing case for option %c\n", ch);
+ break;
+ } /* End switch */
+ } /* End while */
+
+ argc -= optind; /* get ready for non-option args */
+ argv += optind;
+
+} /* End of options */
+
+/*****************************************************************************/
+
+char *get_font(name)
+
+ char *name; /* name the user asked for */
+
+{
+
+ int i; /* for looking through fontmap[] */
+
+/*
+ *
+ * Called from options() to map a user's font name into a legal PostScript name.
+ * If the lookup fails *name is returned to the caller. That should let you choose
+ * any PostScript font, although things will only work well for constant width
+ * fonts.
+ *
+ */
+
+ for ( i = 0; fontmap[i].name != NULL; i++ )
+ if ( strcmp(name, fontmap[i].name) == 0 )
+ return(fontmap[i].val);
+
+ return(name);
+
+} /* End of get_font */
+
+/*****************************************************************************/
+
+setup()
+
+{
+
+/*
+ *
+ * Handles things that must be done after the options are read but before the
+ * input files are processed.
+ *
+ */
+
+ writerequest(0, stdout); /* global requests eg. manual feed */
+ setencoding(fontencoding);
+ fprintf(stdout, "setup\n");
+
+ if ( formsperpage > 1 ) {
+ if ( cat(formfile) == FALSE )
+ error(FATAL, "can't read %s", formfile);
+ fprintf(stdout, "%d setupforms\n", formsperpage);
+ } /* End if */
+
+ fprintf(stdout, "%s", ENDSETUP);
+
+} /* End of setup */
+
+/*****************************************************************************/
+
+arguments()
+
+{
+
+/*
+ *
+ * Makes sure all the non-option command line arguments are processed. If we get
+ * here and there aren't any arguments left, or if '-' is one of the input files
+ * we'll process stdin.
+ *
+ */
+
+ fp_in = stdin;
+
+ if ( argc < 1 )
+ text();
+ else { /* at least one argument is left */
+ while ( argc > 0 ) {
+ if ( strcmp(*argv, "-") == 0 )
+ fp_in = stdin;
+ else if ( (fp_in = fopen(*argv, "r")) == NULL )
+ error(FATAL, "can't open %s", *argv);
+ text();
+ if ( fp_in != stdin )
+ fclose(fp_in);
+ argc--;
+ argv++;
+ } /* End while */
+ } /* End else */
+
+} /* End of arguments */
+
+/*****************************************************************************/
+
+done()
+
+{
+
+/*
+ *
+ * Finished with all the input files, so mark the end of the pages, make sure the
+ * last page is printed, and restore the initial environment.
+ *
+ */
+
+ fprintf(stdout, "%s", TRAILER);
+ fprintf(stdout, "done\n");
+ fprintf(stdout, "%s %s\n", DOCUMENTFONTS, fontname);
+ fprintf(stdout, "%s %d\n", PAGES, printed);
+
+} /* End of done */
+
+/*****************************************************************************/
+
+account()
+
+{
+
+/*
+ *
+ * Writes an accounting record to *fp_acct provided it's not NULL. Accounting
+ * is requested using the -A or -J options.
+ *
+ */
+
+ if ( fp_acct != NULL )
+ fprintf(fp_acct, " print %d\n copies %d\n", printed, copies);
+
+} /* End of account */
+
+/*****************************************************************************/
+
+text()
+
+{
+
+ int ch; /* next input character */
+
+/*
+ *
+ * Translates the next input file into PostScript. The redirect(-1) call forces
+ * the initial output to go to /dev/null - so the stuff formfeed() does at the
+ * end of each page doesn't go to stdout.
+ *
+ */
+
+ redirect(-1); /* get ready for the first page */
+ formfeed(); /* force PAGE comment etc. */
+ inittabs();
+
+ while ( (ch = getc(fp_in)) != EOF )
+ switch ( ch ) {
+ case '\010': /* backspace */
+ backspace();
+ break;
+
+ case '\011': /* horizontal tab */
+ htab();
+ break;
+
+ case '\012': /* new line */
+ linefeed();
+ break;
+
+ case '\013': /* vertical tab */
+ vtab();
+ break;
+
+ case '\014': /* form feed */
+ formfeed();
+ break;
+
+ case '\015': /* carriage return */
+ carriage();
+ break;
+
+ case '\016': /* extended character set - SO */
+ break;
+
+ case '\017': /* extended character set - SI */
+ break;
+
+ case '\031': /* next char from supplementary set */
+ break;
+
+ case '\033': /* 2 or 3 byte escape sequence */
+ escape();
+ break;
+
+ default:
+ oput(ch);
+ break;
+ } /* End switch */
+
+ formfeed(); /* next file starts on a new page? */
+
+} /* End of text */
+
+/*****************************************************************************/
+
+inittabs()
+
+{
+
+ int i; /* loop index */
+
+/*
+ *
+ * Initializes the horizontal and vertical tab arrays. The way tabs are handled is
+ * quite inefficient and may not work for all initial hmi or vmi values.
+ *
+ */
+
+ for ( i = 0; i < COLUMNS; i++ )
+ htabstops[i] = ((i % 8) == 0) ? ON : OFF;
+
+ for ( i = 0; i < ROWS; i++ )
+ vtabstops[i] = ((i * ovmi) > BOTTOMMARGIN) ? ON : OFF;
+
+} /* End of inittabs */
+
+/*****************************************************************************/
+
+cleartabs()
+
+{
+
+ int i; /* loop index */
+
+/*
+ *
+ * Clears all horizontal and vertical tab stops.
+ *
+ */
+
+ for ( i = 0; i < ROWS; i++ )
+ htabstops[i] = OFF;
+
+ for ( i = 0; i < COLUMNS; i++ )
+ vtabstops[i] = OFF;
+
+} /* End of cleartabs */
+
+/*****************************************************************************/
+
+formfeed()
+
+{
+
+/*
+ *
+ * Called whenever we've finished with the last page and want to get ready for the
+ * next one. Also used at the beginning and end of each input file, so we have to
+ * be careful about what's done. I've added a simple test before the showpage that
+ * should eliminate the extra blank page that was put out at the end of many jobs,
+ * but the PAGES comments may be wrong.
+ *
+ */
+
+ if ( fp_out == stdout ) /* count the last page */
+ printed++;
+
+ endline(); /* print the last line */
+
+ fprintf(fp_out, "cleartomark\n");
+ if ( feof(fp_in) == 0 || markedpage == TRUE )
+ fprintf(fp_out, "showpage\n");
+ fprintf(fp_out, "saveobj restore\n");
+ fprintf(fp_out, "%s %d %d\n", ENDPAGE, page, printed);
+
+ if ( ungetc(getc(fp_in), fp_in) == EOF )
+ redirect(-1);
+ else redirect(++page);
+
+ fprintf(fp_out, "%s %d %d\n", PAGE, page, printed+1);
+ fprintf(fp_out, "/saveobj save def\n");
+ fprintf(fp_out, "mark\n");
+ writerequest(printed+1, fp_out);
+ fprintf(fp_out, "%d pagesetup\n", printed+1);
+
+ vgoto(topmargin);
+ hgoto(leftmargin);
+
+ markedpage = FALSE;
+
+} /* End of formfeed */
+
+/*****************************************************************************/
+
+linefeed()
+
+{
+
+ int line = 0; /* current line - based on ovmi */
+
+/*
+ *
+ * Adjust our current vertical position. If we've passed the bottom of the page
+ * or exceeded the number of lines per page, print it and go to the upper left
+ * corner of the next page. This routine is also called from carriage() if crislf
+ * is ON.
+ *
+ */
+
+ vmot(vmi);
+
+ if ( lfiscr == ON )
+ hgoto(leftmargin);
+
+ if ( linespp > 0 ) /* means something so see where we are */
+ line = vpos / ovmi + 1;
+
+ if ( vpos > bottommargin || line > linespp )
+ formfeed();
+
+} /* End of linefeed */
+
+/*****************************************************************************/
+
+carriage()
+
+{
+
+/*
+ *
+ * Handles carriage return character. If crislf is ON we'll generate a line feed
+ * every time we get a carriage return character.
+ *
+ */
+
+ if ( shadowprint == ON ) /* back to normal mode */
+ changefont(fontname);
+
+ advance = 1;
+ shadowprint = OFF;
+
+ hgoto(leftmargin);
+
+ if ( crislf == ON )
+ linefeed();
+
+} /* End of carriage */
+
+/*****************************************************************************/
+
+htab()
+
+{
+
+ int col; /* 'column' we'll be at next */
+ int i; /* loop index */
+
+/*
+ *
+ * Tries to figure out where the next tab stop is. Wasn't positive about this
+ * one, since hmi can change. I'll assume columns are determined by the original
+ * value of hmi. That fixes them on the page, which seems to make more sense than
+ * letting them float all over the place.
+ *
+ */
+
+ endline();
+
+ col = hpos/ohmi + 1;
+ for ( i = col; i < ROWS; i++ )
+ if ( htabstops[i] == ON ) {
+ col = i;
+ break;
+ } /* End if */
+
+ hgoto(col * ohmi);
+ lastx = hpos;
+
+} /* End of htab */
+
+/*****************************************************************************/
+
+vtab()
+
+{
+
+ int line; /* line we'll be at next */
+ int i; /* loop index */
+
+/*
+ *
+ * Looks for the next vertical tab stop in the vtabstops[] array and moves to that
+ * line. If we don't find a tab we'll just move down one line - shouldn't happen.
+ *
+ */
+
+ endline();
+
+ line = vpos/ovmi + 1;
+ for ( i = line; i < COLUMNS; i++ )
+ if ( vtabstops[i] == ON ) {
+ line = i;
+ break;
+ } /* End if */
+
+ vgoto(line * ovmi);
+
+} /* End of vtab */
+
+/*****************************************************************************/
+
+backspace()
+
+{
+
+/*
+ *
+ * Moves backwards a distance equal to the current value of hmi, but don't go
+ * past the left margin.
+ *
+ */
+
+ endline();
+
+ if ( hpos - leftmargin >= hmi )
+ hmot(-hmi);
+ else hgoto(leftmargin); /* maybe just ignore the backspace?? */
+
+ lastx = hpos;
+
+} /* End of backspace */
+
+/*****************************************************************************/
+
+escape()
+
+{
+
+ int ch; /* control character */
+
+/*
+ *
+ * Handles special codes that are expected to follow an escape character. The
+ * initial escape character is followed by one or two bytes.
+ *
+ */
+
+ switch ( ch = getc(fp_in) ) {
+ case 'T': /* top margin */
+ topmargin = vpos;
+ break;
+
+ case 'L': /* bottom margin */
+ bottommargin = vpos;
+ break;
+
+ case 'C': /* clear top and bottom margins */
+ bottommargin = BOTTOMMARGIN;
+ topmargin = TOPMARGIN;
+ break;
+
+ case '9': /* left margin */
+ leftmargin = hpos;
+ break;
+
+ case '0': /* right margin */
+ rightmargin = hpos;
+ break;
+
+ case '1': /* set horizontal tab */
+ htabstops[hpos/ohmi] = ON;
+ break;
+
+ case '8': /* clear horizontal tab at hpos */
+ htabstops[hpos/ohmi] = OFF;
+ break;
+
+ case '-': /* set vertical tab */
+ vtabstops[vpos/ovmi] = ON;
+ break;
+
+ case '2': /* clear all tabs */
+ cleartabs();
+ break;
+
+ case '\014': /* set lines per page */
+ linespp = getc(fp_in);
+ break;
+
+ case '\037': /* set hmi to next byte minus 1 */
+ hmi = HSCALE * (getc(fp_in) - 1);
+ break;
+
+ case 'S': /* reset hmi to default */
+ hmi = ohmi;
+ break;
+
+ case '\011': /* move to column given by next byte */
+ hgoto((getc(fp_in)-1) * ohmi);
+ break;
+
+ case '?': /* do carriage return after line feed */
+ lfiscr = ON;
+ break;
+
+ case '!': /* don't generate carriage return */
+ lfiscr = OFF;
+ break;
+
+ case '5': /* forward print mode */
+ advance = 1;
+ break;
+
+ case '6': /* backward print mode */
+ advance = -1;
+ break;
+
+ case '\036': /* set vmi to next byte minus 1 */
+ vmi = VSCALE * (getc(fp_in) - 1);
+ break;
+
+ case '\013': /* move to line given by next byte */
+ vgoto((getc(fp_in)-1) * ovmi);
+ break;
+
+ case 'U': /* positive half line feed */
+ vmot(vmi/2);
+ break;
+
+ case 'D': /* negative half line feed */
+ vmot(-vmi/2);
+ break;
+
+ case '\012': /* negative line feed */
+ vmot(-vmi);
+ break;
+
+ case '\015': /* clear all margins */
+ bottommargin = BOTTOMMARGIN;
+ topmargin = TOPMARGIN;
+ leftmargin = BOTTOMMARGIN;
+ rightmargin = RIGHTMARGIN;
+ break;
+
+ case 'E': /* auto underscore - use italic font */
+ changefont("/Courier-Oblique");
+ break;
+
+ case 'R': /* disable auto underscore */
+ changefont(fontname);
+ break;
+
+ case 'O': /* bold/shadow printing */
+ case 'W':
+ changefont("/Courier-Bold");
+ shadowprint = ON;
+ break;
+
+ case '&': /* disable bold printing */
+ changefont(fontname);
+ shadowprint = OFF;
+ break;
+
+ case '/': /* ignored 2 byte escapes */
+ case '\\':
+ case '<':
+ case '>':
+ case '%':
+ case '=':
+ case '.':
+ case '4':
+ case 'A':
+ case 'B':
+ case 'M':
+ case 'N':
+ case 'P':
+ case 'Q':
+ case 'X':
+ case '\010':
+ break;
+
+ case ',': /* ignored 3 byte escapes */
+ case '\016':
+ case '\021':
+ getc(fp_in);
+ break;
+
+ case '3': /* graphics mode - should quit! */
+ case '7':
+ case 'G':
+ case 'V':
+ case 'Y':
+ case 'Z':
+ error(FATAL, "graphics mode is not implemented");
+ break;
+
+ default:
+ error(FATAL, "missing case for escape o%o\n", ch);
+ break;
+ } /* End switch */
+
+} /* End of escape */
+
+/*****************************************************************************/
+
+vmot(n)
+
+ int n; /* move this far vertically */
+
+{
+
+/*
+ *
+ * Move vertically n units from where we are.
+ *
+ */
+
+ vpos += n;
+
+} /* End of vmot */
+
+/*****************************************************************************/
+
+vgoto(n)
+
+ int n; /* new vertical position */
+
+{
+
+/*
+ *
+ * Moves to absolute vertical position n.
+ *
+ */
+
+ vpos = n;
+
+} /* End of vgoto */
+
+/*****************************************************************************/
+
+hmot(n)
+
+ int n; /* move this horizontally */
+
+{
+
+/*
+ *
+ * Moves horizontally n units from our current position.
+ *
+ */
+
+ hpos += n * advance;
+
+ if ( hpos < leftmargin )
+ hpos = leftmargin;
+
+} /* End of hmot */
+
+/*****************************************************************************/
+
+hgoto(n)
+
+ int n; /* go to this horizontal position */
+
+{
+
+/*
+ *
+ * Moves to absolute horizontal position n.
+ *
+ */
+
+ hpos = n;
+
+} /* End of hgoto */
+
+/*****************************************************************************/
+
+changefont(name)
+
+ char *name;
+
+{
+
+/*
+ *
+ * Changes the current font. Used to get in and out of auto underscore and bold
+ * printing.
+ *
+ */
+
+ endline();
+ fprintf(fp_out, "%s f\n", name);
+
+} /* End of changefont */
+
+/*****************************************************************************/
+
+startline()
+
+{
+
+/*
+ *
+ * Called whenever we want to be certain we're ready to start pushing characters
+ * into an open string on the stack. If stringcount is positive we've already
+ * started, so there's nothing to do. The first string starts in column 1.
+ *
+ */
+
+ if ( stringcount < 1 ) {
+ putc('(', fp_out);
+ stringstart = lastx = hpos;
+ lasty = vpos;
+ lasthmi = hmi;
+ lastc = -1;
+ prevx = -1;
+ stringcount = 1;
+ } /* End if */
+
+} /* End of startline */
+
+/*****************************************************************************/
+
+endline()
+
+{
+
+/*
+ *
+ * Generates a call to the PostScript procedure that processes the text on the
+ * the stack - provided stringcount is positive.
+ *
+ */
+
+ if ( stringcount > 0 )
+ fprintf(fp_out, ")%d %d %d t\n", stringstart, lasty, lasthmi);
+
+ stringcount = 0;
+
+} /* End of endline */
+
+/*****************************************************************************/
+
+endstring()
+
+{
+
+/*
+ *
+ * Takes the string we've been working on and adds it to the output file. Called
+ * when we need to adjust our horizontal position before starting a new string.
+ * Also called from endline() when we're done with the current line.
+ *
+ */
+
+ if ( stringcount > 0 ) {
+ fprintf(fp_out, ")%d(", stringstart);
+ lastx = stringstart = hpos;
+ stringcount++;
+ } /* End if */
+
+} /* End of endstring */
+
+/*****************************************************************************/
+
+oput(ch)
+
+ int ch; /* next output character */
+
+{
+
+/*
+ *
+ * Responsible for adding all printing characters from the input file to the
+ * open string on top of the stack. The only other characters that end up in
+ * that string are the quotes required for special characters. Reverse printing
+ * mode hasn't been tested but it should be close. hpos and lastx should disagree
+ * each time (except after startline() does something), and that should force a
+ * call to endstring() for every character.
+ *
+ */
+
+ if ( stringcount > 100 ) /* don't put too much on the stack */
+ endline();
+
+ if ( vpos != lasty )
+ endline();
+
+ if ( advance == -1 ) /* for reverse printing - move first */
+ hmot(hmi);
+
+ startline();
+
+ if ( lastc != ch || hpos != prevx ) {
+ if ( lastx != hpos )
+ endstring();
+
+ if ( isascii(ch) && isprint(ch) ) {
+ if ( ch == '\\' || ch == '(' || ch == ')' )
+ putc('\\', fp_out);
+ putc(ch, fp_out);
+ } else fprintf(fp_out, "\\%.3o", ch & 0377);
+
+ lastc = ch;
+ prevx = hpos;
+ lastx += lasthmi;
+ } /* End if */
+
+ if ( advance != -1 )
+ hmot(hmi);
+
+ markedpage = TRUE;
+
+} /* End of oput */
+
+/*****************************************************************************/
+
+redirect(pg)
+
+ int pg; /* next page we're printing */
+
+{
+
+ static FILE *fp_null = NULL; /* if output is turned off */
+
+/*
+ *
+ * If we're not supposed to print page pg, fp_out will be directed to /dev/null,
+ * otherwise output goes to stdout.
+ *
+ */
+
+ if ( pg >= 0 && in_olist(pg) == ON )
+ fp_out = stdout;
+ else if ( (fp_out = fp_null) == NULL )
+ fp_out = fp_null = fopen("/dev/null", "w");
+
+} /* End of redirect */
+
+/*****************************************************************************/
+
diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.h b/sys/src/cmd/postscript/postdaisy/postdaisy.h
new file mode 100755
index 000000000..e8eef0c16
--- /dev/null
+++ b/sys/src/cmd/postscript/postdaisy/postdaisy.h
@@ -0,0 +1,88 @@
+/*
+ *
+ * Definitions used by the PostScript translator for Diablo 1640 files.
+ *
+ * Diablo printers have horizontal and vertical resolutions of 120 and 48 dpi.
+ * We'll use a single resolution of 240 dpi and let the program scale horizontal
+ * and vertical positions by HSCALE and VSCALE.
+ *
+ */
+
+#define RES 240
+#define HSCALE 2
+#define VSCALE 5
+
+/*
+ *
+ * HMI is the default character spacing and VMI is the line spacing. Both values
+ * are in terms of the 240 dpi resolution.
+ *
+ */
+
+#define HMI (12 * HSCALE)
+#define VMI (8 * VSCALE)
+
+/*
+ *
+ * Paper dimensions don't seem to be all that important. They're just used to
+ * set the right and bottom margins. Both are given in terms of the 240 dpi
+ * resolution.
+ *
+ */
+
+#define LEFTMARGIN 0
+#define RIGHTMARGIN 3168
+#define TOPMARGIN 0
+#define BOTTOMMARGIN 2640
+
+/*
+ *
+ * ROWS and COLUMNS set the dimensions of the horizontal and vertical tab arrays.
+ * The way I've implemented both kinds of tabs leaves something to be desired, but
+ * it was simple and should be good enough for now. If arrays are going to be used
+ * to mark tab stops I probably should use malloc() to get enough space once the
+ * initial hmi and vmi are know.
+ *
+ */
+
+#define ROWS 400
+#define COLUMNS 200
+
+/*
+ *
+ * An array of type Fontmap helps convert font names requested by users into
+ * legitimate PostScript names. The array is initialized using FONTMAP, which must
+ * end with an entry that has NULL defined as its name field.
+ *
+ */
+
+typedef struct {
+ char *name; /* user's font name */
+ char *val; /* corresponding PostScript name */
+} Fontmap;
+
+#define FONTMAP \
+ \
+ { \
+ "R", "Courier", \
+ "I", "Courier-Oblique", \
+ "B", "Courier-Bold", \
+ "CO", "Courier", \
+ "CI", "Courier-Oblique", \
+ "CB", "Courier-Bold", \
+ "CW", "Courier", \
+ "PO", "Courier", \
+ "courier", "Courier", \
+ "cour", "Courier", \
+ "co", "Courier", \
+ NULL, NULL \
+ }
+
+/*
+ *
+ * Some of the non-integer functions in postdaisy.c.
+ *
+ */
+
+char *get_font();
+
diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.mk b/sys/src/cmd/postscript/postdaisy/postdaisy.mk
new file mode 100755
index 000000000..a771ccd6e
--- /dev/null
+++ b/sys/src/cmd/postscript/postdaisy/postdaisy.mk
@@ -0,0 +1,93 @@
+MAKE=/bin/make
+MAKEFILE=postdaisy.mk
+
+SYSTEM=V9
+VERSION=3.3.2
+
+GROUP=bin
+OWNER=bin
+
+MAN1DIR=/tmp
+POSTBIN=/usr/bin/postscript
+POSTLIB=/usr/lib/postscript
+
+COMMONDIR=../common
+
+CFLGS=-O
+LDFLGS=-s
+
+CFLAGS=$(CFLGS) -I$(COMMONDIR)
+LDFLAGS=$(LDFLGS)
+
+HFILES=postdaisy.h \
+ $(COMMONDIR)/comments.h\
+ $(COMMONDIR)/ext.h\
+ $(COMMONDIR)/gen.h\
+ $(COMMONDIR)/path.h
+
+OFILES=postdaisy.o\
+ $(COMMONDIR)/glob.o\
+ $(COMMONDIR)/misc.o\
+ $(COMMONDIR)/request.o
+
+all : postdaisy
+
+install : all
+ @if [ ! -d "$(POSTBIN)" ]; then \
+ mkdir $(POSTBIN); \
+ chmod 755 $(POSTBIN); \
+ chgrp $(GROUP) $(POSTBIN); \
+ chown $(OWNER) $(POSTBIN); \
+ fi
+ @if [ ! -d "$(POSTLIB)" ]; then \
+ mkdir $(POSTLIB); \
+ chmod 755 $(POSTLIB); \
+ chgrp $(GROUP) $(POSTLIB); \
+ chown $(OWNER) $(POSTLIB); \
+ fi
+ cp postdaisy $(POSTBIN)/postdaisy
+ @chmod 755 $(POSTBIN)/postdaisy
+ @chgrp $(GROUP) $(POSTBIN)/postdaisy
+ @chown $(OWNER) $(POSTBIN)/postdaisy
+ cp postdaisy.ps $(POSTLIB)/postdaisy.ps
+ @chmod 644 $(POSTLIB)/postdaisy.ps
+ @chgrp $(GROUP) $(POSTLIB)/postdaisy.ps
+ @chown $(OWNER) $(POSTLIB)/postdaisy.ps
+ cp postdaisy.1 $(MAN1DIR)/postdaisy.1
+ @chmod 644 $(MAN1DIR)/postdaisy.1
+ @chgrp $(GROUP) $(MAN1DIR)/postdaisy.1
+ @chown $(OWNER) $(MAN1DIR)/postdaisy.1
+
+clean :
+ rm -f *.o
+
+clobber : clean
+ rm -f postdaisy
+
+postdaisy : $(OFILES)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o postdaisy $(OFILES)
+
+postdaisy.o : $(HFILES)
+
+$(COMMONDIR)/glob.o\
+$(COMMONDIR)/misc.o\
+$(COMMONDIR)/request.o :
+ @cd $(COMMONDIR); $(MAKE) -f common.mk `basename $@`
+
+changes :
+ @trap "" 1 2 3 15; \
+ sed \
+ -e "s'^SYSTEM=.*'SYSTEM=$(SYSTEM)'" \
+ -e "s'^VERSION=.*'VERSION=$(VERSION)'" \
+ -e "s'^GROUP=.*'GROUP=$(GROUP)'" \
+ -e "s'^OWNER=.*'OWNER=$(OWNER)'" \
+ -e "s'^MAN1DIR=.*'MAN1DIR=$(MAN1DIR)'" \
+ -e "s'^POSTBIN=.*'POSTBIN=$(POSTBIN)'" \
+ -e "s'^POSTLIB=.*'POSTLIB=$(POSTLIB)'" \
+ $(MAKEFILE) >XXX.mk; \
+ mv XXX.mk $(MAKEFILE); \
+ sed \
+ -e "s'^.ds dQ.*'.ds dQ $(POSTLIB)'" \
+ postdaisy.1 >XXX.1; \
+ mv XXX.1 postdaisy.1
+
diff --git a/sys/src/cmd/postscript/postdaisy/postdaisy.ps b/sys/src/cmd/postscript/postdaisy/postdaisy.ps
new file mode 100755
index 000000000..eda3a9d35
--- /dev/null
+++ b/sys/src/cmd/postscript/postdaisy/postdaisy.ps
@@ -0,0 +1,74 @@
+%
+% Version 3.3.2 prologue for Diablo 1640 files.
+%
+
+/#copies 1 store
+/aspectratio 1 def
+/font /Courier def
+/formsperpage 1 def
+/hmi 12 def
+/landscape false def
+/magnification 1 def
+/margin 10 def
+/orientation 0 def
+/resolution 240 def
+/rotation 1 def
+/xoffset .25 def
+/yoffset .25 def
+
+/roundpage true def
+/useclippath true def
+/pagebbox [0 0 612 792] def
+
+/inch {72 mul} bind def
+/min {2 copy gt {exch} if pop} bind def
+
+/ashow {ashow} bind def % so later references don't bind
+/stringwidth {stringwidth} bind def
+
+/setup {
+ counttomark 2 idiv {def} repeat pop
+
+ landscape {/orientation 90 orientation add def} if
+ /scaling 72 resolution div def
+ currentdict /pointsize known not {/pointsize hmi def} if
+ font findfont pointsize scaling div scalefont setfont
+ /charwidth (M) stringwidth pop def
+
+ pagedimensions
+ xcenter ycenter translate
+ orientation rotation mul rotate
+ width 2 div neg height 2 div translate
+ xoffset inch yoffset inch neg translate
+ margin 2 div dup neg translate
+ magnification dup aspectratio mul scale
+ height width div 1 min dup scale
+ scaling dup scale
+} def
+
+/pagedimensions {
+ useclippath userdict /gotpagebbox known not and {
+ /pagebbox [clippath pathbbox newpath] def
+ roundpage currentdict /roundpagebbox known and {roundpagebbox} if
+ } if
+ pagebbox aload pop
+ 4 -1 roll exch 4 1 roll 4 copy
+ landscape {4 2 roll} if
+ sub /width exch def
+ sub /height exch def
+ add 2 div /xcenter exch def
+ add 2 div /ycenter exch def
+ userdict /gotpagebbox true put
+} def
+
+/pagesetup {/page exch def 0 0 moveto} bind def
+
+/t {
+ charwidth sub /advance exch def
+ neg /y exch def
+ counttomark 2 idiv {y moveto advance 0 3 -1 roll ashow} repeat
+} bind def
+
+/f {findfont pointsize scaling div scalefont setfont} bind def
+
+/done {/lastpage where {pop lastpage} if} def