/* *********************************************************************
  This programm reads and executes tektronix graphics
  from the named pipe tek.pipe
  the graphic cursor is send to /tmp/gcursor
 *********************************************************************** */

#include <sys/types.h>
#include <sys/stat.h>

#include <stdio.h>
#include <auxcfg.h>
#include <spec.h>


#define _TEKXMAX 1024
#define _TEKYMAX 780

int   cx,cy,cb1,cb2,
      esc,fdstdin,fdstdout,
      ink=2,
       opt=1,
       prt_passes=2,
       prt_lsbmsb=1,
       x_prt_siz=1024,
       y_prt_siz=1024,
       aposx=0,
       aposy=0,
       fdprinter=0,
       pribufptr=0,
       pribufsiz=8190,
      paper=0,
      ptr=0,
      tekptr=0,
      bufsiz=200000,
      tekbufsiz=8192,     
      nohco=FALSE,
      msizex=3,
      msizey=3,
      sizex=3,
      sizey=3,
      thickx=1,
      thicky=1,
      txtangle=0,
      sinphi=0,
      cosphi=262144,
      gramode=0,
      flg_half=FALSE;

unsigned char tekname[80],
                prt_init[80]="\x1B@",
                prt_gra[80]="\x1BZ",
                prt_halflf[80]="\x1B3\x02\n",
                prt_lf[80]="\x1B3\x14\n",
                prt_fin[80]="\x1B@\x0C",
               *buf,
                *printerbuf,
               *tekbuf,
               vectorfont[256][40];

help()
{
printf("This is the server, which reads the named pipe for tektronix\n");
printf("Vector grafic, and draws this grafic at the specified window\n");
printf("call it like:\n(xterm -t -e tekdaemon [-p n])&\n");
printf("optional parameters:\n");
printf("    -p n         specifies a number for the pipe.\n");
printf("    -buf n       change size of vector buffer(used for hardcopy)\n");
printf("    -nohco       display only, no buffer for hardcopy\n");
}


teknewopen()
{
int   n,i,m,_tek4014;
char  c,s[80],z[80];


   strcpy(s,"gfx");
   c=_tekpipe+48;
   z[0]=c; z[1]=0;
   strcat(s,z);
   _tek4014=auxopen(s); /* _tekpipe is defined in spec.h */
   strcpy(tekname,auxparams[0]);
   if(_tek4014 > 0) { /* other programm active */
      fprintf(stderr,"tekdaemon: graphic pipe >%s< allready exists\n",tekname);
      fprintf(stderr,"you should delete it, before you try next time\n");
      if(!nohco) free(buf); free(tekbuf);
      exit(0);
   }
   mknod(tekname,S_IFIFO | S_IROTH |S_IWOTH | S_IRUSR | S_IWUSR,0);
   _tek4014 = open(tekname,2);
   return(_tek4014);
}


main(argc,argv)
int argc;
char *argv[];
{
int  i,j,n,m,fd,fd2,nohco,ioctlarg;
char c,s[256],z[8192];

  esc=FALSE;
  fdstdin=fileno(stdin); /* may cause trouble when porting ! then you will */
  fdstdout=fileno(stdout); /* have to find the filedescriptor by yourself */

  bufsiz=200000;
  tekbufsiz=8192;
  if(checkopt(argc,argv,"-buf",s)) bufsiz=atoi(s);
  nohco=FALSE;
  if(checkopt(argc,argv,"-nohco",s)) nohco=TRUE;

  fd=teknewopen();
  readfont("font1");

  ptr=0; tekptr=0;
  if(!nohco) buf=(unsigned char *)calloc(bufsiz,sizeof(char));
  tekbuf=(unsigned char *)calloc(tekbufsiz,sizeof(char));

  while(1==1) {
    n=read(fd,z,8191);
    if(n>0) {
       m=writebuf(z,n); /* writebuf returns some flags */
       if(m==-1) break;         /* quit flag */
    } else {
       close(fd);
       fd=open(tekname,2);
    }
  }
  close(fd);
  unlink(tekname);
  if(!nohco) free(buf); free(tekbuf);
}

