#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* LJ1710.ASC
   LJ1780.ASC */

#define TRUE 1
#define FALSE 0
#define MAXX 96
#define MAXY 128

#define NUMLEN 8
#define SEQLEN 10
#define PJLLEN 256

typedef int boolean;

int main(int argc, char *argv[]);

static char VERSION_STRING[]="HP_Count v2.0.25  02/10/1998";

//char t[MAXX][MAXY];
char divx,divy,pointsize=12,seq[SEQLEN+1],num[NUMLEN+1],dir=0;
char pjlstr[PJLLEN+1];
boolean landscape=FALSE,stringend=FALSE,copying=FALSE,inpcl=FALSE;
boolean display=FALSE,hpgl=FALSE;
int recx,recy,recdx,recdy,xsize=826,ysize=1170,res=600,numpoi=0,poi=0,pages=1;
long actualcount=0,copy=0,copynum=0;


/*void plusz(int x, int y, int dx, int dy, char dens)
{
  long l;

  l=((long)dens*dx*dy+divx*divy/2)/divx/divy;
  t[x][y]+=l;
}

void fillrect(int x1, int y1, int dx, int dy, char dens)
{
  char mode,x,y,xx,yy;
  int f;

  x=x1/divx;
  y=y1/divy;
  xx=(x1+dx-1)/divx;
  yy=(y1+dy-1)/divy;
  mode=(x == xx ? 0:1);
  mode|=(y == yy ? 0:2);
  switch (mode) {
    case 0: plusz(x,y,dx,dy,dens); break;
    case 1: {
      plusz(x,y,divx-x1%divx,dy,dens);
      plusz(xx,y,(x1+dx-1)%divx+1,dy,dens);
      for (f=x+1; f<xx; f++) plusz(f,y,divx,dy,dens);
    } break;
    case 2: {
      plusz(x,y,divx,divy-y1%divy,dens);
      plusz(x,yy,dx,(y1+dy-1)%divy+1,dens);
      for (f=y+1; f<yy; f++) plusz(x,f,dx,divy,dens);
    } break;
    case 3: {
      fillrect(x1,y1,dx,divy-y1%divy,dens);
      for (f=y+1; f<yy; f++) fillrect(x1,f*divy,dx,divy,dens);
      fillrect(x1,yy*divy,dx,(y1+dy-1)%divy+1,dens);
    } break;
  }
}

int survey(void)
{
  int f,g;
  long l;

  for (l=0, f=0; f<MAXX; f++)
    for (g=0; g<MAXY; g++) l+=t[f][g];
  return l/MAXX/MAXY;
}
*/


void divcalc(void)
{
  divx=(long)xsize*res/100/MAXX+1;
  divy=(long)ysize*res/100/MAXY+1;
}


