diff options
author | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2006-01-17 21:41:51 +0000 |
commit | 487ca4806cc046076293cf6cc5fbba0db282bac7 (patch) | |
tree | 847b412ab5158dd7bdd7ed7e5a4cc3fbca94be32 /Build/source/texk/dvidvi/dvidvi.c | |
parent | a3d3111bfe26b8e5f5bc6049dfb2a4ca2edc7881 (diff) |
texk 1
git-svn-id: svn://tug.org/texlive/trunk@1485 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/texk/dvidvi/dvidvi.c')
-rw-r--r-- | Build/source/texk/dvidvi/dvidvi.c | 1271 |
1 files changed, 1271 insertions, 0 deletions
diff --git a/Build/source/texk/dvidvi/dvidvi.c b/Build/source/texk/dvidvi/dvidvi.c new file mode 100644 index 00000000000..5d9a4948a39 --- /dev/null +++ b/Build/source/texk/dvidvi/dvidvi.c @@ -0,0 +1,1271 @@ +/* + * This program converts dvi files to dvi files; + * the command line options are: + * + * page n is first page selected -f n + * page n is last page selected -l n + * print at most n pages -n n + * include pages (ranges allowed) -i { n1..n2 | n1 }[,...] + * exclude pages (ranges allowed) -x { n1..n2 | n1 }[,...] + * work in quiet mode -q + * reverse pages -r + * select even -m 2:1 + * select odd -m 2:0 + * print both on same page -m 2:0,1(5.5in,0in) + * do folded brochures -m 4:-3,0(5.5in,0in) + * -m 4:1,-2(5.5in,0in) + * round up number of pages to a + * multiple of n -p n + * sort pages to print one from top -j + * next one from end + * etc. + * + * The original program is by Tomas Rokicki (version 0.5) but it was + * modified and improved by Esteban ZIMANYI ezimanyi@rc1.vub.ac.be + * to give version 1.0. + * To give version 1.1 it was improved by Markus_Kohm@ka.maus.de. + * + * This version has been tested for the IBM PC and compatibles under + * compilers Turbo C 2.0 and Microsoft C 6.0 and for Atari ST under + * compiler Turbo C 2.0 with MiNTLIB. + * + */ +#define SEEK_SET 0 +#define SEEK_CUR 1 +#define SEEK_END 2 + +#define BANNER "\nThis is dvidvi 1.1, Copyright (C) 1988-91, Radical Eye Software\n" \ + "Improved from 1.0 to 1.1, 1994, Markus Kohm\n" +#define STRINGSIZE (500L) /* maximum number of strings in program */ + +#ifdef WIN32 +#include <stdlib.h> +#include <malloc.h> +#endif +void error(char *); + +#ifndef VMS +#include <stdio.h> +#include <string.h> +#else /* VMS */ +#include "sys$library:stdio.h" /* AKT: added sys$library: */ +#include <alloc.h> +#endif /* VMS */ +#define MAXPPERP (32) + +/* defines READBIN, WRITEBIN, PATHSEP and IS_DIR_SEP*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef KPATHSEA +#include <kpathsea/c-fopen.h> +#define READBIN FOPEN_RBIN_MODE +#ifdef VMS +#define WRITEBIN "wb" /* VMS doesn't have FOPEN_WBIN_MODE defined */ +#else +#define WRITEBIN FOPEN_WBIN_MODE +#endif +#include <kpathsea/c-pathch.h> +#define PATHSEP ENV_SEP +#else /* not KPATHSEA */ +#if defined(__TOS__) +#define READBIN "rb" /* TOS must use binary mode */ +#define WRITEBIN "wb" +#define PATHSEP ';' +#define IS_DIR_SEP(c) ((c) == '\\') +#elif defined (MSDOS) || defined(WIN32) +#define READBIN "rb" /* MSDOS must use binary mode */ +#define WRITEBIN "wb" +#define PATHSEP ';' +#define IS_DIR_SEP(c) ((c) == '\\' || (c) == '/') +#elif defined(VMS) +#define READBIN "rb" /* VMS must use binary mode */ +#define WRITEBIN "wb" +#define PATHSEP ',' +#define IS_DIR_SEP ((c) == ':') +#else +#define READBIN "r" /* UNIX doesn't care */ +#define WRITEBIN "w" +#define PATHSEP ':' +#define IS_DIR_SEP ((c) == '/') +#endif +#endif /* not KPATHSEA */ + +#ifdef XENIX +#define SHORTINT +#else +#undef SHORTINT +#endif +#ifdef MSDOS +#define SHORTINT +#endif +#ifdef __TOS__ +#ifdef __TURBOC__ +#define SHORTINT +#endif +#endif + +/* + * Type declarations. integer must be a 32-bit signed; shalfword must + * be a sixteen-bit signed; halfword must be a sixteen-bit unsigned; + * quarterword must be an eight-bit unsigned. + */ +typedef long integer; +typedef short shalfword ; +typedef unsigned short halfword ; +typedef unsigned char quarterword ; +typedef short Boolean ; + +/* + * Some globals to keep everyone happy. + */ +integer numpages ; /* the total number of pages in the dvi file. */ +integer TeXfonts[256] ; /* information about each font */ +char fontseen[256] ; /* have we defined this font yet? */ +int modulo ; /* our mod value */ +integer pagemodulo ; /* additional mod value for number of pages */ +struct pagespec { + int pageno, reversed ; + long hoffset, voffset ; /* in scaled points */ +} pages[MAXPPERP] ; /* the organization of the pages on output */ +int pagesperpage ; /* how many pages crammed onto each page? */ +FILE *infile ; /* input dvi file (cannot be a stream) */ +FILE *outfile ; /* output dvi file */ + +char *temp ; /* a temporary place to put things */ +char *nextstring, *maxstring ; +char *oname=NULL ; /* output dvi file name */ +char *iname ; /* input dvi file name */ +char *strings ; /* pointer of the string pool */ + +char banner[] = BANNER ; /* the startup message */ +integer inlength ; /* the length of the input dvi file */ +integer postloc ; /* location of the postamble */ +integer mag ; /* magnification factor */ +integer pagecount ; /* number of actual pages */ +integer landscape = 0; /* if landscape special, here it is! */ +int rem0special ; /* should we remove the first first-page special? */ +integer prevpp = -1 ; /* previous page pointer on output */ +integer outputpages ; /* number of pages output */ +integer dviloc ; /* our position in the output file */ +integer pagefake ; /* number of pages, rounded up to multiple of + pagemodulo */ + +Boolean firsttransf = 0, lasttransf = 0; +Boolean jumpingpages = 0; +integer firstpage ; /* first page selected (option -p) */ +integer lastpage ; /* last page selected (option -l) */ +integer maxpages ; /* maximum number of page selected (option -n) */ +short quiet ; /* quiet mode (option -q) */ +Boolean exctransf[40][2] ; /* if the ranges of pages to exclude (option -x) + have to be transformed */ +integer exclude[40][2] ; /* the ranges of pages to exclude (option -x) + It is supposed that there are at most 40 ranges + to exclude in the command line */ +short excludeseq ; /* number of ranges to exclude (option -x) */ +Boolean inctransf[40][2] ; /* if the ranges of pages to exclude (option -x) + have to be transformed */ +integer include[40][2] ; /* the ranges of pages to include (option -i) + It is supposed that there are at most 40 ranges + to include in the command line */ +short includeseq ; /* number of ranges to include (option -i) */ +integer *pageloc ; +integer *pagenumbers ; +int prettycolumn ; /* the column we are at when running pretty */ + +/* + * This array holds values that indicate the length of a command, if + * we aren't concerned with that command (which is most of them) or + * zero, if it is a special case. This makes running through the + * dvi file a lot easier (and probably faster) than any form of + * dispatch table, especially since we really don't care what the + * pages are made of. + */ +short comlen[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0-15 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 16-31 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 32-47 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 48-63 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80-95 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 112-127 */ + 2, 3, 4, 5, 9, 2, 3, 4, 5, 9, 1, 0, 0, 1, 1, 2, /* 128-143 */ + 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 2, 3, 4, /* 144-159 */ + 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, /* 160-175 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176-191 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192-207 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208-223 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 0, /* 224-239 */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };/* 240-255 */ + +/* + * Input bytes from the dvi file. + * These routines could probably be sped up significantly; but they are + * very machine dependent, so I will leave such tuning to the installer. + * They simply get and return bytes in batches of one, two, three, and four, + * updating the current position as necessary. + */ + +void +abortpage() +{ + error("! unexpected eof on DVI file") ; +} + +shalfword dvibyte() +{ + register shalfword i ; + if ((i=getc(infile))==EOF) + abortpage() ; + return(i) ; +} + +halfword twobytes() +{ + register halfword i ; + i = dvibyte() ; + return(i*256+dvibyte()) ; } + +integer threebytes() +{ + register integer i ; + i = twobytes() ; + return(i*256+dvibyte()) ; } + +shalfword +signedbyte() +{ + register shalfword i ; + if ((i=getc(infile))==EOF) + abortpage() ; + if (i<128) return(i) ; + else return(i-256) ; +} + +shalfword +signedpair() +{ + register shalfword i ; + i = signedbyte() ; + return(i*256+dvibyte()) ; +} + +integer +signedtrio() +{ + register integer i ; + i = signedpair() ; + return(i*256+dvibyte()) ; +} + +integer +signedquad() +{ + register integer i ; + i = signedpair() ; + return(i*65536+twobytes()) ; +} + +/* + * Routines for the transformation of the pages specified with + * the @ parameter into the actual number of page from the file + * + * trans(p,q) looks for the q'th occurrence of the page numbered p + * transformpages makes the transformation for the options -f -i -l -x + */ + +integer transf(p,q) +integer p; +halfword q; +{ +int i=0, j=0; + + while( j != q && i < pagecount ) + if ( pagenumbers[i++] == p ) j++; + if ( j != q ) error ("! Page specified not found"); + return (i++); +} +void transformpages() +{ +int i; + + if (firsttransf) firstpage=transf(firstpage,firsttransf); + if (lasttransf) lastpage=transf(lastpage,lasttransf); + for ( i= 0; i< 40; i++) { + if (exctransf[i][0]) exclude[i][0]=transf(exclude[i][0],exctransf[i][0]); + if (exctransf[i][1]) exclude[i][1]=transf(exclude[i][1],exctransf[i][1]); + if (inctransf[i][0]) include[i][0]=transf(include[i][0],inctransf[i][0]); + if (inctransf[i][1]) include[i][1]=transf(include[i][1],inctransf[i][1]); + } +} +/* + * + */ +integer fontdeflen(p) +integer p; +{ + fseek(infile,p+14,SEEK_SET); + return (16L+dvibyte()+dvibyte()); +} + +/* + * Simulation of dvibuf, get the character located at the position + * p in the input dvi file + */ +unsigned char dvibuf(p) +integer p; +{ + fseek(infile,p,SEEK_SET); + return(dvibyte()); +} + +/* + * Read a string of length n from the file into the string temp + */ +void stringdvibuf(p,n) +integer p,n; +{ + fseek(infile,p,SEEK_SET); + while ( n-- > 0 ) + *temp++ = dvibyte(); +} + +/* + * Print a usage error messsage, and quit. + */ +void usage() { + (void)fprintf(stderr,banner); + (void)fprintf(stderr,"Usage: dvidvi [options] input[.dvi] [output]\n"); + (void)fprintf(stderr,"where options are:\n"); + (void)fprintf(stderr," [-f n] first page printed [-l n] last page printed\n"); + (void)fprintf(stderr," [-n n] print at most n pages \n"); + (void)fprintf(stderr," [-i {n1..n2 | n3}[,...]] include pages\n"); + (void)fprintf(stderr," [-x {n1..n2 | n3}[,...]] exclude pages\n"); + (void)fprintf(stderr," [-q] quiet mode [-r] reverse pages\n"); + (void)fprintf(stderr," [-m modulo:pagespecs] [-j] jumping pages\n"); + (void)fprintf(stderr," [-p pagemodulo]\n"); +#ifndef VMS + exit(1) ; +#else /* VMS */ + exit(0x10000002) ; + /* AKT: was exit(1) */ +#endif /* VMS */ +} +/* + * Print an error message, and exit if it is fatal. + */ +void error(s) +char *s ; +{ + (void)fprintf(stderr, "%s\n", s) ; /* AKT: was dvidvi: %s */ + if (*s == '!') +#ifndef VMS + exit(1) ; +#else /* VMS */ + exit(0x10000002) ; + /* AKT: was exit(1) */ +#endif /* VMS */ +} +/* + * This function calculates approximately (whole + num/den) * sf. + * No need for real extreme accuracy; one ten thousandth of an + * inch should be sufficient. + * + * No `sf' parameter means to use an old one; inches are assumed + * originally. + * + * Assumptions: + * + * 0 <= num < den <= 10000 + * 0 <= whole + */ +integer defaultscale = 4736286 ; +integer scale(whole, num, den, sf) +integer whole, num, den, sf ; +{ + integer v ; + + if (sf) + defaultscale = sf ; + else + sf = defaultscale ; + v = whole * sf + num * (sf / den) ; + if (v / sf != whole || v < 0 || v > 0x40000000L) + error("! arithmetic overflow in parameter") ; + sf = sf % den ; + v += (sf * num * 2 + den) / (2 * den) ; + return(v) ; +} +/* + * Multiplies *p by 1000 and divides it by mag. Avoiding overflow. + * + * 1 <= mag <= 1000000 ; + * 0 <= *p <= 2^30 + * + * (Could blow up if a parameter * mag / 1000 > 2^30 sp.) + */ +void scalemag(p) +long *p ; +{ + int negative ; + + negative = 0 ; + if (*p < 0) { + negative = 1 ; + *p = - *p ; + } + *p = 1000 * (*p / mag) + (2000 * (*p % mag) + mag) / (2 * mag) ; + if (negative) + *p = - *p ; +} +/* + * Convert a sequence of digits into an integer; return -1 if no digits. + * Advance the passed pointer as well. + */ +integer myatol(s) +char **s ; +{ + register char *p ; + register integer result ; + + result = 0 ; + p = *s ; + while ('0' <= *p && *p <= '9') { + if (result > 100000000) + error("! arithmetic overflow in parameter") ; + result = 10 * result + *p++ - '0' ; + } + if (p == *s) + usage() ; + else { + *s = p ; + return(result) ; + } +} +/* + * Get a dimension, allowing all the various extensions, and + * defaults. + */ +integer myatodim(s) +char **s ; +{ + register integer w, num, den ; + register char *p ; + int negative = 0 ; + + p = *s ; + if (**s == '-') { + (*s)++ ; + negative = 1 ; + } + w = myatol(s) ; + if (w < 0) + usage() ; + p = *s ; + num = 0 ; + den = 1 ; + if (*p == '.') { + p++ ; + while ('0' <= *p && *p <= '9') { + if (den < 1000) { + den *= 10 ; + num = num * 10 + *p - '0' ; + } + p++ ; + } + } +/* + * Allowed units are `in', `cm', `mm', `pt', `sp', `cc', `dd', and `pc'; + * must be in lower case. + */ + if (*p == 'c' && p[1] == 'm') { +/* centimeters need to be multiplied by 72.27 * 2^16 / 2.54, or 1 864 680 */ + w = scale(w, num, den, 1864680L) ; + } else if (*p == 'p' && p[1] == 't') { +/* real points need to be multiplied by 2^16 */ + w = scale(w, num, den, 65536L) ; + } else if (*p == 'p' && p[1] == 'c') { +/* picas need to be multiplied by 65536 * 12, or 786 432 */ + w = scale(w, num, den, 786432L) ; + } else if (*p == 'm' && p[1] == 'm') { +/* millimeters need to be multiplied by 72.27 * 2^16 / 25.4, or 186 468 */ + w = scale(w, num, den, 186468L) ; + } else if (*p == 's' && p[1] == 'p') { +/* scaled points are already taken care of; simply round */ + w = scale(w, num, den, 1L) ; + } else if (*p == 'b' && p[1] == 'p') { +/* big points need to be multiplied by 72.27 * 65536 / 72, or 65782 */ + w = scale(w, num, den, 65782L) ; + } else if (*p == 'd' && p[1] == 'd') { +/* didot points need to be multiplied by 65536 * 1238 / 1157, or 70124 */ + w = scale(w, num, den, 70124L) ; + } else if (*p == 'c' && p[1] == 'c') { +/* cicero need to be multiplied by 65536 * 1238 / 1157 * 12, or 841 489 */ + w = scale(w, num, den, 841489L) ; + } else if (*p == 'i' && p[1] == 'n') { +/* inches need to be multiplied by 72.27 * 65536, or 4 736 286 */ + w = scale(w, num, den, 4736286L) ; + } else { +/* use default values */ + w = scale(w, num, den, 0L) ; + p -= 2 ; + } + p += 2 ; + *s = p ; + return(negative?-w:w) ; +} +/* + * This function determine if the page has to be printed + * depending on the values of options -f, -l, -i and -x + */ + +short selectedpage (n) +integer n; +{ +short i; + + if ( firstpage > n || n > lastpage ) return(0); + for ( i=0 ; i < excludeseq ; i++ ) + if ( exclude[i][0] <= n && n <= exclude[i][1] ) + return(0); + if (includeseq == 0) return (1); + for ( i=0 ; i < includeseq ; i++ ) + if ( include[i][0] <= n && n <= include[i][1] ) + return(1); + return(0); +} + +/* + * Initialize sets up all the globals and data structures. + */ +void +initialize() +{ +int i; +/* initialize values in case of option -m is not specified */ + modulo = 1 ; + pagemodulo = 0; + pages[0].hoffset = 0 ; + pages[0].voffset = 0 ; + pages[0].pageno = 0 ; + pages[0].reversed = 0 ; + pagesperpage = 1 ; + for ( i= 0; i< 40; i++) { + exctransf[i][0] = exctransf[i][1] = 0; + inctransf[i][0] = inctransf[i][1] = 0; + } + firsttransf = lasttransf = 0; + + excludeseq = 0; + includeseq = 0; + firstpage = 1; + lastpage = 1000000; + maxpages = 1000000; + quiet = 0; + strings =(char *) malloc(STRINGSIZE) ; + if (strings == 0) + error("! no memory for strings") ; + maxpages = 100000 ; + nextstring = strings ; + iname = strings ; + *nextstring++ = 0 ; + maxstring = strings + STRINGSIZE - 200; +} + +/* + * Parse the arguments to the routine, and stuff everything away + * into those globals above. + */ +void processargs(argc, argv) +int argc ; +char *argv[] ; +{ + char *p, *q ; + int i, pageno, lastext = -1 ; + long hoffset, voffset ; + int reversed ; + + initialize (); + if (argc < 2 || argc > 8) + usage() ; + +/* + * This next whole big section of code is straightforward; we just scan + * the options. An argument can either immediately follow its option letter + * or be separated by spaces. Any argument not preceded by '-' and an + * option letter is considered a file name. + */ + for (i=1; i<argc; i++) { + if (*argv[i]=='-') { + char *p=argv[i]+2 ; + char c=argv[i][1] ; + switch (c) { +case 'f' : + if (*p == 0 && argv[i+1]) + p = argv[++i] ; + if (*p == '(' && *(p+1) == '@' ) { + p+=2; firsttransf = myatol(&p); p++; + } + else if (*p == '@') { + p++; firsttransf = 1 ; + } +#ifdef SHORTINT + if(sscanf(p, "%ld", &firstpage)==0) +#else /* ~SHORTINT */ + if(sscanf(p, "%d", &firstpage)==0) +#endif /* ~SHORTINT */ + error("! Bad first page option (-f).") ; + break ; +case 'i' : + if (*p == 0 && argv[i+1]) + p = argv[++i] ; + while (*p != 0) { + if (*p == '(' && *(p+1) == '@' ) { + p+=2; inctransf[includeseq][0] = myatol(&p); p++; + } + else if (*p == '@') { + p++; inctransf[includeseq][0] = 1 ; + } + include[includeseq][0]=myatol(&p); + if (*p == '.' && *(p+1) == '.' ) { + p += 2; + if (*p == '(' && *(p+1) == '@' ) { + p+=2; inctransf[includeseq][1] = myatol(&p); p++; + } + else if (*p == '@') { + p++; inctransf[includeseq][1] = 1 ; + } + include[includeseq][1] = myatol(&p); + } + else { + include[includeseq][1] = include[includeseq][0]; + inctransf[includeseq][0] = inctransf[includeseq][1] ; + } + includeseq++ ; + if (*p != ',' && *p !=0 ) + error("! Bad page range option (-i).") ; + if (*p == ',' ) + p++ ; + } /* while */ + break ; +case 'l': + if (*p == 0 && argv[i+1]) + p = argv[++i] ; + if (*p == '(' && *(p+1) == '@' ) { + p+=2; lasttransf = myatol(&p); p++; + } + else if (*p == '@') { + p++; lasttransf = 1 ; + } +#ifdef SHORTINT + if(sscanf(p, "%ld", &lastpage)==0) +#else /* ~SHORTINT */ + if(sscanf(p, "%d", &lastpage)==0) +#endif /* ~SHORTINT */ + error("! Bad last page option (-l).") ; + break ; +case 'p' : + if (*p == 0 && argv[i+1]) + p = argv[++i] ; +#ifdef SHORTINT + if (sscanf(p, "%ld", &pagemodulo)==0) +#else /* ~SHORTINT */ + if (sscanf(p, "%d", &pagemodulo)==0) +#endif /* ~SHORTINT */ + error("! Bad pagemodulo option (-p).") ; + break ; +case 'm' : + if (*p == 0 && argv[i+1]) + p = argv[++i] ; +/* + * Is there a modulo supplied? Grab it if so; otherwise default to 1. + */ + for (q=p; *q != 0; q++) + if (*q == ':') + break ; + if (*q == ':') { + modulo = myatol(&p) ; + if (*p != ':') + usage() ; + if (modulo < 1 || modulo > MAXPPERP) + error("! modulo must lie between 1 and 32") ; + p++ ; + } +/* + * This loop grabs all of the page specifications. + */ + pagesperpage = 0 ; + while (*p != 0) { + if (pagesperpage >= MAXPPERP) + error("! too many page specifications") ; + if (*p == '-') { + reversed = 1 ; + p++ ; + } else + reversed = 0 ; + if (*p == 0 || *p == '(' || *p == ',') + pageno = 0 ; + else + pageno = myatol(&p) ; + if (*p == '(') { + p++ ; + hoffset = myatodim(&p) ; + if (*p++ != ',') + usage() ; + voffset = myatodim(&p) ; + if (*p++ != ')') + usage() ; + } else { + hoffset = 0 ; + voffset = 0 ; + } + pages[pagesperpage].hoffset = hoffset ; + pages[pagesperpage].voffset = voffset ; + pages[pagesperpage].pageno = pageno ; + pages[pagesperpage].reversed = reversed ; + pagesperpage++ ; + if (*p == ',') + p++ ; + } /* while */ + break ; +case 'n' : + if (*p == 0 && argv[i+1]) + p = argv[++i] ; +#ifdef SHORTINT + if (sscanf(p, "%ld", &maxpages)==0) +#else /* ~SHORTINT */ + if (sscanf(p, "%d", &maxpages)==0) +#endif /* ~SHORTINT */ + error("! Bad number of pages option (-n).") ; + break ; +case 'q' : case 'Q' : + quiet = 0 ; + break ; +case 'r' : case 'R' : + pages[0].reversed = 1; + break ; +case 'j' : case 'J' : + jumpingpages = 1; + break; +case 'x' : + if (*p == 0 && argv[i+1]) + p = argv[++i] ; + while (*p != 0) { + if (*p == '(' && *(p+1) == '@' ) { + p+=2; exctransf[excludeseq][0] = myatol(&p); p++; + } + else if (*p == '@') { + p++; exctransf[excludeseq][0] = 1 ; + } + exclude[excludeseq][0]=myatol(&p); + if (*p == '.' && *(p+1) == '.' ) { + p += 2; + if (*p == '(' && *(p+1) == '@' ) { + p+=2; exctransf[excludeseq][1] = myatol(&p); p++; + } + else if (*p == '@') { + p++; exctransf[excludeseq][1] = 1 ; + } + exclude[excludeseq][1] = myatol(&p); + } + else { + exclude[excludeseq][1] = exclude[excludeseq][0]; + exctransf[excludeseq][0] = exctransf[excludeseq][1] ; + } + excludeseq++ ; + if (*p != ',' && *p !=0 ) + error("! Bad page range option (-x).") ; + if (*p == ',' ) + p++ ; + } /* while */ + break ; +case '?' : + usage() ; + break ; +default: + error("! Bad option, not one of filmnqrx?") ; + } /* switch c */ + } else { /* this a file name */ + if (*iname == 0) { /* input file name */ + register char *p ; + + lastext = 0 ; + iname = nextstring ; + p = argv[i] ; + while (*p) { + *nextstring = *p++ ; + if (*nextstring == '.') + lastext = nextstring - iname ; + else if (IS_DIR_SEP(*nextstring) || *nextstring == ':') + lastext = 0 ; + nextstring++ ; + } + if (lastext == 0) { + lastext = nextstring - iname ; + *nextstring++ = '.' ; + *nextstring++ = 'd' ; + *nextstring++ = 'v' ; + *nextstring++ = 'i' ; + } + *nextstring++ = 0 ; + if ((infile=fopen(iname, READBIN))==NULL) + error("! can't open input file") ; + + } else { /* output file name */ + register char *p ; + + lastext = 0 ; + oname = nextstring ; + p = argv[i] ; + while (*p) { + *nextstring = *p++ ; + if (*nextstring == '.') + lastext = nextstring - oname ; + else if (IS_DIR_SEP(*nextstring) || *nextstring == ':') + lastext = 0 ; + nextstring++ ; + } + if (lastext == 0) { + lastext = nextstring - oname ; + *nextstring++ = '.' ; + *nextstring++ = 'd' ; + *nextstring++ = 'v' ; + *nextstring++ = 'i' ; + } + *nextstring++ = 0 ; + if (freopen(oname, WRITEBIN, stdout)==NULL) + error("! can't open output file") ; + } /* end output file name */ + } /* else argument with '-' */ + } /* for */ + if (*iname == 0) { + (void)fprintf(stderr, banner) ; + error("! no input file specified"); + } + /* Inserted by djc@dsmail.hmi.de 3.8.1994 */ + if(!oname) { + oname="stdout"; + if (!isatty(fileno(stdout))) + SET_BINARY(fileno(stdout)); + } + + if (*oname != 0 && !quiet) { + (void)fprintf(stderr, banner) ; + (void)fprintf(stderr, "%s -> %s\n",iname,oname); + temp = nextstring ; + } +} +/* + * Grabs a pointer, and checks it for validity. + */ +integer ptr(where) +register integer where ; +{ + fseek(infile,where,SEEK_SET); + where = signedquad() ; + if (where < -1L || where > inlength) + error("! dvi file malformed; impossible pointer") ; + return(where) ; +} + +/* + * This routine store the page locations by tracing the pointers backwards. + */ +void searchpageloc() +{ + integer p,num ; + + num=pagecount-1; + for (p = ptr(postloc+1); num > 0; num--) { + if (dvibuf(p) != 139) + error("! missed a bop somehow") ; + else { + pageloc[num]=p; + pagenumbers[num]=signedquad(); + } + p = ptr(p+41) ; + } + pageloc[num]=p; + (void)dvibuf(p); + pagenumbers[num]=signedquad(); +} +/* + * This routine simply reads the entire dvi file, and then initializes + * some values about it. + */ +void readdvifile() { + integer p ; + unsigned char c,d,e ; + + fseek(infile, 0L, 2) ; + inlength = ftell(infile) ; + if (inlength < 10) + error("! dvi file too short") ; + fseek(infile,-3L,SEEK_CUR); + for (p=inlength - 3; p > 0; p--) { + c = dvibyte (); d = dvibyte (); e = dvibyte (); + if (c == 2 && d == 0xdf /* dave fuchs */ && + e == 0xdf) + break ; + fseek(infile,-4L,SEEK_CUR); + } + if (p < 10) + error("! rather short dvi file, ain't it?") ; + postloc = ptr(p-4) ; + fseek(infile,postloc+5L,SEEK_SET); + if (signedquad() != 25400000 || + signedquad() != 473628672) + error("! change this program to support non-TeX num/den values") ; + mag = signedquad() ; + if (mag < 1 || mag > 1000000) + error("! impossible magnification value") ; + fseek(infile,postloc+27L,SEEK_SET); + pagecount = twobytes() ; + if (pagecount < 1 || pagecount > 1000000) + error("! impossible page count value") ; +/* + * That's enough error checking; we probably have a correct dvi file. + * Let's convert all the values we got from the command line into + * units that we can actually use in the dvi file. + */ + for (p=0; p<pagesperpage; p++) { + scalemag(&(pages[p].hoffset)) ; + scalemag(&(pages[p].voffset)) ; + } +/* + * Now let's grab us some font pointers. + */ + pageloc = (integer *) calloc (pagecount, sizeof (integer)); + if (pageloc == NULL) + error("! Not enough memory for allocation of page pointers"); + pagenumbers = (integer *) calloc (pagecount, sizeof (integer)); + if (pagenumbers == NULL) + error("! Not enough memory for allocation of page numbers array"); + searchpageloc(); + transformpages(); + free(pagenumbers); + p = postloc + 29 ; + while (1) { + c=dvibuf(p); + if (c == 249) + break ; + if (c == 138) + p++ ; + else if (c == 243) { + TeXfonts[dvibyte()] = p ; + p += fontdeflen(p) ; + } else + error("! only nop's and font def's allowed in postamble") ; + } +/* + * Now we check for a landscape special. It should be the + * *first* thing in the page that is at all complicated. + */ + + p = pageloc[0L] + 45 ; + c=dvibuf(p); + while (comlen[c]) { + p += comlen[c] ; + c = dvibuf(p); + } + if (c == 239) { + stringdvibuf(p+2L,9L); + if (strncmp(temp, "landscape", 9)==0) { + landscape = p ; + rem0special = 1 ; + } + } +} +/* + * Output a single byte, keeping track of where we are. + */ +void outdvibyte(c) +unsigned char c ; +{ + fputc(c, stdout) ; + dviloc++ ; +} +/* + * Send out two bytes. + */ +void outdvi2(v) +integer v ; +{ + outdvibyte((unsigned char)(v >> 8)) ; + outdvibyte((unsigned char)(v & 255)) ; +} +/* + * Send out a longword. + */ +void outdviquad(v) +integer v ; +{ + outdvi2(v >> 16) ; + outdvi2(v & 65535) ; +} +/* + * This routine just copies some stuff from the buffer on out. + * Suppose the file is positioned correctly before + */ +void putbuf(length) +integer length ; +{ + while ( length-- > 0 ) + outdvibyte(dvibyte()) ; +} +/* + * This routine outputs a string, terminated by null. + */ +void putstr(s) +register unsigned char *s ; +{ + while (*s) + outdvibyte(*s++) ; +} +/* + * Here we write the preamble to the dvi file. + */ +void writepreamble() { +/* just copy the first 14 bytes of the file */ + fseek(infile,0L,SEEK_SET); + putbuf(14L) ; +/* and put our identifier. */ + putstr("\015dvidvi output") ; +} +/* + * This routine writes out a font definition. + */ +void putfontdef(f) +int f ; +{ + integer p,q ; + + p = TeXfonts[f] ; + q=fontdeflen(p) ; + fseek(infile,p,SEEK_SET); + putbuf(q) ; +} +/* + * The postamble is next. + */ +void writepostamble() { + int i ; + integer p ; + + p = dviloc ; + outdvibyte(248) ; + outdviquad(prevpp) ; + fseek(infile,postloc+5,SEEK_SET); + putbuf(20L) ; + outdvi2(twobytes()+1L) ; /* increase stack depth by 1 */ + outdvi2(outputpages) ; + for (i=0; i<256; i++) + if (fontseen[i]) + putfontdef(i) ; + outdvibyte(249) ; + outdviquad(p) ; + outdvibyte(2) ; + outdviquad(0xdfdfdfdfL) ; + while (dviloc & 3) + outdvibyte(0xdf) ; + fclose(stdout) ; +} +/* + * This routine starts a page, by writing out a bop command. + */ +void beginpage() { + int i ; + integer p ; + + p = dviloc ; + outdvibyte(139) ; + outdviquad(outputpages+1) ; + for (i=0; i<9; i++) + outdviquad(0L) ; + outdviquad(prevpp) ; + prevpp = p ; +} +/* + * This routine sends out a page. We need to handle the + * landscape special, though. + */ +void dopage(num) +integer num ; +{ + register integer p,q ; + register int len ; + integer v, oldp ; + unsigned char c; + +/* + * We want to take the base 10 log of the number. It's probably + * small, so we do it quick. + */ + if (! quiet) { + int t = num+1, i = 0 ; + if (t < 0) { + t = -t ; + i++ ; + } + do { + i++ ; + t /= 10 ; + } while (t > 0) ; + if (i + prettycolumn > 76) { + fprintf(stderr, "\n") ; + prettycolumn = 0 ; + } + prettycolumn += i + 1 ; +#ifdef SHORTINT + (void)fprintf(stderr, "[%ld", num+1) ; +#else /* ~SHORTINT */ + (void)fprintf(stderr, "[%d", num+1) ; +#endif /* ~SHORTINT */ + (void)fflush(stderr) ; + } + p = pageloc[num] + 45 ; + c=dvibuf(p); + while (c != 140) { + if ((len=comlen[c]) > 0) { /* most commands are simple */ + outdvibyte(c); + putbuf((long)len-1) ; + p += len ; + } else { /* but there are a few we need to treat specially */ + len = c ; + if (171 <= len && len <= 235) { + p++ ; + if (len == 235) + { len = dvibyte (); p++ ;} + else + len -= 171 ; + if (!fontseen[len]) { + putfontdef(len) ; + fontseen[len] = 1 ; + fseek(infile,p,SEEK_SET); + } + if (len < 64) + outdvibyte(171 + len) ; + else { + outdvibyte(235) ; + outdvibyte(len) ; + } + } else { + v = 0 ; + oldp = p++ ; + switch(len) { +case 242: v = dvibyte() ; p++ ; break ; +case 241: v = (v << 8) + dvibyte() ; p++ ; break ; +case 240: v = (v << 8) + dvibyte() ; p++ ; break ; +case 239: v = (v << 8) + dvibyte() ; p++ ; +/* + * Remove a landscape special on page 0, if one is found. + */ stringdvibuf(oldp + len - 327,9); + if (num || ! rem0special || + strncmp(temp, "landscape", 9)) { + fseek (infile,oldp,SEEK_SET); + putbuf(v + len - 237) ; + } + p = oldp + v + len - 237 ; + fseek(infile,p,SEEK_SET); + break ; +case 243: case 244: case 245: case 246: + p += len - 230 ; + p += dvibuf(p) ; + p += dvibyte() + 2 ; + fseek(infile,p,SEEK_SET); + break ; +default: fprintf(stderr, "Bad dvi command was %d at %ld\n", len, p) ; + error("! lost sync dvi in file lost dvi sync file in") ; + } + } + } + c=dvibyte(); + } + if (! quiet) { + (void)fprintf(stderr, "] ") ; + (void)fflush(stderr) ; + prettycolumn += 2 ; + } +} +/* + * Here we end a page. Simple enough. + */ +void endpage() { + outputpages++ ; + outdvibyte(140) ; +} +/* + * This is our main routine for output, which runs through all the + * pages we need to output. + */ +void writedvifile() { + integer pagenum ; + int ppp ; + integer actualpageno, lastpageno ; + struct pagespec *ps ; + integer p ; + Boolean beginp ; + + writepreamble() ; + if ( !pagemodulo ) + pagefake = (pagecount + modulo - 1) / modulo * modulo ; + else + pagefake = (pagecount + pagemodulo - 1) / pagemodulo * pagemodulo ; + if ( maxpages < pagefake ) pagefake = maxpages; + for (lastpageno = -1, pagenum = 0; pagenum < pagefake / ( jumpingpages + 1); pagenum += modulo) { + beginp = 1 ; + for (ppp = 0, ps=pages; ppp < pagesperpage; ppp++, ps++) { + if (ps->reversed) + actualpageno = pagefake - pagenum - modulo + ps->pageno ; + else + actualpageno = pagenum + ps->pageno ; + if ( jumpingpages ) + ps->reversed = !ps->reversed; + if ( actualpageno == lastpageno ) { + pagenum = pagefake; + break; + } + if (actualpageno < pagecount && selectedpage(actualpageno+1) ) { + if (beginp) { + beginpage() ; + beginp = 0 ; + } + if (landscape) { + fseek(infile,landscape,SEEK_SET); + putbuf(dvibuf(landscape+1)+2L) ; + landscape = 0 ; + } + if (pagesperpage) + outdvibyte(141) ; + if (ps->hoffset) { + outdvibyte(146) ; + outdviquad(ps->hoffset) ; + } + if ( pagemodulo ) + lastpageno = actualpageno; + if (ps->voffset) { + outdvibyte(160) ; + outdviquad(ps->voffset) ; + } + dopage(actualpageno) ; + if (pagesperpage) + outdvibyte(142) ; + } + } + if (beginp != 1) endpage() ; + } + writepostamble() ; +} +int main(argc, argv) +int argc ; +char *argv[] ; +{ + processargs(argc, argv) ; + readdvifile() ; + writedvifile() ; + return 0 ; +} + |