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