void proc(char c)
{
  int f,g;
  char *p;

  if (copying) {
    copy++;
    if (copy>=copynum) copying=FALSE;
    return;
  }
  if (poi==0 && (c=='@' || *pjlstr!='\0') && !hpgl && c!=27) {
    f=strlen(pjlstr);
    pjlstr[f]=c;
    if (f<PJLLEN) f++;
    pjlstr[f]='\0';
    if (c=='\r' || c=='\n') {
      if ((p=strchr(pjlstr,'='))!=NULL) {
        for (; *(p-1)==' '; ) strcpy(p-1,p);
        for (; *(p+1)==' '; ) strcpy(p+1,p+2);
      }
      if (!strncmp(pjlstr,"@PJL ENTER LANGUAGE=",20)) {
        if (strncmp(pjlstr+20,"PCL",3)) {
          fprintf(stderr,"Invalid printer language!\r\n");
        }
        else inpcl=TRUE;
      }
      if (!strncmp(pjlstr,"@PJL SET COPIES=",16)) {
        pages=atol(pjlstr+16);
	if (pages<1) pages=1;
      }
      *pjlstr='\0';
    }
    return;
  }
  if (c==12 && !hpgl) {                  // End of the page
    actualcount+=pages;
  }
  if (c==27) {
    poi=0;
    numpoi=0;
    stringend=FALSE;
  }
 
  if (poi==0) {
    if (c!=27 && !stringend) {
      return;		// We process only Escape sequences
    }
    if (c=='E') {		  // Reset
//      for (f=0; f<MAXX; f++) for (g=0; g<MAXY; g++) t[f][g]=0;
      xsize=826;
      ysize=1170;
      res=600;
      pointsize=12;
      divcalc();
      pages=1;
      dir=0;
      display=FALSE;
      return;
    }
    if (c=='Y') {		// Turns on display functions
      display=TRUE;
      return;
    }
  }
  if ((isdigit(c) || (c=='-') || (c=='+'))) {
    if (poi<2 || *seq=='\0') return;   // There should be an Escape first
    if (stringend) {
      poi=strlen(seq)-1; 		// For example: ^&l0d1A  -> ^&l0D + ^&l1A
      numpoi=0;
      stringend=FALSE;
    }
    num[numpoi++]=c;
    if (numpoi>NUMLEN) numpoi=NUMLEN;
    num[numpoi]='\0';
    return;
  }
  else {
    if (numpoi==0) seq[poi++]=c;
    else seq[poi++]=toupper(c);
    if (poi>SEQLEN) poi=SEQLEN;
    seq[poi]='\0';
    if (numpoi==0) return;
  }
  if (islower(c)) stringend=TRUE;
  if ((*seq<27 || seq[1]!='%') && hpgl) {
    poi=0;
    numpoi=0;
    *num='\0';
    *seq='\0';
    return;
  }

  poi=0;
  if (!stringend) *seq='\0';

  if (!strcmp(seq+1,"%B")) {       // Enter HP-GL language
    *seq='\0';
    seq[1]='\0';
    hpgl=TRUE;
    return;
  }
  if (!strcmp(seq+1,"%A")) {       // Exit HP-GL language
    hpgl=FALSE;
    return;
  }
  if (!strcmp(seq+1,"&lX")) {      // Number of Copies
    pages=atol(num);
    return;
  }
  if (!strcmp(seq+1,"&lA")) {      // Page Size
    switch (atol(num)) {
      case 1: {               // Executive
	xsize=1050;	// All sizes are in 1/100th inches
	ysize=725;
      } break;
      case 2: {               // Letter
        xsize=850;
	ysize=1100;
      } break;
      case 3: {               // Legal
	xsize=850;
	ysize=1400;
      } break;
      case 26: {              // A4
	xsize=826;
	ysize=1170;
      } break;
      case 100: {             // B5
        xsize=693;
        ysize=984;
      } break;
      case 80: {              // Monarch
        xsize=750;
	ysize=388;
      } break;
/*      case 81: {              // COM 10
        xsize=;
        ysize=;
      } break;
      case 90: {              // DL
        xsize=;
        ysize=;
      } break;*/
      case 91: {              // C5
        xsize=638;
        ysize=902;
      } break;
/*      case 101: {             // Custom
        xsize=;
        ysize=;
      } break;*/
      default: return;
    }
    divcalc();
    return;
  }
  if (!strcmp(seq+1,"&lO")) {      // Orientation
    landscape=(num[0]%2!=0);
    return;
  }
  if (!strcmp(seq+1,"&aP")) {      // Print direction
    switch (atol(num)) {
      case 90: dir=1; break;
      case 180: dir=2; break;
      case 270: dir=3; break;
      default: dir=0;
    }
    if ((dir%2==1 && ysize>xsize) || (dir%2==0 && ysize<xsize)) {
      f=xsize;			// Rotating page dimensions if necessary
      xsize=ysize;
      ysize=f;  
    }
    divcalc();
    return;
  }
  if (!strcmp(seq+1,"(fW") ||
      !strcmp(seq+1,"(sW") ||
      !strcmp(seq+1,"*bW") ||
      !strcmp(seq+1,"*cW") ||
      !strcmp(seq+1,")sW") ||
      !strcmp(seq+1,"&pX")) {
    copynum=atol(num);
    copying=(copynum>0);
    copy=0;
    return;
  }
  if (!strcmp(seq+1,"*rA")) {
// raster begin:			'0A' or '1A'
    return;
  }
  if (!strcmp(seq+1,"*rB") || !strcmp(seq+1,"*rC")) {
// raster end:			'B' or 'C'
    return;
  }
  if (!strcmp(seq+1,"%X") && !strcmp(num,"-12345")) {  // Universal exit language
    inpcl=FALSE;
    return;
  }

  return;
}