/*
The routine writebuf writes all tektronix vectors to the specified buffer,
and searches for some specific actions. Every Clear Screen resets the buffer.
if the buffer is full, no additional vectors are accepted.
Values returned:
   0   normal return
   -1  program abort
*/

writebuf(s,n)
char s[];
int n;
{
int i,j,p,erg,fd2;
char c,z[80],param[256];

   erg=0;                                /* assume normal return */

   for(i=0;i<n;i++) {
      c=s[i];
      if(esc) {                          /* trap escape sequences */
         switch(c) {
         case 0x1a :                     /* graphic cursor */
            gfxbufin(c); tekflush();
            z[0]=0; while(strlen(z)<5) fgets(z,80,stdin);
            j=strlen(z)-5;
            p=0; while(c!=0) {
               c = z[j++];
               z[p++] = c;
            }
            fd2=creat("/tmp/gcursor",0666);
            if(fd2<=0) {
               printf("\nfailed to open /tmp/gcursor !\n");
               continue;
            }
            p=write(fd2,z,5);
            close(fd2);
            c=0;
            break;
         case 0x0c :                     /* clear screen => reset pointer */
            ptr=0;
            break;
         case 0x40 :                     /* <esc>@ is now defined as quit */
            erg = -1;
            break;
         case 0x1b :                     /* <esc><esc>: special action */
            p=0;
            c=1;
	    i=i+1;
            while(c!=0) {
               c=s[i++];
               param[p++]=c;
            }
            i=i-1;
            do_special(param); 
            esc = FALSE;
            break;
         }
         esc=FALSE;                      /* clear esc flag */
      } 
      esc=FALSE;
      if(c==0x1b)  esc=TRUE;             /* set escape flag */
      if(c==0x1f) {                      /* trap text sequence */
         c=32; p=0; 
         i=i+1;
         if(s[i]==0x1b) {                /* handle textsize changes */
            c=s[i+1];
            switch(c) {
            case ';':                    /* smallest text size */
               sizex = (msizex *2) / 3;
               sizey = (msizey *2) / 3;
               break;
            case ':':                    /* small text size */
               sizex = (msizex * 3) / 4;
               sizey = (msizey * 3) / 4;
               break;
            case '9':
               sizex = msizex;            /* normal text size */
               sizey = msizey;
               break;
            case '8':
               sizex = 2*msizex;          /* big text size */
               sizey = 2*msizey;
               break;
            }
            i=i+2;
         }
         while(c>31) {
            c=s[i++];
            param[p++]=c;
            if(i>n) break;
         }
         i=i-2;
         c=0;
         param[p-1]=0;                   /* set string end identifier */
         plotstr(param);
         continue;
      }
      if(c==0x1d) {               /* posita, store new position */
         p=i+1;
         gettekxy(s,&p,&cx,&cy);
      }
      gfxbufin(c); 
   }
   tekflush();
   return(erg);
}


/* ---------------------------------------------------------------
   Special actions: set text parameters and make hardcopy
   --------------------------------------------------------------- */
do_special(param)
char param[];
{
int i,n,m,sx,sy,tx,ty,w;
char c,s[80];

   sscanf(param,"%d",&n);

   strcpy(s,"");
   switch(n) {
   case 0 :                                     /* textparam */
      sscanf(param,"%d %d %d %d %d %d %s",&i,&sx,&sy,&tx,&ty,&w,s);
      if(sx>0) {sizex=sx; msizex=sx;}
      if(sy>0) {sizey=sy; msizey=sy;}
      if(tx>0) thickx=tx;
      if(ty>0) thicky=ty;
      if(s[0]!=0) readfont(s);
      txtangle=w;
      rotmat(w);
      break;
   case 1 :                                     /* hco */
      sscanf(param,"%d %s",&i,s); 
      hco(s);

      break;
   }
}


