/* * dvipages.c: print out page info of specified DVI file. * * [1998/03/09] OSHIRO Naoki. Assemble from xdvi.page source. * * $Log:$ */ static char rcsid[]="$Id:$"; #include #include #include #include #include #define PAGENUM #define PTEX #define OPEN_MODE "r" #define _Xconst const #define NORETURN volatile /******************************** * Types and data * *******************************/ #ifndef EXTERN #define EXTERN extern #define INIT(x) #define NTINIT(x) #endif typedef unsigned char ubyte; #define Boolean char #define True 1 #define False 0 #define MAXDIM 32767 /* * pixel_conv is currently used only for converting absolute positions * to pixel values; although normally it should be * ((int) ((x) / shrink_factor + (1 << 15) >> 16)), * the rounding is achieved instead by moving the constant 1 << 15 to * PAGE_OFFSET in dvi_draw.c. */ #define pixel_conv(x) ((int) ((x) / shrink_factor >> 16)) #define pixel_round(x) ((int) ROUNDUP(x, shrink_factor << 16)) #define spell_conv0(n, f) ((long) (n * f)) #define spell_conv(n) spell_conv0(n, dimconv) /* entries below with the characters 'dvi' in them are actually stored in scaled pixel units */ int current_page; int total_pages; double dimconv; int n_files_left INIT(32767); /* for LRU closing of fonts */ time_t dvi_time; /* last mod. time for dvi file */ int page_w, page_h; /* * Table of page offsets in DVI file, indexed by page number - 1. * Initialized in prepare_pages(). */ #ifdef PAGENUM typedef struct { long offset; int number; } PAGE_INDEX; PAGE_INDEX *page_index; #else /* !PAGENUM */ long *page_offset; #endif /* PAGENUM */ #ifndef BDPI #define BDPI 300 #endif int pixels_per_inch NTINIT(BDPI); int offset_x, offset_y; int unshrunk_paper_w, unshrunk_paper_h; int unshrunk_page_w, unshrunk_page_h; int density NTINIT(40); double specialConv; char *dvi_name INIT(NULL); FILE *dvi_file; /* user's file */ jmp_buf dvi_env; /* mechanism to communicate dvi file errors */ #define one(fp) ((unsigned char) getc(fp)) #define sone(fp) ((long) one(fp)) #define two(fp) num (fp, 2) #define stwo(fp) snum(fp, 2) #define four(fp) num (fp, 4) #define sfour(fp) snum(fp, 4) /* * Mnemonics for bytes in dvi file. */ #define SETCHAR0 0 #define SET1 128 #ifdef KANJI #define SET2 129 #endif /* KANJI */ #define SETRULE 132 #define PUT1 133 #ifdef KANJI #define PUT2 134 #endif /* KANJI */ #define PUTRULE 137 #define NOP 138 #define BOP 139 #define EOP 140 #define PUSH 141 #define POP 142 #define RIGHT1 143 #define RIGHT2 144 #define RIGHT3 145 #define RIGHT4 146 #define W0 147 #define W1 148 #define W2 149 #define W3 150 #define W4 151 #define X0 152 #define X1 153 #define X2 154 #define X3 155 #define X4 156 #define DOWN1 157 #define DOWN2 158 #define DOWN3 159 #define DOWN4 160 #define Y0 161 #define Y1 162 #define Y2 163 #define Y3 164 #define Y4 165 #define Z0 166 #define Z1 167 #define Z2 168 #define Z3 169 #define Z4 170 #define FNTNUM0 171 #define FNT1 235 #define FNT2 236 #define FNT3 237 #define FNT4 238 #define XXX1 239 #define XXX2 240 #define XXX3 241 #define XXX4 242 #define FNTDEF1 243 #define FNTDEF2 244 #define FNTDEF3 245 #define FNTDEF4 246 #define PRE 247 #define POST 248 #define POSTPOST 249 #define SREFL 250 #define EREFL 251 #ifdef PTEX #define TDIR 255 #endif /* KANJI */ #define TRAILER 223 /* Trailing bytes at end of file */ static struct stat fstatbuf; /* * DVI preamble and postamble information. */ static char job_id[300]; static long numerator, denominator, magnification; /* * Offset in DVI file of last page, set in read_postamble(). */ static long last_page_offset; char * xmalloc(size, why) unsigned size; _Xconst char *why; { char *mem = malloc(size); if (mem == NULL) return NULL; return mem; } unsigned long num(fp, size) register FILE *fp; register int size; { register long x = 0; while (size--) x = (x << 8) | one(fp); return x; } long snum(fp, size) register FILE *fp; register int size; { register long x; #ifdef __STDC__ x = (signed char) getc(fp); #else x = (unsigned char) getc(fp); if (x & 0x80) x -= 0x100; #endif while (--size) x = (x << 8) | one(fp); return x; } /* * process_preamble reads the information in the preamble and stores * it into global variables for later use. */ static void process_preamble() { ubyte k; if (one(dvi_file) != PRE) return; #ifdef PTEX k = one(dvi_file); if (k != 2 && k != 3) #else if (one(dvi_file) != 2) #endif return; numerator = four(dvi_file); denominator = four(dvi_file); magnification = four(dvi_file); dimconv = (((double) numerator * magnification) / ((double) denominator * 1000.)); dimconv = dimconv * (((long) pixels_per_inch)<<16) / 254000; specialConv = pixels_per_inch * magnification / 1000000.0; k = one(dvi_file); fread(job_id, sizeof(char), (int) k, dvi_file); job_id[k] = '\0'; } /* * find_postamble locates the beginning of the postamble * and leaves the file ready to start reading at that location. */ #define TMPSIZ 516 /* 4 trailer bytes + 512 junk bytes allowed */ static void find_postamble() { long pos; ubyte temp[TMPSIZ]; ubyte *p; ubyte *p1; ubyte byte; fseek(dvi_file, (long) 0, 2); pos = ftell(dvi_file) - TMPSIZ; if (pos < 0) pos = 0; fseek(dvi_file, pos, 0); p = temp + fread((char *) temp, sizeof(char), TMPSIZ, dvi_file); for (;;) { p1 = p; while (p1 > temp && *(--p1) != TRAILER) ; p = p1; while (p > temp && *(--p) == TRAILER) ; if (p <= p1 - 4) break; /* found 4 TRAILER bytes */ if (p <= temp) return; } pos += p - temp; byte = *p; while (byte == TRAILER) { fseek(dvi_file, --pos, 0); byte = one(dvi_file); } #ifdef PTEX if (byte != 2 && byte != 3) #else if (byte != 2) #endif return; fseek(dvi_file, pos - 4, 0); fseek(dvi_file, sfour(dvi_file), 0); } /* * read_postamble reads the information in the postamble, * storing it into global variables. * It also takes care of reading in all of the pixel files for the fonts * used in the job. */ static void read_postamble() { ubyte cmnd; struct font *fontp; struct font **fontpp; if (one(dvi_file) != POST) return; last_page_offset = four(dvi_file); if (numerator != four(dvi_file) || denominator != four(dvi_file) || magnification != four(dvi_file)) return; /* read largest box height and width */ unshrunk_page_h = (spell_conv(sfour(dvi_file)) >> 16) + offset_y; if (unshrunk_page_h < unshrunk_paper_h) unshrunk_page_h = unshrunk_paper_h; unshrunk_page_w = (spell_conv(sfour(dvi_file)) >> 16) + offset_x; if (unshrunk_page_w < unshrunk_paper_w) unshrunk_page_w = unshrunk_paper_w; (void) two(dvi_file); /* max stack size */ total_pages = two(dvi_file); } static void prepare_pages() { int i; #ifdef PAGENUM long offset; page_index = (PAGE_INDEX *)xmalloc((unsigned)total_pages * sizeof(PAGE_INDEX), "page directory"); for (offset = last_page_offset, i = total_pages; i > 0; i--) { fseek(dvi_file, offset, 0); if (one(dvi_file) != BOP) { return; } page_index[i-1].offset = offset; page_index[i-1].number = four(dvi_file); /* Read c[0] */ fseek(dvi_file, (long)(9*4), 1); offset = four(dvi_file); } #else page_offset = (long *) xmalloc((unsigned) total_pages * sizeof(long), "page directory"); i = total_pages; page_offset[--i] = last_page_offset; fseek(dvi_file, last_page_offset, 0); /* * Follow back pointers through pages in the DVI file, * storing the offsets in the page_offset table. */ while (i > 0) { fseek(dvi_file, (long) (1+4+(9*4)), 1); fseek(dvi_file, page_offset[--i] = four(dvi_file), 0); } #endif /* PAGENUM */ } /* * init_dvi_file is the main subroutine for reading the startup * information from the dvi file. Returns True on success. */ static Boolean init_dvi_file() { (void) fstat(fileno(dvi_file), &fstatbuf); if (S_ISDIR(fstatbuf.st_mode)) return False; dvi_time = fstatbuf.st_mtime; process_preamble(); find_postamble(); read_postamble(); prepare_pages(); } /** ** open_dvi_file opens the dvi file and calls init_dvi_file() to ** initialize it. **/ void open_dvi_file() { char *errmsg; int n; char *file; if ((errmsg = (char *) setjmp(dvi_env)) != NULL) return; n = strlen(dvi_name); file = dvi_name; /* * Try foo.dvi before foo, in case there's an executable foo with * documentation foo.tex. Unless it already ends with ".dvi". */ if (n < sizeof(".dvi") || strcmp(dvi_name + n - sizeof(".dvi") + 1, ".dvi") != 0) { dvi_name = xmalloc((unsigned) n + sizeof(".dvi"), "dvi file name"); strcpy(dvi_name, file); strcat(dvi_name, ".dvi"); } dvi_file = fopen(dvi_name, OPEN_MODE); init_dvi_file(); } int main(int argc, char **argv) { int i; argv++; dvi_name = *argv; open_dvi_file(); printf("%d", total_pages); #ifdef PAGENUM printf(" "); for (i = 0; i