void clearstr(char *s)
{
  char *p;
  
  if ((p=strchr(s,'\r'))!=NULL) *p='\0';
  if ((p=strchr(s,'\n'))!=NULL) *p='\0';
}

int main(int argc, char *argv[])
{
  char c,jobname[80],user[16];
  char s[256],u[80];
  int f,g;
  FILE *f1,*infile,*outfile;
  time_t timer;
  struct tm *ti;

  infile=(argc>1 ? fopen(argv[1],"rb"):NULL);
  if (infile==NULL) infile=stdin;
  outfile=(argc>2 ? fopen(argv[2],"wb"):NULL);
  if (outfile==NULL) outfile=stdout;
  
  timer=time(NULL);
  ti=localtime (&timer);
  *pjlstr='\0';
  actualcount=0;
//  for (f=0; f<MAXX; f++) for (g=0; g<MAXY; g++) t[f][g]=0;
  divx=826*6/MAXX+1;
  divy=1170*6/MAXY+1;
  for (; !feof(infile); ) {
    c=getc(infile);
    if (feof(infile)) break;
    proc(c);
    fputc(c,stdout);
    fflush(stdout);
    if (!strcmp(seq+1,"(U") && !strcmp(num,"19")) fprintf(stdout,"\033(9E");
        // We want to change Windows Latin 1 charset to Latin 2
	// Not too elegant but should work.
  }
  *user='\0';
  *jobname='\0';
  for (f=1; f<argc; f++) if (!strcmp(argv[f],"-n")) {
    strcpy(user,argv[f+1]);
    break;
  }
  f1=fopen("/var/spool/lpd/hp4p/lock","rb");
  if (f1!=NULL) {
    fgets(u,80,f1);
    fgets(u,80,f1);
    fclose(f1);
    clearstr(u);
    sprintf(s,"/var/spool/lpd/hp4p/%s",u);
    *jobname='\0';
    f1=fopen(s,"rb");
    *s='\0';
    if (f1!=NULL) {
      for (;!feof(f1);) {
        fgets(u,80,f1);
	if (*u=='\0') break;
	switch (*u) {
	  case 'J': strcpy(jobname,u+1); break;
	  case 'L': strcpy(user,u+1); break;
	  case 'P': strcpy(user,u+1); break;
	  case 'N': strcpy(jobname,u+1); break;
	  case 'f': sprintf(s,"/var/spool/lpd/hp4p/%s",u+1); break;
	}
      }
      fclose(f1);
    }
  }
  clearstr(jobname);
  clearstr(user);
  f1=fopen("/var/log/hp-count","ab");
  fprintf(f1,"%d/%02d/%02d %02d:%02d:%02d ",ti->tm_year+1900,ti->tm_mon+1,ti->tm_mday,ti->tm_hour,ti->tm_min,ti->tm_sec);
  fprintf(f1,"%s - %s\tPages: ",user,jobname);
  if (actualcount==0) {
    fputc('*',f1);
    actualcount++;
  }
  if (pages==1) fprintf(f1,"%ld",actualcount);
  else fprintf(f1,"%d (Copies: %ld -> Sum: %ld)",pages,actualcount/pages,actualcount);
  fprintf(f1,"\r\n");
  fclose(f1);
//  printf("%d  %d%%\n",survey(),20*survey()/51);
  return 0;
}