cvtxy(x,y)
int x,y;
{
int n,m,i,h,l;
char ch,cl;

   h=y >> 5; l=y & 31;
   gfxbufin(h | 32); gfxbufin(l | 96);
   h=x >> 5; l=x & 31;
   gfxbufin(h | 32); gfxbufin(l | 64);
}


gettekxy(s,p,x,y)
char s[];
int *p,*x,*y;
{
int xx,yy,i,l,h,ptr,k;
char c;

   xx = -1 ; yy = -1;
   ptr = *p;
   for(k=1;k<10;k++) {
      c=s[ptr++];
      i=(c & 0xe0);
      switch(i) {
      case 32:
         h = (c & 31);
         break;
      case 64:
         l = (c & 31);
         xx = h*32 + l;
         break;
      case 96:
         l = (c & 31);
         yy = h*32 + l;
      }
      if((xx>=0) & (yy>=0)) break;
   }
   *x = xx; *y = yy; *p = ptr;
}

posita(x,y)
int x,y;
{
   int  n,m;

   gfxbufin(0x1d);
   cvtxy(x,y);
}

vectoa(x,y)
int x,y;
{
   int  n,m;

   cvtxy(x,y);
}



gfxbufin(c)
char c;
{
if((ptr<bufsiz) & (!nohco)) buf[ptr++]=c; 
if(tekptr>=tekbufsiz) tekflush();
tekbuf[tekptr++]=c;
}

tekflush()
{
write(fdstdout,tekbuf,tekptr);
tekptr=0;
}

/* *********************************************************************

                  Vector font utilities

   ********************************************************************* */

/* ------------------------------------------------------------------
      Read Vector font from file (as defined in Aux_Config)
   ------------------------------------------------------------------ */
readfont(name)
char *name;
{
int i,n,m;
char c,s[80];
FILE *fp;

   i=auxopen(name);
   close(i);
   strcpy(s,auxparams[0]);
   fp=fopen(s,"r");
   if(fp==NULL) {
      return(0);
   }  

   while(!feof(fp)) {
      i=0;
      fscanf(fp,"%s",s);          /* read next entry , number of character */
      n = xtoi(s);
      if(n==0) continue;
      m=1;
      while(m>0) {
         fscanf(fp,"%s",s);       /* read next entry */
         m=xtoi(s);
         if(m>255) m = 255;        /* signal for new position */
         if(m<0) m = 255;          /* may be negative on some compilers */
         vectorfont[n][i++] = m;   /* store result */
      }
   }
   fclose(fp);
}

/* ------------------------------------------------------------------
      Rotation
   ------------------------------------------------------------------ */
rotate(xx,yy)
int *xx,*yy;
{
int rx,ry,x,y;

   x = *xx ; y = *yy;
   rx = ((x * cosphi) >> 19) - (( y * sinphi) >> 19);
   ry = (( y * cosphi) >> 19) + ((x * sinphi) >> 19);
   *xx = rx ; *yy = ry;
}
/* ------------------------------------------------------------------
      plot one single character
   ------------------------------------------------------------------ */
plotchar(c)
unsigned char c;
{
int n,m,i,x,y,mx,my,rx,ry,flag;
unsigned char uc;

   flag=TRUE;
   i=0; n=c;
   mx=cx; my=cy;

   x = 0; y = 4*sizey;
   rotate(&x,&y); posita(x+mx,y+my);

   for(;;) {
      uc = vectorfont[n][i++];
      if(uc == 255) {
         flag=FALSE;
         continue;
      }
      if(uc == 0) break;
      x = uc / 16;
      y = uc & 15;
      x = x * sizex; y = y * sizey;
      rotate(&x,&y);
      if(flag) {
         vectoa(x+mx,y+my);
      } else {
         posita(x+mx,y+my);
         flag = TRUE;
      }
   }
   x = 8 * sizex; y = 0; rotate(&x,&y);
   cx = mx + x;
   cy = my + y;
}

/* ------------------------------------------------------------------
      plot string
   ------------------------------------------------------------------ */
