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