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