plotstr(s)
char s[];
{
int i,n,m,x,y,mx,my,tx,ty;
unsigned char c;

   cy = cy - 4;
   
   mx = cx ; my = cy;
   for(tx=0;tx<thickx;tx++) {
      for(ty=0;ty<thicky;ty++) {
         cx = mx + tx;
         cy = my + ty;
         i=0;
         while(1==1) {
            c = s[i++];
            if(c==0) break;
            plotchar(c);
         }
      }
   }
}

/* ----------------------------------------------------
       Calculate rotation matrix
   ---------------------------------------------------- */

rotmat(n)
int n;      /* Angle in degree */
{
int i,m;
float phi,cphi,sphi;

   phi = ((float) n) * 3.1415926 / 180.0;
   cphi = 262144 * cos( phi );
   sphi = 262144 * sin( phi );
   sinphi = (int) sphi;
   cosphi = (int) cphi;
}

xtoi(s)
char  s[];
{  int i,m,l,e;
   char c;

   l=strlen(s); e=0;
   for( i = 0 ; i < l ; i++ ) {
      c = s[i] ; c = toupper(c) ;
      m = c - '0' ;
      if( m > 9 ) m = m - 7 ;
      e = 16 * e + m ;
   } ;
   return(e) ;
}

/* ****************************************************************

                  HARDCOPY and related functions

   **************************************************************** */

hco(str)
char str[];
{
unsigned char *bitplane;
char z[80];
int n,m,i,j;

   pribufsiz=8190;
   pribufptr=0;
   printerbuf=(unsigned char *)calloc(pribufsiz+2,sizeof(char));
   if(buf==NULL) {
      fprintf(stderr,"could not allocate printer buffer %d bytes\n",pribufsiz);
      return(0);
   }


   strcpy(z,"defaultprinter");
   if(str[0]!=0) strcpy(z,str);
   fdprinter=auxopen(z);
   n=4;
   prt_passes=atoi(auxparams[n]); n=n+1;
   prt_lsbmsb=atoi(auxparams[n]); n=n+1;
   x_prt_siz=atoi(auxparams[n]); n=n+1;
   y_prt_siz=atoi(auxparams[n]); n=n+1;
   cvtbs(prt_init,auxparams[n]); n=n+1;
   cvtbs(prt_gra,auxparams[n]); n=n+1;
   cvtbs(prt_halflf,auxparams[n]); n=n+1;
   cvtbs(prt_lf,auxparams[n]); n=n+1;
   cvtbs(prt_fin,auxparams[n]);


   n = (x_prt_siz * y_prt_siz) / 8;     /* length of buffer needed */
   n = n + 1024;                        /* to go shure */
   bitplane=(unsigned char *)calloc(n,sizeof(char));
   if(buf==NULL) {
      fprintf(stderr,"could not allocate shadow memory %d bytes\n",n);
      free(printerbuf);
      close(fdprinter);
      return(0);
   }

   redrawhco(bitplane);
   printout(bitplane);

   close(fdprinter);
   free(bitplane); free(printerbuf); 
}

strtoprt(s)
unsigned char s[];
{
int n;
unsigned char c;

   n=0;
   while(1==1) {
      c=s[n++];
      if(c==0) break;
      pribufin(c);
   }
}

pribufin(c)
unsigned char c;
{
if(pribufptr>=pribufsiz) pribufflush();
printerbuf[pribufptr++]=c;
}

pribufflush()
{
write(fdprinter,printerbuf,pribufptr); 
pribufptr=0;
}

redrawhco(bitplane)
unsigned char *bitplane;
{
int x,y,i,n,m,p;
char c,s[80];

   p=0;
   while(buf[p]!=0x1d) p=p+1;          /* find posita first */

   while(p<ptr) {                      /* scan vector buffer */

      c=buf[p];
      if(c==0x1d) {
         p=p+1;
         gettekxy(buf,&p,&x,&y);
         if((x>_TEKXMAX) | (y>_TEKYMAX)) {
            while(buf[p]!=0x1d) p=p+1;
            continue;
         }
         draw_to(bitplane,FALSE,x,y);
         continue;
      }
      if(c>31) {
         gettekxy(buf,&p,&x,&y);
         if((x>_TEKXMAX) | (y>_TEKYMAX)) {
            while(buf[p]!=0x1d) p=p+1;
            continue;
         }
         draw_to(bitplane,TRUE,x,y);
         continue;
      }
      while(buf[p]!=0x1d) p=p+1;          /* find next posita */
   }
}
      
