diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/postscript/postdaisy |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/postscript/postdaisy')
-rwxr-xr-x | sys/src/cmd/postscript/postdaisy/Opostdaisy.c | 1222 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postdaisy/README | 4 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postdaisy/mkfile | 62 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postdaisy/postdaisy.1 | 217 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postdaisy/postdaisy.c | 1225 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postdaisy/postdaisy.h | 88 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postdaisy/postdaisy.mk | 93 | ||||
-rwxr-xr-x | sys/src/cmd/postscript/postdaisy/postdaisy.ps | 74 |
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 |