summaryrefslogtreecommitdiff
path: root/dviware/dvitops/dvi.c
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/dvitops/dvi.c
Initial commit
Diffstat (limited to 'dviware/dvitops/dvi.c')
-rw-r--r--dviware/dvitops/dvi.c625
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:
+*/