From: Libor Skarvada <libor@adelard.dcs.muni.cs>
Newsgroups: comp.text.tex
Subject: Re: how many pages ?
Date: Wed, 18 Nov 92 18:17:41 CET
Organization: Info-Tex<==>Comp.Text.Tex Gateway
X-Gateway-Source-Info: Mailing List

Barbara Beeton in her recent post is looking for an easy way how to
determine the number of pages in a dvi file.  Here is a simple
program that does the task.  I tested it on two plattforms (under
SCO Unix System V with cc compiler and under MSDos with TurboC++).
I hope it should work elsewhere too.  (But I am not sure whether
my uses of strstr, fseek etc. are so much portable.)
I appreciate all remarks ... yes, but Nov 21 thru Dec 6 I'll be out.
--
%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%
%  Libor Skarvada              Department of Computer Science           %
%                              Masaryk University, Brno, Czechoslovakia %
%  libor@dcs.muni.cs           phone:  +42-5-757000 (x369)              %
%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%=%

 -------- save as  npdvi.c  and build as a single one-file program --------

#include <stdio.h>
#include <string.h>

#define Success  1
#define BadPars -1   /* bad # of cmd line args */
#define BadFile -2   /* nonexisting or ill-specified file */
#define CorFile -3   /* dvi file has a strange format */

#define CMD_post_post 249
#define CMD_fill      223

FILE *dvifile;
unsigned long int getbigend(FILE *f,int len);
unsigned int np(FILE *dvifile);

int main(int av,char **ac)
{ char filename[80];
  unsigned int npages;

  if (av != 2) { fprintf(stderr,"npdvi -- usage:\nnpdvi <dvi-file>\n");
                 return BadPars;
               }

  strcpy(filename,*++ac);
  dvifile = fopen(filename,"rb");
  if (dvifile == NULL)
    if (strstr(filename,".dvi") == NULL)
      { strcat(filename,".dvi");   /* try again with filename.dvi */
        dvifile = fopen(filename,"rb");
      }
  if (dvifile == NULL)
    { perror("npdvi -- dvi file open problem");
      return BadFile;
    }

  npages = np(dvifile);

  if (npages == 0) { fprintf(stderr,"npdvi -- dvi file corrupted\n");
                     return CorFile;
                   }

  printf("The file %s has %d pages\n",filename,npages);
  fclose(dvifile);
  return Success;
}

unsigned int np(FILE *dvifile)
/*  returns number of bop cmds in dvifile
 *  it is extracted from the postamble whose format is:
 *    post lastbop[4] num[4] den[4] mag[4] maxh[4] maxw[4] stack[2] np[2]
 *    <font definitions>
 *    post_post q[4] id[1] 223s[>3]
 *  where np is the total number of pages, q is pointer to post cmd
 */

{ unsigned b;
  long unsigned postamble;

  fseek(dvifile,-1,SEEK_END); /* last byte */
  do
    { b = getc(dvifile);
      fseek(dvifile,-2,SEEK_CUR);
    }
  while (b == CMD_fill);     /* the dvi file ends with a couple of 223's */
  fseek(dvifile,-4,SEEK_CUR);   /* now we are at post_post cmd */
  b = getc(dvifile);           /* and now just behind it */
  if (b == CMD_post_post)
    { postamble = getbigend(dvifile,4);        /* offset of post cmd */
      fseek(dvifile,postamble+27,SEEK_SET);    /* now at the desired np */
      return (int) getbigend(dvifile,2);
    }
    else return 0;
}

unsigned long int getbigend(FILE *f,int len)
/* reads len bytes from f and treats them as a number in BigEndian form */
{ unsigned long n;
  int i;
  for (i=0,n=0;i<len;i++)
    n = 256*n + (long) getc(f);
  return n;
}
 ------------------------  end of  npdvi.c  ------------------------