/* --------------------------------------------------------------- */
/*       Draw a line                                               */
/* --------------------------------------------------------------- */
draw_to(bitplane,pen_down,x,y)
unsigned char *bitplane;
int pen_down,x,y;
{
   int   xinc,yinc,
         xcount,ycount,
         fx,fy;


   x = (x_prt_siz * x) / _TEKXMAX ;
   y = (y_prt_siz * y) / _TEKYMAX ; y=y_prt_siz-y;

   if(pen_down == TRUE) {
      xinc=liabs(x-aposx);
      yinc=liabs(y-aposy);
      fx=lisgn(x-aposx);
      fy=lisgn(y-aposy);
      xcount=xinc;
      ycount=yinc;
      do {
         set_pixel(bitplane,aposx,aposy);
         if(xcount>ycount) {
            ycount=ycount+yinc ; aposx=aposx+fx;
         } else {
            xcount=xcount+xinc ; aposy=aposy+fy;
         }
      } while((liabs(x-aposx)>=1) || (liabs(y-aposy)>=1));
   }
   aposx=x; aposy=y;
}

liabs(x)
int x;
{
   if(x>=0) return(x);
   return(-x);
}

lisgn(x)
int  x;
{
   if(x>0) return(1L);
   if(x<0) return(-1L);
   return(0L);
}

/* --------------------------------------------------------------- */
/*       plot one pixel                                            */
/* --------------------------------------------------------------- */
set_pixel(bitplane,x,y)
unsigned char *bitplane;
int x,y;
{
   register int  byte,bit,n;



   byte=y*(x_prt_siz>>3)+(x>>3);
   bit= x & 7; n=128>>bit;
   bitplane[byte] |= n;
}

/* --------------------------------------------------------------- */
/*       get one pixel from shadow memory                          */
/* --------------------------------------------------------------- */
get_pixel(bitplane,x,y)
unsigned char *bitplane;
int x,y;
{
   register int   byte,bit;
   register unsigned char c;

   byte=y*(x_prt_siz>>3)+(x>>3);
   bit=7-(x & 7);
   c=((bitplane[byte])>>bit) & 1;
   return(c);
}

/* ----------------------------------------------------------- */
/*       get one byte ready to print from shadow memory        */
/* ----------------------------------------------------------- */
get_prtbyte(bitplane,x,y)
unsigned char *bitplane;
int x,y;
{
   int    i,m;
   long   n;

   m=0; n=0; x=x_prt_siz-x;
   for(i=1; i<=8; ++i) {
      n=n+prt_passes;
      m=2*m+get_pixel(bitplane,x-n,y);
   }
   return(m);
}

/* ----------------------------------------------------------- */
/*       make hardcopy of shadow memory                        */
/* ----------------------------------------------------------- */
printout(bitplane)
unsigned char *bitplane;
{
   int   m;
   long  x,y,n,i;
   unsigned char c;


   strtoprt(prt_init); pribufflush();

   if(prt_lsbmsb == 2) {              /* trap HP raster row graphics */
      hp_rasterrow(bitplane);
      return(0);

   }

   /* it follows the epson style printout routine */

   x=0;
   while(x<x_prt_siz) {
      y=0;
      for(i=1; i<=prt_passes; ++i) {
         prt_gra_out(y_prt_siz);
         while(y<y_prt_siz) {
            c=get_prtbyte(bitplane,x,y++);
            pribufin(c);
         }
         strtoprt(prt_halflf); 
         y=0; ++x;
      }
      strtoprt(prt_lf); pribufflush();
      x=x+7*prt_passes;
   }

   strtoprt(prt_fin); pribufflush();
}

