1 /*
2  * Copyright (C) 2000, Matias Atria
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #include <config.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <math.h>
25 #include <errno.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28 
29 #include "mdvi.h"
30 #include "private.h"
31 #include "color.h"
32 
33 typedef int (*DviCommand) __PROTO((DviContext *, int));
34 
35 #define DVICMDDEF(x)	static int x __PROTO((DviContext *, int))
36 
37 DVICMDDEF(set_char);
38 DVICMDDEF(set_rule);
39 DVICMDDEF(no_op);
40 DVICMDDEF(push);
41 DVICMDDEF(pop);
42 DVICMDDEF(move_right);
43 DVICMDDEF(move_down);
44 DVICMDDEF(move_w);
45 DVICMDDEF(move_x);
46 DVICMDDEF(move_y);
47 DVICMDDEF(move_z);
48 DVICMDDEF(sel_font);
49 DVICMDDEF(sel_fontn);
50 DVICMDDEF(special);
51 DVICMDDEF(def_font);
52 DVICMDDEF(undefined);
53 DVICMDDEF(unexpected);
54 
55 static const DviCommand dvi_commands[] = {
56 	set_char, set_char, set_char, set_char,
57 	set_char, set_char, set_char, set_char,
58 	set_char, set_char, set_char, set_char,
59 	set_char, set_char, set_char, set_char,
60 	set_char, set_char, set_char, set_char,
61 	set_char, set_char, set_char, set_char,
62 	set_char, set_char, set_char, set_char,
63 	set_char, set_char, set_char, set_char,
64 	set_char, set_char, set_char, set_char,
65 	set_char, set_char, set_char, set_char,
66 	set_char, set_char, set_char, set_char,
67 	set_char, set_char, set_char, set_char,
68 	set_char, set_char, set_char, set_char,
69 	set_char, set_char, set_char, set_char,
70 	set_char, set_char, set_char, set_char,
71 	set_char, set_char, set_char, set_char,
72 	set_char, set_char, set_char, set_char,
73 	set_char, set_char, set_char, set_char,
74 	set_char, set_char, set_char, set_char,
75 	set_char, set_char, set_char, set_char,
76 	set_char, set_char, set_char, set_char,
77 	set_char, set_char, set_char, set_char,
78 	set_char, set_char, set_char, set_char,
79 	set_char, set_char, set_char, set_char,
80 	set_char, set_char, set_char, set_char,
81 	set_char, set_char, set_char, set_char,
82 	set_char, set_char, set_char, set_char,
83 	set_char, set_char, set_char, set_char,
84 	set_char, set_char, set_char, set_char,
85 	set_char, set_char, set_char, set_char,
86 	set_char, set_char, set_char, set_char,
87 	set_char, set_char, set_char, set_char,	/* 0 - 127 */
88 	set_char, set_char, set_char, set_char, /* 128 - 131 */
89 	set_rule,				/* 132 */
90 	set_char, set_char, set_char, set_char, /* 133 - 136 */
91 	set_rule,				/* 137 */
92 	no_op,					/* 138 */
93 	unexpected,				/* 139 (BOP) */
94 	unexpected,				/* 140 (EOP) */
95 	push,					/* 141 */
96 	pop,					/* 142 */
97 	move_right, move_right, move_right, move_right,	/* 143 - 146 */
98 	move_w, move_w, move_w, move_w,	move_w,	/* 147 - 151 */
99 	move_x, move_x, move_x, move_x, move_x,	/* 152 - 156 */
100 	move_down, move_down, move_down, move_down,	/* 157 - 160 */
101 	move_y, move_y, move_y, move_y, move_y,	/* 161 - 165 */
102 	move_z, move_z, move_z, move_z, move_z,	/* 166 - 170 */
103 	sel_font, sel_font, sel_font, sel_font,
104 	sel_font, sel_font, sel_font, sel_font,
105 	sel_font, sel_font, sel_font, sel_font,
106 	sel_font, sel_font, sel_font, sel_font,
107 	sel_font, sel_font, sel_font, sel_font,
108 	sel_font, sel_font, sel_font, sel_font,
109 	sel_font, sel_font, sel_font, sel_font,
110 	sel_font, sel_font, sel_font, sel_font,
111 	sel_font, sel_font, sel_font, sel_font,
112 	sel_font, sel_font, sel_font, sel_font,
113 	sel_font, sel_font, sel_font, sel_font,
114 	sel_font, sel_font, sel_font, sel_font,
115 	sel_font, sel_font, sel_font, sel_font,
116 	sel_font, sel_font, sel_font, sel_font,
117 	sel_font, sel_font, sel_font, sel_font,
118 	sel_font, sel_font, sel_font, sel_font,	/* 171 - 234 */
119 	sel_fontn, sel_fontn, sel_fontn, sel_fontn, 	/* 235 - 238 */
120 	special, special, special, special,	/* 239 - 242 */
121 	def_font, def_font, def_font, def_font,	/* 243 - 246 */
122 	unexpected,				/* 247 (PRE) */
123 	unexpected,				/* 248 (POST) */
124 	unexpected,				/* 249 (POST_POST) */
125 	undefined, undefined, undefined,
126 	undefined, undefined, undefined		/* 250 - 255 */
127 };
128 
129 #define DVI_BUFLEN	4096
130 
131 static int	mdvi_run_macro(DviContext *dvi, Uchar *macro, size_t len);
132 
dummy_draw_glyph(DviContext * dvi,DviFontChar * ch,int x,int y)133 static void dummy_draw_glyph(DviContext *dvi, DviFontChar *ch, int x, int y)
134 {
135 }
136 
dummy_draw_rule(DviContext * dvi,int x,int y,Uint w,Uint h,int f)137 static void dummy_draw_rule(DviContext *dvi, int x, int y, Uint w, Uint h, int f)
138 {
139 }
140 
dummy_alloc_colors(void * a,Ulong * b,int c,Ulong d,Ulong e,double f,int g)141 static int dummy_alloc_colors(void *a, Ulong *b, int c, Ulong d, Ulong e, double f, int g)
142 {
143 	return -1;
144 }
145 
dummy_create_image(void * a,Uint b,Uint c,Uint d)146 static void *dummy_create_image(void *a, Uint b, Uint c, Uint d)
147 {
148 	return NULL;
149 }
150 
dummy_free_image(void * a)151 static void dummy_free_image(void *a)
152 {
153 }
154 
dummy_dev_destroy(void * a)155 static void dummy_dev_destroy(void *a)
156 {
157 }
158 
dummy_dev_putpixel(void * a,int x,int y,Ulong c)159 static void dummy_dev_putpixel(void *a, int x, int y, Ulong c)
160 {
161 }
162 
dummy_dev_refresh(DviContext * a,void * b)163 static void dummy_dev_refresh(DviContext *a, void *b)
164 {
165 }
166 
dummy_dev_set_color(void * a,Ulong b,Ulong c)167 static void dummy_dev_set_color(void *a, Ulong b, Ulong c)
168 {
169 }
170 
171 /* functions to report errors */
dvierr(DviContext * dvi,const char * format,...)172 static void dvierr(DviContext *dvi, const char *format, ...)
173 {
174 	va_list	ap;
175 
176 	va_start(ap, format);
177 	fprintf(stderr, "%s[%d]: Error: ",
178 		dvi->filename, dvi->currpage);
179 	vfprintf(stderr, format, ap);
180 	va_end(ap);
181 }
182 
dviwarn(DviContext * dvi,const char * format,...)183 static void dviwarn(DviContext *dvi, const char *format, ...)
184 {
185 	va_list	ap;
186 
187 	fprintf(stderr, "%s[%d]: Warning: ",
188 		dvi->filename, dvi->currpage);
189 	va_start(ap, format);
190 	vfprintf(stderr, format, ap);
191 	va_end(ap);
192 }
193 
194 #define NEEDBYTES(d,n) \
195 	((d)->buffer.pos + (n) > (d)->buffer.length)
196 
get_bytes(DviContext * dvi,size_t n)197 static int get_bytes(DviContext *dvi, size_t n)
198 {
199 	/*
200 	 * caller wants to read `n' bytes from dvi->buffer + dvi->pos.
201 	 * Make sure there is enough data to satisfy the request
202 	 */
203 	if(NEEDBYTES(dvi, n)) {
204 		size_t	required;
205 		int	newlen;
206 
207 		if(dvi->buffer.frozen || dvi->in == NULL || feof(dvi->in)) {
208 			/* this is EOF */
209 			dviwarn(dvi, _("unexpected EOF\n"));
210 			return -1;
211 		}
212 		/* get more data */
213 		if(dvi->buffer.data == NULL) {
214 			/* first allocation */
215 			dvi->buffer.size = Max(DVI_BUFLEN, n);
216 			dvi->buffer.data = (Uchar *)mdvi_malloc(dvi->buffer.size);
217 			dvi->buffer.length = 0;
218 			dvi->buffer.frozen = 0;
219 		} else if(dvi->buffer.pos < dvi->buffer.length) {
220 			/* move whatever we want to keep */
221 			dvi->buffer.length -= dvi->buffer.pos;
222 			memmove(dvi->buffer.data,
223 				dvi->buffer.data + dvi->buffer.pos,
224 				dvi->buffer.length);
225 		} else {
226 			/* we can discard all the data in this buffer */
227 			dvi->buffer.length = 0;
228 		}
229 
230 		required = n - dvi->buffer.length;
231 		if(required > dvi->buffer.size - dvi->buffer.length) {
232 			/* need to allocate more memory */
233 			dvi->buffer.size = dvi->buffer.length + required + 128;
234 			dvi->buffer.data = (Uchar *)xresize(dvi->buffer.data,
235 				char, dvi->buffer.size);
236 		}
237 		/* now read into the buffer */
238 		newlen = fread(dvi->buffer.data + dvi->buffer.length,
239 			1, dvi->buffer.size - dvi->buffer.length, dvi->in);
240 		if(newlen == -1) {
241 			mdvi_error("%s: %s\n", dvi->filename, strerror(errno));
242 			return -1;
243 		}
244 		dvi->buffer.length += newlen;
245 		dvi->buffer.pos = 0;
246 	}
247 	return 0;
248 }
249 
250 /* only relative forward seeks are supported by this function */
dskip(DviContext * dvi,long offset)251 static int dskip(DviContext *dvi, long offset)
252 {
253 	ASSERT(offset > 0);
254 
255 	if(NEEDBYTES(dvi, offset) && get_bytes(dvi, offset) == -1)
256 		return -1;
257 	dvi->buffer.pos += offset;
258 	return 0;
259 }
260 
261 /* DVI I/O functions (note: here `n' must be <= 4) */
dsgetn(DviContext * dvi,size_t n)262 static long dsgetn(DviContext *dvi, size_t n)
263 {
264 	long	val;
265 
266 	if(NEEDBYTES(dvi, n) && get_bytes(dvi, n) == -1)
267 		return -1;
268 	val = msgetn(dvi->buffer.data + dvi->buffer.pos, n);
269 	dvi->buffer.pos += n;
270 	return val;
271 }
272 
dread(DviContext * dvi,char * buffer,size_t len)273 static int dread(DviContext *dvi, char *buffer, size_t len)
274 {
275 	if(NEEDBYTES(dvi, len) && get_bytes(dvi, len) == -1)
276 		return -1;
277 	memcpy(buffer, dvi->buffer.data + dvi->buffer.pos, len);
278 	dvi->buffer.pos += len;
279 	return 0;
280 }
281 
dugetn(DviContext * dvi,size_t n)282 static long dugetn(DviContext *dvi, size_t n)
283 {
284 	long	val;
285 
286 	if(NEEDBYTES(dvi, n) && get_bytes(dvi, n) == -1)
287 		return -1;
288 	val = mugetn(dvi->buffer.data + dvi->buffer.pos, n);
289 	dvi->buffer.pos += n;
290 	return val;
291 }
292 
dtell(DviContext * dvi)293 static long dtell(DviContext *dvi)
294 {
295 	return dvi->depth ?
296 		dvi->buffer.pos :
297 		ftell(dvi->in) - dvi->buffer.length + dvi->buffer.pos;
298 }
299 
dreset(DviContext * dvi)300 static void dreset(DviContext *dvi)
301 {
302 	if(!dvi->buffer.frozen && dvi->buffer.data)
303 		mdvi_free(dvi->buffer.data);
304 	dvi->buffer.data = NULL;
305 	dvi->buffer.size = 0;
306 	dvi->buffer.length = 0;
307 	dvi->buffer.pos = 0;
308 }
309 
310 #define dsget4(d)	dsgetn((d), 4)
311 #define duget1(d)	dugetn((d), 1)
312 #define duget4(d)	dugetn((d), 4)
313 
314 #ifndef NODEBUG
dviprint(DviContext * dvi,const char * command,int sub,const char * fmt,...)315 static void dviprint(DviContext *dvi, const char *command, int sub, const char *fmt, ...)
316 {
317 	int	i;
318 	va_list	ap;
319 
320 	printf("%s: ", dvi->filename);
321 	for(i = 0; i < dvi->depth; i++)
322 		printf("  ");
323 	printf("%4lu: %s", dtell(dvi), command);
324 	if(sub >= 0) printf("%d", sub);
325 	if(*fmt) printf(": ");
326 	va_start(ap, fmt);
327 	vprintf(fmt, ap);
328 	va_end(ap);
329 }
330 #define SHOWCMD(x)	\
331 	if(_mdvi_debug_mask & DBG_OPCODE) do { dviprint x; } while(0)
332 #else
333 #define SHOWCMD(x)	do { } while(0)
334 #endif
335 
mdvi_find_tex_page(DviContext * dvi,int tex_page)336 int	mdvi_find_tex_page(DviContext *dvi, int tex_page)
337 {
338 	int	i;
339 
340 	for(i = 0; i < dvi->npages; i++)
341 		if(dvi->pagemap[i][1] == tex_page)
342 			return i;
343 	return -1;
344 }
345 
346 /* page sorting functions */
sort_up(const void * p1,const void * p2)347 static int sort_up(const void *p1, const void *p2)
348 {
349 	return ((long *)p1)[1] - ((long *)p2)[1];
350 }
sort_down(const void * p1,const void * p2)351 static int sort_down(const void *p1, const void *p2)
352 {
353 	return ((long *)p2)[1] - ((long *)p1)[1];
354 }
sort_random(const void * p1,const void * p2)355 static int sort_random(const void *p1, const void *p2)
356 {
357 	return (rand() % 1) ? -1 : 1;
358 }
sort_dvi_up(const void * p1,const void * p2)359 static int sort_dvi_up(const void *p1, const void *p2)
360 {
361 	return ((long *)p1)[0] - ((long *)p2)[0];
362 }
sort_dvi_down(const void * p1,const void * p2)363 static int sort_dvi_down(const void *p1, const void *p2)
364 {
365 	return ((long *)p1)[0] - ((long *)p2)[0];
366 }
367 
mdvi_sort_pages(DviContext * dvi,DviPageSort type)368 void	mdvi_sort_pages(DviContext *dvi, DviPageSort type)
369 {
370 	int	(*sortfunc) __PROTO((const void *, const void *));
371 
372 	switch(type) {
373 	case MDVI_PAGE_SORT_UP:
374 		sortfunc = sort_up;
375 		break;
376 	case MDVI_PAGE_SORT_DOWN:
377 		sortfunc = sort_down;
378 		break;
379 	case MDVI_PAGE_SORT_RANDOM:
380 		sortfunc = sort_random;
381 		break;
382 	case MDVI_PAGE_SORT_DVI_UP:
383 		sortfunc = sort_dvi_up;
384 		break;
385 	case MDVI_PAGE_SORT_DVI_DOWN:
386 		sortfunc = sort_dvi_down;
387 		break;
388 	case MDVI_PAGE_SORT_NONE:
389 	default:
390 		sortfunc = NULL;
391 		break;
392 	}
393 
394 	if(sortfunc)
395 		qsort(dvi->pagemap, dvi->npages, sizeof(PageNum), sortfunc);
396 }
397 
define_font(DviContext * dvi,int op)398 static DviFontRef *define_font(DviContext *dvi, int op)
399 {
400 	Int32	arg;
401 	Int32	scale;
402 	Int32	dsize;
403 	Int32	checksum;
404 	int	hdpi;
405 	int	vdpi;
406 	int	n;
407 	char	*name;
408 	DviFontRef *ref;
409 
410 	arg = dugetn(dvi, op - DVI_FNT_DEF1 + 1);
411 	checksum = duget4(dvi);
412 	scale = duget4(dvi);
413 	dsize = duget4(dvi);
414 	hdpi = FROUND(dvi->params.mag * dvi->params.dpi * scale / dsize);
415 	vdpi = FROUND(dvi->params.mag * dvi->params.vdpi * scale / dsize);
416 	n = duget1(dvi) + duget1(dvi);
417 	name = mdvi_malloc(n + 1);
418 	dread(dvi, name, n);
419 	name[n] = 0;
420 	DEBUG((DBG_FONTS, "requesting font %d = `%s' at %.1fpt (%dx%d dpi)\n",
421 		arg, name, (double)scale / (dvi->params.tfm_conv * 0x100000),
422 		hdpi, vdpi));
423 	ref = font_reference(&dvi->params, arg, name, checksum, hdpi, vdpi, scale);
424 	if(ref == NULL) {
425 		mdvi_error(_("could not load font `%s'\n"), name);
426 		mdvi_free(name);
427 		return NULL;
428 	}
429 	mdvi_free(name);
430 	return ref;
431 }
432 
opendvi(const char * name)433 static char *opendvi(const char *name)
434 {
435 	int	len;
436 	char	*file;
437 
438 	len = strlen(name);
439 	/* if file ends with .dvi and it exists, that's it */
440 	if(len >= 4 && STREQ(name+len-4, ".dvi")) {
441 		DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", name));
442 		if(access(name, R_OK) == 0)
443 			return mdvi_strdup(name);
444 	}
445 
446 	/* try appending .dvi */
447 	file = mdvi_malloc(len + 5);
448 	strcpy(file, name);
449 	strcpy(file+len, ".dvi");
450 	DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", file));
451 	if(access(file, R_OK) == 0)
452 		return file;
453 	/* try the given name */
454 	file[len] = 0;
455 	DEBUG((DBG_DVI|DBG_FILES, "opendvi: Trying `%s'\n", file));
456 	if(access(file, R_OK) == 0)
457 		return file;
458 	mdvi_free(file);
459 	return NULL;
460 }
461 
mdvi_reload(DviContext * dvi,DviParams * np)462 int	mdvi_reload(DviContext *dvi, DviParams *np)
463 {
464 	DviContext *newdvi;
465 	DviParams  *pars;
466 
467 	/* close our file */
468 	if(dvi->in) {
469 		fclose(dvi->in);
470 		dvi->in = NULL;
471 	}
472 
473 	pars = np ? np : &dvi->params;
474 	DEBUG((DBG_DVI, "%s: reloading\n", dvi->filename));
475 
476 	/* load it again */
477 	newdvi = mdvi_init_context(pars, dvi->pagesel, dvi->filename);
478 	if(newdvi == NULL) {
479 		mdvi_warning(_("could not reload `%s'\n"), dvi->filename);
480 		return -1;
481 	}
482 
483 	/* drop all our font references */
484 	font_drop_chain(dvi->fonts);
485 	/* destroy our font map */
486 	if(dvi->fontmap)
487 		mdvi_free(dvi->fontmap);
488 	dvi->currfont = NULL;
489 
490 	/* and use the ones we just loaded */
491 	dvi->fonts = newdvi->fonts;
492 	dvi->fontmap = newdvi->fontmap;
493 	dvi->nfonts = newdvi->nfonts;
494 
495 	/* copy the new information */
496 	dvi->params = newdvi->params;
497 	dvi->num = newdvi->num;
498 	dvi->den = newdvi->den;
499 	dvi->dvimag = newdvi->dvimag;
500 	dvi->dviconv = newdvi->dviconv;
501 	dvi->dvivconv = newdvi->dvivconv;
502 	dvi->modtime = newdvi->modtime;
503 
504 	if(dvi->fileid) mdvi_free(dvi->fileid);
505 	dvi->fileid = newdvi->fileid;
506 
507 	dvi->dvi_page_w = newdvi->dvi_page_w;
508 	dvi->dvi_page_h = newdvi->dvi_page_h;
509 
510 	mdvi_free(dvi->pagemap);
511 	dvi->pagemap = newdvi->pagemap;
512 	dvi->npages = newdvi->npages;
513 	if(dvi->currpage > dvi->npages-1)
514 		dvi->currpage = 0;
515 
516 	mdvi_free(dvi->stack);
517 	dvi->stack = newdvi->stack;
518 	dvi->stacksize = newdvi->stacksize;
519 
520 	/* remove fonts that are not being used anymore */
521 	font_free_unused(&dvi->device);
522 
523 	mdvi_free(newdvi->filename);
524 	mdvi_free(newdvi);
525 
526 	DEBUG((DBG_DVI, "%s: reload successful\n", dvi->filename));
527 	if(dvi->device.refresh)
528 		dvi->device.refresh(dvi, dvi->device.device_data);
529 
530 	return 0;
531 }
532 
533 /* function to change parameters ia DVI context
534  * The DVI context is modified ONLY if this function is successful */
mdvi_configure(DviContext * dvi,DviParamCode option,...)535 int mdvi_configure(DviContext *dvi, DviParamCode option, ...)
536 {
537 	va_list	ap;
538 	int	reset_all;
539 	int	reset_font;
540 	DviParams np;
541 
542 	va_start(ap, option);
543 
544 	reset_font = 0;
545 	reset_all  = 0;
546 	np = dvi->params; /* structure copy */
547 	while(option != MDVI_PARAM_LAST) {
548 		switch(option) {
549 		case MDVI_SET_DPI:
550 			np.dpi = np.vdpi = va_arg(ap, Uint);
551 			reset_all = 1;
552 			break;
553 		case MDVI_SET_XDPI:
554 			np.dpi = va_arg(ap, Uint);
555 			reset_all = 1;
556 			break;
557 		case MDVI_SET_YDPI:
558 			np.vdpi = va_arg(ap, Uint);
559 			break;
560 		case MDVI_SET_SHRINK:
561 			np.hshrink = np.vshrink = va_arg(ap, Uint);
562 			reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
563 			break;
564 		case MDVI_SET_XSHRINK:
565 			np.hshrink = va_arg(ap, Uint);
566 			reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
567 			break;
568 		case MDVI_SET_YSHRINK:
569 			np.vshrink = va_arg(ap, Uint);
570 			reset_font = MDVI_FONTSEL_GREY|MDVI_FONTSEL_BITMAP;
571 			break;
572 		case MDVI_SET_ORIENTATION:
573 			np.orientation = va_arg(ap, DviOrientation);
574 			reset_font = MDVI_FONTSEL_GLYPH;
575 			break;
576 		case MDVI_SET_GAMMA:
577 			np.gamma = va_arg(ap, double);
578 			reset_font = MDVI_FONTSEL_GREY;
579 			break;
580 		case MDVI_SET_DENSITY:
581 			np.density = va_arg(ap, Uint);
582 			reset_font = MDVI_FONTSEL_BITMAP;
583 			break;
584 		case MDVI_SET_MAGNIFICATION:
585 			np.mag = va_arg(ap, double);
586 			reset_all = 1;
587 			break;
588 		case MDVI_SET_DRIFT:
589 			np.hdrift = np.vdrift = va_arg(ap, int);
590 			break;
591 		case MDVI_SET_HDRIFT:
592 			np.hdrift = va_arg(ap, int);
593 			break;
594 		case MDVI_SET_VDRIFT:
595 			np.vdrift = va_arg(ap, int);
596 			break;
597 		case MDVI_SET_FOREGROUND:
598 			np.fg = va_arg(ap, Ulong);
599 			reset_font = MDVI_FONTSEL_GREY;
600 			break;
601 		case MDVI_SET_BACKGROUND:
602 			np.bg = va_arg(ap, Ulong);
603 			reset_font = MDVI_FONTSEL_GREY;
604 			break;
605 		default:
606 			break;
607 		}
608 		option = va_arg(ap, DviParamCode);
609 	}
610 	va_end(ap);
611 
612 	/* check that all values make sense */
613 	if(np.dpi <= 0 || np.vdpi <= 0)
614 		return -1;
615 	if(np.mag <= 0.0)
616 		return -1;
617 	if(np.hshrink < 1 || np.vshrink < 1)
618 		return -1;
619 	if(np.hdrift < 0 || np.vdrift < 0)
620 		return -1;
621 	if(np.fg == np.bg)
622 		return -1;
623 
624 	/*
625 	 * If the dpi or the magnification change, we basically have to reload
626 	 * the DVI file again from scratch.
627 	 */
628 
629 	if(reset_all)
630 		return (mdvi_reload(dvi, &np) == 0);
631 
632 	if(np.hshrink != dvi->params.hshrink) {
633 		np.conv = dvi->dviconv;
634 		if(np.hshrink)
635 			np.conv /= np.hshrink;
636 	}
637 	if(np.vshrink != dvi->params.vshrink) {
638 		np.vconv = dvi->dvivconv;
639 		if(np.vshrink)
640 			np.vconv /= np.vshrink;
641 	}
642 
643 	if(reset_font) {
644 		font_reset_chain_glyphs(&dvi->device, dvi->fonts, reset_font);
645 	}
646 	dvi->params = np;
647 	if((reset_font & MDVI_FONTSEL_GLYPH) && dvi->device.refresh) {
648 		dvi->device.refresh(dvi, dvi->device.device_data);
649 		return 0;
650 	}
651 
652 	return 1;
653 }
654 /*
655  * Read the initial data from the DVI file. If something is wrong with the
656  * file, we just spit out an error message and refuse to load the file,
657  * without giving any details. This makes sense because DVI files are ok
658  * 99.99% of the time, and dvitype(1) can be used to check the other 0.01%.
659  */
mdvi_init_context(DviParams * par,DviPageSpec * spec,const char * file)660 DviContext *mdvi_init_context(DviParams *par, DviPageSpec *spec, const char *file)
661 {
662 	FILE	*p;
663 	Int32	arg;
664 	int	op;
665 	long	offset;
666 	int	n;
667 	DviContext *dvi;
668 	char	*filename;
669 	int	pagecount;
670 
671 	/*
672 	 * 1. Open the file and initialize the DVI context
673 	 */
674 
675 	filename = opendvi(file);
676 	if(filename == NULL) {
677 		perror(file);
678 		return NULL;
679 	}
680 	p = fopen(filename, "rb");
681 	if(p == NULL) {
682 		perror(file);
683 		mdvi_free(filename);
684 		return NULL;
685 	}
686 	dvi = xalloc(DviContext);
687 	memzero(dvi, sizeof(DviContext));
688 	dvi->pagemap = NULL;
689 	dvi->filename = filename;
690 	dvi->stack = NULL;
691 	dvi->modtime = get_mtime(fileno(p));
692 	dvi->buffer.data = NULL;
693 	dvi->pagesel = spec;
694 	dvi->in = p; /* now we can use the dget*() functions */
695 
696 	/*
697 	 * 2. Read the preamble, extract scaling information, and
698 	 *    setup the DVI parameters.
699 	 */
700 
701 	if(fuget1(p) != DVI_PRE)
702 		goto bad_dvi;
703 	if((arg = fuget1(p)) != DVI_ID) {
704 		mdvi_error(_("%s: unsupported DVI format (version %u)\n"),
705 			   file, arg);
706 		goto error; /* jump to the end of this routine,
707 			     * where we handle errors */
708 	}
709 	/* get dimensions */
710 	dvi->num = fuget4(p);
711 	dvi->den = fuget4(p);
712 	dvi->dvimag = fuget4(p);
713 
714 	/* check that these numbers make sense */
715 	if(!dvi->num || !dvi->den || !dvi->dvimag)
716 		goto bad_dvi;
717 
718 	dvi->params.mag =
719 		(par->mag > 0 ? par->mag : (double)dvi->dvimag / 1000.0);
720 	dvi->params.hdrift  = par->hdrift;
721 	dvi->params.vdrift  = par->vdrift;
722 	dvi->params.dpi     = par->dpi ? par->dpi : MDVI_DPI;
723 	dvi->params.vdpi    = par->vdpi ? par->vdpi : par->dpi;
724 	dvi->params.hshrink = par->hshrink;
725 	dvi->params.vshrink = par->vshrink;
726 	dvi->params.density = par->density;
727 	dvi->params.gamma   = par->gamma;
728 	dvi->params.conv    = (double)dvi->num / dvi->den;
729 	dvi->params.conv   *= (dvi->params.dpi / 254000.0) * dvi->params.mag;
730 	dvi->params.vconv   = (double)dvi->num / dvi->den;
731 	dvi->params.vconv  *= (dvi->params.vdpi / 254000.0) * dvi->params.mag;
732 	dvi->params.tfm_conv = (25400000.0 / dvi->num) *
733 				((double)dvi->den / 473628672) / 16.0;
734 	dvi->params.flags = par->flags;
735 	dvi->params.orientation = par->orientation;
736 	dvi->params.fg = par->fg;
737 	dvi->params.bg = par->bg;
738 
739 	/* initialize colors */
740 	dvi->curr_fg = par->fg;
741 	dvi->curr_bg = par->bg;
742 	dvi->color_stack = NULL;
743 	dvi->color_top = 0;
744 	dvi->color_size = 0;
745 
746 	/* pixel conversion factors */
747 	dvi->dviconv = dvi->params.conv;
748 	dvi->dvivconv = dvi->params.vconv;
749 	if(dvi->params.hshrink)
750 		dvi->params.conv /= dvi->params.hshrink;
751 	if(dvi->params.vshrink)
752 		dvi->params.vconv /= dvi->params.vshrink;
753 
754 	/* get the comment from the preamble */
755 	n = fuget1(p);
756 	dvi->fileid = mdvi_malloc(n + 1);
757 	fread(dvi->fileid, 1, n, p);
758 	dvi->fileid[n] = 0;
759 	DEBUG((DBG_DVI, "%s: %s\n", filename, dvi->fileid));
760 
761 	/*
762 	 * 3. Read postamble, extract page information (number of
763 	 *    pages, dimensions) and stack depth.
764 	 */
765 
766 	/* jump to the end of the file */
767 	if(fseek(p, (long)-1, SEEK_END) == -1)
768 		goto error;
769 	for(n = 0; (op = fuget1(p)) == DVI_TRAILER; n++)
770 		if(fseek(p, (long)-2, SEEK_CUR) < 0)
771 			break;
772 	if(op != arg || n < 4)
773 		goto bad_dvi;
774 	/* get the pointer to postamble */
775 	fseek(p, (long)-5, SEEK_CUR);
776 	arg = fuget4(p);
777 	/* jump to it */
778 	fseek(p, (long)arg, SEEK_SET);
779 	if(fuget1(p) != DVI_POST)
780 		goto bad_dvi;
781 	offset = fuget4(p);
782 	if(dvi->num != fuget4(p) || dvi->den != fuget4(p) ||
783 	   dvi->dvimag != fuget4(p))
784 		goto bad_dvi;
785 	dvi->dvi_page_h = fuget4(p);
786 	dvi->dvi_page_w = fuget4(p);
787 	dvi->stacksize = fuget2(p);
788 	dvi->npages = fuget2(p);
789 	DEBUG((DBG_DVI, "%s: from postamble: stack depth %d, %d page%s\n",
790 		filename, dvi->stacksize, dvi->npages, dvi->npages > 1 ? "s" : ""));
791 
792 	/*
793 	 * 4. Process font definitions.
794 	 */
795 
796 	/* process font definitions */
797 	dvi->nfonts = 0;
798 	dvi->fontmap = NULL;
799 	/*
800 	 * CAREFUL: here we need to use the dvi->buffer, but it might leave the
801 	 * the file cursor in the wrong position after reading fonts (because of
802 	 * buffering). It's ok, though, because after the font definitions we read
803 	 * the page offsets, and we fseek() to the relevant part of the file with
804 	 * SEEK_SET. Nothing is read after the page offsets.
805 	 */
806 	while((op = duget1(dvi)) != DVI_POST_POST) {
807 		DviFontRef *ref;
808 
809 		if(op == DVI_NOOP)
810 			continue;
811 		else if(op < DVI_FNT_DEF1 || op > DVI_FNT_DEF4)
812 			goto error;
813 		ref = define_font(dvi, op);
814 		if(ref == NULL)
815 			goto error;
816 		ref->next = dvi->fonts;
817 		dvi->fonts = ref;
818 		dvi->nfonts++;
819 	}
820 	/* we don't need the buffer anymore */
821 	dreset(dvi);
822 
823 	if(op != DVI_POST_POST)
824 		goto bad_dvi;
825 	font_finish_definitions(dvi);
826 	DEBUG((DBG_DVI, "%s: %d font%s required by this job\n",
827 		filename, dvi->nfonts, dvi->nfonts > 1 ? "s" : ""));
828 	dvi->findref = font_find_mapped;
829 
830 	/*
831 	 * 5. Build the page map.
832 	 */
833 
834 	dvi->pagemap = xnalloc(PageNum, dvi->npages);
835 	memzero(dvi->pagemap, sizeof(PageNum) * dvi->npages);
836 
837 	n = dvi->npages - 1;
838 	pagecount = n;
839 	while(offset != -1) {
840 		int	i;
841 		PageNum page;
842 
843 		fseek(p, offset, SEEK_SET);
844 		op = fuget1(p);
845 		if(op != DVI_BOP || n < 0)
846 			goto bad_dvi;
847 		for(i = 1; i <= 10; i++)
848 			page[i] = fsget4(p);
849 		page[0] = offset;
850 		offset = fsget4(p);
851 		/* check if the page is selected */
852 		if(spec && mdvi_page_selected(spec, page, n) == 0) {
853 			DEBUG((DBG_DVI, "Page %d (%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld.%ld) ignored by request\n",
854 			n, page[1], page[2], page[3], page[4], page[5],
855 			   page[6], page[7], page[8], page[9], page[10]));
856 		} else {
857 			memcpy(&dvi->pagemap[pagecount], page, sizeof(PageNum));
858 			pagecount--;
859 		}
860 		n--;
861 	}
862 	pagecount++;
863 	if(pagecount >= dvi->npages) {
864 		mdvi_error(_("no pages selected\n"));
865 		goto error;
866 	}
867 	if(pagecount) {
868 		DEBUG((DBG_DVI, "%d of %d pages selected\n",
869 			dvi->npages - pagecount, dvi->npages));
870 		dvi->npages -= pagecount;
871 		memmove(dvi->pagemap, &dvi->pagemap[pagecount],
872 			dvi->npages * sizeof(PageNum));
873 	}
874 
875 	/*
876 	 * 6. Setup stack, initialize device functions
877 	 */
878 
879 	dvi->curr_layer = 0;
880 	dvi->stack = xnalloc(DviState, dvi->stacksize + 8);
881 
882 	dvi->device.draw_glyph   = dummy_draw_glyph;
883 	dvi->device.draw_rule    = dummy_draw_rule;
884 	dvi->device.alloc_colors = dummy_alloc_colors;
885 	dvi->device.create_image = dummy_create_image;
886 	dvi->device.free_image   = dummy_free_image;
887 	dvi->device.dev_destroy  = dummy_dev_destroy;
888 	dvi->device.put_pixel    = dummy_dev_putpixel;
889 	dvi->device.refresh      = dummy_dev_refresh;
890 	dvi->device.set_color    = dummy_dev_set_color;
891 	dvi->device.device_data  = NULL;
892 
893 	DEBUG((DBG_DVI, "%s read successfully\n", filename));
894 	return dvi;
895 
896 bad_dvi:
897 	mdvi_error(_("%s: File corrupted, or not a DVI file\n"), file);
898 error:
899 	/* if we came from the font definitions, this will be non-trivial */
900 	dreset(dvi);
901 	mdvi_destroy_context(dvi);
902 	return NULL;
903 }
904 
mdvi_destroy_context(DviContext * dvi)905 void	mdvi_destroy_context(DviContext *dvi)
906 {
907 	if(dvi->device.dev_destroy)
908 		dvi->device.dev_destroy(dvi->device.device_data);
909 	/* release all fonts */
910 	if(dvi->fonts) {
911 		font_drop_chain(dvi->fonts);
912 		font_free_unused(&dvi->device);
913 	}
914 	if(dvi->fontmap)
915 		mdvi_free(dvi->fontmap);
916 	if(dvi->filename)
917 		mdvi_free(dvi->filename);
918 	if(dvi->stack)
919 		mdvi_free(dvi->stack);
920 	if(dvi->pagemap)
921 		mdvi_free(dvi->pagemap);
922 	if(dvi->fileid)
923 		mdvi_free(dvi->fileid);
924 	if(dvi->in)
925 		fclose(dvi->in);
926 	if(dvi->buffer.data && !dvi->buffer.frozen)
927 		mdvi_free(dvi->buffer.data);
928 	if(dvi->color_stack)
929 		mdvi_free(dvi->color_stack);
930 
931 	mdvi_free(dvi);
932 }
933 
mdvi_setpage(DviContext * dvi,int pageno)934 void	mdvi_setpage(DviContext *dvi, int pageno)
935 {
936 	if(pageno < 0)
937 		pageno = 0;
938 	if(pageno > dvi->npages-1)
939 		pageno = dvi->npages - 1;
940 	dvi->currpage = pageno;
941 }
942 
mdvi_run_macro(DviContext * dvi,Uchar * macro,size_t len)943 static int	mdvi_run_macro(DviContext *dvi, Uchar *macro, size_t len)
944 {
945 	DviFontRef *curr, *fonts;
946 	DviBuffer saved_buffer;
947 	FILE	*saved_file;
948 	int	opcode;
949 	int	oldtop;
950 
951 	dvi->depth++;
952 	push(dvi, DVI_PUSH);
953 	dvi->pos.w = 0;
954 	dvi->pos.x = 0;
955 	dvi->pos.y = 0;
956 	dvi->pos.z = 0;
957 
958 	/* save our state */
959 	curr = dvi->currfont;
960 	fonts = dvi->fonts;
961 	saved_buffer = dvi->buffer;
962 	saved_file = dvi->in;
963 	dvi->currfont = curr->ref->subfonts;
964 	dvi->fonts = curr->ref->subfonts;
965 	dvi->buffer.data = macro;
966 	dvi->buffer.pos = 0;
967 	dvi->buffer.length = len;
968 	dvi->buffer.frozen = 1;
969 	dvi->in = NULL;
970 	oldtop = dvi->stacktop;
971 
972 	/* execute commands */
973 	while((opcode = duget1(dvi)) != DVI_EOP) {
974 		if(dvi_commands[opcode](dvi, opcode) < 0)
975 			break;
976 	}
977 	if(opcode != DVI_EOP)
978 		dviwarn(dvi, _("%s: vf macro had errors\n"),
979 			curr->ref->fontname);
980 	if(dvi->stacktop != oldtop)
981 		dviwarn(dvi, _("%s: stack not empty after vf macro\n"),
982 			curr->ref->fontname);
983 
984 	/* restore things */
985 	pop(dvi, DVI_POP);
986 	dvi->currfont = curr;
987 	dvi->fonts = fonts;
988 	dvi->buffer = saved_buffer;
989 	dvi->in = saved_file;
990 	dvi->depth--;
991 
992 	return (opcode != DVI_EOP ? -1 : 0);
993 }
994 
mdvi_dopage(DviContext * dvi,int pageno)995 int	mdvi_dopage(DviContext *dvi, int pageno)
996 {
997 	int	op;
998 	int	ppi;
999 	int	reloaded = 0;
1000 
1001 again:
1002 	if(dvi->in == NULL) {
1003 		/* try reopening the file */
1004 		dvi->in = fopen(dvi->filename, "rb");
1005 		if(dvi->in == NULL) {
1006 			mdvi_warning(_("%s: could not reopen file (%s)\n"),
1007 				     dvi->filename,
1008 				     strerror(errno));
1009 			return -1;
1010 		}
1011 		DEBUG((DBG_FILES, "reopen(%s) -> Ok\n", dvi->filename));
1012 	}
1013 
1014 	/* check if we need to reload the file */
1015 	if(!reloaded && get_mtime(fileno(dvi->in)) > dvi->modtime) {
1016 		mdvi_reload(dvi, &dvi->params);
1017 		/* we have to reopen the file, again */
1018 		reloaded = 1;
1019 		goto again;
1020 	}
1021 
1022 	if(pageno < 0 || pageno > dvi->npages-1) {
1023 		mdvi_error(_("%s: page %d out of range\n"),
1024 			   dvi->filename, pageno);
1025 		return -1;
1026 	}
1027 
1028 	fseek(dvi->in, (long)dvi->pagemap[pageno][0], SEEK_SET);
1029 	if((op = fuget1(dvi->in)) != DVI_BOP) {
1030 		mdvi_error(_("%s: bad offset at page %d\n"),
1031 			   dvi->filename, pageno+1);
1032 		return -1;
1033 	}
1034 
1035 	/* skip bop */
1036 	fseek(dvi->in, (long)44, SEEK_CUR);
1037 
1038 	/* reset state */
1039 	dvi->currfont = NULL;
1040 	memzero(&dvi->pos, sizeof(DviState));
1041 	dvi->stacktop = 0;
1042 	dvi->currpage = pageno;
1043 	dvi->curr_layer = 0;
1044 
1045 	if(dvi->buffer.data && !dvi->buffer.frozen)
1046 		mdvi_free(dvi->buffer.data);
1047 
1048 	/* reset our buffer */
1049 	dvi->buffer.data   = NULL;
1050 	dvi->buffer.length = 0;
1051 	dvi->buffer.pos    = 0;
1052 	dvi->buffer.frozen = 0;
1053 
1054 #if 0 /* make colors survive page breaks */
1055 	/* reset color stack */
1056 	mdvi_reset_color(dvi);
1057 #endif
1058 
1059 	/* set max horizontal and vertical drift (from dvips) */
1060 	if(dvi->params.hdrift < 0) {
1061 		ppi = dvi->params.dpi / dvi->params.hshrink; /* shrunk pixels per inch */
1062 		if(ppi < 600)
1063 			dvi->params.hdrift = ppi / 100;
1064 		else if(ppi < 1200)
1065 			dvi->params.hdrift = ppi / 200;
1066 		else
1067 			dvi->params.hdrift = ppi / 400;
1068 	}
1069 	if(dvi->params.vdrift < 0) {
1070 		ppi = dvi->params.vdpi / dvi->params.vshrink; /* shrunk pixels per inch */
1071 		if(ppi < 600)
1072 			dvi->params.vdrift = ppi / 100;
1073 		else if(ppi < 1200)
1074 			dvi->params.vdrift = ppi / 200;
1075 		else
1076 			dvi->params.vdrift = ppi / 400;
1077 	}
1078 
1079 	dvi->params.thinsp   = FROUND(0.025 * dvi->params.dpi / dvi->params.conv);
1080 	dvi->params.vsmallsp = FROUND(0.025 * dvi->params.vdpi / dvi->params.vconv);
1081 
1082 	/* execute all the commands in the page */
1083 	while((op = duget1(dvi)) != DVI_EOP) {
1084 		if(dvi_commands[op](dvi, op) < 0)
1085 			break;
1086 	}
1087 
1088 	fflush(stdout);
1089 	fflush(stderr);
1090 	if(op != DVI_EOP)
1091 		return -1;
1092 	if(dvi->stacktop)
1093 		dviwarn(dvi, _("stack not empty at end of page\n"));
1094 	return 0;
1095 }
1096 
move_vertical(DviContext * dvi,int amount)1097 inline static int move_vertical(DviContext *dvi, int amount)
1098 {
1099 	int	rvv;
1100 
1101 	dvi->pos.v += amount;
1102 	rvv = vpixel_round(dvi, dvi->pos.v);
1103 	if(!dvi->params.vdrift)
1104 		return rvv;
1105 	if(amount > dvi->params.vsmallsp || amount <= -dvi->params.vsmallsp)
1106 		return rvv;
1107 	else {
1108 		int	newvv;
1109 
1110 		newvv = dvi->pos.vv + vpixel_round(dvi, amount);
1111 		if(rvv - newvv > dvi->params.vdrift)
1112 			return rvv - dvi->params.vdrift;
1113 		else if(newvv - rvv > dvi->params.vdrift)
1114 			return rvv + dvi->params.vdrift;
1115 		else
1116 			return newvv;
1117 	}
1118 }
1119 
move_horizontal(DviContext * dvi,int amount)1120 inline static int move_horizontal(DviContext *dvi, int amount)
1121 {
1122 	int	rhh;
1123 
1124 	dvi->pos.h += amount;
1125 	rhh = pixel_round(dvi, dvi->pos.h);
1126 	if(!dvi->params.hdrift)
1127 		return rhh;
1128 	else if(amount > dvi->params.thinsp || amount <= -6 * dvi->params.thinsp)
1129 		return rhh;
1130 	else {
1131 		int	newhh;
1132 
1133 		newhh = dvi->pos.hh + pixel_round(dvi, amount);
1134 		if(rhh - newhh > dvi->params.hdrift)
1135 			return rhh - dvi->params.hdrift;
1136 		else if(newhh - rhh > dvi->params.hdrift)
1137 			return rhh + dvi->params.hdrift;
1138 		else
1139 			return newhh;
1140 	}
1141 }
1142 
fix_after_horizontal(DviContext * dvi)1143 inline static void fix_after_horizontal(DviContext *dvi)
1144 {
1145 	int	rhh;
1146 
1147 	rhh = pixel_round(dvi, dvi->pos.h);
1148 	if(!dvi->params.hdrift)
1149 		dvi->pos.hh = rhh;
1150 	else if(rhh - dvi->pos.hh > dvi->params.hdrift)
1151 		dvi->pos.hh = rhh - dvi->params.hdrift;
1152 	else if(dvi->pos.hh - rhh > dvi->params.hdrift)
1153 		dvi->pos.hh = rhh + dvi->params.hdrift;
1154 }
1155 
1156 /* commands */
1157 
1158 #define DBGSUM(a,b,c) \
1159 	(a), (b) > 0 ? '+' : '-', \
1160 	(b) > 0 ? (b) : -(b), (c)
1161 
draw_shrink_rule(DviContext * dvi,int x,int y,Uint w,Uint h,int f)1162 static void draw_shrink_rule (DviContext *dvi, int x, int y, Uint w, Uint h, int f)
1163 {
1164 	Ulong fg, bg;
1165 
1166 	fg = dvi->curr_fg;
1167 	bg = dvi->curr_bg;
1168 
1169 	mdvi_push_color (dvi, fg, bg);
1170 	dvi->device.draw_rule(dvi, x, y, w, h, f);
1171 	mdvi_pop_color (dvi);
1172 
1173 	return;
1174 }
1175 
1176 /*
1177  * The only commands that actually draw something are:
1178  *   set_char, set_rule
1179  */
1180 
draw_box(DviContext * dvi,DviFontChar * ch)1181 static void draw_box(DviContext *dvi, DviFontChar *ch)
1182 {
1183 	DviGlyph *glyph = NULL;
1184 	int	x, y, w, h;
1185 
1186 	if(!MDVI_GLYPH_UNSET(ch->shrunk.data))
1187 		glyph = &ch->shrunk;
1188 	else if(!MDVI_GLYPH_UNSET(ch->grey.data))
1189 		glyph = &ch->grey;
1190 	else if(!MDVI_GLYPH_UNSET(ch->glyph.data))
1191 		glyph = &ch->glyph;
1192 	if(glyph == NULL)
1193 		return;
1194 	x = glyph->x;
1195 	y = glyph->y;
1196 	w = glyph->w;
1197 	h = glyph->h;
1198 	/* this is bad -- we have to undo the orientation */
1199 	switch(dvi->params.orientation) {
1200 	case MDVI_ORIENT_TBLR:
1201 		break;
1202 	case MDVI_ORIENT_TBRL:
1203 		x = w - x;
1204 		break;
1205 	case MDVI_ORIENT_BTLR:
1206 		y = h - y;
1207 		break;
1208 	case MDVI_ORIENT_BTRL:
1209 		x = w - x;
1210 		y = h - y;
1211 		break;
1212 	case MDVI_ORIENT_RP90:
1213 		SWAPINT(w, h);
1214 		SWAPINT(x, y);
1215 		x = w - x;
1216 		break;
1217 	case MDVI_ORIENT_RM90:
1218 		SWAPINT(w, h);
1219 		SWAPINT(x, y);
1220 		y = h - y;
1221 		break;
1222 	case MDVI_ORIENT_IRP90:
1223 		SWAPINT(w, h);
1224 		SWAPINT(x, y);
1225 		break;
1226 	case MDVI_ORIENT_IRM90:
1227 		SWAPINT(w, h);
1228 		SWAPINT(x, y);
1229 		x = w - x;
1230 		y = h - y;
1231 		break;
1232 	}
1233 
1234 	draw_shrink_rule(dvi, dvi->pos.hh - x, dvi->pos.vv - y, w, h, 1);
1235 }
1236 
set_char(DviContext * dvi,int opcode)1237 int	set_char(DviContext *dvi, int opcode)
1238 {
1239 	int	num;
1240 	int	h;
1241 	int	hh;
1242 	DviFontChar *ch;
1243 	DviFont	*font;
1244 
1245 	if(opcode < 128)
1246 		num = opcode;
1247 	else
1248 		num = dugetn(dvi, opcode - DVI_SET1 + 1);
1249 	if(dvi->currfont == NULL) {
1250 		dvierr(dvi, _("no default font set yet\n"));
1251 		return -1;
1252 	}
1253 	font = dvi->currfont->ref;
1254 	ch = font_get_glyph(dvi, font, num);
1255 	if(ch == NULL || ch->missing) {
1256 		/* try to display something anyway */
1257 		ch = FONTCHAR(font, num);
1258 		if(!glyph_present(ch)) {
1259 			dviwarn(dvi,
1260 			_("requested character %d does not exist in `%s'\n"),
1261 				num, font->fontname);
1262 			return 0;
1263 		}
1264 		draw_box(dvi, ch);
1265 	} else if(dvi->curr_layer <= dvi->params.layer) {
1266 		if(ISVIRTUAL(font))
1267 			mdvi_run_macro(dvi, (Uchar *)font->private +
1268 				ch->offset, ch->width);
1269 		else if(ch->width && ch->height)
1270 			dvi->device.draw_glyph(dvi, ch,
1271 				dvi->pos.hh, dvi->pos.vv);
1272 	}
1273 	if(opcode >= DVI_PUT1 && opcode <= DVI_PUT4) {
1274 		SHOWCMD((dvi, "putchar", opcode - DVI_PUT1 + 1,
1275 			"char %d (%s)\n",
1276 			num, dvi->currfont->ref->fontname));
1277 	} else {
1278 		h = dvi->pos.h + ch->tfmwidth;
1279 		hh = dvi->pos.hh + pixel_round(dvi, ch->tfmwidth);
1280 		SHOWCMD((dvi, "setchar", num, "(%d,%d) h:=%d%c%d=%d, hh:=%d (%s)\n",
1281 			dvi->pos.hh, dvi->pos.vv,
1282 			DBGSUM(dvi->pos.h, ch->tfmwidth, h), hh,
1283 			font->fontname));
1284 		dvi->pos.h  = h;
1285 		dvi->pos.hh = hh;
1286 		fix_after_horizontal(dvi);
1287 	}
1288 
1289 	return 0;
1290 }
1291 
set_rule(DviContext * dvi,int opcode)1292 int	set_rule(DviContext *dvi, int opcode)
1293 {
1294 	Int32	a, b;
1295 	int	h, w;
1296 
1297 	a = dsget4(dvi);
1298 	b = dsget4(dvi); w = rule_round(dvi, b);
1299 	if(a > 0 && b > 0) {
1300 		h = vrule_round(dvi, a);
1301 		SHOWCMD((dvi, opcode == DVI_SET_RULE ? "setrule" : "putrule", -1,
1302 			"width %d, height %d (%dx%d pixels)\n",
1303 			b, a, w, h));
1304 		/* the `draw' functions expect the origin to be at the top left
1305 		 * corner of the rule, not the bottom left, as in DVI files */
1306 		if(dvi->curr_layer <= dvi->params.layer) {
1307 			draw_shrink_rule(dvi,
1308 					 dvi->pos.hh, dvi->pos.vv - h + 1, w, h, 1);
1309 		}
1310 	} else {
1311 		SHOWCMD((dvi, opcode == DVI_SET_RULE ? "setrule" : "putrule", -1,
1312 			"(moving left only, by %d)\n", b));
1313 	}
1314 
1315 	if(opcode == DVI_SET_RULE) {
1316 		dvi->pos.h  += b;
1317 		dvi->pos.hh += w;
1318 		fix_after_horizontal(dvi);
1319 	}
1320 	return 0;
1321 }
1322 
no_op(DviContext * dvi,int opcode)1323 int	no_op(DviContext *dvi, int opcode)
1324 {
1325 	SHOWCMD((dvi, "noop", -1, ""));
1326 	return 0;
1327 }
1328 
push(DviContext * dvi,int opcode)1329 int	push(DviContext *dvi, int opcode)
1330 {
1331 	if(dvi->stacktop == dvi->stacksize) {
1332 		if(!dvi->depth)
1333 			dviwarn(dvi, _("enlarging stack\n"));
1334 		dvi->stacksize += 8;
1335 		dvi->stack = xresize(dvi->stack,
1336 			DviState, dvi->stacksize);
1337 	}
1338 	memcpy(&dvi->stack[dvi->stacktop], &dvi->pos, sizeof(DviState));
1339 	SHOWCMD((dvi, "push", -1,
1340 		"level %d: (h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)\n",
1341 		dvi->stacktop,
1342 		dvi->pos.h, dvi->pos.v, dvi->pos.w, dvi->pos.x,
1343 		dvi->pos.y, dvi->pos.z, dvi->pos.hh, dvi->pos.vv));
1344 	dvi->stacktop++;
1345 	return 0;
1346 }
1347 
pop(DviContext * dvi,int opcode)1348 int	pop(DviContext *dvi, int opcode)
1349 {
1350 	if(dvi->stacktop == 0) {
1351 		dvierr(dvi, _("stack underflow\n"));
1352 		return -1;
1353 	}
1354 	memcpy(&dvi->pos, &dvi->stack[dvi->stacktop-1], sizeof(DviState));
1355 	SHOWCMD((dvi, "pop", -1,
1356 		"level %d: (h=%d,v=%d,w=%d,x=%d,y=%d,z=%d,hh=%d,vv=%d)\n",
1357 		dvi->stacktop,
1358 		dvi->pos.h, dvi->pos.v, dvi->pos.w, dvi->pos.x,
1359 		dvi->pos.y, dvi->pos.z, dvi->pos.hh, dvi->pos.vv));
1360 	dvi->stacktop--;
1361 	return 0;
1362 }
1363 
move_right(DviContext * dvi,int opcode)1364 int	move_right(DviContext *dvi, int opcode)
1365 {
1366 	Int32	arg;
1367 	int	h, hh;
1368 
1369 	arg = dsgetn(dvi, opcode - DVI_RIGHT1 + 1);
1370 	h = dvi->pos.h;
1371 	hh = move_horizontal(dvi, arg);
1372 	SHOWCMD((dvi, "right", opcode - DVI_RIGHT1 + 1,
1373 		"%d h:=%d%c%d=%d, hh:=%d\n",
1374 		arg, DBGSUM(h, arg, dvi->pos.h), hh));
1375 	dvi->pos.hh = hh;
1376 	return 0;
1377 }
1378 
move_down(DviContext * dvi,int opcode)1379 int	move_down(DviContext *dvi, int opcode)
1380 {
1381 	Int32	arg;
1382 	int	v, vv;
1383 
1384 	arg = dsgetn(dvi, opcode - DVI_DOWN1 + 1);
1385 	v = dvi->pos.v;
1386 	vv = move_vertical(dvi, arg);
1387 	SHOWCMD((dvi, "down", opcode - DVI_DOWN1 + 1,
1388 		"%d v:=%d%c%d=%d, vv:=%d\n",
1389 		arg, DBGSUM(v, arg, dvi->pos.v), vv));
1390 	dvi->pos.vv = vv;
1391 	return 0;
1392 }
1393 
move_w(DviContext * dvi,int opcode)1394 int	move_w(DviContext *dvi, int opcode)
1395 {
1396 	int	h, hh;
1397 
1398 	if(opcode != DVI_W0)
1399 		dvi->pos.w = dsgetn(dvi, opcode - DVI_W0);
1400 	h = dvi->pos.h;
1401 	hh = move_horizontal(dvi, dvi->pos.w);
1402 	SHOWCMD((dvi, "w", opcode - DVI_W0,
1403 		"%d h:=%d%c%d=%d, hh:=%d\n",
1404 		dvi->pos.w, DBGSUM(h, dvi->pos.w, dvi->pos.h), hh));
1405 	dvi->pos.hh = hh;
1406 	return 0;
1407 }
1408 
move_x(DviContext * dvi,int opcode)1409 int	move_x(DviContext *dvi, int opcode)
1410 {
1411 	int	h, hh;
1412 
1413 	if(opcode != DVI_X0)
1414 		dvi->pos.x = dsgetn(dvi, opcode - DVI_X0);
1415 	h = dvi->pos.h;
1416 	hh = move_horizontal(dvi, dvi->pos.x);
1417 	SHOWCMD((dvi, "x", opcode - DVI_X0,
1418 		"%d h:=%d%c%d=%d, hh:=%d\n",
1419 		dvi->pos.x, DBGSUM(h, dvi->pos.x, dvi->pos.h), hh));
1420 	dvi->pos.hh = hh;
1421 	return 0;
1422 }
1423 
move_y(DviContext * dvi,int opcode)1424 int	move_y(DviContext *dvi, int opcode)
1425 {
1426 	int	v, vv;
1427 
1428 	if(opcode != DVI_Y0)
1429 		dvi->pos.y = dsgetn(dvi, opcode - DVI_Y0);
1430 	v = dvi->pos.v;
1431 	vv = move_vertical(dvi, dvi->pos.y);
1432 	SHOWCMD((dvi, "y", opcode - DVI_Y0,
1433 		"%d h:=%d%c%d=%d, hh:=%d\n",
1434 		dvi->pos.y, DBGSUM(v, dvi->pos.y, dvi->pos.v), vv));
1435 	dvi->pos.vv = vv;
1436 	return 0;
1437 }
1438 
move_z(DviContext * dvi,int opcode)1439 int	move_z(DviContext *dvi, int opcode)
1440 {
1441 	int	v, vv;
1442 
1443 	if(opcode != DVI_Z0)
1444 		dvi->pos.z = dsgetn(dvi, opcode - DVI_Z0);
1445 	v = dvi->pos.v;
1446 	vv = move_vertical(dvi, dvi->pos.z);
1447 	SHOWCMD((dvi, "z", opcode - DVI_Z0,
1448 		"%d h:=%d%c%d=%d, hh:=%d\n",
1449 		dvi->pos.z, DBGSUM(v, dvi->pos.z, dvi->pos.v), vv));
1450 	dvi->pos.vv = vv;
1451 	return 0;
1452 }
1453 
sel_font(DviContext * dvi,int opcode)1454 int	sel_font(DviContext *dvi, int opcode)
1455 {
1456 	DviFontRef *ref;
1457 	int	ndx;
1458 
1459 	ndx = opcode - DVI_FNT_NUM0;
1460 	if(dvi->depth)
1461 		ref = font_find_flat(dvi, ndx);
1462 	else
1463 		ref = dvi->findref(dvi, ndx);
1464 	if(ref == NULL) {
1465 		dvierr(dvi, _("font %d is not defined\n"),
1466 			opcode - DVI_FNT_NUM0);
1467 		return -1;
1468 	}
1469 	SHOWCMD((dvi, "fntnum", opcode - DVI_FNT_NUM0,
1470 		"current font is %s\n",
1471 		ref->ref->fontname));
1472 	dvi->currfont = ref;
1473 	return 0;
1474 }
1475 
sel_fontn(DviContext * dvi,int opcode)1476 int	sel_fontn(DviContext *dvi, int opcode)
1477 {
1478 	Int32	arg;
1479 	DviFontRef *ref;
1480 
1481 	arg = dugetn(dvi, opcode - DVI_FNT1 + 1);
1482 	if(dvi->depth)
1483 		ref = font_find_flat(dvi, arg);
1484 	else
1485 		ref = dvi->findref(dvi, arg);
1486 	if(ref == NULL) {
1487 		dvierr(dvi, _("font %d is not defined\n"), arg);
1488 		return -1;
1489 	}
1490 	SHOWCMD((dvi, "fnt", opcode - DVI_FNT1 + 1,
1491 		"current font is %s (id %d)\n",
1492 		ref->ref->fontname, arg));
1493 	dvi->currfont = ref;
1494 	return 0;
1495 }
1496 
special(DviContext * dvi,int opcode)1497 int	special(DviContext *dvi, int opcode)
1498 {
1499 	char	*s;
1500 	Int32	arg;
1501 
1502 	arg = dugetn(dvi, opcode - DVI_XXX1 + 1);
1503 	if (arg <= 0) {
1504 		dvierr(dvi, _("malformed special length\n"));
1505 		return -1;
1506 	}
1507 	s = mdvi_malloc(arg + 1);
1508 	dread(dvi, s, arg);
1509 	s[arg] = 0;
1510 	mdvi_do_special(dvi, s);
1511 	SHOWCMD((dvi, "XXXX", opcode - DVI_XXX1 + 1,
1512 		"[%s]", s));
1513 	mdvi_free(s);
1514 	return 0;
1515 }
1516 
def_font(DviContext * dvi,int opcode)1517 int	def_font(DviContext *dvi, int opcode)
1518 {
1519 	DviFontRef *ref;
1520 	Int32	arg;
1521 
1522 	arg = dugetn(dvi, opcode - DVI_FNT_DEF1 + 1);
1523 	if(dvi->depth)
1524 		ref = font_find_flat(dvi, arg);
1525 	else
1526 		ref = dvi->findref(dvi, arg);
1527 	/* skip the rest */
1528 	dskip(dvi, 12);
1529 	dskip(dvi, duget1(dvi) + duget1(dvi));
1530 	if(ref == NULL) {
1531 		dvierr(dvi, _("font %d is not defined in postamble\n"), arg);
1532 		return -1;
1533 	}
1534 	SHOWCMD((dvi, "fntdef", opcode - DVI_FNT_DEF1 + 1,
1535 		"%d -> %s (%d links)\n",
1536 		ref->fontid, ref->ref->fontname,
1537 		ref->ref->links));
1538 	return 0;
1539 }
1540 
unexpected(DviContext * dvi,int opcode)1541 int	unexpected(DviContext *dvi, int opcode)
1542 {
1543 	dvierr(dvi, _("unexpected opcode %d\n"), opcode);
1544 	return -1;
1545 }
1546 
undefined(DviContext * dvi,int opcode)1547 int	undefined(DviContext *dvi, int opcode)
1548 {
1549 	dvierr(dvi, _("undefined opcode %d\n"), opcode);
1550 	return -1;
1551 }
1552 
1553