1*92970570Sslatteng /* dvar.c 1.15 85/08/05
2f92359bfSslatteng *
3f92359bfSslatteng * Varian driver for the new troff
4f92359bfSslatteng *
5f92359bfSslatteng * Authors: BWK(BELL)
6f92359bfSslatteng * VCAT(berkley)
7f92359bfSslatteng * Richard L. Hyde, Perdue University
84da297a9Sslatteng * and David Slattengren, U.C. Berkeley
9f92359bfSslatteng */
10f92359bfSslatteng
11f92359bfSslatteng
12f92359bfSslatteng /*******************************************************************************
13f92359bfSslatteng
14f92359bfSslatteng output language from troff:
15f92359bfSslatteng all numbers are character strings
16f92359bfSslatteng
17f92359bfSslatteng #..\n comment
18f92359bfSslatteng sn size in points
19f92359bfSslatteng fn font as number from 1 to n
2069c7ec87Sslatteng in stipple `font' as number from 1 to n
21f92359bfSslatteng cx ascii character x
22f92359bfSslatteng Cxyz funny char \(xyz. terminated by white space
23f92359bfSslatteng Hn go to absolute horizontal position n
24f92359bfSslatteng Vn go to absolute vertical position n (down is positive)
25f92359bfSslatteng hn go n units horizontally (relative)
26f92359bfSslatteng vn ditto vertically
27f92359bfSslatteng nnc move right nn, then print c (exactly 2 digits!)
28f92359bfSslatteng (this wart is an optimization that shrinks output file size
29f92359bfSslatteng about 35% and run-time about 15% while preserving ascii-ness)
30f92359bfSslatteng p new page begins -- set v to 0
31f92359bfSslatteng nb a end of line (information only -- no action needed)
32f92359bfSslatteng b = space before line, a = after
33f92359bfSslatteng w paddable word space -- no action needed
34f92359bfSslatteng
35f92359bfSslatteng Dt ..\n draw operation 't':
3669c7ec87Sslatteng Dt d set line thickness to d
3769c7ec87Sslatteng Ds d set line style (mask) to d
38f92359bfSslatteng Dl x y line from here by x,y
39f92359bfSslatteng Dc d circle of diameter d with left side here
40f92359bfSslatteng De x y ellipse of axes x,y with left side here
41f92359bfSslatteng Da x y r arc counter-clockwise by x,y of radius r
42f92359bfSslatteng D~ x y x y ... B-spline curve by x,y then x,y ...
4369c7ec87Sslatteng Dg x y x y ... gremlin spline curve by x,y then x,y ...
4469c7ec87Sslatteng Dp s x y ... polygon by x,y then ... filled with stipple s
45f92359bfSslatteng
46f92359bfSslatteng x ..\n device control functions:
47f92359bfSslatteng x i init
48f92359bfSslatteng x T s name of device is s
49f92359bfSslatteng x r n h v resolution is n/inch h = min horizontal motion, v = min vert
50f92359bfSslatteng x p pause (can restart)
51f92359bfSslatteng x s stop -- done for ever
52f92359bfSslatteng x t generate trailer
53f92359bfSslatteng x f n s font position n contains font s
54f92359bfSslatteng x H n set character height to n
55f92359bfSslatteng x S n set slant to N
56f92359bfSslatteng
57f92359bfSslatteng Subcommands like "i" are often spelled out like "init".
58f92359bfSslatteng
59f92359bfSslatteng *******************************************************************************/
60f92359bfSslatteng
61f92359bfSslatteng
62f92359bfSslatteng #include <stdio.h>
63f92359bfSslatteng #include <ctype.h>
64f92359bfSslatteng #include <sys/vcmd.h>
65f92359bfSslatteng #include "dev.h"
66f92359bfSslatteng
67f92359bfSslatteng
681c9df754Sslatteng /* #define DEBUGABLE /* No, not debugable... */
691c9df754Sslatteng #define DRIVER /* Yes, we're driving directly */
701c9df754Sslatteng /* #define FULLPAGE /* No, don't output full pages */
7169c7ec87Sslatteng #define NFONTS 65 /* total number of fonts useable */
72f92359bfSslatteng #define MAXSTATE 6 /* number of environments rememberable */
73f92359bfSslatteng #define OPENREAD 0 /* mode for openning files */
74f92359bfSslatteng #define RESTART 1 /* upon exit, return either RESTART */
75f92359bfSslatteng #define ABORT 2 /* or ABORT */
76f92359bfSslatteng #define FATAL 1 /* type of error */
77f92359bfSslatteng #define BMASK 0377 /* byte grabber */
7822d5b456Sslatteng #ifndef FONTDIR
794da297a9Sslatteng #define FONTDIR "/usr/lib/font" /* default place to find font descriptions */
8022d5b456Sslatteng #endif
815b07345cSslatteng #ifndef BITDIR
824da297a9Sslatteng #define BITDIR "/usr/lib/vfont" /* default place to look for font rasters */
835b07345cSslatteng #endif
84f92359bfSslatteng #define MAXWRIT 4096 /* max characters allowed to write at once */
85f92359bfSslatteng
86ebd02298Sslatteng #define hmot(n) hgoto(hpos + n)
87f92359bfSslatteng #define vmot(n) vgoto(vpos + n)
88f92359bfSslatteng
89f92359bfSslatteng
90*92970570Sslatteng char SccsId[]= "dvar.c 1.15 85/08/05";
91f92359bfSslatteng
92f92359bfSslatteng int output = 0; /* do we do output at all? */
93f92359bfSslatteng int nolist = 0; /* output page list if > 0 */
94f92359bfSslatteng int olist[20]; /* pairs of page numbers */
95f92359bfSslatteng int spage = 9999; /* stop every spage pages */
96f92359bfSslatteng int scount = 0;
97f92359bfSslatteng struct dev dev;
98f92359bfSslatteng struct font *fontbase[NFONTS+1];
99f92359bfSslatteng short * pstab; /* point size table pointer */
100f92359bfSslatteng int nsizes; /* number of sizes device is capable of printing */
101f92359bfSslatteng int nfonts; /* number of fonts device is capable of printing */
10269c7ec87Sslatteng int nstips; /* number of stipple fonts device can print */
103f92359bfSslatteng int nchtab;
104f92359bfSslatteng char * chname;
105f92359bfSslatteng short * chtab;
1064da297a9Sslatteng char * fitab[NFONTS+1]; /* font inclusion table - maps ascii to ch # */
1074da297a9Sslatteng char * widtab[NFONTS+1]; /* width table for each font */
108f92359bfSslatteng char * codetab[NFONTS+1]; /* device codes */
1094da297a9Sslatteng char * fontdir = FONTDIR; /* place to find devxxx directories */
1104da297a9Sslatteng char * bitdir = BITDIR; /* place to find raster fonts and fontmap */
1111c9df754Sslatteng char * fontname[NFONTS+1]; /* table of what font is on what position */
1124da297a9Sslatteng struct { /* table of what font */
1134da297a9Sslatteng char fname[3]; /* name maps to what */
1144da297a9Sslatteng char *ffile; /* filename in bitdirectory */
1154da297a9Sslatteng } fontmap[NFONTS+1];
1164da297a9Sslatteng
117f92359bfSslatteng
118f92359bfSslatteng #ifdef DEBUGABLE
119f92359bfSslatteng int dbg = 0;
120f92359bfSslatteng #endif
1214da297a9Sslatteng int size = -1; /* current point size (internal pstable index) */
122f92359bfSslatteng int font = -1; /* current font - not using any to start with */
12369c7ec87Sslatteng int stip = -1; /* current stipple font - not using any to start with */
12469c7ec87Sslatteng int stipmem = 0; /* current member to use from stipple font */
125f92359bfSslatteng int hpos; /* horizontal position we are to be at next; left = 0 */
126f92359bfSslatteng int vpos; /* current vertical position (down positive) */
1274da297a9Sslatteng extern linethickness; /* thickness (in pixels) of any drawn object */
128ebd02298Sslatteng extern linmod; /* line style (a bit mask - dotted, etc.) of objects */
129f92359bfSslatteng int lastw; /* width of last character printed */
130f92359bfSslatteng
131f92359bfSslatteng
132f92359bfSslatteng #define DISPATCHSIZE 256 /* must be a power of two */
133f92359bfSslatteng #define CHARMASK (DISPATCHSIZE-1)
134f92359bfSslatteng #define DSIZ ((sizeof *dispatch)*DISPATCHSIZE)
135f92359bfSslatteng #define OUTFILE fileno (stdout)
1364da297a9Sslatteng #define RES 200 /* resolution of the device (dots/in) */
137f92359bfSslatteng
1381a4ecc79Sslatteng #define RASTER_LENGTH 2112 /* device line length */
139f92359bfSslatteng #define BYTES_PER_LINE (RASTER_LENGTH/8)
1401c9df754Sslatteng #ifndef FULLPAGE
1411c9df754Sslatteng # define NLINES 1600 /* page width, 8 inches */
1421c9df754Sslatteng #endif
1431c9df754Sslatteng #ifdef FULLPAGE
144ebd02298Sslatteng # define NLINES 1700 /* page width, 8.5 inches */
1451c9df754Sslatteng #endif
146f92359bfSslatteng #define BUFFER_SIZE (NLINES*BYTES_PER_LINE) /* number of chars in picture */
147f92359bfSslatteng
148f92359bfSslatteng
149f92359bfSslatteng int pltmode[] = { VPLOT };
150f92359bfSslatteng int prtmode[] = { VPRINT };
151cb97edc8Sslatteng char buffer1[BUFFER_SIZE]; /* Big line buffers */
152cb97edc8Sslatteng char buffer2[BUFFER_SIZE];
153cb97edc8Sslatteng char * fill = &buffer1[0]; /* Zero origin in filling buffer */
154cb97edc8Sslatteng char * empty = &buffer2[0]; /* Zero origin in emptying buffer */
155cb97edc8Sslatteng char * elevel = &buffer2[0]; /* current position in emptying buffer */
156cb97edc8Sslatteng int emptypos = NLINES; /* amount of emptying done (initially "done") */
157cb97edc8Sslatteng
158f92359bfSslatteng
159f92359bfSslatteng char * calloc();
160f92359bfSslatteng char * nalloc();
161f92359bfSslatteng char * allpanic();
1624dabf413Sslatteng char * operand();
163f92359bfSslatteng
164f92359bfSslatteng struct header {
165f92359bfSslatteng short magic;
166f92359bfSslatteng unsigned short size;
167f92359bfSslatteng short maxx;
168f92359bfSslatteng short maxy;
169f92359bfSslatteng short xtnd;
170f92359bfSslatteng } header;
171f92359bfSslatteng
172f92359bfSslatteng struct dispatch{
173f92359bfSslatteng unsigned short addr;
174f92359bfSslatteng short nbytes;
175f92359bfSslatteng char up;
176f92359bfSslatteng char down;
177f92359bfSslatteng char left;
178f92359bfSslatteng char right;
179f92359bfSslatteng short width;
180f92359bfSslatteng };
181f92359bfSslatteng
182f92359bfSslatteng struct fontdes {
183cb97edc8Sslatteng int fnum; /* if == -1, then this position is empty */
184f92359bfSslatteng int psize;
185f92359bfSslatteng struct dispatch *disp;
186f92359bfSslatteng char *bits;
187cb97edc8Sslatteng } fontdes[NFONTS+1]; /* initialized at program start */
188f92359bfSslatteng
189f92359bfSslatteng struct dispatch *dispatch;
19069c7ec87Sslatteng struct dispatch *stip_disp;
191f92359bfSslatteng int cfnum = -1;
192f92359bfSslatteng int cpsize = 10;
193f92359bfSslatteng int cfont = 1;
194f92359bfSslatteng char *bits;
19569c7ec87Sslatteng char *stip_bits;
19669c7ec87Sslatteng int bordered = 1; /* flag: "do polygons get bordered?" */
197f92359bfSslatteng int fontwanted = 1; /* flag: "has a new font been requested?" */
198f92359bfSslatteng int nfontnum = -1;
199f92359bfSslatteng int npsize = 10;
200f92359bfSslatteng
201f92359bfSslatteng
202f92359bfSslatteng
main(argc,argv)203f92359bfSslatteng main(argc, argv)
204f92359bfSslatteng char *argv[];
205f92359bfSslatteng {
206cb97edc8Sslatteng register FILE *fp;
207cb97edc8Sslatteng register int i;
208f92359bfSslatteng
209cb97edc8Sslatteng for (i = 0; i <= NFONTS; fontdes[i++].fnum = -1);
2104dabf413Sslatteng while (--argc > 0 && **++argv == '-') {
2114dabf413Sslatteng switch ((*argv)[1]) {
212f92359bfSslatteng case 'F':
2131c9df754Sslatteng bitdir = operand(&argc, &argv);
2144da297a9Sslatteng break;
2154da297a9Sslatteng case 'f':
2161c9df754Sslatteng fontdir = operand(&argc, &argv);
217f92359bfSslatteng break;
218f92359bfSslatteng case 'o':
2194dabf413Sslatteng outlist(operand(&argc, &argv));
220f92359bfSslatteng break;
221f92359bfSslatteng #ifdef DEBUGABLE
222f92359bfSslatteng case 'd':
2234dabf413Sslatteng dbg = atoi(operand(&argc, &argv));
224f92359bfSslatteng if (dbg == 0) dbg = 1;
225f92359bfSslatteng break;
226f92359bfSslatteng #endif
227f92359bfSslatteng case 's':
2284dabf413Sslatteng spage = atoi(operand(&argc, &argv));
229f92359bfSslatteng if (spage <= 0)
230f92359bfSslatteng spage = 9999;
231f92359bfSslatteng break;
232f92359bfSslatteng }
233f92359bfSslatteng }
234f92359bfSslatteng
2351c9df754Sslatteng #ifdef DRIVER
236f92359bfSslatteng ioctl(OUTFILE, VSETSTATE, pltmode);
2371c9df754Sslatteng #endif
238f92359bfSslatteng
2394dabf413Sslatteng if (argc < 1)
240f92359bfSslatteng conv(stdin);
241f92359bfSslatteng else
2424dabf413Sslatteng while (argc--) {
2434dabf413Sslatteng if (strcmp(*argv, "-") == 0)
244f92359bfSslatteng fp = stdin;
245f92359bfSslatteng else if ((fp = fopen(*argv, "r")) == NULL)
246f92359bfSslatteng error(FATAL, "can't open %s", *argv);
247f92359bfSslatteng conv(fp);
248f92359bfSslatteng fclose(fp);
2494dabf413Sslatteng argv++;
250f92359bfSslatteng }
251f92359bfSslatteng exit(0);
252f92359bfSslatteng }
253f92359bfSslatteng
2544dabf413Sslatteng
2554dabf413Sslatteng /*----------------------------------------------------------------------------*
2564dabf413Sslatteng | Routine: char * operand (& argc, & argv)
2574dabf413Sslatteng |
2584dabf413Sslatteng | Results: returns address of the operand given with a command-line
2594dabf413Sslatteng | option. It uses either "-Xoperand" or "-X operand", whichever
2604dabf413Sslatteng | is present. The program is terminated if no option is present.
2614dabf413Sslatteng |
2624dabf413Sslatteng | Side Efct: argc and argv are updated as necessary.
2634dabf413Sslatteng *----------------------------------------------------------------------------*/
2644dabf413Sslatteng
operand(argcp,argvp)2654dabf413Sslatteng char *operand(argcp, argvp)
2664dabf413Sslatteng int * argcp;
2674dabf413Sslatteng char ***argvp;
2684dabf413Sslatteng {
2694dabf413Sslatteng if ((**argvp)[2]) return(**argvp + 2); /* operand immediately follows */
2704dabf413Sslatteng if ((--*argcp) <= 0) /* no operand */
2714dabf413Sslatteng error (FATAL, "command-line option operand missing.\n");
2724dabf413Sslatteng return(*(++(*argvp))); /* operand next word */
2734dabf413Sslatteng }
2744dabf413Sslatteng
2754dabf413Sslatteng
outlist(s)276f92359bfSslatteng outlist(s) /* process list of page numbers to be printed */
277f92359bfSslatteng char *s;
278f92359bfSslatteng {
279f92359bfSslatteng int n1, n2, i;
280f92359bfSslatteng
281f92359bfSslatteng nolist = 0;
282f92359bfSslatteng while (*s) {
283f92359bfSslatteng n1 = 0;
284f92359bfSslatteng if (isdigit(*s))
285f92359bfSslatteng do
286f92359bfSslatteng n1 = 10 * n1 + *s++ - '0';
287f92359bfSslatteng while (isdigit(*s));
288f92359bfSslatteng else
289f92359bfSslatteng n1 = -9999;
290f92359bfSslatteng n2 = n1;
291f92359bfSslatteng if (*s == '-') {
292f92359bfSslatteng s++;
293f92359bfSslatteng n2 = 0;
294f92359bfSslatteng if (isdigit(*s))
295f92359bfSslatteng do
296f92359bfSslatteng n2 = 10 * n2 + *s++ - '0';
297f92359bfSslatteng while (isdigit(*s));
298f92359bfSslatteng else
299f92359bfSslatteng n2 = 9999;
300f92359bfSslatteng }
301f92359bfSslatteng olist[nolist++] = n1;
302f92359bfSslatteng olist[nolist++] = n2;
303f92359bfSslatteng if (*s != '\0')
304f92359bfSslatteng s++;
305f92359bfSslatteng }
306f92359bfSslatteng olist[nolist] = 0;
307f92359bfSslatteng #ifdef DEBUGABLE
308f92359bfSslatteng if (dbg)
309f92359bfSslatteng for (i=0; i<nolist; i += 2)
310f92359bfSslatteng fprintf(stderr,"%3d %3d\n", olist[i], olist[i+1]);
311f92359bfSslatteng #endif
312f92359bfSslatteng }
313f92359bfSslatteng
conv(fp)314f92359bfSslatteng conv(fp)
315f92359bfSslatteng register FILE *fp;
316f92359bfSslatteng {
317f92359bfSslatteng register int c, k;
318f92359bfSslatteng int m, n, n1, m1;
319f92359bfSslatteng char str[100], buf[300];
320f92359bfSslatteng
321f92359bfSslatteng while ((c = getc(fp)) != EOF) {
322f92359bfSslatteng switch (c) {
323f92359bfSslatteng case '\n': /* when input is text */
324f92359bfSslatteng case ' ':
325f92359bfSslatteng case 0: /* occasional noise creeps in */
326f92359bfSslatteng break;
327f92359bfSslatteng case '{': /* push down current environment */
328f92359bfSslatteng t_push();
329f92359bfSslatteng break;
330f92359bfSslatteng case '}':
331f92359bfSslatteng t_pop();
332f92359bfSslatteng break;
333f92359bfSslatteng case '0': case '1': case '2': case '3': case '4':
334f92359bfSslatteng case '5': case '6': case '7': case '8': case '9':
335f92359bfSslatteng /* two motion digits plus a character */
336f92359bfSslatteng hmot((c-'0')*10 + getc(fp)-'0');
337f92359bfSslatteng put1(getc(fp));
338f92359bfSslatteng break;
339f92359bfSslatteng case 'c': /* single ascii character */
340f92359bfSslatteng put1(getc(fp));
341f92359bfSslatteng break;
342f92359bfSslatteng case 'C':
343f92359bfSslatteng fscanf(fp, "%s", str);
344f92359bfSslatteng put1s(str);
345f92359bfSslatteng break;
346f92359bfSslatteng case 't': /* straight text */
347f92359bfSslatteng fgets(buf, sizeof(buf), fp);
348f92359bfSslatteng t_text(buf);
349f92359bfSslatteng break;
350f92359bfSslatteng case 'D': /* draw function */
351289ea231Sslatteng if (fgets(buf, sizeof(buf), fp) == NULL)
352289ea231Sslatteng error(FATAL, "unexpected end of input");;
353f92359bfSslatteng switch (buf[0]) {
354f92359bfSslatteng case 'l': /* draw a line */
355f92359bfSslatteng sscanf(buf+1, "%d %d", &n, &m);
356f92359bfSslatteng drawline(n, m);
357f92359bfSslatteng break;
358f92359bfSslatteng case 'c': /* circle */
359f92359bfSslatteng sscanf(buf+1, "%d", &n);
360f92359bfSslatteng drawcirc(n);
361f92359bfSslatteng break;
362f92359bfSslatteng case 'e': /* ellipse */
363f92359bfSslatteng sscanf(buf+1, "%d %d", &m, &n);
364f92359bfSslatteng drawellip(m, n);
365f92359bfSslatteng break;
366f92359bfSslatteng case 'a': /* arc */
367f92359bfSslatteng sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1);
368f92359bfSslatteng drawarc(n, m, n1, m1);
369f92359bfSslatteng break;
37069c7ec87Sslatteng case 'P': /* unbordered polygon */
37169c7ec87Sslatteng bordered = 0; /* unset border flag */
37269c7ec87Sslatteng case 'p': /* polygon */
37369c7ec87Sslatteng sscanf(buf+1, "%d", &m); /* get stipple */
37469c7ec87Sslatteng n = 1; /* number first */
37569c7ec87Sslatteng while (buf[++n] == ' ');
37669c7ec87Sslatteng while (isdigit(buf[++n]));
37769c7ec87Sslatteng setfill(m); /* set up stipple */
37869c7ec87Sslatteng drawwig(buf+n, fp, -1); /* draw polygon */
37969c7ec87Sslatteng bordered = 1; /* ALWAYS set after */
38069c7ec87Sslatteng break;
381f92359bfSslatteng case '~': /* wiggly line */
38269c7ec87Sslatteng drawwig(buf+1, fp, 1);
38369c7ec87Sslatteng break;
3841a4ecc79Sslatteng case 'g': /* gremlin spline */
38569c7ec87Sslatteng drawwig(buf+1, fp, 0);
3861a4ecc79Sslatteng break;
3871a4ecc79Sslatteng case 't': /* line thickness */
3881a4ecc79Sslatteng sscanf(buf+1, "%d", &n);
3891a4ecc79Sslatteng drawthick(n);
3901a4ecc79Sslatteng break;
3911a4ecc79Sslatteng case 's': /* line style */
3921a4ecc79Sslatteng sscanf(buf+1, "%d", &n);
3931a4ecc79Sslatteng drawstyle(n);
394f92359bfSslatteng break;
395f92359bfSslatteng default:
396ebd02298Sslatteng error(FATAL, "unknown drawing function %s", buf);
397f92359bfSslatteng break;
398f92359bfSslatteng }
399f92359bfSslatteng break;
400f92359bfSslatteng case 's':
401f92359bfSslatteng fscanf(fp, "%d", &n); /* ignore fractional sizes */
402f92359bfSslatteng setsize(t_size(n));
403f92359bfSslatteng break;
404f92359bfSslatteng case 'f':
405f92359bfSslatteng fscanf(fp, "%s", str);
406f92359bfSslatteng setfont(t_font(str));
407f92359bfSslatteng break;
40869c7ec87Sslatteng case 'i':
40969c7ec87Sslatteng fscanf(fp, "%d", &n);
41069c7ec87Sslatteng setstip(n);
41169c7ec87Sslatteng break;
412f92359bfSslatteng case 'H': /* absolute horizontal motion */
413f92359bfSslatteng /* fscanf(fp, "%d", &n); */
414f92359bfSslatteng while ((c = getc(fp)) == ' ')
415f92359bfSslatteng ;
416f92359bfSslatteng k = 0;
417f92359bfSslatteng do {
418f92359bfSslatteng k = 10 * k + c - '0';
419f92359bfSslatteng } while (isdigit(c = getc(fp)));
420f92359bfSslatteng ungetc(c, fp);
421f92359bfSslatteng hgoto(k);
422f92359bfSslatteng break;
423f92359bfSslatteng case 'h': /* relative horizontal motion */
424f92359bfSslatteng while ((c = getc(fp)) == ' ')
425f92359bfSslatteng ;
426f92359bfSslatteng k = 0;
427f92359bfSslatteng do {
428f92359bfSslatteng k = 10 * k + c - '0';
429f92359bfSslatteng } while (isdigit(c = getc(fp)));
430f92359bfSslatteng ungetc(c, fp);
431f92359bfSslatteng hmot(k);
432f92359bfSslatteng break;
433f92359bfSslatteng case 'w': /* word space */
434f92359bfSslatteng break;
435f92359bfSslatteng case 'V':
436f92359bfSslatteng fscanf(fp, "%d", &n);
437f92359bfSslatteng vgoto(n);
438f92359bfSslatteng break;
439f92359bfSslatteng case 'v':
440f92359bfSslatteng fscanf(fp, "%d", &n);
441f92359bfSslatteng vmot(n);
442f92359bfSslatteng break;
443f92359bfSslatteng case 'p': /* new page */
444f92359bfSslatteng fscanf(fp, "%d", &n);
445f92359bfSslatteng t_page(n);
446f92359bfSslatteng break;
447f92359bfSslatteng case 'n': /* end of line */
448f92359bfSslatteng t_newline();
449289ea231Sslatteng
450f92359bfSslatteng case '#': /* comment */
451289ea231Sslatteng do
452289ea231Sslatteng c = getc(fp);
453289ea231Sslatteng while (c != '\n' && c != EOF);
454f92359bfSslatteng break;
455f92359bfSslatteng case 'x': /* device control */
45619de12e6Sslatteng if (devcntrl(fp)) return;
457f92359bfSslatteng break;
458f92359bfSslatteng default:
459ebd02298Sslatteng error(FATAL, "unknown input character %o %c", c, c);
460f92359bfSslatteng }
461cb97edc8Sslatteng if (emptypos < NLINES) { /* for each input operation */
462cb97edc8Sslatteng slop_lines(1); /* put out an output line */
463cb97edc8Sslatteng #ifdef DRIVER
464cb97edc8Sslatteng if (emptypos == NLINES) {
465cb97edc8Sslatteng ioctl(OUTFILE, VSETSTATE, prtmode);
466cb97edc8Sslatteng if (write(OUTFILE, "\f", 2) != 2)
467cb97edc8Sslatteng exit(RESTART);
468cb97edc8Sslatteng ioctl(OUTFILE, VSETSTATE, pltmode);
469cb97edc8Sslatteng }
470cb97edc8Sslatteng #endif
471cb97edc8Sslatteng }
472f92359bfSslatteng }
473f92359bfSslatteng }
474f92359bfSslatteng
devcntrl(fp)47519de12e6Sslatteng int devcntrl(fp) /* interpret device control functions */
47619de12e6Sslatteng FILE *fp; /* returns -1 upon "stop" command */
477f92359bfSslatteng {
478f92359bfSslatteng char str[20], str1[50], buf[50];
479f92359bfSslatteng int c, n;
480f92359bfSslatteng
481f92359bfSslatteng fscanf(fp, "%s", str);
482f92359bfSslatteng switch (str[0]) { /* crude for now */
483f92359bfSslatteng case 'i': /* initialize */
484f92359bfSslatteng fileinit();
485f92359bfSslatteng t_init();
486f92359bfSslatteng break;
487f92359bfSslatteng case 't': /* trailer */
488f92359bfSslatteng break;
489f92359bfSslatteng case 'p': /* pause -- can restart */
490f92359bfSslatteng t_reset('p');
491f92359bfSslatteng break;
492f92359bfSslatteng case 's': /* stop */
493f92359bfSslatteng t_reset('s');
49419de12e6Sslatteng return -1;
495f92359bfSslatteng case 'r': /* resolution assumed when prepared */
4964da297a9Sslatteng fscanf(fp, "%d", &n);
49769c7ec87Sslatteng if (n!=RES) error(FATAL,"Input computed for wrong printer");
498f92359bfSslatteng break;
499f92359bfSslatteng case 'f': /* font used */
500f92359bfSslatteng fscanf(fp, "%d %s", &n, str);
501f92359bfSslatteng fgets(buf, sizeof buf, fp); /* in case there's a filename */
502f92359bfSslatteng ungetc('\n', fp); /* fgets goes too far */
503f92359bfSslatteng str1[0] = 0; /* in case nothing comes in */
504f92359bfSslatteng sscanf(buf, "%s", str1);
505f92359bfSslatteng loadfont(n, str, str1);
506f92359bfSslatteng break;
507f92359bfSslatteng /* these don't belong here... */
508f92359bfSslatteng case 'H': /* char height */
509f92359bfSslatteng fscanf(fp, "%d", &n);
510f92359bfSslatteng t_charht(n);
511f92359bfSslatteng break;
512f92359bfSslatteng case 'S': /* slant */
513f92359bfSslatteng fscanf(fp, "%d", &n);
514f92359bfSslatteng t_slant(n);
515f92359bfSslatteng break;
516f92359bfSslatteng }
517f92359bfSslatteng while ((c = getc(fp)) != '\n') /* skip rest of input line */
518f92359bfSslatteng if (c == EOF)
51919de12e6Sslatteng return -1;
52019de12e6Sslatteng return 0;
521f92359bfSslatteng }
522f92359bfSslatteng
523f92359bfSslatteng /* fileinit: read in font and code files, etc.
524f92359bfSslatteng Must open table for device, read in resolution,
5254da297a9Sslatteng size info, font info, etc. and set params.
5264da297a9Sslatteng Also read in font name mapping.
527f92359bfSslatteng */
5284da297a9Sslatteng
fileinit()529f92359bfSslatteng fileinit()
530f92359bfSslatteng {
5314da297a9Sslatteng register int i;
5324da297a9Sslatteng register int fin;
5334da297a9Sslatteng register int nw;
5344da297a9Sslatteng register char *filebase;
5354da297a9Sslatteng register char *p;
5364da297a9Sslatteng register FILE *fp;
5374da297a9Sslatteng char temp[100];
5384da297a9Sslatteng
5394da297a9Sslatteng /* first, read in font map file. The file must be of Format:
5404da297a9Sslatteng XX FILENAME (XX = troff font name)
5414da297a9Sslatteng with one entry per text line of the file.
5424da297a9Sslatteng Extra stuff after FILENAME is ignored */
5434da297a9Sslatteng
5444da297a9Sslatteng sprintf(temp, "%s/fontmap", bitdir);
5454da297a9Sslatteng if ((fp = fopen(temp, "r")) == NULL)
5464da297a9Sslatteng error(FATAL, "Can't open %s", temp);
5474da297a9Sslatteng for (i = 0; i <= NFONTS && fgets(temp, 100, fp) != NULL; i++) {
5484da297a9Sslatteng sscanf(temp, "%2s", fontmap[i].fname);
5494da297a9Sslatteng p = &temp[0];
5504da297a9Sslatteng while (*p != ' ' && *p != ' ') p++;
5514da297a9Sslatteng while (*p == ' ' || *p == ' ') p++;
5524da297a9Sslatteng filebase = p;
5534da297a9Sslatteng for (nw = 1; *p != '\n' && *p != ' ' && *p != '\t'; p++) nw++;
5544da297a9Sslatteng fontmap[i].ffile = nalloc(1, nw);
5554da297a9Sslatteng sscanf(filebase, "%s", fontmap[i].ffile);
5564da297a9Sslatteng }
5574da297a9Sslatteng fontmap[++i].fname[0] = '0'; /* finish off with zeros */
5584da297a9Sslatteng fontmap[i].ffile = (char *) 0;
5594da297a9Sslatteng fclose(fp);
5604da297a9Sslatteng #ifdef DEBUGABLE
5614da297a9Sslatteng if(dbg) {
5624da297a9Sslatteng fprintf(stderr, "font map:\n");
5634da297a9Sslatteng for (i = 0; fontmap[i].ffile; i++)
5644da297a9Sslatteng fprintf(stderr,"%s = %s\n", fontmap[i].fname, fontmap[i].ffile);
5654da297a9Sslatteng }
5664da297a9Sslatteng #endif
567f92359bfSslatteng
568cb97edc8Sslatteng sprintf(temp, "%s/devva/DESC.out", fontdir);
569f92359bfSslatteng if ((fin = open(temp, 0)) < 0)
570ebd02298Sslatteng error(FATAL, "can't open tables for %s", temp);
571f92359bfSslatteng read(fin, &dev, sizeof(struct dev));
572f92359bfSslatteng nfonts = dev.nfonts;
57369c7ec87Sslatteng nstips = dev.nstips;
574f92359bfSslatteng nsizes = dev.nsizes;
575f92359bfSslatteng nchtab = dev.nchtab;
576f92359bfSslatteng filebase = calloc(1, dev.filesize); /* enough room for whole file */
577f92359bfSslatteng read(fin, filebase, dev.filesize); /* all at once */
578f92359bfSslatteng pstab = (short *) filebase;
579f92359bfSslatteng chtab = pstab + nsizes + 1;
580f92359bfSslatteng chname = (char *) (chtab + dev.nchtab);
581f92359bfSslatteng p = chname + dev.lchname;
582f92359bfSslatteng for (i = 1; i <= nfonts; i++) {
583f92359bfSslatteng fontbase[i] = (struct font *) p;
584f92359bfSslatteng nw = *p & BMASK; /* 1st thing is width count */
5851c9df754Sslatteng p += sizeof(struct font);
586f92359bfSslatteng widtab[i] = p;
587f92359bfSslatteng codetab[i] = p + 2 * nw;
588f92359bfSslatteng fitab[i] = p + 3 * nw;
589f92359bfSslatteng p += 3 * nw + dev.nchtab + 128 - 32;
590f92359bfSslatteng t_fp(i, fontbase[i]->namefont, fontbase[i]->intname);
591f92359bfSslatteng #ifdef DEBUGABLE
592f92359bfSslatteng if (dbg > 1) fontprint(i);
593f92359bfSslatteng #endif
594f92359bfSslatteng }
59569c7ec87Sslatteng for (i = 1; i <= nstips; i++) { /* add in stipple "filenames" */
59669c7ec87Sslatteng if (nfonts + i <= NFONTS)
59769c7ec87Sslatteng t_fp(nfonts + i, p, (char *)0);
59869c7ec87Sslatteng p += strlen(p) + 1;
59969c7ec87Sslatteng }
600f92359bfSslatteng fontbase[0] = (struct font *)
601f92359bfSslatteng calloc(1,3*255 + dev.nchtab + (128-32) + sizeof (struct font));
602f92359bfSslatteng widtab[0] = (char *) fontbase[0] + sizeof (struct font);
603f92359bfSslatteng fontbase[0]->nwfont = 255;
604f92359bfSslatteng close(fin);
6054da297a9Sslatteng
606f92359bfSslatteng }
607f92359bfSslatteng
6084da297a9Sslatteng
6096dfd4b55Sslatteng #ifdef DEBUGABLE
fontprint(i)610f92359bfSslatteng fontprint(i) /* debugging print of font i (0,...) */
611f92359bfSslatteng {
612f92359bfSslatteng int j, n;
613f92359bfSslatteng char *p;
614f92359bfSslatteng
615f92359bfSslatteng fprintf(stderr,"font %d:\n", i);
616f92359bfSslatteng p = (char *) fontbase[i];
617f92359bfSslatteng n = fontbase[i]->nwfont & BMASK;
618f92359bfSslatteng fprintf(stderr,
619f92359bfSslatteng "base=0%o, nchars=%d, spec=%d, name=%s, widtab=0%o, fitab=0%o\n",p,
620f92359bfSslatteng n,fontbase[i]->specfont,fontbase[i]->namefont,widtab[i],fitab[i]);
621f92359bfSslatteng fprintf(stderr,"widths:\n");
622f92359bfSslatteng for (j=0; j <= n; j++) {
623f92359bfSslatteng fprintf(stderr," %2d", widtab[i][j] & BMASK);
624f92359bfSslatteng if (j % 20 == 19) fprintf(stderr,"\n");
625f92359bfSslatteng }
626f92359bfSslatteng fprintf(stderr,"\ncodetab:\n");
627f92359bfSslatteng for (j=0; j <= n; j++) {
628f92359bfSslatteng fprintf(stderr," %2d", codetab[i][j] & BMASK);
629f92359bfSslatteng if (j % 20 == 19) fprintf(stderr,"\n");
630f92359bfSslatteng }
631f92359bfSslatteng fprintf(stderr,"\nfitab:\n");
632f92359bfSslatteng for (j=0; j <= dev.nchtab + 128-32; j++) {
633f92359bfSslatteng fprintf(stderr," %2d", fitab[i][j] & BMASK);
634f92359bfSslatteng if (j % 20 == 19) fprintf(stderr,"\n");
635f92359bfSslatteng }
636f92359bfSslatteng fprintf(stderr,"\n");
637f92359bfSslatteng }
6386dfd4b55Sslatteng #endif
639f92359bfSslatteng
64019de12e6Sslatteng
loadfont(n,s,s1)641f92359bfSslatteng loadfont(n, s, s1) /* load font info for font s on position n (0...) */
642f92359bfSslatteng int n;
643f92359bfSslatteng char *s, *s1;
644f92359bfSslatteng {
645f92359bfSslatteng char temp[60];
64619de12e6Sslatteng register int fin;
64719de12e6Sslatteng register int nw;
64819de12e6Sslatteng register int norig;
6494da297a9Sslatteng
650f92359bfSslatteng if (n < 0 || n > NFONTS)
651f92359bfSslatteng error(FATAL, "illegal fp command %d %s", n, s);
652f92359bfSslatteng if (strcmp(s, fontbase[n]->namefont) == 0)
653f92359bfSslatteng return;
65419de12e6Sslatteng
65519de12e6Sslatteng for (fin = 1; fin <= NFONTS; fin++) /* first check to see if the */
65619de12e6Sslatteng if (strcmp(s, fontbase[fin]->namefont) == 0) { /* font is loaded */
65719de12e6Sslatteng register char *c; /* somewhere else */
65819de12e6Sslatteng
65919de12e6Sslatteng #define ptrswap(x, y) { c = (char*) (x); x = y; y = c; }
6606dfd4b55Sslatteng #define ptrfswap(x, y) { c = (char*) (x); x = y; y = (struct font *) c; }
66119de12e6Sslatteng
6626dfd4b55Sslatteng ptrfswap(fontbase[n], fontbase[fin]);
66319de12e6Sslatteng ptrswap(codetab[n], codetab[fin]);
66419de12e6Sslatteng ptrswap(widtab[n], widtab[fin]);
66519de12e6Sslatteng ptrswap(fitab[n], fitab[fin]);
66619de12e6Sslatteng t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
66719de12e6Sslatteng t_fp(fin, fontbase[fin]->namefont, fontbase[fin]->intname);
66819de12e6Sslatteng return;
66919de12e6Sslatteng }
67019de12e6Sslatteng
671f92359bfSslatteng if (s1 == NULL || s1[0] == '\0')
672cb97edc8Sslatteng sprintf(temp, "%s/devva/%s.out", fontdir, s);
673f92359bfSslatteng else
674f92359bfSslatteng sprintf(temp, "%s/%s.out", s1, s);
675f92359bfSslatteng if ((fin = open(temp, 0)) < 0)
676f92359bfSslatteng error(FATAL, "can't open font table %s", temp);
677f92359bfSslatteng norig = fontbase[n]->nwfont & BMASK;
678f92359bfSslatteng read(fin, fontbase[n], 3*norig + nchtab+128-32 + sizeof(struct font));
679f92359bfSslatteng if ((fontbase[n]->nwfont & BMASK) > norig)
680ebd02298Sslatteng error(FATAL, "Font %s too big for position %d", s, n);
681f92359bfSslatteng close(fin);
682f92359bfSslatteng nw = fontbase[n]->nwfont & BMASK;
683f92359bfSslatteng widtab[n] = (char *) fontbase[n] + sizeof(struct font);
684f92359bfSslatteng codetab[n] = (char *) widtab[n] + 2 * nw;
685f92359bfSslatteng fitab[n] = (char *) widtab[n] + 3 * nw;
686f92359bfSslatteng t_fp(n, fontbase[n]->namefont, fontbase[n]->intname);
687f92359bfSslatteng fontbase[n]->nwfont = norig; /* to later use full original size */
688f92359bfSslatteng #ifdef DEBUGABLE
689f92359bfSslatteng if (dbg > 1) fontprint(n);
690f92359bfSslatteng #endif
691f92359bfSslatteng }
692f92359bfSslatteng
693ebd02298Sslatteng
694f92359bfSslatteng /*VARARGS1*/
error(f,s,a1,a2,a3,a4,a5,a6,a7)695f92359bfSslatteng error(f, s, a1, a2, a3, a4, a5, a6, a7) {
696ebd02298Sslatteng fprintf(stderr, "dvar: ");
697f92359bfSslatteng fprintf(stderr, s, a1, a2, a3, a4, a5, a6, a7);
698f92359bfSslatteng fprintf(stderr, "\n");
6991c9df754Sslatteng if (f) exit(ABORT);
700f92359bfSslatteng }
701f92359bfSslatteng
702f92359bfSslatteng
t_init()703f92359bfSslatteng t_init() /* initialize device */
704f92359bfSslatteng {
705f92359bfSslatteng int i;
706f92359bfSslatteng
707f92359bfSslatteng hpos = vpos = 0;
708f92359bfSslatteng
709f92359bfSslatteng setsize(t_size(10)); /* start somewhere */
710f92359bfSslatteng setfont(1);
711f92359bfSslatteng }
712f92359bfSslatteng
713f92359bfSslatteng
714f92359bfSslatteng struct state {
715f92359bfSslatteng int ssize;
716f92359bfSslatteng int sfont;
717f92359bfSslatteng int shpos;
718f92359bfSslatteng int svpos;
719ebd02298Sslatteng int sstyle;
720ebd02298Sslatteng int sthick;
721f92359bfSslatteng };
722f92359bfSslatteng struct state state[MAXSTATE];
723f92359bfSslatteng struct state *statep = state;
724f92359bfSslatteng
t_push()725f92359bfSslatteng t_push() /* begin a new block */
726f92359bfSslatteng {
727f92359bfSslatteng statep->ssize = size;
728f92359bfSslatteng statep->sfont = font;
729ebd02298Sslatteng statep->sstyle = linmod;
730ebd02298Sslatteng statep->sthick = linethickness;
731f92359bfSslatteng statep->shpos = hpos;
732f92359bfSslatteng statep->svpos = vpos;
733f92359bfSslatteng if (statep++ >= state+MAXSTATE)
734f92359bfSslatteng error(FATAL, "{ nested too deep");
735f92359bfSslatteng }
736f92359bfSslatteng
t_pop()737f92359bfSslatteng t_pop() /* pop to previous state */
738f92359bfSslatteng {
739f92359bfSslatteng if (--statep < state)
740f92359bfSslatteng error(FATAL, "extra }");
741f92359bfSslatteng size = statep->ssize;
742f92359bfSslatteng font = statep->sfont;
743f92359bfSslatteng hpos = statep->shpos;
744f92359bfSslatteng vpos = statep->svpos;
745ebd02298Sslatteng linmod = statep->sstyle;
746ebd02298Sslatteng linethickness = statep->sthick;
747f92359bfSslatteng }
748f92359bfSslatteng
t_page(n)749f92359bfSslatteng t_page(n) /* do whatever new page functions */
750f92359bfSslatteng {
751f92359bfSslatteng int i;
752f92359bfSslatteng
753f92359bfSslatteng
754cb97edc8Sslatteng if (emptypos < NLINES) { /* finish off last page, if */
755cb97edc8Sslatteng slop_lines(NLINES - emptypos); /* it's not done yet */
7561c9df754Sslatteng #ifdef DRIVER
757f92359bfSslatteng ioctl(OUTFILE, VSETSTATE, prtmode);
758f92359bfSslatteng if (write(OUTFILE, "\f", 2) != 2)
759f92359bfSslatteng exit(RESTART);
760f92359bfSslatteng ioctl(OUTFILE, VSETSTATE, pltmode);
7611c9df754Sslatteng #endif
762f92359bfSslatteng }
763cb97edc8Sslatteng if (output) {
764cb97edc8Sslatteng emptypos = 0; /* set emptying to be started */
765cb97edc8Sslatteng elevel = fill; /* swap buffer pointers */
766cb97edc8Sslatteng fill = empty;
767cb97edc8Sslatteng empty = elevel;
768cb97edc8Sslatteng }
769f92359bfSslatteng
770f92359bfSslatteng vpos = 0;
771f92359bfSslatteng output = 1;
772f92359bfSslatteng if (nolist == 0)
773f92359bfSslatteng return; /* no -o specified */
774f92359bfSslatteng output = 0;
775f92359bfSslatteng for (i = 0; i < nolist; i += 2)
776f92359bfSslatteng if (n >= olist[i] && n <= olist[i+1]) {
777f92359bfSslatteng output = 1;
778f92359bfSslatteng break;
779f92359bfSslatteng }
780f92359bfSslatteng }
781f92359bfSslatteng
t_newline()782f92359bfSslatteng t_newline() /* do whatever for the end of a line */
783f92359bfSslatteng {
784f92359bfSslatteng hpos = 0; /* because we're now back at the left margin */
785f92359bfSslatteng }
786f92359bfSslatteng
t_size(n)787f92359bfSslatteng t_size(n) /* convert integer to internal size number*/
788f92359bfSslatteng int n;
789f92359bfSslatteng {
790f92359bfSslatteng int i;
791f92359bfSslatteng
792f92359bfSslatteng if (n <= pstab[0])
7934da297a9Sslatteng return(0);
794f92359bfSslatteng else if (n >= pstab[nsizes - 1])
7954da297a9Sslatteng return(nsizes - 1);
796f92359bfSslatteng for (i = 0; n > pstab[i]; i++)
797f92359bfSslatteng ;
7984da297a9Sslatteng return(i);
799f92359bfSslatteng }
800f92359bfSslatteng
t_charht(n)801f92359bfSslatteng t_charht(n) /* set character height to n */
802f92359bfSslatteng int n;
803f92359bfSslatteng {
804f92359bfSslatteng #ifdef DEBUGABLE
8054da297a9Sslatteng if (dbg) error(!FATAL, "can't set height on varian");
806f92359bfSslatteng #endif
807f92359bfSslatteng }
808f92359bfSslatteng
t_slant(n)809f92359bfSslatteng t_slant(n) /* set slant to n */
810f92359bfSslatteng int n;
811f92359bfSslatteng {
812f92359bfSslatteng #ifdef DEBUGABLE
8134da297a9Sslatteng if (dbg) error(!FATAL, "can't set slant on varian");
814f92359bfSslatteng #endif
815f92359bfSslatteng }
816f92359bfSslatteng
t_font(s)817f92359bfSslatteng t_font(s) /* convert string to internal font number */
818f92359bfSslatteng char *s;
819f92359bfSslatteng {
820f92359bfSslatteng int n;
821f92359bfSslatteng
822f92359bfSslatteng n = atoi(s);
823f92359bfSslatteng if (n < 0 || n > nfonts)
824f92359bfSslatteng n = 1;
825f92359bfSslatteng return(n);
826f92359bfSslatteng }
827f92359bfSslatteng
t_text(s)828f92359bfSslatteng t_text(s) /* print string s as text */
829f92359bfSslatteng char *s;
830f92359bfSslatteng {
831f92359bfSslatteng int c;
832f92359bfSslatteng char str[100];
833f92359bfSslatteng
834f92359bfSslatteng if (!output)
835f92359bfSslatteng return;
836f92359bfSslatteng while (c = *s++) {
837f92359bfSslatteng if (c == '\\') {
838f92359bfSslatteng switch (c = *s++) {
839f92359bfSslatteng case '\\':
840f92359bfSslatteng case 'e':
841f92359bfSslatteng put1('\\');
842f92359bfSslatteng break;
843f92359bfSslatteng case '(':
844f92359bfSslatteng str[0] = *s++;
845f92359bfSslatteng str[1] = *s++;
846f92359bfSslatteng str[2] = '\0';
847f92359bfSslatteng put1s(str);
848f92359bfSslatteng break;
849f92359bfSslatteng }
850f92359bfSslatteng } else {
851f92359bfSslatteng put1(c);
852f92359bfSslatteng }
853f92359bfSslatteng hmot(lastw);
854f92359bfSslatteng #ifdef DEBUGABLE
855f92359bfSslatteng if (dbg) fprintf(stderr,"width = %d\n", lastw);
856f92359bfSslatteng #endif
857f92359bfSslatteng }
858f92359bfSslatteng }
859f92359bfSslatteng
860cb97edc8Sslatteng
t_reset(c)861f92359bfSslatteng t_reset(c)
862f92359bfSslatteng {
863cb97edc8Sslatteng if (c == 's') {
864cb97edc8Sslatteng t_page();
865cb97edc8Sslatteng output = 0;
866cb97edc8Sslatteng t_page();
8671c9df754Sslatteng #ifdef DRIVER
868f92359bfSslatteng ioctl(OUTFILE, VSETSTATE, prtmode);
869f92359bfSslatteng if (write(OUTFILE, "\f", 2) != 2)
870f92359bfSslatteng exit(RESTART);
8711c9df754Sslatteng #endif
872f92359bfSslatteng }
873f92359bfSslatteng }
874f92359bfSslatteng
875ebd02298Sslatteng
876ebd02298Sslatteng /*----------------------------------------------------------------------------*
877ebd02298Sslatteng | Routine: hgoto (horizontal_spot)
878ebd02298Sslatteng |
879ebd02298Sslatteng | Results: hpos is set to n. If n overlaps in either direction, it wraps
880ebd02298Sslatteng | around to the other end of the page.
881ebd02298Sslatteng *----------------------------------------------------------------------------*/
882ebd02298Sslatteng
hgoto(n)883ebd02298Sslatteng hgoto(n)
884ebd02298Sslatteng int n;
885f92359bfSslatteng {
886ebd02298Sslatteng if (n < 0)
887ebd02298Sslatteng n += NLINES;
888ebd02298Sslatteng else if (n >= NLINES)
889ebd02298Sslatteng n -= NLINES;
890ebd02298Sslatteng hpos = n;
891f92359bfSslatteng }
892ebd02298Sslatteng
893ebd02298Sslatteng
894ebd02298Sslatteng /*----------------------------------------------------------------------------*
895ebd02298Sslatteng | Routine: vgoto (vertical_spot)
896ebd02298Sslatteng |
897ebd02298Sslatteng | Results: vpos is set to n. If n overlaps in either direction, it wraps
898ebd02298Sslatteng | around to the other end of the page.
899ebd02298Sslatteng *----------------------------------------------------------------------------*/
900ebd02298Sslatteng
vgoto(n)901ebd02298Sslatteng vgoto(n)
902ebd02298Sslatteng int n;
903ebd02298Sslatteng {
904ebd02298Sslatteng if (n < 0)
905ebd02298Sslatteng n += RASTER_LENGTH;
906ebd02298Sslatteng else if (n > RASTER_LENGTH)
907ebd02298Sslatteng n -= RASTER_LENGTH;
908f92359bfSslatteng vpos = n;
909f92359bfSslatteng }
910f92359bfSslatteng
put1s(s)911f92359bfSslatteng put1s(s) /* s is a funny char name */
912f92359bfSslatteng char *s;
913f92359bfSslatteng {
914f92359bfSslatteng int i;
915f92359bfSslatteng
916f92359bfSslatteng if (!output)
917f92359bfSslatteng return;
918f92359bfSslatteng #ifdef DEBUGABLE
919f92359bfSslatteng if (dbg) fprintf(stderr,"%s ", s);
920f92359bfSslatteng #endif
921f92359bfSslatteng for (i = 0; i < nchtab; i++)
922f92359bfSslatteng if (strcmp(&chname[chtab[i]], s) == 0)
923f92359bfSslatteng break;
924f92359bfSslatteng if (i < nchtab)
925f92359bfSslatteng put1(i + 128);
926f92359bfSslatteng }
927f92359bfSslatteng
put1(c)928f92359bfSslatteng put1(c) /* output char c */
929f92359bfSslatteng int c;
930f92359bfSslatteng {
931f92359bfSslatteng char *pw;
932f92359bfSslatteng register char *p;
933f92359bfSslatteng register int i, k;
934f92359bfSslatteng int j, ofont, code;
935f92359bfSslatteng
936f92359bfSslatteng if (!output)
937f92359bfSslatteng return;
938f92359bfSslatteng c -= 32;
939f92359bfSslatteng if (c <= 0) {
940f92359bfSslatteng #ifdef DEBUGABLE
941f92359bfSslatteng if (dbg) fprintf(stderr,"non-exist 0%o\n", c + 32);
942f92359bfSslatteng #endif
9434da297a9Sslatteng lastw = (widtab[font][0] * pstab[size] + dev.unitwidth/2)
944f92359bfSslatteng / dev.unitwidth;
945f92359bfSslatteng return;
946f92359bfSslatteng }
947f92359bfSslatteng k = ofont = font;
948f92359bfSslatteng i = fitab[font][c] & BMASK;
949f92359bfSslatteng if (i != 0) { /* it's on this font */
950f92359bfSslatteng p = codetab[font]; /* get the printing value of ch */
951f92359bfSslatteng pw = widtab[font]; /* get the width */
9526dfd4b55Sslatteng } else { /* on another font - run down the font list */
9536dfd4b55Sslatteng for (j=0; j++ <= nfonts; k = (k+1) % (nfonts+1)) {
954f92359bfSslatteng if (fitab[k] == 0)
955f92359bfSslatteng continue;
956f92359bfSslatteng if ((i=fitab[k][c] & BMASK) != 0) {
957f92359bfSslatteng p = codetab[k];
958f92359bfSslatteng pw = widtab[k];
959f92359bfSslatteng setfont(k);
960f92359bfSslatteng break;
961f92359bfSslatteng }
962f92359bfSslatteng }
9636dfd4b55Sslatteng }
9641c9df754Sslatteng
9656dfd4b55Sslatteng if (i == 0) {
966f92359bfSslatteng #ifdef DEBUGABLE
967f92359bfSslatteng if (dbg) fprintf(stderr,"not found 0%o\n", c+32);
968f92359bfSslatteng #endif
969f92359bfSslatteng return;
970f92359bfSslatteng }
9716dfd4b55Sslatteng code = p[i] & BMASK;
972f92359bfSslatteng #ifdef DEBUGABLE
973f92359bfSslatteng if (dbg) {
974f92359bfSslatteng if (isprint(c+32))
975f92359bfSslatteng fprintf(stderr,"%c %d\n", c+32, code);
976f92359bfSslatteng else
977f92359bfSslatteng fprintf(stderr,"%03o %d\n", c+32, code);
978f92359bfSslatteng }
979f92359bfSslatteng #endif
980f92359bfSslatteng outc(code); /* character is < 254 */
981f92359bfSslatteng if (font != ofont)
982f92359bfSslatteng setfont(ofont);
9834da297a9Sslatteng lastw = ((pw[i]&077) * pstab[size] + dev.unitwidth/2) / dev.unitwidth;
984f92359bfSslatteng }
985f92359bfSslatteng
986f92359bfSslatteng
987f92359bfSslatteng
setsize(n)988f92359bfSslatteng setsize(n) /* set point size to n (internal) */
989f92359bfSslatteng int n;
990f92359bfSslatteng {
991f92359bfSslatteng
992f92359bfSslatteng if (n == size)
993f92359bfSslatteng return; /* already there */
9944da297a9Sslatteng if (vloadfont(font, pstab[n]) != -1)
995f92359bfSslatteng size = n;
996f92359bfSslatteng }
997f92359bfSslatteng
t_fp(n,s,si)998f92359bfSslatteng t_fp(n, s, si) /* font position n now contains font s, intname si */
9991c9df754Sslatteng int n; /* internal name is ignored */
1000f92359bfSslatteng char *s, *si;
1001f92359bfSslatteng {
10024da297a9Sslatteng register int i;
1003f92359bfSslatteng
10044da297a9Sslatteng
10054da297a9Sslatteng /* first convert s to filename if possible */
10064da297a9Sslatteng for (i = 0; fontmap[i].ffile != (char *) 0; i++) {
10074da297a9Sslatteng #ifdef DEBUGABLE
10084da297a9Sslatteng if(dbg>1)fprintf(stderr,"testing :%s:%s:\n",s,fontmap[i].fname);
10094da297a9Sslatteng #endif
10104da297a9Sslatteng if (strcmp(s, fontmap[i].fname) == 0) {
10114da297a9Sslatteng s = fontmap[i].ffile;
10124da297a9Sslatteng #ifdef DEBUGABLE
10134da297a9Sslatteng if(dbg)fprintf(stderr, "found :%s:\n",fontmap[i].ffile);
10144da297a9Sslatteng #endif
10154da297a9Sslatteng break;
10164da297a9Sslatteng }
10174da297a9Sslatteng }
10181c9df754Sslatteng fontname[n] = s;
1019cb97edc8Sslatteng for(i = 0;i <= NFONTS;i++) /* free the bits of that font */
1020f92359bfSslatteng if (fontdes[i].fnum == n){
1021f92359bfSslatteng nfree(fontdes[i].bits);
1022f92359bfSslatteng fontdes[i].fnum = -1;
1023f92359bfSslatteng }
1024f92359bfSslatteng }
1025f92359bfSslatteng
10264da297a9Sslatteng
setfont(n)1027f92359bfSslatteng setfont(n) /* set font to n */
1028f92359bfSslatteng int n;
1029f92359bfSslatteng {
103069c7ec87Sslatteng if (n < 0 || n > nfonts)
1031ebd02298Sslatteng error(FATAL, "illegal font %d", n);
10324da297a9Sslatteng if (vloadfont(n,pstab[size]) != -1)
1033f92359bfSslatteng font = n;
1034f92359bfSslatteng }
1035f92359bfSslatteng
103669c7ec87Sslatteng
setstip(n)103769c7ec87Sslatteng setstip(n) /* set stipple font to n */
103869c7ec87Sslatteng int n;
103969c7ec87Sslatteng {
104069c7ec87Sslatteng if (n < 1 || n > nstips)
104169c7ec87Sslatteng error(FATAL, "illegal stipple %d", n);
104269c7ec87Sslatteng stip = n;
104369c7ec87Sslatteng }
104469c7ec87Sslatteng
104569c7ec87Sslatteng
vloadfont(fnum,fsize)1046f92359bfSslatteng vloadfont(fnum, fsize)
1047f92359bfSslatteng register int fnum;
1048f92359bfSslatteng register int fsize;
1049f92359bfSslatteng {
1050f92359bfSslatteng register int i;
1051f92359bfSslatteng
1052f92359bfSslatteng fontwanted = 0;
1053f92359bfSslatteng if (fnum == cfnum && fsize == cpsize)
1054f92359bfSslatteng return(0);
1055f92359bfSslatteng for (i = 0; i < NFONTS; i++) {
1056f92359bfSslatteng if (fontdes[i].fnum == fnum && fontdes[i].psize == fsize) {
1057f92359bfSslatteng cfnum = fontdes[i].fnum;
1058f92359bfSslatteng cpsize = fontdes[i].psize;
1059f92359bfSslatteng dispatch = &fontdes[i].disp[0];
1060f92359bfSslatteng bits = fontdes[i].bits;
1061f92359bfSslatteng cfont = i;
1062f92359bfSslatteng return (0);
1063f92359bfSslatteng }
1064f92359bfSslatteng }
1065f92359bfSslatteng /* this is a new font */
10661c9df754Sslatteng if (fnum < 0 || fnum > NFONTS || fontname[fnum] == 0) {
1067a2d3d00eSslatteng error(!FATAL,"error: illegal font %d, size %d\n", fnum, fsize);
1068f92359bfSslatteng return(-1);
1069f92359bfSslatteng }
1070f92359bfSslatteng /* Need to verify the existance of that font/size here*/
1071f92359bfSslatteng nfontnum = fnum;
1072f92359bfSslatteng npsize = fsize;
1073f92359bfSslatteng fontwanted++;
1074f92359bfSslatteng return (0);
1075f92359bfSslatteng }
1076f92359bfSslatteng
1077f92359bfSslatteng
getfont()1078f92359bfSslatteng getfont()
1079f92359bfSslatteng {
10804da297a9Sslatteng register int fnum;
10814da297a9Sslatteng register int fsize;
10824da297a9Sslatteng register int fontd;
10834da297a9Sslatteng register int d;
10841c9df754Sslatteng register int sizehunt = size;
1085f92359bfSslatteng char cbuf[BUFSIZ];
1086f92359bfSslatteng
1087f92359bfSslatteng fnum = nfontnum;
1088f92359bfSslatteng fsize = npsize;
10894da297a9Sslatteng /* try to open font file - if unsuccessful, hunt for */
10904da297a9Sslatteng /* a file of same style, different size to substitute */
10914da297a9Sslatteng d = -1; /* direction to look in pstab (smaller first) */
10924da297a9Sslatteng do {
10931c9df754Sslatteng sprintf(cbuf, "%s/%s.%dr", bitdir, fontname[fnum], fsize);
1094f92359bfSslatteng fontd = open(cbuf, OPENREAD);
10954da297a9Sslatteng if (fontd == -1) { /* File wasn't found. Try another ps */
10961c9df754Sslatteng sizehunt += d;
10971c9df754Sslatteng if (sizehunt < 0) { /* past beginning - look higher */
10984da297a9Sslatteng d = 1;
10991c9df754Sslatteng sizehunt = size + 1;
11004da297a9Sslatteng }
11011c9df754Sslatteng if (sizehunt > nsizes) { /* past top - forget it */
11024da297a9Sslatteng d = 0;
11034da297a9Sslatteng } else {
11041c9df754Sslatteng fsize = pstab[sizehunt];
11054da297a9Sslatteng }
11064da297a9Sslatteng }
11074da297a9Sslatteng } while (fontd == -1 && d != 0);
11084da297a9Sslatteng
11094da297a9Sslatteng if (fontd == -1) { /* completely unsuccessful */
1110f92359bfSslatteng perror(cbuf);
11114da297a9Sslatteng error(!FATAL,"fnum = %d, psize = %d, name = %s",
11121c9df754Sslatteng fnum, npsize, fontname[fnum]);
1113f92359bfSslatteng fontwanted = 0;
1114f92359bfSslatteng return (-1);
1115f92359bfSslatteng }
1116f92359bfSslatteng if (read(fontd, &header, sizeof (header)) != sizeof (header)
1117f92359bfSslatteng || header.magic != 0436)
1118f92359bfSslatteng fprintf(stderr, "%s: Bad font file", cbuf);
1119f92359bfSslatteng else {
1120f92359bfSslatteng cfont = relfont();
1121f92359bfSslatteng if ((bits=nalloc(header.size+DSIZ+1,1))== NULL)
1122f92359bfSslatteng if ((bits=allpanic(header.size+DSIZ+1))== NULL) {
11231c9df754Sslatteng error(FATAL,"%s: ran out of memory", cbuf);
1124f92359bfSslatteng }
1125f92359bfSslatteng
1126f92359bfSslatteng /*
1127f92359bfSslatteng * have allocated one chunk of mem for font, dispatch.
1128f92359bfSslatteng * get the dispatch addr, align to word boundary.
1129f92359bfSslatteng */
1130f92359bfSslatteng
1131f92359bfSslatteng d = (int) bits+header.size;
1132f92359bfSslatteng d += 1;
1133f92359bfSslatteng d &= ~1;
1134f92359bfSslatteng if (read (fontd, d, DSIZ) != DSIZ
1135f92359bfSslatteng || read (fontd, bits, header.size) != header.size)
1136f92359bfSslatteng fprintf(stderr, "bad font header");
1137f92359bfSslatteng else {
1138f92359bfSslatteng close(fontd);
1139f92359bfSslatteng cfnum = fontdes[cfont].fnum = fnum;
1140f92359bfSslatteng cpsize = fontdes[cfont].psize = fsize;
1141f92359bfSslatteng fontdes [cfont].bits = bits;
1142f92359bfSslatteng fontdes [cfont].disp = (struct dispatch *) d;
1143f92359bfSslatteng dispatch = &fontdes[cfont].disp[0];
1144f92359bfSslatteng fontwanted = 0;
1145f92359bfSslatteng return (0);
1146f92359bfSslatteng }
1147f92359bfSslatteng }
1148f92359bfSslatteng close(fontd);
1149f92359bfSslatteng fontwanted = 0;
1150f92359bfSslatteng return(-1);
1151f92359bfSslatteng }
1152f92359bfSslatteng
1153f92359bfSslatteng /*
1154f92359bfSslatteng * "release" a font position - find an empty one, if possible
1155f92359bfSslatteng */
1156f92359bfSslatteng
relfont()1157f92359bfSslatteng relfont()
1158f92359bfSslatteng {
1159f92359bfSslatteng register int newfont;
1160f92359bfSslatteng
1161f92359bfSslatteng for (newfont = 0; newfont < NFONTS; newfont++)
1162cb97edc8Sslatteng if (fontdes [newfont].fnum == -1)
1163f92359bfSslatteng break;
1164cb97edc8Sslatteng if (fontdes [newfont].fnum != -1) {
1165f92359bfSslatteng nfree (fontdes [newfont].bits);
1166f92359bfSslatteng #ifdef DEBUGABLE
1167f92359bfSslatteng if (dbg) fprintf (stderr, "freeing position %d\n", newfont);
1168f92359bfSslatteng } else {
1169f92359bfSslatteng if (dbg)
1170f92359bfSslatteng fprintf (stderr, "taking, not freeing, position %d\n", newfont);
1171f92359bfSslatteng #endif
1172f92359bfSslatteng }
1173cb97edc8Sslatteng fontdes[newfont].fnum = -1;
1174f92359bfSslatteng return (newfont);
1175f92359bfSslatteng }
1176f92359bfSslatteng
allpanic(nbytes)1177f92359bfSslatteng char *allpanic (nbytes)
1178f92359bfSslatteng int nbytes;
1179f92359bfSslatteng {
1180f92359bfSslatteng register int i;
1181f92359bfSslatteng
1182f92359bfSslatteng for (i = 0; i <= NFONTS; i++) {
1183cb97edc8Sslatteng if (fontdes[i].fnum != -1) nfree(fontdes[i].bits);
1184cb97edc8Sslatteng fontdes[i].fnum = -1;
1185f92359bfSslatteng cfnum = cpsize = -1;
1186f92359bfSslatteng }
1187f92359bfSslatteng return(nalloc(nbytes,1));
1188f92359bfSslatteng }
1189f92359bfSslatteng
1190f92359bfSslatteng int M[] = { 0xffffffff, 0xfefefefe, 0xfcfcfcfc, 0xf8f8f8f8,
1191f92359bfSslatteng 0xf0f0f0f0, 0xe0e0e0e0, 0xc0c0c0c0, 0x80808080, 0x0 };
1192f92359bfSslatteng int N[] = { 0x00000000, 0x01010101, 0x03030303, 0x07070707,
1193f92359bfSslatteng 0x0f0f0f0f, 0x1f1f1f1f, 0x3f3f3f3f, 0x7f7f7f7f, 0xffffffff };
1194f92359bfSslatteng int strim[] = { 0xffffffff, 0xffffff00, 0xffff0000, 0xff000000, 0 };
1195f92359bfSslatteng
outc(code)1196f92359bfSslatteng outc(code)
1197f92359bfSslatteng int code; /* character to print */
1198f92359bfSslatteng {
1199f92359bfSslatteng register struct dispatch *dis; /* ptr to character font record */
1200f92359bfSslatteng register char *addr; /* addr of font data */
1201f92359bfSslatteng int llen; /* length of each font line */
1202f92359bfSslatteng int nlines; /* number of font lines */
1203f92359bfSslatteng register char *scanp; /* ptr to output buffer */
1204f92359bfSslatteng int scanp_inc; /* increment to start of next buffer */
1205f92359bfSslatteng int offset; /* bit offset to start of font data */
12064da297a9Sslatteng register int i; /* loop counter */
1207f92359bfSslatteng register int count; /* font data ptr */
1208f92359bfSslatteng register unsigned fontdata; /* font data temporary */
1209f92359bfSslatteng register int off8; /* offset + 8 */
1210f92359bfSslatteng
1211f92359bfSslatteng if (fontwanted)
1212f92359bfSslatteng getfont();
1213f92359bfSslatteng dis = dispatch + code;
1214f92359bfSslatteng if (dis->nbytes) {
1215f92359bfSslatteng addr = bits + dis->addr;
12161a4ecc79Sslatteng llen = (dis->up + dis->down + 7) >> 3;
12171a4ecc79Sslatteng nlines = dis->right + dis->left;
1218cb97edc8Sslatteng scanp = fill + (hpos + 1 - dis->left) * BYTES_PER_LINE
1219cb97edc8Sslatteng - (1 + ((dis->down + vpos - 1) >> 3));
1220cb97edc8Sslatteng if (scanp < fill)
1221cb97edc8Sslatteng scanp += BUFFER_SIZE;
1222f92359bfSslatteng scanp_inc = BYTES_PER_LINE - llen;
1223cb97edc8Sslatteng off8 = ((dis->down + vpos - 1) &07);
12241a4ecc79Sslatteng offset = off8 - 8;
1225f92359bfSslatteng for (i = 0; i < nlines; i++) {
1226cb97edc8Sslatteng if (scanp >= fill + BUFFER_SIZE)
12271c9df754Sslatteng scanp -= BUFFER_SIZE;
1228f92359bfSslatteng count = llen;
1229cb97edc8Sslatteng if (scanp + count < fill + BUFFER_SIZE) {
1230f92359bfSslatteng do {
1231f92359bfSslatteng fontdata = *(unsigned *)addr;
1232f92359bfSslatteng addr += 4;
1233f92359bfSslatteng if (count < 4)
1234f92359bfSslatteng fontdata &= ~strim[count];
1235f92359bfSslatteng *(unsigned*)scanp |=(fontdata << offset) & ~M[off8];
1236f92359bfSslatteng scanp++;
1237f92359bfSslatteng *(unsigned*)scanp |=(fontdata << off8) & ~N[off8];
1238f92359bfSslatteng scanp += 3;
1239f92359bfSslatteng count -= 4;
1240f92359bfSslatteng } while (count > 0);
1241f92359bfSslatteng }
1242f92359bfSslatteng scanp += scanp_inc+count;
1243f92359bfSslatteng addr += count;
1244f92359bfSslatteng }
1245f92359bfSslatteng return;
1246f92359bfSslatteng }
1247f92359bfSslatteng return;
1248f92359bfSslatteng }
1249f92359bfSslatteng
125069c7ec87Sslatteng
125169c7ec87Sslatteng /*----------------------------------------------------------------------------*
125269c7ec87Sslatteng | Routine: setfill(stipple_number)
125369c7ec87Sslatteng |
125469c7ec87Sslatteng | Results: sets the fill-pattern pointers (stip_disp and
125569c7ec87Sslatteng | stip_bits) for a particular stipple. Takes stipple
125669c7ec87Sslatteng | font from current "stip" number.
125769c7ec87Sslatteng *----------------------------------------------------------------------------*/
125869c7ec87Sslatteng
setfill(number)125969c7ec87Sslatteng setfill(number)
126069c7ec87Sslatteng int number;
126169c7ec87Sslatteng {
126269c7ec87Sslatteng int curfont; /* places to save current text font */
126369c7ec87Sslatteng int cursize;
126469c7ec87Sslatteng
126569c7ec87Sslatteng /* set global stipmem for polygon */
126669c7ec87Sslatteng if (number < 0 || number >= DISPATCHSIZE)
126769c7ec87Sslatteng stipmem = 0;
126869c7ec87Sslatteng else
126969c7ec87Sslatteng stipmem = number;
127069c7ec87Sslatteng
127169c7ec87Sslatteng curfont = cfnum; /* get pointers to */
127269c7ec87Sslatteng cursize = cpsize; /* the inuse font */
127369c7ec87Sslatteng if (vloadfont(nfonts + stip, 0)) {
127469c7ec87Sslatteng stip_disp = (struct dispatch *) NULL; /* stipple not here */
127569c7ec87Sslatteng } else {
127669c7ec87Sslatteng if (fontwanted) {
127769c7ec87Sslatteng if (getfont()) {
127869c7ec87Sslatteng stip_disp = (struct dispatch *) NULL;
127969c7ec87Sslatteng } else {
128069c7ec87Sslatteng stip_disp = dispatch; /* save for polygon routine */
128169c7ec87Sslatteng stip_bits = bits;
128269c7ec87Sslatteng }
128369c7ec87Sslatteng } else {
128469c7ec87Sslatteng stip_disp = dispatch; /* save for polygon routine */
128569c7ec87Sslatteng stip_bits = bits;
128669c7ec87Sslatteng }
128769c7ec87Sslatteng }
1288a2d3d00eSslatteng if (curfont >= 0) vloadfont(curfont, cursize);
128969c7ec87Sslatteng }
129069c7ec87Sslatteng
129169c7ec87Sslatteng
slop_lines(nlines)1292f92359bfSslatteng slop_lines(nlines)
1293f92359bfSslatteng int nlines;
1294f92359bfSslatteng
1295f92359bfSslatteng /* Output "nlines" lines from the buffer, and clear that section of the */
1296cb97edc8Sslatteng /* buffer. Also updates the pointers to the emptying buffer */
1297f92359bfSslatteng
1298f92359bfSslatteng {
1299f92359bfSslatteng unsigned usize;
1300f92359bfSslatteng
1301f92359bfSslatteng usize = BYTES_PER_LINE * nlines;
1302cb97edc8Sslatteng vwrite(elevel, usize);
1303cb97edc8Sslatteng vclear(elevel, usize);
1304cb97edc8Sslatteng elevel += usize;
1305cb97edc8Sslatteng emptypos += nlines;
1306f92359bfSslatteng }
1307f92359bfSslatteng
vwrite(buf,usize)13084da297a9Sslatteng vwrite(buf,usize)
1309f92359bfSslatteng char *buf;
1310f92359bfSslatteng unsigned usize;
1311f92359bfSslatteng {
1312f92359bfSslatteng register int tsize = 0;
1313f92359bfSslatteng
1314f92359bfSslatteng while (usize){
1315f92359bfSslatteng buf += tsize;
1316f92359bfSslatteng tsize = usize > MAXWRIT ? MAXWRIT : usize;
1317f92359bfSslatteng #ifdef DEBUGABLE
1318f92359bfSslatteng if (dbg)fprintf(stderr,"buf = %d size = %d\n",buf,tsize);
1319f92359bfSslatteng #endif
1320f92359bfSslatteng if ((tsize = write(OUTFILE, buf, tsize)) < 0) {
1321ebd02298Sslatteng perror("dvar: write failed");
1322f92359bfSslatteng exit(RESTART);
1323f92359bfSslatteng }
1324f92359bfSslatteng usize -= tsize;
1325f92359bfSslatteng }
1326f92359bfSslatteng }
1327f92359bfSslatteng
vclear(ptr,nbytes)1328f92359bfSslatteng vclear (ptr, nbytes)
1329f92359bfSslatteng char *ptr;
1330f92359bfSslatteng unsigned nbytes;
1331f92359bfSslatteng {
1332f92359bfSslatteng register tsize = 0;
1333f92359bfSslatteng
1334f92359bfSslatteng while (nbytes){
1335f92359bfSslatteng if ((unsigned)(16*1024) < nbytes) {
1336f92359bfSslatteng tsize = 16 * 1024;
1337f92359bfSslatteng } else
1338f92359bfSslatteng tsize = nbytes;
1339f92359bfSslatteng nbytes -= tsize;
1340f92359bfSslatteng #ifdef DEBUGABLE
1341f92359bfSslatteng if (dbg) fprintf(stderr,"clearing ptr = %d size = %d\n",ptr,tsize);
1342f92359bfSslatteng #endif
1343f92359bfSslatteng clear(ptr,tsize);
1344f92359bfSslatteng ptr += tsize;
1345f92359bfSslatteng }
1346f92359bfSslatteng }
1347f92359bfSslatteng
1348f92359bfSslatteng /*ARGSUSED*/
clear(lp,nbytes)1349f92359bfSslatteng clear(lp, nbytes)
1350f92359bfSslatteng int *lp;
1351f92359bfSslatteng int nbytes;
1352f92359bfSslatteng {
1353*92970570Sslatteng #ifdef vax
1354f92359bfSslatteng asm("movc5 $0,(sp),$0,8(ap),*4(ap)");
1355*92970570Sslatteng #else
1356*92970570Sslatteng register int i = nbytes;
1357*92970570Sslatteng register int *cp = lp;
1358*92970570Sslatteng
1359*92970570Sslatteng while (i-- > 0)
1360*92970570Sslatteng *(cp++) = 0;
1361*92970570Sslatteng #endif
1362f92359bfSslatteng }
1363f92359bfSslatteng
1364f92359bfSslatteng char *
nalloc(i,j)1365f92359bfSslatteng nalloc(i, j)
1366f92359bfSslatteng int i, j;
1367f92359bfSslatteng {
1368f92359bfSslatteng register char *cp;
1369f92359bfSslatteng
1370f92359bfSslatteng cp = calloc(i, j);
1371f92359bfSslatteng #ifdef DEBUGABLE
1372f92359bfSslatteng if (dbg) fprintf(stderr, "allocated %d bytes at %x\n", i * j, cp);
1373f92359bfSslatteng #endif
1374f92359bfSslatteng return(cp);
1375f92359bfSslatteng }
1376f92359bfSslatteng
nfree(cp)1377f92359bfSslatteng nfree(cp)
1378f92359bfSslatteng char *cp;
1379f92359bfSslatteng {
1380f92359bfSslatteng #ifdef DEBUGABLE
1381f92359bfSslatteng if (dbg) fprintf(stderr, "freeing at %x\n", cp);
1382f92359bfSslatteng #endif
1383f92359bfSslatteng free(cp);
1384f92359bfSslatteng }
1385f92359bfSslatteng
1386f92359bfSslatteng
1387f92359bfSslatteng /*
1388f92359bfSslatteng * Points should be in the range 0 <= x < RASTER_LENGTH, 0 <= y < NLINES.
1389f92359bfSslatteng * The origin is the top left-hand corner with increasing x towards the
13904da297a9Sslatteng * right and increasing y going down. X and Y should be sent as (0,0) being
13914da297a9Sslatteng * at the bottom left. The output array is NLINES x BYTES_PER_LINE pixels.
1392f92359bfSslatteng */
point(x,y)1393f92359bfSslatteng point(x, y)
13941a4ecc79Sslatteng register int x;
13951a4ecc79Sslatteng register int y;
1396f92359bfSslatteng {
139769c7ec87Sslatteng if ((unsigned)(y=(RASTER_LENGTH-1)-y)<RASTER_LENGTH && (unsigned)x<NLINES) {
1398cb97edc8Sslatteng *(fill + x * BYTES_PER_LINE + (y >> 3)) |= 1 << (7 - (y & 07));
1399f92359bfSslatteng }
1400f92359bfSslatteng }
140169c7ec87Sslatteng
140269c7ec87Sslatteng
140369c7ec87Sslatteng #define pv(x) ((polyvector *)x)
140469c7ec87Sslatteng
140569c7ec87Sslatteng typedef struct poly {
140669c7ec87Sslatteng struct poly *next; /* doublely-linked lists of vectors */
140769c7ec87Sslatteng struct poly *prev;
140869c7ec87Sslatteng int param; /* bressenham line algorithm parameter */
140969c7ec87Sslatteng short dy; /* delta-y for calculating line */
141069c7ec87Sslatteng short dx; /* delta-x for calculating line */
141169c7ec87Sslatteng short curry; /* current y in this vector */
141269c7ec87Sslatteng short endx; /* where vector ends */
141369c7ec87Sslatteng } polyvector;
141469c7ec87Sslatteng
141569c7ec87Sslatteng
141669c7ec87Sslatteng /*----------------------------------------------------------------------------*
141769c7ec87Sslatteng | Routine: polygon ( x_coordinates, y_coordinates, num_of_points )
141869c7ec87Sslatteng |
141969c7ec87Sslatteng | Results: draws a polygon starting at (x[1], y[1]) going through
142069c7ec87Sslatteng | each of (x_coordinates, y_coordinates), and fills it
142169c7ec87Sslatteng | with a stipple pattern from stip_disp and stip_bits,
142269c7ec87Sslatteng | which point to the stipple font. The pattern is defined
142369c7ec87Sslatteng | by "stip" and "stipmem".
142469c7ec87Sslatteng |
142569c7ec87Sslatteng | The scan-line algorithm implemented scans from left to
142669c7ec87Sslatteng | right (low x to high x). It also scans, within a line,
142769c7ec87Sslatteng | from bottom to top (high y to low y).
142869c7ec87Sslatteng |
142969c7ec87Sslatteng | polygons are clipped to page boundary.
143069c7ec87Sslatteng |
143169c7ec87Sslatteng | Bugs: stipple pattern MUST be a power of two bytes "wide" and
143269c7ec87Sslatteng | square. The square restriction comes from the fact that
143369c7ec87Sslatteng | the varian and versatec are respectively rotated.
143469c7ec87Sslatteng *----------------------------------------------------------------------------*/
143569c7ec87Sslatteng
polygon(x,y,npts)143669c7ec87Sslatteng polygon(x, y, npts)
143769c7ec87Sslatteng int x[];
143869c7ec87Sslatteng int y[];
143969c7ec87Sslatteng int npts;
144069c7ec87Sslatteng {
144169c7ec87Sslatteng int nextx; /* at what x value the next vector starts */
144269c7ec87Sslatteng int maxx, minx, maxy, miny; /* finds bounds of polygon */
144369c7ec87Sslatteng polyvector *activehead; /* doing fill, is active edge list */
144469c7ec87Sslatteng polyvector *waitinghead; /* edges waiting to be active */
144569c7ec87Sslatteng register polyvector *vectptr; /* random vector */
144669c7ec87Sslatteng register int i; /* random register */
144769c7ec87Sslatteng
144869c7ec87Sslatteng char *topstipple; /* points to beginning of stipple glyph */
144969c7ec87Sslatteng char *leftstipple; /* points to beginning of line of stipple */
145069c7ec87Sslatteng char *bottompage; /* points to the edge of a raster line */
145169c7ec87Sslatteng int bytewidth; /* glyph width in bytes */
145269c7ec87Sslatteng int mask; /* mask to pick off pixel index into stipple */
145369c7ec87Sslatteng int bytemask; /* mask to pick off byte index into stipple */
145469c7ec87Sslatteng
145569c7ec87Sslatteng
145669c7ec87Sslatteng if (bordered) {
145769c7ec87Sslatteng for (i = 1; i < npts; i++) /* first draw outlines */
145869c7ec87Sslatteng HGtline(x[i], y[i], x[i+1], y[i+1]);
145969c7ec87Sslatteng }
146069c7ec87Sslatteng
146169c7ec87Sslatteng /* if no stipple, don't fill */
146269c7ec87Sslatteng if (stip_disp == (struct dispatch *) NULL || stip_bits == (char *) NULL)
146369c7ec87Sslatteng return;
146469c7ec87Sslatteng
146569c7ec87Sslatteng stip_disp += stipmem; /* set up parameters for */
146669c7ec87Sslatteng if (!stip_disp->nbytes) { /* tiling with the stipple */
146769c7ec87Sslatteng #ifdef DEBUGABLE
146869c7ec87Sslatteng error(!FATAL, "member not found: member %d, stipple %d", stipmem, stip);
146969c7ec87Sslatteng #endif
147069c7ec87Sslatteng return;
147169c7ec87Sslatteng }
147269c7ec87Sslatteng topstipple = stip_bits + stip_disp->addr;
147369c7ec87Sslatteng bytewidth = stip_disp->up + stip_disp->down;
147469c7ec87Sslatteng for (i = 1 << 30; i && i != bytewidth; i = i >> 1)
147569c7ec87Sslatteng ;
147669c7ec87Sslatteng if (i==0 || bytewidth<8 || bytewidth != stip_disp->right+stip_disp->left) {
147769c7ec87Sslatteng error(!FATAL, "invalid stipple: number %d, member %d", stip, stipmem);
147869c7ec87Sslatteng return;
147969c7ec87Sslatteng }
148069c7ec87Sslatteng mask = bytewidth - 1;
148169c7ec87Sslatteng bytewidth = bytewidth >> 3;
148269c7ec87Sslatteng bytemask = bytewidth - 1;
148369c7ec87Sslatteng
148469c7ec87Sslatteng /* allocate space for raster-fill algorithm*/
148569c7ec87Sslatteng if ((vectptr = pv( nalloc(sizeof(polyvector), npts + 6) )) == NULL) {
148669c7ec87Sslatteng error(!FATAL, "unable to allocate space for polygon");
148769c7ec87Sslatteng return;
148869c7ec87Sslatteng }
148969c7ec87Sslatteng #ifdef DEBUGABLE
149069c7ec87Sslatteng if (dbg) fprintf(stderr, "polygon, %d points\n", npts);
149169c7ec87Sslatteng #endif
149269c7ec87Sslatteng
149369c7ec87Sslatteng waitinghead = vectptr;
149469c7ec87Sslatteng minx = maxx = x[1];
149569c7ec87Sslatteng miny = maxy = y[1];
149669c7ec87Sslatteng (vectptr++)->prev = pv( NULL ); /* put dummy entry at start */
149769c7ec87Sslatteng waitinghead->next = vectptr;
149869c7ec87Sslatteng vectptr->prev = waitinghead;
149969c7ec87Sslatteng i = 1; /* starting point of coords */
150069c7ec87Sslatteng if (y[1] != y[npts] || x[1] != x[npts]) {
150169c7ec87Sslatteng y[0] = y[npts]; /* close polygon if it's not */
150269c7ec87Sslatteng x[0] = x[npts];
150369c7ec87Sslatteng i = 0;
150469c7ec87Sslatteng }
150569c7ec87Sslatteng while (i < npts) { /* set up the vectors */
150669c7ec87Sslatteng register int j; /* indexes to work off of */
150769c7ec87Sslatteng register int k;
150869c7ec87Sslatteng
150969c7ec87Sslatteng if (miny > y[i]) miny = y[i]; /* remember limits */
151069c7ec87Sslatteng else if (maxy < y[i]) maxy = y[i];
151169c7ec87Sslatteng if (maxx < x[i]) maxx = x[i];
151269c7ec87Sslatteng else if (minx > x[i]) minx = x[i];
151369c7ec87Sslatteng
151469c7ec87Sslatteng j = i; /* j "points" to the higher (lesser) point */
151569c7ec87Sslatteng k = ++i;
151669c7ec87Sslatteng if (x[j] == x[k]) /* ignore vertical lines */
151769c7ec87Sslatteng continue;
151869c7ec87Sslatteng
151969c7ec87Sslatteng if (x[j] > x[k]) {
152069c7ec87Sslatteng j++;
152169c7ec87Sslatteng k--;
152269c7ec87Sslatteng }
152369c7ec87Sslatteng vectptr->next = vectptr + 1;
152469c7ec87Sslatteng vectptr->param = x[j]; /* starting point of vector */
152569c7ec87Sslatteng vectptr->dy = y[k] - y[j]; /* line-calculating parameters */
152669c7ec87Sslatteng vectptr->dx = x[k] - x[j];
152769c7ec87Sslatteng vectptr->curry = y[j]; /* starting point */
152869c7ec87Sslatteng (vectptr++)->endx = x[k]; /* ending point */
152969c7ec87Sslatteng vectptr->prev = vectptr - 1;
153069c7ec87Sslatteng }
153169c7ec87Sslatteng /* set now because we didn't know minx before */
153269c7ec87Sslatteng leftstipple = topstipple + (minx & mask) * bytewidth;
153369c7ec87Sslatteng bottompage = fill + minx * BYTES_PER_LINE;
153469c7ec87Sslatteng waitinghead->param = minx - 1;
153569c7ec87Sslatteng /* if no useable vectors, quit */
153669c7ec87Sslatteng if (vectptr == waitinghead + 1)
153769c7ec87Sslatteng goto leavepoly;
153869c7ec87Sslatteng
153969c7ec87Sslatteng vectptr->param = maxx + 1; /* dummy entry at end, too */
154069c7ec87Sslatteng vectptr->next = pv( NULL );
154169c7ec87Sslatteng
154269c7ec87Sslatteng activehead = ++vectptr; /* two dummy entries for active list */
154369c7ec87Sslatteng vectptr->curry = maxy + 1; /* head */
154469c7ec87Sslatteng vectptr->endx = maxx + 1;
154569c7ec87Sslatteng vectptr->param = vectptr->dx = vectptr->dy = 0;
154669c7ec87Sslatteng activehead->next = ++vectptr;
154769c7ec87Sslatteng activehead->prev = vectptr;
154869c7ec87Sslatteng
154969c7ec87Sslatteng vectptr->prev = activehead; /* tail */
155069c7ec87Sslatteng vectptr->next = activehead;
155169c7ec87Sslatteng vectptr->curry = miny - 1;
155269c7ec87Sslatteng vectptr->endx = maxx + 1;
155369c7ec87Sslatteng vectptr->param = vectptr->dx = vectptr->dy = 0;
155469c7ec87Sslatteng
155569c7ec87Sslatteng
155669c7ec87Sslatteng /* main loop -- gets vectors off the waiting list, */
155769c7ec87Sslatteng /* then displays spans while updating the vectors in */
155869c7ec87Sslatteng /* the active list */
155969c7ec87Sslatteng while (minx <= maxx) {
156069c7ec87Sslatteng i = maxx + 1; /* this is the NEXT time to get a new vector */
156169c7ec87Sslatteng for (vectptr = waitinghead->next; vectptr != pv( NULL ); ) {
156269c7ec87Sslatteng if (minx == vectptr->param) {
156369c7ec87Sslatteng /* the entry in waiting list (vectptr) is */
156469c7ec87Sslatteng /* ready to go into active list. Need to */
156569c7ec87Sslatteng /* convert some vector stuff and sort the */
156669c7ec87Sslatteng /* entry into the list. */
156769c7ec87Sslatteng register polyvector *p; /* random vector pointers */
156869c7ec87Sslatteng register polyvector *v;
156969c7ec87Sslatteng
157069c7ec87Sslatteng /* convert this */
157169c7ec87Sslatteng if (vectptr->dy < 0) /* entry to active */
157269c7ec87Sslatteng vectptr->param = (vectptr->dy >> 1) - (vectptr->dx >> 1);
157369c7ec87Sslatteng else
157469c7ec87Sslatteng vectptr->param = -((vectptr->dx >> 1) + (vectptr->dy >> 1));
157569c7ec87Sslatteng
157669c7ec87Sslatteng p = vectptr; /* remove from the */
157769c7ec87Sslatteng vectptr = vectptr->next; /* waiting list */
157869c7ec87Sslatteng vectptr->prev = p->prev;
157969c7ec87Sslatteng p->prev->next = vectptr;
158069c7ec87Sslatteng /* find where it goes */
158169c7ec87Sslatteng /* in the active list */
158269c7ec87Sslatteng /* (sorted greatest first) */
158369c7ec87Sslatteng for (v = activehead->next; v->curry > p->curry; v = v->next)
158469c7ec87Sslatteng ;
158569c7ec87Sslatteng p->next = v; /* insert into active list */
158669c7ec87Sslatteng p->prev = v->prev; /* before the one it stopped on */
158769c7ec87Sslatteng v->prev = p;
158869c7ec87Sslatteng p->prev->next = p;
158969c7ec87Sslatteng } else {
159069c7ec87Sslatteng if (i > vectptr->param) {
159169c7ec87Sslatteng i = vectptr->param;
159269c7ec87Sslatteng }
159369c7ec87Sslatteng vectptr = vectptr->next;
159469c7ec87Sslatteng }
159569c7ec87Sslatteng }
159669c7ec87Sslatteng nextx = i;
159769c7ec87Sslatteng
159869c7ec87Sslatteng /* print the polygon while there */
159969c7ec87Sslatteng /* are no more vectors to add */
160069c7ec87Sslatteng while (minx < nextx) {
160169c7ec87Sslatteng /* remove any finished vectors */
160269c7ec87Sslatteng vectptr = activehead->next;
160369c7ec87Sslatteng do {
160469c7ec87Sslatteng if (vectptr->endx <= minx) {
160569c7ec87Sslatteng vectptr->prev->next = vectptr->next;
160669c7ec87Sslatteng vectptr->next->prev = vectptr->prev;
160769c7ec87Sslatteng }
160869c7ec87Sslatteng } while ((vectptr = vectptr->next) != activehead);
160969c7ec87Sslatteng
161069c7ec87Sslatteng /* draw the span */
161169c7ec87Sslatteng if (((unsigned) minx) < NLINES) {
161269c7ec87Sslatteng vectptr = activehead->next;
161369c7ec87Sslatteng while (vectptr->next != activehead) {
161469c7ec87Sslatteng register int start; /* get the beginning */
161569c7ec87Sslatteng register int length; /* and the end of span */
161669c7ec87Sslatteng register char *glyph;
161769c7ec87Sslatteng register char *raster;
161869c7ec87Sslatteng
161969c7ec87Sslatteng start = (RASTER_LENGTH - 1) - vectptr->curry;
162069c7ec87Sslatteng vectptr = vectptr->next;
162169c7ec87Sslatteng length = RASTER_LENGTH - vectptr->curry;
162269c7ec87Sslatteng vectptr = vectptr->next;
162369c7ec87Sslatteng
162469c7ec87Sslatteng /* bound the polygon to the page */
162569c7ec87Sslatteng if (start >= RASTER_LENGTH)
162669c7ec87Sslatteng break;
162769c7ec87Sslatteng if (start < 0) start = 0;
162869c7ec87Sslatteng if (length > RASTER_LENGTH) length = RASTER_LENGTH;
162969c7ec87Sslatteng length -= start; /* length is in pixels */
163069c7ec87Sslatteng
163169c7ec87Sslatteng i = start & 7;
163269c7ec87Sslatteng start = start >> 3; /* start is in bytes */
163369c7ec87Sslatteng raster = bottompage + start;
163469c7ec87Sslatteng glyph = leftstipple + (start & bytemask);
163569c7ec87Sslatteng
163669c7ec87Sslatteng if (i) { /* do any piece of byte */
163769c7ec87Sslatteng register char data; /* that hangs on the front */
163869c7ec87Sslatteng
163969c7ec87Sslatteng data = (*(glyph++)) & (0x7f >> --i);
164069c7ec87Sslatteng length -= 7 - i;
164169c7ec87Sslatteng if (length < 0) { /* less than one byte wide? */
164269c7ec87Sslatteng data &= 0xff << -length;
164369c7ec87Sslatteng length = 0; /* force clean stoppage */
164469c7ec87Sslatteng }
164569c7ec87Sslatteng *(raster++) |= data;
164669c7ec87Sslatteng /* update glyph ptr after first byte */
164769c7ec87Sslatteng if (!(++start & bytemask))
164869c7ec87Sslatteng glyph = leftstipple;
164969c7ec87Sslatteng }
165069c7ec87Sslatteng /* fill the line of raster */
165169c7ec87Sslatteng while ((length -= 8) >= 0) {
165269c7ec87Sslatteng *(raster++) |= *(glyph++);
165369c7ec87Sslatteng if (!(++start & bytemask))
165469c7ec87Sslatteng glyph = leftstipple;
165569c7ec87Sslatteng }
165669c7ec87Sslatteng if (length & 7) { /* add any part hanging off the end */
165769c7ec87Sslatteng *raster |= (*glyph) & (0xff << -length);
165869c7ec87Sslatteng }
165969c7ec87Sslatteng }
166069c7ec87Sslatteng }
166169c7ec87Sslatteng
166269c7ec87Sslatteng #ifdef DEBUGABLE
166369c7ec87Sslatteng if (dbg) {
166469c7ec87Sslatteng vectptr = activehead;
166569c7ec87Sslatteng do {
166669c7ec87Sslatteng fprintf (stderr, "%d ", vectptr->curry);
166769c7ec87Sslatteng vectptr = vectptr->next;
166869c7ec87Sslatteng } while (vectptr != activehead);
166969c7ec87Sslatteng }
167069c7ec87Sslatteng #endif
167169c7ec87Sslatteng /* update the vectors */
167269c7ec87Sslatteng vectptr = activehead->next;
167369c7ec87Sslatteng do {
167469c7ec87Sslatteng if (vectptr->dy > 0) {
167569c7ec87Sslatteng while (vectptr->param >= 0) {
167669c7ec87Sslatteng vectptr->param -= vectptr->dx;
167769c7ec87Sslatteng vectptr->curry++;
167869c7ec87Sslatteng }
167969c7ec87Sslatteng vectptr->param += vectptr->dy;
168069c7ec87Sslatteng } else if (vectptr->dy < 0) {
168169c7ec87Sslatteng while (vectptr->param >= 0) {
168269c7ec87Sslatteng vectptr->param -= vectptr->dx;
168369c7ec87Sslatteng vectptr->curry--;
168469c7ec87Sslatteng }
168569c7ec87Sslatteng vectptr->param -= vectptr->dy;
168669c7ec87Sslatteng }
168769c7ec87Sslatteng /* must sort the vectors if updates */
168869c7ec87Sslatteng /* caused them to cross */
168969c7ec87Sslatteng /* also move to next vector here */
169069c7ec87Sslatteng if (vectptr->curry > vectptr->prev->curry) {
169169c7ec87Sslatteng register polyvector *v; /* vector to move */
169269c7ec87Sslatteng register polyvector *p; /* vector to put it after */
169369c7ec87Sslatteng
169469c7ec87Sslatteng v = vectptr;
169569c7ec87Sslatteng p = v->prev;
169669c7ec87Sslatteng while (v->curry > p->curry) /* find the */
169769c7ec87Sslatteng p = p->prev; /* right vector */
169869c7ec87Sslatteng
169969c7ec87Sslatteng vectptr = vectptr->next; /* remove from spot */
170069c7ec87Sslatteng vectptr->prev = v->prev;
170169c7ec87Sslatteng v->prev->next = vectptr;
170269c7ec87Sslatteng
170369c7ec87Sslatteng v->prev = p; /* put in new spot */
170469c7ec87Sslatteng v->next = p->next;
170569c7ec87Sslatteng p->next = v;
170669c7ec87Sslatteng v->next->prev = v;
170769c7ec87Sslatteng } else {
170869c7ec87Sslatteng vectptr = vectptr->next;
170969c7ec87Sslatteng }
171069c7ec87Sslatteng } while (vectptr != activehead);
171169c7ec87Sslatteng #ifdef DEBUGABLE
171269c7ec87Sslatteng if (dbg) fprintf(stderr, "line done\n");
171369c7ec87Sslatteng #endif
171469c7ec87Sslatteng
171569c7ec87Sslatteng if (++minx & mask) {
171669c7ec87Sslatteng leftstipple += bytewidth;
171769c7ec87Sslatteng } else {
171869c7ec87Sslatteng leftstipple = topstipple;
171969c7ec87Sslatteng }
172069c7ec87Sslatteng bottompage += BYTES_PER_LINE;
172169c7ec87Sslatteng } /* while (minx < nextx) */
172269c7ec87Sslatteng } /* while (minx <= maxx) */
172369c7ec87Sslatteng
172469c7ec87Sslatteng leavepoly:
172569c7ec87Sslatteng nfree(waitinghead);
172669c7ec87Sslatteng } /* polygon function */
1727