static char rcsid[] = "$Header: /usr/jjc/dvitops/RCS/dvi.c,v 1.6 90/08/14 13:09:18 jjc Rel $"; #include "dvitops.h" static struct stack { integer h, v, w, x, y, z; } *stack; struct addr_count0 { integer addr; integer count0; }; struct postamble_info { integer num; integer den; int mag; integer last_bop; /* address of last bop */ int npages; int stack_size; }; #ifdef PROTO static void first_pass(int, long *, int, struct addr_count0 *); static void read_page(struct page_info *page); static int read_opcode(void); static void read_postamble(struct postamble_info *postamble); static void bad_dvi_file(void); static int count_compare(char *p1, char *p2); #else static void first_pass(); static void read_page(); static int read_opcode(); static void read_postamble(); static void bad_dvi_file(); static int count_compare(); #endif #if 0 typedef enum { SET_CHAR_0 = 0, SET1 = 128, SET_RULE = 132, PUT1 = 133, PUT_RULE = 137, BOP = 139, EOP = 140, PUSH = 141, POP = 142, RIGHT1 = 143, W0 = 147, W1 = 148, X0 = 152, X1 = 153, DOWN1 = 157, Y0 = 161, Y1 = 162, Z0 = 166, Z1 = 167, FNT_NUM_0 = 171, FNT1 = 235, NOP = 138, XXX1 = 239, FNT_DEF1 = 243, PRE = 247, POST = 248, POST_POST = 249 } dvi_opcode; #else #define SET_CHAR_0 0 #define SET1 128 #define SET_RULE 132 #define PUT1 133 #define PUT_RULE 137 #define BOP 139 #define EOP 140 #define PUSH 141 #define POP 142 #define RIGHT1 143 #define W0 147 #define W1 148 #define X0 152 #define X1 153 #define DOWN1 157 #define Y0 161 #define Y1 162 #define Z0 166 #define Z1 167 #define FNT_NUM_0 171 #define FNT1 235 #define NOP 138 #define XXX1 239 #define FNT_DEF1 243 #define PRE 247 #define POST 248 #define POST_POST 249 #endif static FILE *dvifp; #define SPECIAL_BUF_SIZE 2048 static char special_buf[SPECIAL_BUF_SIZE]; static void first_pass(totalpages, start_page, maxpages, pagevec) int totalpages, maxpages; long start_page[10]; struct addr_count0 *pagevec; { integer count[10]; int pageno; int started = FALSE; int selected = FALSE; int pages_selected = 0; fseek(dvifp, 14L, 0); if (fseek(dvifp, (long)uread1(dvifp), 1) != 0) bad_dvi_file(); for (pageno = 0; pageno < totalpages; pageno++) { unsigned char opcode; int i; int donepage = FALSE; int f = -1; pagevec[pageno].addr = ftell(dvifp); while (!donepage) { unsigned char c; integer n = 0; /* deal with the most common case in its own loop */ while ((opcode = uread1(dvifp)) <= 127) { if (feof(dvifp) || ferror(dvifp)) bad_dvi_file(); if (selected) used_char(f, opcode); } /* we use the fact that SET_CHAR_0 is 0 */ if (FNT_NUM_0 <= opcode && opcode <= FNT_NUM_0 + 63) { n = opcode - FNT_NUM_0; opcode = FNT1; } else switch (opcode) { case SET1 + 3 : case PUT1 + 3 : case XXX1 + 3: case FNT_DEF1 + 3: case FNT1 + 3: n = sread4(dvifp); break; case SET1 + 2 : case PUT1 + 2 : case XXX1 + 2: case FNT_DEF1 + 2: case FNT1 + 2: n = uread3(dvifp); break; case SET1 + 1 : case PUT1 + 1 : case XXX1 + 1: case FNT_DEF1 + 1: case FNT1 + 1: n = uread2(dvifp); break; case SET1 : case PUT1 : case XXX1: case FNT_DEF1: case FNT1: n = uread1(dvifp); break; case RIGHT1 + 3: case W1 + 3: case X1 + 3: case DOWN1 + 3: case Y1 + 3: case Z1 + 3: (void)uread1(dvifp); /* falls through */ case RIGHT1 + 2: case W1 + 2: case X1 + 2: case DOWN1 + 2: case Y1 + 2: case Z1 + 2: (void)uread1(dvifp); /* falls through */ case RIGHT1 + 1: case W1 + 1: case X1 + 1: case DOWN1 + 1: case Y1 + 1: case Z1 + 1: (void)uread1(dvifp); /* falls through */ case RIGHT1: case W1: case X1: case DOWN1: case Y1: case Z1: (void)uread1(dvifp); break; case SET_RULE: case PUT_RULE : sread4(dvifp); sread4(dvifp); break; } switch (opcode) { case SET1 + 3 : case SET1 + 2 : case SET1 + 1 : case SET1 : case PUT1 + 3 : case PUT1 + 2 : case PUT1 + 1 : case PUT1 : if (!selected) break; c = (unsigned char) n; if (n >= MAXCHARS || n < 0) message(ERROR, "character code %ld too large: using %d instead", (long)n, c); used_char(f, c); break; case BOP : for (i = 0; i < 10; ++i) count[i] = sread4(dvifp); pagevec[pageno].count0 = count[0]; (void) sread4(dvifp); if (!started) { int j; started = TRUE; for (j = 0; j < 10; j++) if (start_page[j] != WILD && start_page[j] != count[j]) started = FALSE; } if (started && ++pages_selected <= maxpages) selected = TRUE; else { selected = FALSE; pagevec[pageno].addr = -1; } break; case EOP : if (selected) store_page_usage(); donepage = TRUE; break; case FNT1 : case FNT1 + 1 : case FNT1 + 2 : case FNT1 + 3 : if (!selected) break; if (n < 0 || n >= MAXFONTS) /* this should have been spotted in the postamble */ cant_happen(); f = (int) n; break; case XXX1 + 3 : case XXX1 + 2 : case XXX1 + 1 : case XXX1: if (n >= SPECIAL_BUF_SIZE) { message(ERROR, "special string too long: ignoring it"); fseek(dvifp, (long)n, 1); break; } fread(special_buf, 1, (size_t)n, dvifp); special_buf[n] = '\0'; STRXCHAR(special_buf) if (selected) special(PASS1, special_buf,(integer)0,(integer)0); break; case FNT_DEF1 : case FNT_DEF1 + 1 : case FNT_DEF1 + 2 : case FNT_DEF1 + 3 : fseek(dvifp, 12L, 1); n = uread1(dvifp); n += uread1(dvifp); fseek(dvifp, (long)n, 1); break; case POST : bad_dvi_file(); default : break; } } } } static int read_opcode() { for (;;) { int c = uread1(dvifp); if (c == EOF) cant_happen(); if (XXX1 <= c && c <= XXX1 + 3) { integer k; switch (c) { case XXX1 : k = uread1(dvifp); break; case XXX1 + 1: k = uread2(dvifp); break; case XXX1 + 2: k = uread3(dvifp); break; case XXX1 + 3: k = sread4(dvifp); break; } fseek(dvifp, (long)k, 1); } else if (c != NOP) return c; } } static void read_postamble(postamble) struct postamble_info *postamble; { int c; integer n; long offset; /* Avoid using a negative offset. Some implementations can't handle this. */ if (fseek(dvifp, 0L, 2) != 0) message(FATAL_ERROR, "can't perform seek on dvi file"); offset = ftell(dvifp); do { offset--; fseek(dvifp, offset, 0); c = uread1(dvifp); } while (c == 223); if (c != ID_BYTE) message(FATAL_ERROR, "this is the wrong type of dvi file"); offset -= 5; fseek(dvifp, offset, 0); if (uread1(dvifp) != POST_POST) cant_happen(); offset = sread4(dvifp); fseek(dvifp, offset, 0); if (uread1(dvifp) != POST) cant_happen(); postamble->last_bop = sread4(dvifp); postamble->num = sread4(dvifp); postamble->den = sread4(dvifp); n = sread4(dvifp); if (postamble->mag == 0) { postamble->mag = (int)n; if (n < 0 || n > INT_MAX) { message(ERROR, "bad magnification: using 1000 instead"); n = 1000; } } (void) sread4(dvifp); (void) sread4(dvifp); postamble->stack_size = sread2(dvifp); postamble->npages = sread2(dvifp); while ((c = read_opcode()) >= FNT_DEF1 && c <= FNT_DEF1 + 3) { integer k; integer cs, s, d; int a, l; char area[257]; char name[257]; switch (c + 1 - FNT_DEF1) { case 1: k = uread1(dvifp); break; case 2: k = uread2(dvifp); break; case 3: k = uread3(dvifp); break; case 4: k = sread4(dvifp); break; } cs = sread4(dvifp); s = sread4(dvifp); d = sread4(dvifp); a = uread1(dvifp); l = uread1(dvifp); if (a) fread(area, 1, a, dvifp); area[a] = '\0'; fread(name, 1, l, dvifp); name[l] = '\0'; STRXCHAR(name) STRXCHAR(area) f_def(k, name, area, cs, s, d, postamble->mag); } if (c != POST_POST) cant_happen(); } static int count_compare(p1, p2) char *p1, *p2; { integer n1 = ((struct addr_count0 *)p1)->count0; integer n2 = ((struct addr_count0 *)p2)->count0; if (n1 == n2) return (int)(((struct addr_count0 *)p1)->addr - ((struct addr_count0 *)p2)->addr); else if (n1 <= 0 || n2 <= 0) { if (n2 > 0) return -1; else if (n1 > 0) return 1; else return (int)(n2 - n1); } else return (int)(n1 - n2); } void read_dvi_file(fp, ofp, option) FILE *fp, *ofp; struct option_info *option; { struct postamble_info postamble; struct page_info page; FILE *psfp; int i; int actual_npages; struct addr_count0 *pagevec; dvifp = fp; postamble.mag = option->mag; read_postamble(&postamble); if ((stack = (struct stack *)malloc(sizeof(struct stack)*postamble.stack_size)) == NULL) out_of_memory(); if ((pagevec = (struct addr_count0 *)malloc((1 + postamble.npages) *sizeof(struct addr_count0))) == NULL) out_of_memory(); first_pass(postamble.npages, option->start_page, option->maxpages, pagevec); psfp = ofp; #ifdef HAVE_SETVBUF setvbuf(psfp, (char *)NULL, _IOFBF, 16384); /* ignore any error */ #endif for (i = 0, actual_npages = 0; i < postamble.npages; i++) if (pagevec[i].addr != -1L) actual_npages++; prologue(psfp, actual_npages, option->reverse, option->paper); page.num = postamble.num; page.den = postamble.den; page.hoffset = option->hoffset; page.voffset = option->voffset; page.copies = option->copies; page.paper = option->paper; page.max_drift = (int)((254000.0/page.num) * (page.den/(double)dpi) * 2.0); if (option->sort) qsort((char *)pagevec, postamble.npages, sizeof(struct addr_count0), count_compare); if (option->reverse) { for (i = postamble.npages - 1; i >= 0; i--) if (pagevec[i].addr != -1L) { page.address = pagevec[i].addr; page.mag = postamble.mag; read_page(&page); } } else { for (i = 0; i < postamble.npages; i++) if (pagevec[i].addr != -1L) { page.address = pagevec[i].addr; page.mag = postamble.mag; read_page(&page); } } trailer(); } static void read_page(page) struct page_info *page; { unsigned char opcode; int had_large_hmotion = FALSE; int i; char buf[512]; int nbuf = 0; /* number of characters in buf */ integer endh = 0, rounded_endh = 0; integer h, v, w, x, y, z; struct stack *sp = stack; int f = -1; integer fs = 0; /* = f_space(f) */ h = v = w = x = y = z = 0; fseek(dvifp, (long)page->address, 0); for (;;) { integer starth; integer startv; int startf; unsigned char c; integer a, b; integer wd; integer n = (integer)0; opcode = uread1(dvifp); /* we use the fact that SET_CHAR_0 is 0 */ if (opcode <= 127) { /* we checked for eof and error on pass 1 */ n = opcode; opcode = SET1; } else if (FNT_NUM_0 <= opcode && opcode <= FNT_NUM_0 + 63) { n = opcode - FNT_NUM_0; opcode = FNT1; } else switch (opcode) { case SET1 + 3 : case PUT1 + 3 : case XXX1 + 3: case RIGHT1 + 3: case W1 + 3: case X1 + 3: case DOWN1 + 3: case Y1 + 3: case Z1 + 3: case FNT_DEF1 + 3: case FNT1 + 3: n = sread4(dvifp); break; case SET1 + 2 : case PUT1 + 2 : case XXX1 + 2: case FNT_DEF1 + 2: case FNT1 + 2: n = uread3(dvifp); break; case SET1 + 1 : case PUT1 + 1 : case XXX1 + 1: case FNT_DEF1 + 1: case FNT1 + 1: n = uread2(dvifp); break; case SET1 : case PUT1 : case XXX1: case FNT_DEF1: case FNT1: n = uread1(dvifp); break; case RIGHT1 + 2: case W1 + 2: case X1 + 2: case DOWN1 + 2: case Y1 + 2: case Z1 + 2: n = sread3(dvifp); break; case RIGHT1 + 1: case W1 + 1: case X1 + 1: case DOWN1 + 1: case Y1 + 1: case Z1 + 1: n = sread2(dvifp); break; case RIGHT1: case W1: case X1: case DOWN1: case Y1: case Z1: n = sread1(dvifp); break; } switch (opcode) { case SET1 + 3 : case SET1 + 2 : case SET1 + 1 : case SET1 : case PUT1 + 3 : case PUT1 + 2 : case PUT1 + 1 : case PUT1 : /* we checked it wasn't out of range on pass 1 */ c = (unsigned char)n; if (nbuf > 0 && (h != endh || v != startv || f != startf || had_large_hmotion || nbuf >= sizeof(buf) || endh - rounded_endh > page->max_drift || endh - rounded_endh < -page->max_drift)) { set_string(buf, nbuf, startf, starth, startv); nbuf = 0; } if (nbuf == 0) { if (endh != rounded_endh && !had_large_hmotion) { if (rounded_endh - endh > page->max_drift) starth = h + page->max_drift; else if (rounded_endh - endh < -page->max_drift) starth = h - page->max_drift; else starth = h + (rounded_endh - endh); } else starth = h; endh = h; rounded_endh = starth; startv = v; startf = f; had_large_hmotion = FALSE; } buf[nbuf++] = c; used_char(f, c); wd = f_width(f, c); endh += wd; rounded_endh += f_rounded_width(f, c); /* we rely on the fact that SET1 < PUT1 */ if (opcode < PUT1) h += wd; break; case SET_RULE : case PUT_RULE : a = sread4(dvifp); b = sread4(dvifp); set_rule(a, b, h, v); if (opcode == SET_RULE) h += b; break; case NOP : break; case BOP : for (i = 0; i < 10; ++i) page->count[i] = sread4(dvifp); (void) sread4(dvifp); break; case EOP : if (nbuf) set_string(buf, nbuf, startf, starth, startv); eop(page); return; case PUSH : sp->h = h; sp->v = v; sp->w = w; sp->x = x; sp->y = y; sp->z = z; ++sp; break; case POP : --sp; h = sp->h; v = sp->v; w = sp->w; x = sp->x; y = sp->y; z = sp->z; break; case RIGHT1 : case RIGHT1 + 1 : case RIGHT1 + 2 : case RIGHT1 + 3 : h += n; if (n >= fs || n <= fs*-4) had_large_hmotion = TRUE; break; case W0 : h += w; break; case W1 : case W1 + 1 : case W1 + 2 : case W1 + 3 : h += w = n; break; case X0 : h += x; break; case X1 : case X1 + 1 : case X1 + 2 : case X1 + 3 : h += x = n; break; case DOWN1 : case DOWN1 + 1 : case DOWN1 + 2 : case DOWN1 + 3: v += n; break; case Y0 : v += y; break; case Y1 : case Y1 + 1 : case Y1 + 2 : case Y1 + 3 : v += y = n; break; case Z0 : v += z; break; case Z1 : case Z1 + 1 : case Z1 + 2 : case Z1 + 3 : v += z = n; break; case FNT1 : case FNT1 + 1 : case FNT1 + 2 : case FNT1 + 3 : if (n < 0 || n >= MAXFONTS) /* this should have caused a fatal error on pass 1 */ cant_happen(); f = (int)n; fs = f_space(f); break; case XXX1 + 3 : case XXX1 + 2 : case XXX1 + 1 : case XXX1 : if (n >= SPECIAL_BUF_SIZE) { /* we printed an error on the first pass */ fseek(dvifp, (long)n, 1); break; } if (nbuf > 0) { /* flush buf */ set_string(buf, nbuf, startf, starth, startv); nbuf = 0; } fread(special_buf, 1, (int)n, dvifp); special_buf[n] = '\0'; STRXCHAR(special_buf) special(PASS2, special_buf, h, v); break; case FNT_DEF1 : case FNT_DEF1 + 1 : case FNT_DEF1 + 2 : case FNT_DEF1 + 3 : fseek(dvifp, 12L, 1); n = uread1(dvifp); n += uread1(dvifp); fseek(dvifp, (long)n, 1); break; case POST : if (nbuf) set_string(buf, nbuf, startf, starth, startv); return; default : bad_dvi_file(); } } } static void bad_dvi_file() { message(FATAL_ERROR, "this dvi file is bad -- use dvitype"); } /* Local Variables: tab-width: 4 c-indent-level: 4 c-continued-statement-offset: 4 c-brace-offset: -4 c-argdecl-indent: 0 c-label-offset: -4 End: */