xref: /csrg-svn/old/vplot/vplot.c (revision 11517)
1 /*  VPLOT: version 4.1				updated 03/10/83
2  *
3  *  Reads standard graphics input and produces a plot on the
4  *  Varian or Versatec
5  *  -- creates in /usr/tmp a raster file of 500 1K-blocks.
6  */
7 #include <stdio.h>
8 #include <signal.h>
9 #include <vfont.h>
10 
11 #define LPR "/usr/ucb/lpr"
12 #define VAX		/* Machine Flag (don't simulate VM on vax) */
13 
14 #ifdef VAX
15 #define NB	1024		/* Number of blocks in virtual memory */
16 #else
17 #define	NB	88		/* Number of blocks kept in memory */
18 #endif
19 #define BSIZ	512		/* Size of blocks */
20 #define LOGBSIZ	9		/* log base 2 of BSIZ */
21 
22 #define	mapx(x)	((DevRange*((x)-botx)/del)+centx)
23 #define	mapy(y)	((DevRange*(del-(y)+boty)/del)-centy)
24 #define SOLID -1
25 #define DOTTED 014
26 #define SHORTDASHED 034
27 #define DOTDASHED 054
28 #define LONGDASHED 074
29 
30 char *Sid = "@(#)\t03/10/83";
31 
32 int	linmod	= SOLID;
33 int	done1;
34 char	chrtab[][16];
35 char	blocks[NB][BSIZ];
36 int	lastx;
37 int	lasty;
38 int	radius, startx, starty, endx, endy;
39 double	topx;
40 double	topy;
41 double	botx;
42 double	boty;
43 int	centx = 0;
44 int	centy = 0;
45 double	delx;
46 double	dely;
47 double	del;
48 
49 int	warned = 0;	/* Indicates whether the warning message about
50 			 * unimplemented routines has been printed */
51 
52 #ifdef VAX
53 char	dirty[NB];		/* marks if a block has been written into */
54 #else
55 struct	buf {
56 	int	bno;
57 	char	*block;
58 } bufs[NB];
59 #endif
60 
61 FILE	*infile;
62 int	fd;
63 char	picture[] = "/usr/tmp/rastAXXXXXX";
64 int	run = 13;		/* index of 'a' in picture[] */
65 int	DevRange = 1536;	/* output array size (square) in pixels */
66 int	BytesPerLine = 264;	/* Bytes per raster line (physical) */
67 int	lparg = 7;		/* index into lpargs */
68 
69 char	*lpargs[50] = { "lpr", "-Pvarian", "-v", "-s", "-r", "-J", "vplot" };
70 
71 /* variables for used to print from font file */
72 int	fontSet = 0;		/* Has the font file been read */
73 struct	header header;
74 struct	dispatch dispatch[256];
75 char	*bits;
76 char	*fontFile = "/usr/lib/vfont/R.6";
77 
78 main(argc, argv)
79 int argc;
80 char **argv;
81 {
82 	extern int cleanup();
83 	extern char *malloc();
84 	register i, j;
85 	register char *arg;
86 	int again;
87 
88 	infile = stdin;
89 	while (argc > 1 && argv[1][0] == '-') {
90 		argc--;
91 		arg = *++argv;
92 		switch (*++arg) {
93 		case 'W':
94 			DevRange = 2047;
95 			BytesPerLine = 880;
96 			lpargs[1] = "-Pversatec";
97 			break;
98 		case 'V':
99 			DevRange = 1536;
100 			BytesPerLine = 264;
101 			lpargs[1] = "-Pvarian";
102 			break;
103 		case 'b':
104 			if (argc-- > 1)
105 				lpargs[lparg-1] = *++argv;
106 			break;
107 		default:
108 			fprintf(stderr, "vplot: %s option unknown\n", *argv);
109 			break;
110 		}
111 	}
112 	if (argc > 1) {
113 		if ((infile = fopen(*++argv, "r")) == NULL) {
114 			perror(*argv);
115 			cleanup();
116 		}
117 	}
118 
119 	/* init constants for scaling */
120 	topx = topy = DevRange;
121 	botx = boty = 0;
122 	delx = dely = del = DevRange;
123 	centx = (DevRange - mapx(topx))/2;
124 	centy = mapy(topy)/2;
125 	signal(SIGTERM, cleanup);
126 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
127 		signal(SIGINT, cleanup);
128 	mktemp(picture);
129 	do {
130 		if ((fd = creat(picture, 0666)) < 0) {
131 			fprintf(stderr, "can't create %s\n", picture);
132 			cleanup();
133 		}
134 #ifndef VAX
135 		close(fd);
136 		if ((fd = open(picture, 2)) < 0) {
137 			fprintf(stderr, "can't reopen %s\n", picture);
138 			cleanup();
139 		}
140 #endif
141 		i = strlen(picture) + 1;
142 		if ((arg = malloc(i)) == NULL) {
143 			fprintf(stderr, "ran out of memory\n");
144 			cleanup();
145 		}
146 		strcpy(arg, picture);
147 		lpargs[lparg++] = arg;
148 		picture[run]++;
149 		for (i=0; i<NB; i++) {
150 #ifdef VAX
151 			dirty[i] = 0;
152 			for (j=0; j<BSIZ; ++j)
153 				blocks[i][j] = 0;
154 #else
155 			bufs[i].bno = -1;
156 			bufs[i.block = blocks[i];
157 #endif
158 		}
159 #ifdef NOHOLES
160 		/* clear the entire file */
161 		for (i=0; i<BSIZ; i++)
162 			blocks[0][i] = '\0';
163 		for (i=0; i<1024; i++)
164 			write(fd, blocks[0], BSIZ);
165 #endif
166 
167 		again = getpict();
168 
169 		for (i=0; i<NB; i++) {
170 #ifdef VAX
171 			if (dirty[i]) {		/* write out non-zero blocks */
172 				zseek(fd, i);
173 				write(fd, blocks[i], BSIZ);
174 			}
175 #else
176 			if (bufs[i].bno != -1) {
177 				zseek(fd, bufs[i].bno);
178 				write(fd, bufs[i].blocks[i], BSIZ);
179 			}
180 #endif
181 		}
182 		close(fd);
183 	} while (again);
184 	lpargs[lparg] = 0;
185 	execv(LPR, lpargs);
186 	fprintf(stderr, "can't exec %s\n", LPR);
187 	cleanup();
188 }
189 
190 getpict()
191 {
192 	register x1, y1;
193 
194 	for (;;) switch (x1 = getc(infile)) {
195 
196 	case '\n':
197 		continue;
198 
199 	case 's':
200 		botx = getinteger(infile);
201 		boty = getinteger(infile);
202 		topx = getinteger(infile);
203 		topy = getinteger(infile);
204 		delx = topx-botx;
205 		dely = topy-boty;
206 		if (dely/delx > 1536./2048.)
207 			del = dely;
208 		else
209 			del = delx;
210 		centx = 0;
211 		centx = (DevRange - mapx(topx))/2;
212 		centy = 0;
213 		centy = mapy(topy) / 2;
214 		continue;
215 
216 	case 'b':
217 		x1 = getc(infile);
218 		continue;
219 
220 	case 'l':
221 		done1 |= 01;
222 		x1 = mapx(getinteger(infile));
223 		y1 = mapy(getinteger(infile));
224 		lastx = mapx(getinteger(infile));
225 		lasty = mapy(getinteger(infile));
226 		line(x1, y1, lastx, lasty);
227 		continue;
228 
229 	case 'c':
230 		x1 = mapx(getinteger(infile));
231 		y1 = mapy(getinteger(infile));
232 		radius = mapx(getinteger(infile));
233 		if (!warned) {
234 			fprintf(stderr,"Circles are Implemented\n");
235 			warned++;
236 		}
237 		circle(x1, y1, radius);
238 		continue;
239 
240 	case 'a':
241 		x1 = mapx(getinteger(infile));
242 		y1 = mapy(getinteger(infile));
243 		startx = mapx(getinteger(infile));
244 		starty = mapy(getinteger(infile));
245 		endx = mapx(getinteger(infile));
246 		endy = mapy(getinteger(infile));
247 		if (!warned) {
248 			fprintf(stderr,"Circles and Arcs are unimplemented\n");
249 			warned++;
250 		}
251 		continue;
252 
253 	case 'm':
254 		lastx = mapx(getinteger(infile));
255 		lasty = mapy(getinteger(infile));
256 		continue;
257 
258 	case 't':
259 		lastx = lastx - 6;
260 		lasty = lasty + 6;
261 		done1 |= 01;
262 		while ((x1 = getc(infile)) != '\n')
263 			plotch(x1);
264 		continue;
265 
266 	case 'e':
267 		if (done1)
268 			return(1);
269 		continue;
270 
271 	case 'p':
272 		done1 |= 01;
273 		lastx = mapx(getinteger(infile));
274 		lasty = mapy(getinteger(infile));
275 		point(lastx, lasty);
276 		point(lastx+1, lasty);
277 		point(lastx, lasty+1);
278 		point(lastx+1, lasty+1);
279 		continue;
280 
281 	case 'n':
282 		done1 |= 01;
283 		x1 = mapx(getinteger(infile));
284 		y1 = mapy(getinteger(infile));
285 		line(lastx, lasty, x1, y1);
286 		lastx = x1;
287 		lasty = y1;
288 		continue;
289 
290 	case 'f':
291 		getinteger(infile);
292 		getc(infile);
293 		switch (getc(infile)) {
294 		case 't':
295 			linmod = DOTTED;
296 			break;
297 		default:
298 		case 'i':
299 			linmod = SOLID;
300 			break;
301 		case 'g':
302 			linmod = LONGDASHED;
303 			break;
304 		case 'r':
305 			linmod = SHORTDASHED;
306 			break;
307 		case 'd':
308 			linmod = DOTDASHED;
309 			break;
310 		}
311 		while ((x1 = getc(infile)) != '\n')
312 			if (x1 == EOF)
313 				return(0);
314 		continue;
315 
316 	case 'd':
317 		getinteger(infile);
318 		getinteger(infile);
319 		getinteger(infile);
320 		x1 = getinteger(infile);
321 		while (--x1 >= 0)
322 			getinteger(infile);
323 		continue;
324 
325 	case 0:		/* ignore null characters */
326 		continue;
327 
328 	case 255:
329 	case EOF:
330 		return(0);
331 
332 	default:
333 		fprintf(stderr, "Input format error %c(%o)\n",x1,x1);
334 		cleanup();
335 	}
336 }
337 
338 plotch(ch)
339 char ch;
340 {
341 	register int i,j,k;
342 	register char *ptr,c;
343 	int nbytes;
344 
345 	if (!fontSet)
346 		InitFont();	/* Read font if not already read */
347 
348 	ptr = bits + dispatch[ch].addr;
349 
350 	for (i = dispatch[ch].up; i > -dispatch[ch].down; --i) {
351 		nbytes = (dispatch[ch].right + dispatch[ch].left + 7)/8;
352 		for (j = 0; j < nbytes; j++) {
353 			c = *ptr++;
354 			for (k = 7; k >= 0; k--)
355 				if ((c >> k) & 1)
356 					point(lastx+7-k+j*8-dispatch[ch].left, lasty-i);
357 		}
358 	}
359 	if (ch != ' ')
360 		lastx += dispatch[ch].width;
361 	else
362 		lastx += dispatch['a'].width;
363 }
364 
365 InitFont()
366 {
367 	char *s;
368 	int fonts;
369 	int i;
370 
371 	fontSet = 1;
372 	/* Get the font file */
373 	s = fontFile;
374 	if ((fonts = open(s, 0)) == -1) {
375 		perror(s);
376 		fprintf(stderr, "Can't get font file");
377 		cleanup();
378 	}
379 	/* Get the header and check magic number */
380 	if (read(fonts, &header, sizeof(header)) != sizeof(header)) {
381 		perror(s);
382 		fprintf(stderr, "Bad read in font file");
383 		cleanup();
384 	}
385 	if (header.magic != 0436) {
386 		fprintf(stderr,"Bad magic numer in font file");
387 		cleanup();
388 	}
389 	/* Get dispatches */
390 	if (read(fonts, dispatch, sizeof(dispatch)) != sizeof(dispatch)) {
391 		perror(s);
392 		fprintf(stderr, "Bad read in font file");
393 		cleanup();
394 	}
395 	/* Allocate space for bit map and read in bits */
396 	bits = (char *) malloc(header.size);
397 	if (read(fonts, bits, header.size) != header.size) {
398 		perror(s);
399 		fprintf(stderr,"Can't read bit map in font file");
400 		cleanup();
401 	}
402 	/* Close font file */
403 	if (close(fonts) != 0) {
404 		perror(s);
405 		fprintf(stderr,"Can't close font file");
406 		cleanup();
407 	}
408 }
409 
410 line(x0, y0, x1, y1)
411 register x0, y0;
412 {
413 	int dx, dy;
414 	int xinc, yinc;
415 	register res1;
416 	int res2;
417 	int slope;
418 
419 	xinc = 1;
420 	yinc = 1;
421 	if ((dx = x1-x0) < 0) {
422 		xinc = -1;
423 		dx = -dx;
424 	}
425 	if ((dy = y1-y0) < 0) {
426 		yinc = -1;
427 		dy = -dy;
428 	}
429 	slope = xinc*yinc;
430 	res1 = 0;
431 	res2 = 0;
432 	if (dx >= dy) while (x0 != x1) {
433 		if ((x0+slope*y0) & linmod)
434 			point(x0, y0);
435 		if (res1 > res2) {
436 			res2 += dx - res1;
437 			res1 = 0;
438 			y0 += yinc;
439 		}
440 		res1 += dy;
441 		x0 += xinc;
442 	} else while (y0 != y1) {
443 		if ((x0+slope*y0) & linmod)
444 		point(x0, y0);
445 		if (res1 > res2) {
446 			res2 += dy - res1;
447 			res1 = 0;
448 			x0 += xinc;
449 		}
450 		res1 += dx;
451 		y0 += yinc;
452 	}
453 	if ((x1+slope*y1) & linmod)
454 		point(x1, y1);
455 }
456 
457 #define labs(a) (a >= 0 ? a : -a)
458 
459 circle(x,y,c)
460 {
461 	register dx, dy;
462 	long ep;
463 	int de;
464 
465 	dx = 0;
466 	ep = 0;
467 	for (dy=c; dy>=dx; dy--) {
468 		for (;;) {
469 			point(x+dx, y+dy);
470 			point(x-dx, y+dy);
471 			point(x+dx, y-dy);
472 			point(x-dx, y-dy);
473 			point(x+dy, y+dx);
474 			point(x-dy, y+dx);
475 			point(x+dy, y-dx);
476 			point(x-dy, y-dx);
477 			ep += 2*dx + 1;
478 			de = -2*dy + 1;
479 			dx++;
480 			if (labs(ep) >= labs(ep+de)) {
481 				ep += de;
482 				break;
483 			}
484 		}
485 	}
486 }
487 
488 /*
489  * Points should be in the range 0 <= x (or y) <= DevRange.
490  * The origin is the top left-hand corner with increasing x towards the
491  * right and increasing y going down.
492  */
493 point(x, y)
494 register int x, y;
495 {
496 	register unsigned bno, byte;
497 
498 	byte = y * BytesPerLine + (x >> 3);
499 	bno = byte >> LOGBSIZ;
500 	byte &= BSIZ - 1;
501 	if (bno >= 1024)
502 		return;
503 #ifndef VAX
504 	if (bno != bufs[0].bno)
505 		getblk(bno);
506 	bufs[0].block[byte] |= 1 << (7 - (x & 07));
507 #else
508 	blocks[bno][byte] |= 1 << (7 - (x & 07));
509 	dirty[bno] = 1;
510 #endif
511 }
512 
513 #ifndef VAX
514 getblk(b)
515 register b;
516 {
517 	register struct buf *bp1;
518 	register char *tp;
519 
520 loop:
521 	for (bp1 = bufs; bp1 < &bufs[NB]; bp1++) {
522 		if (bp1->bno == b || bp1->bno == -1) {
523 			tp = bp1->block;
524 			while (bp1 > bufs) {
525 				bp1->bno = (bp1-1)->bno;
526 				bp1->block = (bp1-1)->block;
527 				bp1--;
528 			}
529 			bp1->bno = b;
530 			bp1->block = tp;
531 			return;
532 		}
533 	}
534 	zseek(fd, bufs[NB-1].bno);
535 	write(fd, bufs[NB-1].block, BSIZ);
536 	zseek(fd, b);
537 	read(fd, bufs[NB-1].block, BSIZ);
538 	bufs[NB-1].bno = b;
539 	goto loop;
540 }
541 #endif
542 
543 cleanup()
544 {
545 	while (picture[run] != 'a') {
546 		unlink(picture);
547 		picture[run]--;
548 	}
549 	exit(1);
550 }
551 
552 zseek(a, b)
553 {
554 	return(lseek(a, (long)b*BSIZ, 0));
555 }
556 
557 getinteger(f)
558 FILE *f;
559 {
560 	register int low, high, result;
561 
562 	low = getc(f);
563 	high = getc(f);
564 	result = ((high << 8) | low);
565 	if (high > 127)
566 		result |= ~0xffff;
567 	return(result);
568 }
569