/* -----------------------------
   HP mode raster row graphics 
   ----------------------------- */

hp_rasterrow(bitplane)
unsigned char *bitplane;
{
   int  x,y,m,n,i;
   unsigned char c;


   m = x_prt_siz / 8;
   n = (y_prt_siz -1) * m;
   x=0;
   while(x<n) {
      strtoprt(prt_gra);
      for(i=0; i<m; i++) {
	 c=bitplane[x++];
	 pribufin(c);
      }
      pribufflush();
   }
   strtoprt(prt_fin); pribufflush();
}

/* ------------------------------------------------------------ */
/* some printer dependend routines:                             */
/* ------------------------------------------------------------ */

prt_gra_out(x)
int  x;
{
unsigned char c1,c2;

   c1=x/256; c2=x-256*c1;
   strtoprt(prt_gra);
   if(prt_lsbmsb==1) {
      pribufin(c2);
      pribufin(c1);
   } else {
      pribufin(c1);
      pribufin(c2);
   }
}


/* convert string which includes the backslash */

cvtbs(s2,s1)
char s2[] , s1[];
{  int   i , l , i2 , i1 ;
   char  c , cc , s[8];

   l=strlen(s1); i2=0 ;
   for (i1 = 0; i1 <= l; i1++) {
      c=s1[i1];
      if(c == ' ') continue;
      if(c == '\\') {
         cc=s1[++i1];
         switch(cc) {
         case 'n':
            c='\n' ;  break ;
         case 'f':
            c='\f' ;  break ;
         case 't':
            c='\t' ;  break ;
         case 'b':
            c='\b' ;  break ;
         case 'x': /* hexadecimal conversion */
            s[0]=s1[++i1] ; s[1]=s1[++i1] ; s[2]=0 ;
            c=xtoi(s) ; break ;
         default:
            ; } ;
         } ;
      s2[i2++]=c ; }
   s2[i2]=0 ;
   return(i2-1);
}

/* ---------------------------------------------------------------

      Diverse Vektororientierte Ausgabe formate:

      HP-GL , DXF, TEX

   !!!!!!!!!!!!!!!! Noch nicht ERREICHBAR !!!!!!!!!!

   --------------------------------------------------------------- */

vector_out(output,x_faktor,y_faktor,move_to,draw_to)
 FILE *output;
 char move_to[], draw_to[];
 float x_faktor, y_faktor;
{
int x,y,i,n,m,p;
float fx,fy;
char c,s[80];

   p=0;
   while(buf[p]!=0x1d) p=p+1;          /* find posita first */

   while(p<ptr) {                      /* scan vector buffer */

      c=buf[p];
      if(c==0x1d) {
         p=p+1;
         gettekxy(buf,&p,&x,&y);
         if((x>_TEKXMAX) | (y>_TEKYMAX)) {
            while(buf[p]!=0x1d) p=p+1;
            continue;
         }
         fx = x_faktor * x;
         fy = y_faktor * y;
         fprintf(output,move_to,fx,fy);
         continue;
      }
      if(c>31) {
         gettekxy(buf,&p,&x,&y);
         if((x>_TEKXMAX) | (y>_TEKYMAX)) {
            while(buf[p]!=0x1d) p=p+1;
            continue;
         }
         fx = x_faktor * x;
         fy = y_faktor * y;
         fprintf(output,draw_to,fx,fy);
         continue;
      }
      while(buf[p]!=0x1d) p=p+1;          /* find next posita */
   }
   fclose(output);
}

save_hpgl()
{
char s[80];
FILE *output;

/*
   FileSelect("Select HP-GL file",s);
*/
   output = fopen(s,"w");
   fprintf(output,"IN;\nLT;\n1;\n");
   vector_out(output,(float)15,(float)15,
      "PU;PA %5.0f,%5.0f;\n",
      "PD;PA %5.0f,%5.0f;\n");
   fprintf(output,"PU;SP;IP;SC;PA 0,7650\n");
   fclose(output);
}

