diff options
author | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2019-09-02 13:46:59 +0900 |
commit | e0c6872cf40896c7be36b11dcc744620f10adf1d (patch) | |
tree | 60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/dvitops/dvi.c |
Initial commit
Diffstat (limited to 'dviware/dvitops/dvi.c')
-rw-r--r-- | dviware/dvitops/dvi.c | 625 |
1 files changed, 625 insertions, 0 deletions
diff --git a/dviware/dvitops/dvi.c b/dviware/dvitops/dvi.c new file mode 100644 index 0000000000..6038eca5f6 --- /dev/null +++ b/dviware/dvitops/dvi.c @@ -0,0 +1,625 @@ +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: +*/ |