home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 4 / FreshFish_May-June1994.bin / bbs / may94 / text / tex / dvidvi.lha / DviDvi / dvidvi.c next >
Encoding:
C/C++ Source or Header  |  1994-02-05  |  48.8 KB  |  1,790 lines

  1. /*
  2.  *   This program converts dvi files to dvi files;
  3.  *   the command line options are:
  4.  *
  5.  *    page n is first page selected         -f n
  6.  *    page n is last page selected          -l n
  7.  *    print at most n pages                 -n n
  8.  *    include pages (ranges allowed)        -i { n1..n2 | n1 }[,...]
  9.  *    exclude pages (ranges allowed)        -x { n1..n2 | n1 }[,...]
  10.  *    work in quiet mode                    -q
  11.  *    reverse pages                         -r
  12.  *    select even                           -m 2:1
  13.  *    select odd                            -m 2:0
  14.  *    print both on same page               -m 2:0,1(5.5in,0in)
  15.  *    do folded brochures                   -m 4:-3,0(5.5in,0in)
  16.  *                                          -m 4:1,-2(5.5in,0in)
  17.  *    etc.
  18.  *
  19.  *    scale magnification                   -sm m
  20.  *    scale document-width                  -sw m
  21.  *    scale document-height                 -sh m
  22.  *
  23.  *    The arguments m are instances of magsteps. For example -sm 2
  24.  *    multiplies the document-magnification by magstep(2) (1.44) and
  25.  *    -sw -2 multiplies the document-with by magstep(2) (0.694).
  26.  *
  27.  *    The original program is by Tomas Rokicki (version 0.5) but it was
  28.  *    modified and improved by Esteban ZIMANYI ezimanyi@rc1.vub.ac.be
  29.  *    to give version 1.0.
  30.  *
  31.  *    This version has been tested for the IBM PC and compatibles under
  32.  *    compilers Turbo C 2.0 and Microsoft C 6.0.
  33.  *
  34.  *    The options -sm, -sw and -sh were added by Jochen Wiedmann to support
  35.  *    PasTeX on the Amiga. This was needed because PasTeX doesn't ignore
  36.  *    the Width- and Height-Parameters included in the Postamble. PasTeX
  37.  *    needs them to be rearranged to work fine.
  38.  */
  39.  
  40. /* Changed 19.01.1994 thb
  41.  *
  42.  * After some major hassles with all Amiga ports of DVIDVI 1.0, I have taken
  43.  * this version and added support for a clean compile under SAS/C 6.50. All 
  44.  * relevant parts of the code have been enclosed in #ifdef _AMIGA ... #endif
  45.  * statements, so that it should still compile fine on other platforms.
  46.  *
  47.  * Besides, I have taken the liberty to modify the following "features" of 
  48.  * the code:
  49.  *
  50.  * - malloc'ed and calloc'ed memory is now explicitly freed on exit. While
  51.  *   resource tracking is just fine, I prefer doing things the proper way.
  52.  *
  53.  * - the function stringdvibuf() would use a pointer to string space that was
  54.  *   forever incremented, and never set back. Eventually, it would overwrite
  55.  *   other data and crash my machine. Even worse, the check for the landscape
  56.  *   special couldn't work this way. See my comments in the code.
  57.  * 
  58.  * - Fixed a typo in a part of the \special{landscape} handling, where 237
  59.  *   was mistyped to spell 327. As landscape handling didn't work anyways, I
  60.  *   can see why nobody noticed it.
  61.  *
  62.  * - Fixed also the proper inclusion of the \special{landscape} in another
  63.  *   place. Here, somebody overlooked the side-effects of dvibuf(). See also
  64.  *   comments in the code.
  65.  *
  66.  * - Fixed a problem when only one filename is given. I guess the proper
  67.  *   behaviour for such a case is that output will go to stdout, so that
  68.  *   is what I do.
  69.  *
  70.  * - I have bumped the revision to 1.1, so that this can't be confused with 
  71.  *   all of those other DVIDVI 1.0 ports.
  72.  *
  73.  * However, there are still a few things that this version of DVIDVI won't
  74.  * do:
  75.  *
  76.  * - the -n page selector "print at most n pages" appears to be broken, so
  77.  *   that it will only do the same as -l, i.e. set the number of the last
  78.  *   page to be printed.
  79.  *
  80.  * - it seems like the page selection doesn't look at the logical page numbers
  81.  *
  82.  * I have commented and signed all my changes "Changed 19.01.1994 thb", so 
  83.  * you should look up what I have done if you're knowledgeable about DVIDVI.
  84.  *
  85.  * If you modify or enhance this code, please send me a copy :-)
  86.  *
  87.  * Disclaimer:
  88.  *
  89.  * I'm still a C novice, and don't really know anything about the DVI format.
  90.  *
  91.  *   Thomas Baetzler
  92.  *   Herrenstr. 62      email: thb@mil.ka.sub.org (Usenet)
  93.  *   76133 Karlsruhe           2:2476/454.2       (Fido)
  94.  *   Germany                   thb@norton.zer     (Z-Netz)
  95.  */
  96.  
  97. #define SEEK_SET 0
  98. #define SEEK_CUR 1
  99. #define SEEK_END 2
  100.  
  101. /* Changed 19.01.1994 thb
  102.  *
  103.  * Bumped revision so that it isn't confused with all those broken 1.0
  104.  * releases of DVIDVI.
  105.  */
  106.  
  107. #define BANNER "\nThis is dvidvi 1.1, Copyright (C) 1988-91, Radical Eye Software\n"
  108.  
  109. /* Changed 19.01.1994 thb
  110.  *
  111.  * Incremented string space to 1k. You never know what happens...
  112.  */
  113.    
  114. #define STRINGSIZE (1000)  /* maximum number of strings in program */
  115.  
  116. /* Changed 19.01.1994 thb
  117.  *
  118.  * SAS/C needs this for the malloc() proto
  119.  */
  120.  
  121. #ifdef _AMIGA
  122. #include <stdlib.h>
  123. #endif
  124.  
  125. #ifndef VMS
  126. #include <stdio.h>
  127. #include <string.h>
  128. #include <math.h>
  129. #else /* VMS */
  130. #include "sys$library:stdio.h"       /* AKT: added sys$library: */
  131. #include <alloc.h>
  132. #endif /* VMS */
  133. #define MAXPPERP (32)
  134.  
  135. /* defines READBIN, WRITEBIN, PATHSEP and DIRSEP*/
  136.  
  137. #ifdef MSDOS
  138. #define READBIN     "rb"    /* MSDOS must use binary mode */
  139. #define WRITEBIN    "wb"
  140. #define PATHSEP     ';'
  141. #define DIRSEP      '\\'
  142. #else
  143. #ifdef VMS
  144. #define READBIN     "rb"    /* VMS must use binary mode */
  145. #define WRITEBIN    "wb"
  146. #define PATHSEP     ','
  147. #define DIRSEP        ':'
  148. #else
  149. #define READBIN     "r"     /* UNIX doesn't care */
  150. #define WRITEBIN    "w"
  151. #define PATHSEP     ':'
  152. #define DIRSEP      '/'
  153. #endif
  154. #endif
  155.  
  156. #ifdef XENIX
  157. #define SHORTINT
  158. #else
  159. #undef SHORTINT
  160. #endif
  161. #ifdef MSDOS
  162. #define SHORTINT
  163. #endif
  164.  
  165. /*
  166.  *   Type declarations.  integer must be a 32-bit signed; shalfword must
  167.  *   be a sixteen-bit signed; halfword must be a sixteen-bit unsigned;
  168.  *   quarterword must be an eight-bit unsigned.
  169.  */
  170.  
  171. typedef long integer;
  172. typedef char boolean;
  173. typedef short shalfword ;
  174. typedef unsigned long longword;
  175. typedef unsigned short halfword ;
  176. typedef unsigned char quarterword ;
  177. typedef short Boolean ;
  178.  
  179. /* Changed 19.01.1994 thb
  180.  *
  181.  * Prototypes to keep SAS/C happy
  182.  */
  183.  
  184. #ifdef __STDC__
  185. void            cleanup( void );
  186. void            abortpage( void );
  187. shalfword       dvibyte( void );
  188. halfword        twobytes( void );
  189. integer         threebytes( void );
  190. longword        fourbytes( void );
  191. shalfword       signedbyte( void );
  192. shalfword       signedpair( void );
  193. integer         signedtrio( void );
  194. integer         signedquad( void );
  195. integer         transf(integer p, halfword q);
  196. void            transformpages( void );
  197. integer         fontdeflen(integer p);
  198. unsigned char   dvibuf(integer p);
  199. void            stringdvibuf(integer p, integer n);
  200. void            usage( void );
  201. void            error( char *s);
  202. integer         scale(integer whole, integer num, integer den, integer sf);
  203. void            scalemag( long *p );
  204. integer         myatol(char **s);
  205. integer         myatodim(char **s);
  206. short           selectedpage ( integer n );
  207. void            initialize( void );
  208. void            processargs( int argc, char *argv[]);
  209. integer         ptr(integer where);
  210. void            searchpageloc( void );
  211. void            readdvifile( void );
  212. void            outdvibyte(unsigned char c);
  213. void            outdvi2( integer v );
  214. void            outdviquad( integer v );
  215. void            putbuf( integer length );
  216. void            putstr( unsigned char *s );
  217. void            writepreamble( void );
  218. void            putfontdef( int f);
  219. void            writepostamble( void );
  220. void            beginpage( void );
  221. void            dopage( integer num );
  222. void            endpage( void );
  223. void            writedvifile( void );
  224. int             main( int argc, char *argv[]);
  225. #endif /* __STDC__ */
  226.  
  227. /*
  228.  *   Some globals to keep everyone happy.
  229.  */
  230.  
  231. integer numpages;       /* the total number of pages in the dvi file. */
  232. integer TeXfonts[256];  /* information about each font */
  233. char fontseen[256];     /* have we defined this font yet? */
  234. int modulo;             /* our mod value */
  235.  
  236. struct pagespec {
  237.     int pageno, reversed;
  238.     long hoffset, voffset;  /* in scaled points */
  239. } pages[MAXPPERP];          /* the organization of the pages on output */
  240.  
  241. int pagesperpage;       /* how many pages crammed onto each page? */
  242. FILE *infile = NULL;    /* input dvi file (cannot be a stream) */
  243. FILE *outfile = NULL;   /* output dvi file */
  244.  
  245. /* Changed 19.01.1994 thb
  246.  *
  247.  * Initialized strings pointer just in case...
  248.  */
  249.  
  250. char *temp = NULL;          /* a temporary place to put things */
  251. char *nextstring = NULL;
  252. char *maxstring = NULL;
  253. char *oname = NULL;         /* output dvi file name */
  254. char *iname = NULL;         /* input dvi file name */
  255. char *strings = NULL;       /* pointer of the string pool */
  256.  
  257. char banner[] = BANNER ;    /* the startup message */
  258. integer inlength;           /* the length of the input dvi file */
  259. integer postloc;            /* location of the postamble */
  260. integer mag;                /* magnification factor */
  261. integer pagecount;          /* number of actual pages */
  262. integer landscape = 0;      /* if landscape special, here it is! */
  263. int rem0special;            /* should we remove the first first-page special? */
  264. integer prevpp = -1;        /* previous page pointer on output */
  265. integer outputpages;        /* number of pages output */
  266. integer dviloc;             /* our position in the output file */
  267. integer pagefake ;          /* number of pages, rounded up to multiple of modulo */
  268.  
  269. Boolean firsttransf = 0, lasttransf = 0;
  270. integer firstpage;          /*  first page selected (option -p) */
  271. integer lastpage;           /*  last page selected (option -l) */
  272. integer maxpages;           /*  maximum number of page selected (option -n) */
  273. short quiet;                /*  quiet mode (option -q) */
  274. Boolean exctransf[40][2];   /*  if the ranges of pages to exclude (option -x)
  275.                                 have to be transformed */
  276. integer exclude[40][2];     /*  the ranges of pages to exclude (option -x)
  277.                                 It is supposed that there are at most 40 ranges
  278.                                 to exclude in the command line */
  279. short excludeseq;           /*  number of ranges to exclude (option -x) */
  280. Boolean inctransf[40][2];   /*  if the ranges of pages to exclude (option -x)
  281.                                 have to be transformed */
  282. integer include[40][2];     /*  the ranges of pages to include (option -i)
  283.                                 It is supposed that there are at most 40 ranges
  284.                                 to include in the command line */
  285. short includeseq;           /*  number of ranges to include (option -i) */
  286.  
  287. /* Changed 19.01.1994 thb
  288.  *
  289.  * Cleared pointers just to be on the safe side.
  290.  */
  291.  
  292. integer *pageloc = NULL; 
  293. integer *pagenumbers = NULL;
  294.  
  295. int prettycolumn ;          /* the column we are at when running pretty */
  296.  
  297. /*  Added 28.07.1993,    Jochen Wiedmann     */
  298. double scale_magstep = 0.0;
  299. double scale_width = 0.0;
  300. double scale_height = 0.0;
  301. /*                        */
  302.  
  303.  
  304. /*
  305.  *   This array holds values that indicate the length of a command, if
  306.  *   we aren't concerned with that command (which is most of them) or
  307.  *   zero, if it is a special case.  This makes running through the
  308.  *   dvi file a lot easier (and probably faster) than any form of
  309.  *   dispatch table, especially since we really don't care what the
  310.  *   pages are made of.
  311.  */
  312.  
  313. short comlen[256] = {
  314.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 0-15 */
  315.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 16-31 */
  316.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 32-47 */
  317.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 48-63 */
  318.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 64-79 */
  319.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 80-95 */
  320.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 96-111 */
  321.    1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 112-127 */
  322.    2, 3, 4, 5, 9, 2, 3, 4, 5, 9, 1, 0, 0, 1, 1, 2, /* 128-143 */
  323.    3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 2, 3, 4, /* 144-159 */
  324.    5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 0, 0, 0, 0, 0, /* 160-175 */
  325.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 176-191 */
  326.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 192-207 */
  327.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 208-223 */
  328.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 4, 5, 0, /* 224-239 */
  329.    0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };/* 240-255 */
  330.  
  331. /*
  332.  *   Input bytes from the dvi file.
  333.  *   These routines could probably be sped up significantly; but they are
  334.  *   very machine dependent, so I will leave such tuning to the installer.
  335.  *   They simply get and return bytes in batches of one, two, three, and four,
  336.  *   updating the current position as necessary.
  337.  */
  338.  
  339. void
  340. abortpage()
  341. {
  342.     error("! unexpected eof on DVI file");
  343. }
  344.  
  345.  
  346. shalfword dvibyte()
  347. {
  348.     register shalfword i;
  349.     if ((i=getc(infile))==EOF){
  350.         abortpage();
  351.     }
  352.     return( i );
  353. }
  354.  
  355.  
  356. halfword  twobytes()
  357. {
  358.     register halfword i;
  359.     i = dvibyte();
  360. #ifdef _AMIGA
  361.     return( (halfword) ( dvibyte() + i*256 ) ); 
  362. #else
  363.     return( i*256+dvibyte() ); 
  364. #endif
  365. }
  366.  
  367.  
  368. integer   threebytes()
  369. {
  370.     register integer i;
  371.     i = twobytes();
  372.     return( i * 256 + dvibyte() ); 
  373. }
  374.  
  375.  
  376. longword  fourbytes()
  377. {
  378.     register longword i;
  379.     i = twobytes();
  380.     return((i<<16)+twobytes());
  381. }
  382.  
  383.  
  384. shalfword
  385. signedbyte()
  386. {
  387.     register shalfword i ;
  388.     if ((i=getc(infile))==EOF){
  389.         abortpage();
  390.     }
  391.     if (i<128) return(i);
  392. #ifdef _AMIGA
  393.     else return((shalfword)(i-256));
  394. #else
  395.     else return(i-256);
  396. #endif
  397. }
  398.  
  399.  
  400. shalfword
  401. signedpair()
  402. {
  403.     register shalfword i ;
  404.     i = signedbyte();
  405. #ifdef _AMIGA
  406.     return((shalfword)(i*256+dvibyte()));
  407. #else
  408.     return(i*256+dvibyte());
  409. #endif
  410. }
  411.  
  412.  
  413. integer
  414. signedtrio()
  415. {
  416.     register integer i ;
  417.  
  418.     i = signedpair();
  419.     return(i*256+dvibyte());
  420. }
  421.  
  422.  
  423. integer
  424. signedquad()
  425. {
  426.     register integer i;
  427.  
  428.     i = signedpair();
  429.     return(i*65536+twobytes());
  430. }
  431.  
  432.  
  433. /*
  434.  * Routines for the transformation of the pages specified with
  435.  * the @ parameter into the actual number of page from the file
  436.  *
  437.  * trans(p,q) looks for the q'th occurrence of the page numbered p
  438.  * transformpages makes the transformation for the options -f -i -l -x
  439.  */
  440.  
  441. integer transf(p, q)
  442. integer p;
  443. halfword q;
  444. {
  445.     int i=0, j=0;
  446.  
  447.     while( j != q && i < pagecount )
  448.         if ( pagenumbers[i++] == p ) j++;
  449.     if ( j != q ) error ("! Page specified not found");
  450.     return (i++);
  451. }
  452.  
  453. void
  454. transformpages()
  455. {
  456.     int i;
  457.  
  458.     if (firsttransf) firstpage=transf(firstpage,firsttransf);
  459.     if (lasttransf) lastpage=transf(lastpage,lasttransf);
  460.     for ( i= 0; i< 40; i++) {
  461.         if (exctransf[i][0]) exclude[i][0]=transf(exclude[i][0],exctransf[i][0]);
  462.         if (exctransf[i][1]) exclude[i][1]=transf(exclude[i][1],exctransf[i][1]);
  463.         if (inctransf[i][0]) include[i][0]=transf(include[i][0],inctransf[i][0]);
  464.         if (inctransf[i][1]) include[i][1]=transf(include[i][1],inctransf[i][1]);
  465.     }
  466. }
  467.  
  468.  
  469. /*
  470.  *
  471.  */
  472.  
  473. integer fontdeflen(p)
  474. integer p;
  475. {
  476.     fseek(infile,p+14,SEEK_SET);
  477.     return (16L+dvibyte()+dvibyte());
  478. }
  479.  
  480.  
  481. /*
  482.  *     Simulation of dvibuf, get the character located at the position
  483.  *     p in the input dvi file
  484.  */
  485.  
  486. unsigned char 
  487. dvibuf(p)
  488. integer p;
  489. {
  490.     fseek(infile,p,SEEK_SET);
  491.     return( (unsigned char) dvibyte());
  492. }
  493.  
  494.  
  495. /*
  496.  *     Read a string of length n from the file into the string temp
  497.  */
  498.  
  499. void 
  500. stringdvibuf(p,n)
  501. integer p,n;
  502. {
  503.  
  504. #if 0
  505.     fseek(infile,p,SEEK_SET);
  506.     while ( n-- > 0 )
  507.         *temp++ = dvibyte();
  508. #else
  509.  
  510. /* Changed 19.01.1994 thb
  511.  *
  512.  * Note: The way I see it, the global temp must not be changed, because 
  513.  * it will never be reset by the callers. If one lets this run wild, it 
  514.  * will eventually trash other variables on the stack. Also; I can not 
  515.  * understand how the check for "Landscape" could  work otherwise. See 
  516.  * the calling functions for an example of what I mean.
  517.  */ 
  518.  
  519.     char *reallytemp = temp;
  520.  
  521.     fseek(infile,p,SEEK_SET);
  522.     while ( n-- > 0 ){
  523.         *reallytemp++ = dvibyte();
  524.     }
  525. #endif
  526. }
  527.  
  528.  
  529. /*
  530.  *   Print a usage error messsage, and quit.
  531.  */
  532.  
  533. void
  534. usage() 
  535. {
  536.     (void)fprintf(stderr,banner);
  537.     (void)fprintf(stderr,"Usage:  dvidvi [options] input[.dvi] [output]\n");
  538.     (void)fprintf(stderr,"where options are:\n");
  539.     (void)fprintf(stderr,"    [-f n] first page printed     [-l n] last page printed\n");
  540.     (void)fprintf(stderr,"    [-n n] print at most n pages  \n");
  541.     (void)fprintf(stderr,"    [-i {n1..n2 | n3}[,...]] include pages\n");
  542.     (void)fprintf(stderr,"    [-x {n1..n2 | n3}[,...]] exclude pages\n");
  543.     (void)fprintf(stderr,"    [-q] quiet mode               [-r] reverse pages\n");
  544.  
  545.  
  546. /*  Added 28.07.1993,    Jochen Wiedmann     */
  547.     (void)fprintf(stderr,"    [-sm m] scale magnification by magstep(m)\n");
  548.     (void)fprintf(stderr,"    [-sw m] scale width by magstep(m)\n");
  549.     (void)fprintf(stderr,"    [-sh m] scale height by magstep(m)\n");
  550. /*                        */
  551.  
  552.  
  553.     (void)fprintf(stderr,"    [-m modulo:pagespecs]\n");
  554. #ifndef VMS
  555.  
  556. /* Changed 19.01.1994 thb
  557.  *
  558.  * Inserted call to free allocated strings 
  559.  */
  560.  
  561.     cleanup();
  562.  
  563.     exit(1);
  564. #else /* VMS */
  565.     exit(0x10000002);
  566.    /* AKT: was exit(1) */
  567. #endif /* VMS */
  568. }
  569.  
  570.  
  571. /*
  572.  *   Print an error message, and exit if it is fatal.
  573.  */
  574.  
  575. void
  576. error(s)
  577. char *s ;
  578. {
  579.     (void)fprintf(stderr, "%s\n", s);    /* AKT: was dvidvi: %s */
  580.     if (*s == '!')
  581. #ifndef VMS
  582.  
  583. /* Changed 19.01.1994 thb
  584.  *
  585.  * Inserted call to free allocated strings.
  586.  */
  587.     cleanup();
  588.  
  589.     exit(1);
  590. #else /* VMS */
  591.     exit(0x10000002);
  592.       /* AKT: was exit(1) */
  593. #endif /* VMS */
  594. }
  595.  
  596.  
  597. /*
  598.  *   This function calculates approximately (whole + num/den) * sf.
  599.  *   No need for real extreme accuracy; one ten thousandth of an
  600.  *   inch should be sufficient.
  601.  *
  602.  *   No `sf' parameter means to use an old one; inches are assumed
  603.  *   originally.
  604.  *
  605.  *   Assumptions:
  606.  *
  607.  *    0 <= num < den <= 10000
  608.  *    0 <= whole
  609.  */
  610. integer defaultscale = 4736286 ;
  611.  
  612. integer scale(whole, num, den, sf)
  613. integer whole, num, den, sf ;
  614. {
  615.     integer v ;
  616.  
  617.     if (sf) {
  618.         defaultscale = sf ;
  619.     } else {
  620.         sf = defaultscale ;
  621.     }
  622.     v = whole * sf + num * (sf / den);
  623.     if (v / sf != whole || v < 0 || v > 0x40000000L){
  624.         error("! arithmetic overflow in parameter");
  625.     }
  626.     sf = sf % den ;
  627.     v += (sf * num * 2 + den) / (2 * den);
  628.     return(v);
  629. }
  630.  
  631.  
  632. /*
  633.  *   Multiplies *p by 1000 and divides it by mag.  Avoiding overflow.
  634.  *
  635.  *   1 <= mag <= 1000000 ;
  636.  *   0 <= *p <= 2^30
  637.  *
  638.  *   (Could blow up if a parameter * mag / 1000 > 2^30 sp.)
  639.  */
  640.  
  641. void 
  642. scalemag(p)
  643. long *p ;
  644. {
  645.     int negative ;
  646.  
  647.     negative = 0 ;
  648.     if (*p < 0) {
  649.         negative = 1 ;
  650.         *p = - *p ;
  651.     }
  652.     *p = 1000 * (*p / mag) + (2000 * (*p % mag) + mag) / (2 * mag);
  653.     if (negative){
  654.         *p = - *p ;
  655.     }
  656. }
  657.  
  658.  
  659. /*
  660.  *   Convert a sequence of digits into an integer; return -1 if no digits.
  661.  *   Advance the passed pointer as well.
  662.  */
  663.  
  664. integer myatol(s)
  665. char **s ;
  666. {
  667.    register char *p ;
  668.    register integer result ;
  669.  
  670.     result = 0 ;
  671.     p = *s ;
  672.     while ('0' <= *p && *p <= '9') {
  673.         if (result > 100000000){
  674.             error("! arithmetic overflow in parameter");
  675.         }
  676.         result = 10 * result + *p++ - '0' ;
  677.     }
  678.     if (p == *s){
  679.         usage();
  680.     }
  681.     else {
  682.         *s = p ;
  683.         return(result);
  684.     }
  685. }
  686.  
  687.  
  688. /*
  689.  *   Get a dimension, allowing all the various extensions, and
  690.  *   defaults.
  691.  */
  692.  
  693. integer myatodim(s)
  694. char **s ;
  695. {
  696.     register integer w, num, den ;
  697.     register char *p ;
  698.     int negative = 0 ;
  699.  
  700.     p = *s ;
  701.     if (**s == '-') {
  702.         (*s)++ ;
  703.         negative = 1 ;
  704.     }
  705.     w = myatol(s);
  706.     if (w < 0){
  707.         usage();
  708.     }
  709.     p = *s ;
  710.     num = 0 ;
  711.     den = 1 ;
  712.     if (*p == '.') {
  713.         p++ ;
  714.         while ('0' <= *p && *p <= '9') {
  715.             if (den < 1000) {
  716.                 den *= 10 ;
  717.                 num = num * 10 + *p - '0' ;
  718.             }
  719.             p++ ;
  720.         }
  721.     }
  722. /*
  723.  *   Allowed units are `in', `cm', `mm', `pt', `sp', `cc', `dd', and `pc';
  724.  *   must be in lower case.
  725.  */
  726.     if (*p == 'c' && p[1] == 'm') {
  727. /*  centimeters need to be multiplied by 72.27 * 2^16 / 2.54, or 1 864 680 */
  728.         w = scale(w, num, den, 1864680L);
  729.     } else if (*p == 'p' && p[1] == 't') {
  730. /*  real points need to be multiplied by 2^16 */
  731.         w = scale(w, num, den, 65536L);
  732.     } else if (*p == 'p' && p[1] == 'c') {
  733. /*  picas need to be multiplied by 65536 * 12, or 786 432 */
  734.         w = scale(w, num, den, 786432L);
  735.     } else if (*p == 'm' && p[1] == 'm') {
  736. /*  millimeters need to be multiplied by 72.27 * 2^16 / 25.4, or 186 468 */
  737.         w = scale(w, num, den, 186468L);
  738.     } else if (*p == 's' && p[1] == 'p') {
  739. /*  scaled points are already taken care of; simply round */
  740.         w = scale(w, num, den, 1L);
  741.     } else if (*p == 'b' && p[1] == 'p') {
  742. /*  big points need to be multiplied by 72.27 * 65536 / 72, or 65782 */
  743.         w = scale(w, num, den, 65782L);
  744.     } else if (*p == 'd' && p[1] == 'd') {
  745. /*  didot points need to be multiplied by 65536 * 1238 / 1157, or 70124 */
  746.         w = scale(w, num, den, 70124L);
  747.     } else if (*p == 'c' && p[1] == 'c') {
  748. /*  cicero need to be multiplied by 65536 * 1238 / 1157 * 12, or 841 489 */
  749.         w = scale(w, num, den, 841489L);
  750.     } else if (*p == 'i' && p[1] == 'n') {
  751. /*  inches need to be multiplied by 72.27 * 65536, or 4 736 286 */
  752.         w = scale(w, num, den, 4736286L);
  753.     } else {
  754. /*  use default values */
  755.         w = scale(w, num, den, 0L);
  756.         p -= 2 ;
  757.     }
  758.     p += 2 ;
  759.     *s = p ;
  760.     return(negative?-w:w);
  761. }
  762.  
  763.  
  764. /*
  765.  * This function determine if the page has to be printed
  766.  * depending on the values of options -f, -l, -i and -x
  767.  */
  768.  
  769. short selectedpage (n)
  770. integer n;
  771. {
  772. short i;
  773.  
  774.     if ( firstpage > n || n > lastpage ){
  775.         fprintf(stderr,"refused page %d, firstpage=%d, lastpage=%d\n",n,firstpage,lastpage);
  776.         return(0);
  777.     }
  778.     for ( i=0 ; i < excludeseq ; i++ ){
  779.         if ( exclude[i][0] <= n && n <= exclude[i][1] ){
  780.             return(0);
  781.         }
  782.     }
  783.     if (includeseq == 0) return (1);
  784.     for ( i=0 ; i < includeseq ; i++ ){
  785.         if ( include[i][0] <= n && n <= include[i][1] ){
  786.             return(1);
  787.         }
  788.     }
  789.     return(0);
  790. }
  791.  
  792.  
  793. /*
  794.  *   Initialize sets up all the globals and data structures.
  795.  */
  796.  
  797. void
  798. initialize()
  799. {
  800.     int i;
  801. /* initialize values in case of option -m is not specified */
  802.     modulo = 1 ;
  803.     pages[0].hoffset = 0 ;
  804.     pages[0].voffset = 0 ;
  805.     pages[0].pageno = 0 ;
  806.     pages[0].reversed = 0 ;
  807.     pagesperpage = 1 ;
  808.     for ( i= 0; i< 40; i++) {
  809.         exctransf[i][0] = exctransf[i][1] = 0;
  810.         inctransf[i][0] = inctransf[i][1] = 0;
  811.     }
  812.     firsttransf = lasttransf = 0;
  813.  
  814.     excludeseq = 0;
  815.     includeseq = 0;
  816.     firstpage = 1;
  817.     lastpage = 1000000;
  818.     maxpages = 1000000;
  819.     quiet = 0;
  820.  
  821.     strings =(char *) malloc(STRINGSIZE);
  822.     if (strings == 0){
  823.         error("! no memory for strings");
  824.     }
  825.  
  826.     maxpages = 100000 ;
  827.     nextstring = strings ;
  828.     iname = strings ;
  829.     *nextstring++ = 0 ;
  830.     maxstring = strings + STRINGSIZE - 200;
  831. }
  832.  
  833.  
  834. /* Changed 19.01.1994 thb
  835.  *
  836.  * Nobody ever cared what happened to the memory that was allocated
  837.  * earlier on. I'm calling this prior to exit to free up the memory
  838.  * again. Calls to this are found at the end of main() as well as just
  839.  * prior to the exit()s in usage() and error().
  840.  */
  841.  
  842. void
  843. cleanup()
  844. {
  845.     if( pageloc ) free( pageloc );
  846.     if( strings ) free( strings );
  847. }
  848.  
  849.  
  850. /*
  851.  *   Parse the arguments to the routine, and stuff everything away
  852.  *   into those globals above.
  853.  */
  854.  
  855. void
  856. processargs(argc, argv)
  857. int argc ;
  858. char *argv[] ;
  859. {
  860.     char *q ;
  861.     int i, pageno, lastext = -1 ;
  862.     long hoffset, voffset ;
  863.     int reversed ;
  864.  
  865.     initialize ();
  866.     if (argc < 2 || argc > 14){
  867.         usage();
  868.     }
  869.  
  870. /*
  871.  *   This next whole big section of code is straightforward; we just scan
  872.  *   the options.  An argument can either immediately follow its option letter
  873.  *   or be separated by spaces.  Any argument not preceded by '-' and an
  874.  *   option letter is considered a file name.
  875.  */
  876.     for (i=1; i<argc; i++) {
  877.         if (*argv[i]=='-') {
  878.             char *p=argv[i]+2 ;
  879.             char c=argv[i][1] ;
  880.             switch (c) {
  881.  
  882.                 case 'f' :
  883.                     if (*p == 0 && argv[i+1]){
  884.                         p = argv[++i] ;
  885.                     }
  886.                     if (*p == '(' && *(p+1) == '@' ) {
  887.                        p+=2; firsttransf = myatol(&p); p++;
  888.                     }
  889.                     else if (*p == '@') {
  890.                         p++; firsttransf = 1 ;
  891.                     }
  892. #ifdef SHORTINT
  893.                     if(sscanf(p, "%d", &firstpage)==0)
  894. #else    /* ~SHORTINT */
  895.                     if(sscanf(p, "%ld", &firstpage)==0)
  896. #endif    /* ~SHORTINT */
  897.                         error("! Bad first page option (-f).");
  898.                     break ;
  899.  
  900.                 case 'i' :
  901.                     if (*p == 0 && argv[i+1]){
  902.                         p = argv[++i] ;
  903.                     }
  904.                     while (*p != 0) {
  905.                         if (*p == '(' && *(p+1) == '@' ) {
  906.                             p+=2; inctransf[includeseq][0] = myatol(&p); p++;
  907.                         }
  908.                         else if (*p == '@') {
  909.                             p++; inctransf[includeseq][0] = 1 ;
  910.                         }
  911.                         include[includeseq][0]=myatol(&p);
  912.                         if (*p == '.' && *(p+1) == '.' ) {
  913.                             p += 2;
  914.                             if (*p == '(' && *(p+1) == '@' ) {
  915.                                 p+=2; inctransf[includeseq][1] = myatol(&p); p++;
  916.                             }
  917.                             else if (*p == '@') {
  918.                                 p++; inctransf[includeseq][1] = 1 ;
  919.                             }
  920.                             include[includeseq][1] = myatol(&p);
  921.                         } else {
  922.                             include[includeseq][1] = include[includeseq][0];
  923.                             inctransf[includeseq][0] = inctransf[includeseq][1] ;
  924.                         }
  925.                         includeseq++ ;
  926.                         if (*p != ',' && *p !=0 ){
  927.                             error("! Bad page range option (-i).");
  928.                         }
  929.                         if (*p == ',' ){
  930.                             p++ ;
  931.                         }
  932.                     } /* while */
  933.                     break ;
  934.  
  935.                 case 'l':
  936.                     if (*p == 0 && argv[i+1]){
  937.                         p = argv[++i];
  938.                     }
  939.                     if (*p == '(' && *(p+1) == '@' ) {
  940.                         p+=2; lasttransf = myatol(&p); p++;
  941.                     }
  942.                     else if (*p == '@') {
  943.                         p++; lasttransf = 1 ;
  944.                     }
  945. #ifdef SHORTINT
  946.                     if(sscanf(p, "%ld", &lastpage)==0)
  947. #else    /* ~SHORTINT */
  948.                     if(sscanf(p, "%d", &lastpage)==0)
  949. #endif    /* ~SHORTINT */
  950.                         error("! Bad last page option (-l).");
  951.                     break ;
  952.  
  953.                 case 'm' :
  954.                     if (*p == 0 && argv[i+1]){
  955.                         p = argv[++i] ;
  956.                     }
  957. /*
  958.  *   Is there a modulo supplied?  Grab it if so; otherwise default to 1.
  959.  */
  960.                     for (q=p; *q != 0; q++)
  961.                         if (*q == ':')
  962.                             break ;
  963.                     if (*q == ':') {
  964.                         modulo = myatol(&p);
  965.                         if (*p != ':'){
  966.                             usage();
  967.                         }
  968.                         if (modulo < 1 || modulo > MAXPPERP){
  969.                             error("! modulo must lie between 1 and 32");
  970.                         }
  971.                         p++ ;
  972.                     }
  973. /*
  974.  *   This loop grabs all of the page specifications.
  975.  */
  976.                     pagesperpage = 0 ;
  977.                     while (*p != 0) {
  978.                         if (pagesperpage >= MAXPPERP){
  979.                            error("! too many page specifications");
  980.                         }
  981.                         if (*p == '-') {
  982.                             reversed = 1 ;
  983.                             p++ ;
  984.                         } else {
  985.                             reversed = 0 ;
  986.                         }
  987.                         if (*p == 0 || *p == '(' || *p == ','){
  988.                             pageno = 0 ;
  989.                         } else {
  990.                             pageno = myatol(&p);
  991.                         }
  992.                         if (*p == '(') {
  993.                             p++ ;
  994.                             hoffset = myatodim(&p);
  995.                             if (*p++ != ','){
  996.                                 usage();
  997.                             }
  998.                             voffset = myatodim(&p);
  999.                             if (*p++ != ')'){
  1000.                                 usage();
  1001.                             }
  1002.                         } else {
  1003.                             hoffset = 0 ;
  1004.                             voffset = 0 ;
  1005.                         }
  1006.                         pages[pagesperpage].hoffset = hoffset ;
  1007.                         pages[pagesperpage].voffset = voffset ;
  1008.                         pages[pagesperpage].pageno = pageno ;
  1009.                         pages[pagesperpage].reversed = reversed ;
  1010.                         pagesperpage++ ;
  1011.                         if (*p == ','){
  1012.                             p++ ;
  1013.                         }
  1014.                     } /* while */
  1015.                     break ;
  1016.  
  1017.                 case 'n' :
  1018.                     if (*p == 0 && argv[i+1]){
  1019.                         p = argv[++i] ;
  1020.                     }
  1021. #ifdef SHORTINT
  1022.                     if (sscanf(p, "%ld", &maxpages)==0)
  1023. #else    /* ~SHORTINT */
  1024.                     if (sscanf(p, "%d", &maxpages)==0)
  1025. #endif    /* ~SHORTINT */
  1026.                         error("! Bad number of pages option (-n).");
  1027.                     break ;
  1028.  
  1029.                 case 'q' : case 'Q' :
  1030.                     quiet = 0 ;
  1031.                     break ;
  1032.  
  1033.                 case 'r' : case 'R' :
  1034.                     pages[0].reversed = 1;
  1035.                     break ;
  1036.  
  1037. /*  Added 28.07.1993,    Jochen Wiedmann     */
  1038.                 case 's' : case 'S' :
  1039.                     c = *p;
  1040.                     if (*(++p) == 0  &&  argv[i+1]){ 
  1041.                         p = argv[++i];
  1042.                     }
  1043.                     switch(c){ 
  1044.                         case 'm' : case 'M' :
  1045.                             if (*p == 0){
  1046.                                 error("Option -sm: Missing parameter?");
  1047.                             }
  1048.                             scale_magstep = atof(p);
  1049.                             break;
  1050.  
  1051.                         case 'w' : case 'W' :
  1052.                             if (*p == 0){
  1053.                                 error("Option -sw: Missing parameter?");
  1054.                             }
  1055.                             scale_width = atof(p);
  1056.                             break;
  1057.  
  1058.                         case 'h' : case 'H' :
  1059.                             if (*p == 0){
  1060.                                 error("Option -sh: Missing parameter?");
  1061.                             }
  1062.                             scale_height = atof(p);
  1063.                             break;
  1064.  
  1065.                         default :
  1066.                             error("Bad option: Not one of -sh, -sm, or -sw?");
  1067.                     }
  1068.                     break;
  1069. /*                        */
  1070.  
  1071.                 case 'x' :
  1072.                     if (*p == 0 && argv[i+1]){
  1073.                         p = argv[++i];
  1074.                     }
  1075.                     while (*p != 0) {
  1076.                         if (*p == '(' && *(p+1) == '@' ) {
  1077.                             p+=2; exctransf[excludeseq][0] = myatol(&p); p++;
  1078.                         }
  1079.                         else if (*p == '@') {
  1080.                             p++; exctransf[excludeseq][0] = 1 ;
  1081.                         }
  1082.                         exclude[excludeseq][0]=myatol(&p);
  1083.                         if (*p == '.' && *(p+1) == '.' ) {
  1084.                             p += 2;
  1085.                             if (*p == '(' && *(p+1) == '@' ) {
  1086.                                 p+=2; exctransf[excludeseq][1] = myatol(&p); p++;
  1087.                             }
  1088.                             else if (*p == '@') {
  1089.                                 p++; exctransf[excludeseq][1] = 1 ;
  1090.                             }
  1091.                             exclude[excludeseq][1] = myatol(&p);
  1092.                         } else {
  1093.                             exclude[excludeseq][1] = exclude[excludeseq][0];
  1094.                             exctransf[excludeseq][0] = exctransf[excludeseq][1] ;
  1095.                         }
  1096.                         excludeseq++ ;
  1097.                         if (*p != ',' && *p !=0 ){
  1098.                             error("! Bad page range option (-x).");
  1099.                         }
  1100.                         if (*p == ',' ){
  1101.                             p++ ;
  1102.                         }
  1103.                     } /* while */
  1104.                     break ;
  1105.  
  1106.                 case '?' :
  1107.                     usage();
  1108.                     break ;
  1109.  
  1110.                 default:
  1111.                     error("! Bad option, not one of filmnqrsx?");
  1112.             }  /* switch c */
  1113.         } else {    /* this a file name */
  1114.             if (*iname == 0) { /* input file name */
  1115.                 register char *p ;
  1116.  
  1117.                 lastext = 0 ;
  1118.                 iname = nextstring ;
  1119.                  p = argv[i];
  1120.                 while (*p) {
  1121.                     *nextstring = *p++ ;
  1122.                     if (*nextstring == '.'){
  1123.                         lastext = nextstring - iname ;
  1124.                     }
  1125.                     else if (*nextstring == '/' || *nextstring == ':'){
  1126.                         lastext = 0 ;
  1127.                     }
  1128.                     nextstring++ ;
  1129.                 }
  1130.                 if (lastext == 0) {
  1131.                     lastext = nextstring - iname ;
  1132.                     *nextstring++ = '.' ;
  1133.                     *nextstring++ = 'd' ;
  1134.                     *nextstring++ = 'v' ;
  1135.                     *nextstring++ = 'i' ;
  1136.                 }
  1137.                 *nextstring++ = 0 ;
  1138.                 if ((infile=fopen(iname, READBIN))==NULL){
  1139.                     error("! can't open input file");
  1140.                 }
  1141.              } else { /* output file name */
  1142.                 register char *p ;
  1143.  
  1144.                 lastext = 0 ;
  1145.                 oname = nextstring ;
  1146.                 p = argv[i] ;
  1147.                 while (*p) {
  1148.                     *nextstring = *p++ ;
  1149.                     if (*nextstring == '.'){
  1150.                         lastext = nextstring - oname ;
  1151.                     }
  1152.                     else if (*nextstring == '/' || *nextstring == ':'){
  1153.                         lastext = 0 ;
  1154.                     }
  1155.                     nextstring++ ;
  1156.                 }
  1157.                 if (lastext == 0) {
  1158.                     lastext = nextstring - oname ;
  1159.                     *nextstring++ = '.' ;
  1160.                     *nextstring++ = 'd' ;
  1161.                     *nextstring++ = 'v' ;
  1162.                     *nextstring++ = 'i' ;
  1163.                 }
  1164.                 *nextstring++ = 0 ;
  1165.                 if (freopen(oname, WRITEBIN, stdout)==NULL){
  1166.                     error("! can't open output file");
  1167.                 }
  1168.             }  /* end output file name */
  1169.         } /* else argument with '-' */
  1170.     }  /* for */
  1171.  
  1172. /* Changed 19.01.1994 thb
  1173.  *
  1174.  * Arguments have been parsed, and input and output files should have
  1175.  * been opened by now. While this worked fine if you stuck to specifying
  1176.  * two filenames, I had trouble when only specifying one. Obviously the
  1177.  * *oname reference is a 0 pointer deref when oname is not given. I
  1178.  * guess the intended behaviour was that DVIDVI would output to stdout
  1179.  * if no file was specified, so I have changed the code to work just
  1180.  * like this.
  1181.  */
  1182.  
  1183. #if 0
  1184.     if (*iname == 0) {
  1185.         (void)fprintf(stderr, banner);
  1186.         error("! no input file specified");
  1187.     }
  1188.     if ( *oname != 0 && !quiet) {
  1189.         (void)fprintf(stderr, banner);
  1190.         (void)fprintf(stderr, "%s -> %s\n",iname,oname);
  1191.         temp = nextstring ;
  1192.     }
  1193. #else
  1194.     (void)fprintf(stderr, banner);
  1195.     if (*iname == 0) {
  1196.         error("! no input file specified");
  1197.     }
  1198.     if ( oname != 0 && !quiet) {
  1199.         (void)fprintf(stderr, "%s -> %s\n",iname,oname);
  1200.     } else {
  1201.         (void)fprintf(stderr, "%s -> stdout\n",iname);
  1202.     }
  1203.     temp = nextstring;
  1204. #endif
  1205.  
  1206. }
  1207.  
  1208.  
  1209. /*
  1210.  *   Grabs a pointer, and checks it for validity.
  1211.  */
  1212.  
  1213. integer ptr(where)
  1214. register integer where ;
  1215. {
  1216.     fseek(infile,where,SEEK_SET);
  1217.     where = signedquad();
  1218.     if (where < -1L || where > inlength){
  1219.         error("! dvi file malformed; impossible pointer");
  1220.     }
  1221.     return(where);
  1222. }
  1223.  
  1224.  
  1225. /*
  1226.  *   This routine store the page locations by tracing the pointers backwards.
  1227.  */
  1228.  
  1229. void searchpageloc()
  1230. {
  1231.     integer p,num ;
  1232.  
  1233.     num=pagecount-1;
  1234.     for (p = ptr(postloc+1); num > 0; num--) {
  1235.         if (dvibuf(p) != 139){
  1236.             error("! missed a bop somehow");
  1237.         }
  1238.         else {
  1239.             pageloc[num]=p;
  1240.             pagenumbers[num]=signedquad();
  1241.         }
  1242.         p = ptr(p+41);
  1243.     }
  1244.     pageloc[num]=p;
  1245.     (void)dvibuf(p);
  1246.     pagenumbers[num]=signedquad();
  1247. }
  1248.  
  1249.  
  1250. /*
  1251.  *   This routine simply reads the entire dvi file, and then initializes
  1252.  *   some values about it.
  1253.  */
  1254.  
  1255. void
  1256. readdvifile() 
  1257. {
  1258.     integer p ; 
  1259.     unsigned char c,d,e ;
  1260.  
  1261.     fseek(infile, 0L, 2);
  1262.     inlength = ftell(infile);
  1263.     if (inlength < 10){
  1264.         error("! dvi file too short");
  1265.     }
  1266.     fseek(infile,-3L,SEEK_CUR);
  1267.     for (p=inlength - 3; p > 0; p--) {
  1268.         c = dvibyte (); d = dvibyte (); e = dvibyte ();
  1269.         if (c == 2 && d == 0xdf /* dave fuchs */ && e == 0xdf){
  1270.             break ;
  1271.         }
  1272.         fseek(infile,-4L,SEEK_CUR);
  1273.     }
  1274.     if (p < 10){
  1275.         error("! rather short dvi file, ain't it?");
  1276.     }
  1277.     postloc = ptr(p-4);
  1278.     fseek(infile,postloc+5L,SEEK_SET);
  1279.     if (signedquad() != 25400000 || signedquad() != 473628672){
  1280.         error("! change this program to support non-TeX num/den values");
  1281.     }
  1282.     mag = signedquad();
  1283.     if (mag < 1 || mag > 1000000){
  1284.         error("! impossible magnification value");
  1285.     }
  1286.     fseek(infile,postloc+27L,SEEK_SET);
  1287.     pagecount = twobytes();
  1288.  
  1289.     if (pagecount < 1 || pagecount > 1000000){
  1290.         error("! impossible page count value");
  1291.     }
  1292. /*
  1293.  *   That's enough error checking; we probably have a correct dvi file.
  1294.  *   Let's convert all the values we got from the command line into
  1295.  *   units that we can actually use in the dvi file.
  1296.  */
  1297.     for (p=0; p<pagesperpage; p++) {
  1298.         scalemag(&(pages[p].hoffset));
  1299.         scalemag(&(pages[p].voffset));
  1300.     }
  1301. /*
  1302.  *   Now let's grab us some font pointers.
  1303.  */
  1304.     pageloc = (integer *) calloc (pagecount, sizeof (integer));
  1305.     if (pageloc == NULL){
  1306.         error("!  Not enough memory for allocation of page pointers");
  1307.     }
  1308.     pagenumbers = (integer *) calloc (pagecount, sizeof (integer));
  1309.     if (pagenumbers == NULL){
  1310.         error("! Not enough memory for allocation of page numbers array");
  1311.     }
  1312.     searchpageloc();
  1313.     transformpages();
  1314.     free(pagenumbers);
  1315.     p = postloc + 29 ;
  1316.     while (1) {
  1317.         c=dvibuf(p);
  1318.         if (c == 249){
  1319.             break ;
  1320.         }
  1321.         if (c == 138){
  1322.              p++ ;
  1323.         }
  1324.         else if (c == 243) {
  1325.             TeXfonts[dvibyte()] = p ;
  1326.              p += fontdeflen(p);
  1327.         } else {
  1328.             error("! only nop's and font def's allowed in postamble");
  1329.         }
  1330.     }
  1331. /*
  1332.  *   Now we check for a landscape special.  It should be the
  1333.  *   *first* thing in the page that is at all complicated.
  1334.  */
  1335.  
  1336.     p = pageloc[0L] + 45 ;
  1337.     c=dvibuf(p);
  1338.     while (comlen[c]) {
  1339.         p += comlen[c] ;
  1340.         c = dvibuf(p);
  1341.     }
  1342.     if (c == 239) {
  1343.         stringdvibuf(p+2L,9L);
  1344.         if (strncmp(temp, "landscape", 9)==0) {
  1345.             landscape = p ;
  1346.             rem0special = 1 ;
  1347.         }
  1348.     }
  1349. }
  1350.  
  1351.  
  1352. /*
  1353.  *   Output a single byte, keeping track of where we are.
  1354.  */
  1355.  
  1356. void
  1357. outdvibyte(c)
  1358. unsigned char c;
  1359. {
  1360.     fputc(c, stdout);
  1361.     dviloc++;
  1362. }
  1363.  
  1364.  
  1365. /*
  1366.  *   Send out two bytes.
  1367.  */
  1368.  
  1369. void
  1370. outdvi2(v)
  1371. integer v ;
  1372. {
  1373.     outdvibyte((unsigned char)(v >> 8));
  1374.     outdvibyte((unsigned char)(v & 255));
  1375. }
  1376.  
  1377.  
  1378. /*
  1379.  *   Send out a longword.
  1380.  */
  1381.  
  1382. void 
  1383. outdviquad(v)
  1384. integer v ;
  1385. {
  1386.     outdvi2(v >> 16);
  1387.     outdvi2(v & 65535);
  1388. }
  1389.  
  1390.  
  1391. /*
  1392.  *   This routine just copies some stuff from the buffer on out.
  1393.  *   Suppose the file is positioned correctly before
  1394.  */
  1395.  
  1396. void
  1397. putbuf(length)
  1398. integer length ;
  1399. {
  1400.     while ( length-- > 0 ){
  1401.         outdvibyte(dvibyte());
  1402.     }
  1403. }
  1404.  
  1405.  
  1406. /*
  1407.  *   This routine outputs a string, terminated by null.
  1408.  */
  1409.  
  1410. void
  1411. putstr(s)
  1412. register unsigned char *s ;
  1413. {
  1414.     while (*s){
  1415.         outdvibyte(*s++);
  1416.     }
  1417. }
  1418.  
  1419.  
  1420. /*
  1421.  *   Here we write the preamble to the dvi file.
  1422.  */
  1423.  
  1424. void
  1425. writepreamble() 
  1426. {
  1427.     longword mag;
  1428.  
  1429. /*   just copy the first 14 bytes of the file */
  1430.     fseek(infile,0L,SEEK_SET);
  1431.  
  1432. /*  Modified and added 28.07.1993,  Jochen Wiedmann    */
  1433. /*  Was: putbuf(14L);                                  */
  1434.     putbuf(10L); /*  Don't change DVI format, NUMerator and DENominator  */
  1435.     mag = fourbytes() *                  /*  Scale the magnification     */
  1436.     pow((double)1.2,scale_magstep);
  1437.     outdviquad(mag);
  1438. /*                            */
  1439.  
  1440. /*   and put our identifier. */
  1441.     putstr("\015dvidvi output");
  1442. }
  1443.  
  1444.  
  1445. /*
  1446.  *   This routine writes out a font definition.
  1447.  */
  1448.  
  1449. void 
  1450. putfontdef(f)
  1451. int f ;
  1452. {
  1453.     integer p,q ;
  1454.  
  1455.     p = TeXfonts[f] ;
  1456.     q=fontdeflen(p);
  1457.     fseek(infile,p,SEEK_SET);
  1458.     putbuf(q);
  1459. }
  1460.  
  1461.  
  1462. /*
  1463.  *   The postamble is next.
  1464.  */
  1465.  
  1466. void
  1467. writepostamble() 
  1468. {
  1469.     int i ;
  1470.     integer p ;
  1471.     longword mag, height, width;
  1472.  
  1473.     p = dviloc ;
  1474.     outdvibyte(248);
  1475.     outdviquad(prevpp);
  1476.     fseek(infile,postloc+5,SEEK_SET);
  1477.  
  1478.  
  1479. /*  Modified and added    28.07.1993,    Jochen Wiedmann     */
  1480. /*  was: putbuf(20L);                                        */
  1481.     putbuf(8L);  /*  Don't change NUMerator and DENominator  */
  1482.  
  1483.     mag = fourbytes() * pow(1.2,scale_magstep);  /*  Scale magnification */
  1484.     outdviquad(mag);
  1485.     height = fourbytes() * pow(1.2,scale_height);/*  Scale height        */
  1486.     outdviquad(height);
  1487.     width = fourbytes() * pow(1.2,scale_width);  /*  Scale width         */
  1488.     outdviquad(width);
  1489. /*                                */
  1490.  
  1491.  
  1492.     outdvi2(twobytes()+1L); /* increase stack depth by 1 */
  1493.     outdvi2(outputpages);
  1494.     for (i=0; i<256; i++){
  1495.         if (fontseen[i]){
  1496.             putfontdef(i);
  1497.         }
  1498.     }
  1499.     outdvibyte(249);
  1500.     outdviquad(p);
  1501.     outdvibyte(2);
  1502.     outdviquad(0xdfdfdfdfL);
  1503.     while (dviloc & 3){
  1504.         outdvibyte(0xdf);
  1505.     }
  1506.     fclose(stdout);
  1507. }
  1508.  
  1509.  
  1510. /*
  1511.  *   This routine starts a page, by writing out a bop command.
  1512.  */
  1513.  
  1514. void
  1515. beginpage() 
  1516. {
  1517.     int i ;
  1518.     integer p ;
  1519.  
  1520.     p = dviloc ;
  1521.     outdvibyte(139);
  1522.     outdviquad(outputpages+1);
  1523.     for (i=0; i<9; i++){
  1524.         outdviquad(0L);
  1525.     }
  1526.     outdviquad(prevpp);
  1527.     prevpp = p ;
  1528. }
  1529.  
  1530.  
  1531. /*
  1532.  *   This routine sends out a page.  We need to handle the
  1533.  *   landscape special, though.
  1534.  */
  1535.  
  1536. void 
  1537. dopage(num)
  1538. integer num ;
  1539. {
  1540.     register integer p ;
  1541.     register int len ;
  1542.     integer v, oldp ;
  1543.     unsigned char c;
  1544.  
  1545. /*
  1546.  *   We want to take the base 10 log of the number.  It's probably
  1547.  *   small, so we do it quick.
  1548.  */
  1549.     if (! quiet) {
  1550.         int t = num+1, i = 0 ;
  1551.         if (t < 0) {
  1552.             t = -t ;
  1553.             i++ ;
  1554.         }
  1555.         do {
  1556.             i++ ;
  1557.             t /= 10 ;
  1558.         } while (t > 0);
  1559.         if (i + prettycolumn > 76) {
  1560.             fprintf(stderr, "\n");
  1561.             prettycolumn = 0 ;
  1562.         }
  1563.         prettycolumn += i + 1 ;
  1564. #ifdef SHORTINT
  1565.         (void)fprintf(stderr, "[%ld", num+1);
  1566. #else  /* ~SHORTINT */
  1567.         (void)fprintf(stderr, "[%d", num+1);
  1568. #endif /* ~SHORTINT */
  1569.         (void)fflush(stderr);
  1570.     }
  1571.     p = pageloc[num] + 45 ;
  1572.     c=dvibuf(p);
  1573.     while (c != 140) {
  1574.         if ((len=comlen[c]) > 0) {    /* most commands are simple */
  1575.             outdvibyte(c);
  1576.             putbuf((long)len-1);
  1577.             p += len ;
  1578.         } else {     /* but there are a few we need to treat specially */
  1579.             len = c ;
  1580.             if (171 <= len && len <= 235) {
  1581.                 p++ ;
  1582.                 if (len == 235){ 
  1583.                     len = dvibyte(); 
  1584.                     p++ ;
  1585.                 } else {
  1586.                    len -= 171;
  1587.                 }
  1588.                 if (!fontseen[len]) {
  1589.                     putfontdef(len);
  1590.                     fontseen[len] = 1 ;
  1591.                     fseek(infile,p,SEEK_SET);
  1592.                 }
  1593.                 if (len < 64){
  1594.                     outdvibyte(171 + len);
  1595.                 }
  1596.                 else {
  1597.                     outdvibyte(235);
  1598.                     outdvibyte(len);
  1599.                 }
  1600.             } else {
  1601.                 v = 0 ;
  1602.                 oldp = p++ ;
  1603.                 switch(len) {
  1604.  
  1605.                     case 242:      v = dvibyte(); p++ ;  break ;
  1606.                     case 241:      v = (v << 8) + dvibyte(); p++ ; break ;
  1607.                     case 240:      v = (v << 8) + dvibyte(); p++ ; break ;
  1608.                     case 239:      v = (v << 8) + dvibyte(); p++ ;
  1609. /*
  1610.  *   Remove a landscape special on page 0, if one is found.
  1611.  */    
  1612.  
  1613. /*   Changed 19.01.1994 thb
  1614.  * 
  1615.  *   Additional comment as I figure things are assumed to be:
  1616.  *   oldp points to the position in the file where code len may
  1617.  *   be found. v should be the length of the command, right?
  1618.  */
  1619.  
  1620. #if 0
  1621.                     stringdvibuf(oldp + len - 327,9);
  1622. #endif
  1623.  
  1624. /* Changed 19.01.1994 thb
  1625.  *
  1626.  * The line above is commented out because it looks suspiciously like a typo.
  1627.  * If 237 instead of 327 was assumed to be right, it would make sense as
  1628.  * this would copy the string landscape to the buffer if it was there.
  1629.  * So I think it should read as:
  1630.  */
  1631.  
  1632.                     stringdvibuf(oldp + len - 237,9);
  1633.  
  1634. /* Changed 19.01.1994 thb
  1635.  *
  1636.  * num is the page number we're on. rem0special is set to 1 if the landscape
  1637.  * special is found during reading. And the strncmp will return 0 if there
  1638.  * is the landscape string in the buffer. Hmmm. If a landscape special was
  1639.  * on page 0, we would skip it.
  1640.  */
  1641.  
  1642.                     if (num || ! rem0special || strncmp(temp, "landscape", 9)) {
  1643.                         fseek (infile,oldp,SEEK_SET);
  1644.                         putbuf(v + len - 237);
  1645.                     }
  1646.  
  1647.                     p = oldp + v + len - 237 ;
  1648.                     fseek(infile,p,SEEK_SET);
  1649.                     break ;
  1650.  
  1651.                 case 243: case 244: case 245: case 246:
  1652.                     p += len - 230 ;
  1653.                     p += dvibuf(p);
  1654.                     p += dvibyte() + 2 ;
  1655.                     fseek(infile,p,SEEK_SET);
  1656.                     break ;
  1657.                 default:       
  1658.                     fprintf(stderr, "Bad dvi command was %d at %ld\n", len, p);
  1659.                     error("! lost sync dvi in file lost dvi sync file in");
  1660.                 }
  1661.             }
  1662.         }
  1663.         c=dvibyte();
  1664.     }
  1665.     if (! quiet) {
  1666.         (void)fprintf(stderr, "] ");
  1667.         (void)fflush(stderr);
  1668.         prettycolumn += 2 ;
  1669.     }
  1670. }
  1671.  
  1672.  
  1673. /*
  1674.  *   Here we end a page.  Simple enough.
  1675.  */
  1676.  
  1677. void 
  1678. endpage() 
  1679. {
  1680.    outputpages++ ;
  1681.    outdvibyte(140);
  1682. }
  1683.  
  1684.  
  1685. /*
  1686.  *   This is our main routine for output, which runs through all the
  1687.  *   pages we need to output.
  1688.  */
  1689.  
  1690. void
  1691. writedvifile() 
  1692. {
  1693.     integer pagenum ;
  1694.     int ppp ;
  1695.     integer actualpageno ;
  1696.     struct pagespec *ps ;
  1697.     Boolean beginp ;
  1698.  
  1699. /* Changed 19.01.1994 thb
  1700.  *
  1701.  * Need this one later on to store the length of the special command.
  1702.  */
  1703.  
  1704.     unsigned char landscapelen;
  1705.  
  1706.  
  1707.     writepreamble();
  1708.     pagefake = (pagecount + modulo - 1) / modulo * modulo ;
  1709.     if ( maxpages < pagefake ) pagefake = maxpages;
  1710.     for (pagenum = 0; pagenum < pagefake; pagenum += modulo) {
  1711.         beginp = 1 ;
  1712.         for (ppp = 0, ps=pages; ppp < pagesperpage; ppp++, ps++) {
  1713.             if (ps->reversed){
  1714.                 actualpageno = pagefake - pagenum - modulo + ps->pageno ;
  1715.             } else {
  1716.                 actualpageno = pagenum + ps->pageno ;
  1717.             }
  1718.  
  1719.             if (actualpageno < pagecount && selectedpage(actualpageno+1) ) {
  1720.                 if (beginp) {
  1721.                     beginpage();
  1722.                     beginp = 0 ;
  1723.                 }
  1724.                 if (landscape) {
  1725.  
  1726. /*
  1727.  * Changed 19.01.1994 thb
  1728.  * 
  1729.  * This looks suspiciously like somebody tried to optimize the code to
  1730.  * run faster and/or to use less local data. However, (s)he did not take
  1731.  * into account that dvibuf() has the side effect of seeking and moving
  1732.  * along in the input stream. His version would copy the landscape
  1733.  * string plus two chars beyond it -> *boom* when you dvixx it.
  1734.  *
  1735.  * I am using an extra variable to obtain the length of the special
  1736.  * command in question. THEN I seek to the special code introducer
  1737.  * position and then I copy that introducer, the length, and the special.
  1738.  */ 
  1739.  
  1740. #if 0
  1741.                 fseek(infile,landscape,SEEK_SET);
  1742.                 putbuf(dvibuf(landscape+1)+2L);
  1743.                 landscape = 0 ;
  1744. #else
  1745.                 landscapelen = dvibuf(landscape+1);
  1746.                 fseek(infile,landscape,SEEK_SET);
  1747.                 putbuf( landscapelen + 2L );
  1748.                 landscape = 0;
  1749. #endif
  1750.                 }
  1751.                 if (pagesperpage)
  1752.                     outdvibyte(141);
  1753.                 if (ps->hoffset) {
  1754.                     outdvibyte(146);
  1755.                     outdviquad(ps->hoffset);
  1756.                 }
  1757.                 if (ps->voffset) {
  1758.                     outdvibyte(160);
  1759.                     outdviquad(ps->voffset);
  1760.                 }
  1761.                 dopage(actualpageno);
  1762.                 if (pagesperpage)
  1763.                     outdvibyte(142);
  1764.             }
  1765.         }
  1766.         if (beginp != 1) endpage();
  1767.    }
  1768.    writepostamble();
  1769. }
  1770.  
  1771.  
  1772. int
  1773. main(argc, argv)
  1774. int argc ;char *argv[] ;
  1775. {
  1776.     processargs(argc, argv);
  1777.     readdvifile();
  1778.     writedvifile();
  1779.  
  1780. /* Changed 19.01.1994 thb
  1781.  *
  1782.  * Inserted call to free allocated strings, a linefeed for cosmetical
  1783.  * reasons, and of course a proper return value.
  1784.  */
  1785.  
  1786.     cleanup();
  1787.     fprintf(stderr,"\n");
  1788.     return( 0 );
  1789. }
  1790.