#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>

#ifdef HAVE_DVIPGM
#include <libdvipgm.h>
#endif

#define correction 0.353

char *psname = NULL, *pdfname = NULL, *texname = NULL, *dvifile = NULL;
char *writing = NULL, *formula = NULL;
char rgb_e[4];
int curve_div = 50, wrlen = 0, formlen = 0;
int canvasx, canvasy, canvash;
int width, height;
double *x = NULL, *y = NULL;
double w, rescale = 1.0;
FILE *fo;
int n;
int brushmode = 0, arcmode = 0, ellipsemode = 0, boxmode = 0,
  objectmode = 0, splinemode = 0, polygonmode = 0, ticksmode =0;
int tt = 1, tn = 5, fn = 0, boxradius = 7;
int sides = 5, dpi = 192, text_x, text_y, text_w, text_h, ascent, opacity;
double angle = 25, ngonparam = 3236, arrowparam = 125, boxratio = 0.0;
int tex_output = 0;
unsigned int tcolor, color1 = 0, color2 = 0;

#define FLAGOP 0x36df7df
#define DRAWOP 0x3000300
#define FILLOP 0x2492000

#ifdef HAVE_DVIPGM
void setup_tex_file(FILE *fd, char *buf)
{
  FILE *ft;
  char tmpdir[256];
  int i, n = 0, f = 0;
  
  n = 0;
  while (!feof(fd)) {
    fgets(buf, 1020, fd);    
    i = strlen(buf) - 1;
    if (i >= 0 && buf[i] == '\n') buf[i] = '\0';
    if (!strncmp(buf, "*canvas ", 8)) {
      texname = "xpaint_formulas_output";
      sprintf(tmpdir, "%s%s",
	    (getenv("HOME")?getenv("HOME"):""),
	    (getenv("HOME")?"/.xpaint/tmp":"/tmp"));
      sprintf(buf, "%s/%s.tex", tmpdir, texname);
      ft = fopen(buf, "w");
      if (!ft) {
        fprintf(stderr, "File %s cannot be created!\n", buf);
        exit(1);
      }
      fprintf(ft, "\\input /usr/share/dvipgm/formulas.tex\n");
    } else
    if (*buf == '=') {
      fprintf(ft, "%s\n", buf+1);
      f = 1;
    } else
    if (!strncmp(buf, "*textoutput ", 12)) {
      if (f) {
	fprintf(ft, "%s", "\\ve\n");
        n += f;
      }	
      f = 0;
    }
  }
  if (n) {
    fprintf(ft, "\\end\n");
    fclose(ft);
    sprintf(buf, "tex -interaction=nonstopmode -output-directory=%s "
	    "%s/%s.tex", tmpdir, tmpdir, texname);
    if (system(buf));
    sprintf(buf, "%s/%s.dvi", tmpdir, texname);
    dvifile = strdup(buf);
    if ((ft = fopen(dvifile, "r")))
      fclose(ft);
    else {
      fprintf(stderr, "File %s cannot be created!\n", dvifile);
      exit(1);
    }
  } else {
    sprintf(buf, "%s/%s.tex", tmpdir, texname);
    unlink(buf);
  }
}

void pgm_print()
{
  FILE *fd;
  int i, j, k, n, u, v, ascent;
  char *texpix;

  dvipgm_init();
  dvipgm_set_kpathsea();
  dvipgm_set_psfontmap();
  dvipgm_set_dpi(dpi);
  dvipgm_set_page(fn);
  dvipgm_destroy_image();
  texpix = dvipgm_process_file(dvifile);
  dvipgm_close();

  if (!texpix) return;
  memcpy(&u, texpix, sizeof(int));
  memcpy(&v, texpix + sizeof(int), sizeof(int));
  if (!u || !v) return;
  texpix += 2*sizeof(int);
  j = 0;
  k = u * v;
  while ((j < k) && (texpix[j] == (char)255)) j++;
  if (j == k) return;
  j = j / u;
  texpix += j * u;
  v -= j;
  ascent = dvipgm_height - j;
  
  fprintf(fo, "%g %g %g rgb ",
	  ((tcolor >> 16) & 255) / 255.0,
	  ((tcolor >> 8) & 255) / 255.0,
	  (tcolor & 255) / 255.0);
  fprintf(fo, "%d %d m\n", text_x, canvash - (text_y + ascent + 3));
  fprintf(fo, "%d %d 1 %g pgm\n", u, v, v - ascent);
  n = u * v;
  for (i=0; i<n; i++) {
    fprintf(fo, "%02x", texpix[i] & 255);
    if (i%36 == 35) fprintf(fo, "\n");
  }
  if (i%36) fprintf(fo, "\n");
}
#else
void setup_tex_file(FILE *fd, char *buf)
{
  fprintf(stderr, "%s\n",
  "vxp2ps compiled without libdvipgm support. TeX formulas will be ignored!");
}
void pgm_print()
{
  fprintf(stderr, "TeX formula %d ignored: %s\n", fn, formula);
}
#endif

void ps_init()
{
  fprintf(fo, "%%!PS-Adobe-2.0\n");
  fprintf(fo, "%%%%Creator: vxp2ps\n");
  fprintf(fo, "%%%%Title: %s\n", psname);
  fprintf(fo, "%%%%Pages: 1\n");
  fprintf(fo, "%%%%BoundingBox: 0 0 %d %d\n", width, height);
  fprintf(fo, "%%%%%%HiResBoundingBox: 0 0 %g %g\n", width, height);
  fprintf(fo, "%%%%EndComments\n");
  fprintf(fo, "%%%%BeginSetup\n");
  fprintf(fo, "%%%%EndSetup\n");
  fprintf(fo, "1 setlinejoin 1 setlinecap\n");
  fprintf(fo, "/latinize {\n");
  fprintf(fo, "  findfont dup length\n");
  fprintf(fo, "  dict begin { 1 index /FID ne {def}{pop pop} ifelse} forall\n");
  fprintf(fo, "  /Encoding ISOLatin1Encoding def currentdict end definefont pop} bind def\n");
  fprintf(fo, "/rgb {setrgbcolor} def\n");
  fprintf(fo, "/e {%.3f %.3f %.3f rgb} def\n",
	      rgb_e[0]/255.0, rgb_e[1]/255.0, rgb_e[2]/255.0);
  fprintf(fo, "/drawsegment {/y0 exch def /x0 exch def /n 0 def x0 y0 lineto} def\n");
  fprintf(fo, "/d {drawsegment} def\n");
  fprintf(fo, "/sd {setdash} def /sd0 {[] 0 setdash} def\n");
  fprintf(fo, "/m {/yi exch def /xi exch def /x0 xi def /y0 yi def /d {drawsegment} def\n");
  fprintf(fo, "  /n 0 def xi yi moveto} def\n");
  fprintf(fo, "/l {lineto} def\n");
  fprintf(fo, "/Times-Roman-Latin1 /Times-Roman latinize\n");
  fprintf(fo, "/F {/Times-Roman-Latin1 findfont exch dup /fs exch def scalefont setfont} def\n");
  fprintf(fo, "/fsm 1.1 def\n");
  fprintf(fo, "/s {show x0 /y0 y0 fs fsm mul sub def y0 moveto} def\n");
  fprintf(fo, "/lw {setlinewidth} def\n");
  fprintf(fo, "/va 1 def /vp {/va exch def} def\n");
  fprintf(fo, "/oa 0 def /om {/oa exch def} def\n");
  fprintf(fo, "/ts 4 def /ta 0 def /tp {/ta exch def /ts exch def /e1 exch 1 exch sub def\n");
  fprintf(fo, "  /e0 exch 1 exch sub def} def /e0 0 def /e1 0 def\n");
  fprintf(fo, "/drawarc {\n");
  fprintf(fo, "  n 0 eq {/y1 exch def /x1 exch def /n 1 def}\n");
  fprintf(fo, "         {/y2 exch def /x2 exch def /n 0 def} ifelse\n");
  fprintf(fo, "  n 0 eq {/h x1 x0 sub y2 y0 sub mul x2 x0 sub y1 y0 sub mul sub 2 mul def\n");
  fprintf(fo, "    h 0 eq {x1 y1 lineto x2 y2 lineto} {\n");
  fprintf(fo, "  /t1 x1 dup mul x0 dup mul sub y1 dup mul y0 dup mul sub add def\n");
  fprintf(fo, "  /t2 x2 dup mul x0 dup mul sub y2 dup mul y0 dup mul sub add def\n");
  fprintf(fo, "  /cx y2 y0 sub t1 mul y1 y0 sub t2 mul sub h div def\n");
  fprintf(fo, "  /cy x1 x0 sub t2 mul x2 x0 sub t1 mul sub h div def\n");
  fprintf(fo, "  /x0 x0 cx sub def /y0 y0 cy sub def /a0 y0 x0 atan def\n");
  fprintf(fo, "  /x1 x1 cx sub def /y1 y1 cy sub def /a1 y1 x1 atan def\n");
  fprintf(fo, "  /x2 x2 cx sub def /y2 y2 cy sub def /a2 y2 x2 atan def\n");
  fprintf(fo, "  /r x0 dup mul y0 dup mul add sqrt def\n");
  fprintf(fo, "  a1 a0 lt {/a1 a1 360 add def} if\n");
  fprintf(fo, "  a2 a1 lt {/a2 a2 360 add def} if\n");
  fprintf(fo, "  a2 a1 lt {/a1 a1 360 sub def /a2 a2 360 sub def \n");
  fprintf(fo, "    a2 a0 gt {/a2 a2 360 sub def} if} if\n");
  fprintf(fo, "  a2 a0 sub 360 gt {/a1 a1 360 sub def /a2 a2 720 sub def} if\n");
  fprintf(fo, "  /da a2 a0 sub def\n");
  fprintf(fo, "  /p %d da abs mul 180 div 1 add truncate def\n", curve_div);
  fprintf(fo, "  /da da p div def\n");
  fprintf(fo, "  0 1 p {da mul a0 add dup cos r mul cx add exch\n");
  fprintf(fo, "    sin r mul cy add lineto} for} ifelse\n");
  fprintf(fo, "  /x0 x2 cx add def /y0 y2 cy add def} if} def\n");
  fprintf(fo, "/ellipse {\n");
  fprintf(fo, "  /y1 exch def /x1 exch def\n");
  fprintf(fo, "  /dx x1 x0 sub def /dy y1 y0 sub def\n");
  fprintf(fo, "  dy 0 eq {x1 y1 lineto} if\n");
  fprintf(fo, "  dy pb 0 gt {neg} if 0 gt {/cx x1 def /cy y0 def\n");
  fprintf(fo, "    1 1 %d {1.8 mul /u exch def\n", curve_div);
  fprintf(fo, "      cx dx u cos mul sub cy dy u sin mul add lineto} for}\n");
  fprintf(fo, "    {/cx x0 def /cy y1 def\n");
  fprintf(fo, "    1 1 %d {1.8 mul /u exch def\n", curve_div);
  fprintf(fo, "      cx dx u sin mul add cy dy u cos mul sub lineto} for} ifelse\n");
  fprintf(fo, "  /x0 x1 def /y0 y1 def /n 0 def\n");
  fprintf(fo, "} def\n");
  fprintf(fo, "/spline {/n n 1 add def\n");
  fprintf(fo, "  n 1 eq {/y1 exch def /x1 exch def /pc pb 1 add def\n");
  fprintf(fo, "    /ux x1 x0 sub def /uy y1 y0 sub def\n");
  fprintf(fo, "    /xx x0 ux 3 div add def /yy y0 uy 3 div add def\n");
  fprintf(fo, "    /ru ux dup mul uy dup mul add 1E-36 add def\n");
  fprintf(fo, "    /ux ux ru div def /uy uy ru div def /ru ru sqrt 3 div def} {\n");
  fprintf(fo, "  n 2 eq {/y2 exch def /x2 exch def pb 1 eq {\n");
  fprintf(fo, "    /xj x1 def /yj y1 def /xk x2 def /yk y2 def} if} {\n");
  fprintf(fo, "    /x0 x1 def /y0 y1 def /x1 x2 def /y1 y2 def /y2 exch def /x2 exch def\n");
  fprintf(fo, "    /wx zx def /wy zy def /ux vx def /uy vy def /ru rv def\n");
  fprintf(fo, "    /xx x0 wx ru mul add def /yy y0 wy ru mul add def} ifelse\n");
  fprintf(fo, "  /vx x2 x1 sub def /vy y2 y1 sub def\n");
  fprintf(fo, "  /rv vx dup mul vy dup mul add 1E-36 add def\n");
  fprintf(fo, "  /vx vx rv div def /vy vy rv div def /rv rv sqrt 3 div def\n");
  fprintf(fo, "  /zx ux vx add def /zy uy vy add def\n");
  fprintf(fo, "  /r zx dup mul zy dup mul add 1E-36 add sqrt def\n");
  fprintf(fo, "  /zx zx r div def /zy zy r div def\n");
  fprintf(fo, "  /xxp x1 zx ru mul sub def /yyp y1 zy ru mul sub def\n");
  fprintf(fo, "  n 2 eq { /ru ru dup mul 3 mul def\n");
  fprintf(fo, "    /xx xxp ux ru mul sub def /yy yyp uy ru mul sub def } if\n");
  fprintf(fo, "  n pc eq {x1 y1 moveto} {xx yy xxp yyp x1 y1 curveto} ifelse} ifelse\n");
  fprintf(fo, "} def\n");
  fprintf(fo, "/endspline {n 0 gt {\n");
  fprintf(fo, "  pb 1 eq {xi yi spline xj yj spline xk yk spline} {\n");
  fprintf(fo, "  /xx x1 zx rv mul add def /yy y1 zy rv mul add def /rv rv dup mul 3 mul def\n");
  fprintf(fo, "  /xxp xx vx rv mul add def /yyp yy vy rv mul add def\n");
  fprintf(fo, "  xx yy xxp yyp x2 y2 curveto /x0 x2 def /y0 y2 def} ifelse} if\n");
  fprintf(fo, "} def\n");
  fprintf(fo, "/ngon {\n");
  fprintf(fo, "  /cy exch y0 add 2 div def /cx exch x0 add 2 div def\n");
  fprintf(fo, "  /dx x0 cx sub def /dy y0 cy sub def\n");
  fprintf(fo, "  /u 360 pb div def /a u cos def /b u sin def\n");
  fprintf(fo, "  1 1 pb {pop dx a mul dy b mul sub dy a mul dx b mul add\n");
  fprintf(fo, "    /dy exch def /dx exch def cx dx add cy dy add lineto} for /n 0 def\n");
  fprintf(fo, "} def\n");
  fprintf(fo, "/nstar {\n");
  fprintf(fo, "  /cy exch y0 add 2 div def /cx exch x0 add 2 div def /fa pc 1000 div def\n");
  fprintf(fo, "  /dx x0 cx sub fa div def /dy y0 cy sub fa div def\n");
  fprintf(fo, "  /u 360 pb div def /a u cos def /b u sin def /q b a 1 add div def\n");
  fprintf(fo, "  cx dx add dy q mul add cy dy add dx q mul sub moveto\n");
  fprintf(fo, "  1 1 pb {pop cx dx fa mul add cy dy fa mul add lineto\n");
  fprintf(fo, "    cx dx add dy q mul sub cy dy add dx q mul add lineto\n");
  fprintf(fo, "    dx a mul dy b mul sub dy a mul dx b mul add\n");
  fprintf(fo, "    /dy exch def /dx exch def} for /n 0 def\n");
  fprintf(fo, "} def\n");
  fprintf(fo, "/vector {/y1 exch def /x1 exch def /dx x1 x0 sub def /dy y1 y0 sub def\n");
  fprintf(fo, "  /r dx dup mul dy dup mul add sqrt 1E-36 add def\n");
  fprintf(fo, "  /dx dx r div def /dy dy r div def\n");
  fprintf(fo, "  oa 2 and 0 eq {x1 y1 lineto stroke} {/x1 x0 def /y1 y0 def} ifelse\n");
  fprintf(fo, "  /fa pc 0.0341 mul def /a pb cos def /b pb sin def\n");  
  fprintf(fo, "  gsave sd0\n");
  fprintf(fo, "  x1 dx a mul dy b mul add fa mul sub\n");
  fprintf(fo, "  y1 dx b mul dy a mul sub fa mul add moveto x1 y1 lineto\n");
  fprintf(fo, "  x1 dx a mul dy b mul sub fa mul sub\n");
  fprintf(fo, "  y1 dx b mul dy a mul add fa mul sub lineto\n");
  fprintf(fo, "  va 1 eq {closepath fill} {stroke} ifelse x1 y1 moveto\n");
  fprintf(fo, "  grestore /x0 x1 def /y0 y1 def /n 0 def\n");
  fprintf(fo, "} def\n");
  fprintf(fo, "/box {/y1 exch def /x1 exch def\n");
  fprintf(fo, "  pc 0 eq not {/pb x1 x0 sub abs def y1 y0 sub abs dup\n");
  fprintf(fo, "  pb gt {pop pb} if pc mul 0.01 mul /pb exch def} if\n");
  fprintf(fo, "  pb 0 eq {x0 y0 moveto x1 y0 lineto x1 y1 lineto x0 y1 lineto}\n");
  fprintf(fo, "  {x0 x1 add 2 div y0 moveto x1 y0 x1 y1 pb arct x1 y1 x0 y1 pb arct\n");
  fprintf(fo, "  x0 y1 x0 y0 pb arct x0 y0 x1 y0 pb arct} ifelse closepath stroke\n");
  fprintf(fo, "  /x0 x1 def /y0 y1 def x0 y0 moveto} def\n");
  fprintf(fo, "/ticks {/y1 exch def /x1 exch def /dx x1 x0 sub def /dy y1 y0 sub def\n");
  fprintf(fo, "  pc 1 ge {/dx dx pc div def /dy dy pc div def} if /a 0 def\n");
  fprintf(fo, "  pb 1 eq {/a dx neg dy atan def} if pb 2 eq {/a dy dx atan 45 add def} if\n");
  fprintf(fo, "  /b a ta sub sin ts mul def /a a ta sub cos ts mul def\n");
  fprintf(fo, "  gsave sd0 e0 1 pc e1 sub {pop\n");
  fprintf(fo, "  pb 1 eq {x0 a sub y0 b sub moveto x0 a add y0 b add lineto stroke} if\n");
  fprintf(fo, "  pb 2 eq {x0 a add y0 b add moveto x0 a sub y0 b sub lineto stroke\n");
  fprintf(fo, "    x0 b add y0 a sub moveto x0 b sub y0 a add lineto stroke} if\n");
  fprintf(fo, "  pb 3 eq {x0 ts add y0 moveto x0 y0 ts 0 360 arc fill} if\n");
  fprintf(fo, "  pb 4 eq {x0 ts add y0 moveto x0 y0 ts 0 360 arc stroke} if\n");
  fprintf(fo, "  /x0 x0 dx add def /y0 y0 dy add def} for\n");
  fprintf(fo, "  grestore /x0 x1 def /y0 y1 def /n 0 def\n");
  fprintf(fo, "} def\n");
  fprintf(fo, "/endpath {\n");
  fprintf(fo, "  pa 1 eq { n 1 eq {x1 y1 lineto /x0 x1 def /y0 y1 def /n 0 def} if} if\n");
  fprintf(fo, "  pa 3 eq {endspline} if /n -1 def\n");
  fprintf(fo, "} def\n");
  fprintf(fo, "/pa 0 def\n");
  fprintf(fo, "/t {endpath /pc exch def /pb exch def /pa exch def\n");
  fprintf(fo, "  currentpoint /y0 exch def /x0 exch def /n 0 def\n");
  fprintf(fo, "  pa 0 eq {/d {drawsegment} def} if\n");
  fprintf(fo, "  pa 1 eq {/d {drawarc} def} if\n");
  fprintf(fo, "  pa 2 eq {/d {ellipse} def} if\n");
  fprintf(fo, "  pa 3 eq {/d {spline} def} if\n");
  fprintf(fo, "  pa 4 eq {/d {ngon} def} if\n");
  fprintf(fo, "  pa 5 eq {/d {nstar} def} if\n");
  fprintf(fo, "  pa 6 eq {/d {vector} def} if\n");
  fprintf(fo, "  pa 7 eq {/d {ticks} def} if\n");
  fprintf(fo, "  pa 8 eq {/d {box} def} if\n");    
  fprintf(fo, "} def\n");
  fprintf(fo, "/k {endpath stroke sd0} def\n");
  fprintf(fo, "/f {endpath closepath fill sd0} def\n");
  fprintf(fo, "/c {endpath gsave closepath rgb fill grestore stroke sd0} def\n");
#ifdef HAVE_DVIPGM  
  fprintf(fo, "/pgm {/q exch def /a exch def /y exch def /x exch def currentcolor\n");
  fprintf(fo, "  /b exch 1 sub def /g exch 1 sub def /r exch 1 sub def\n");
  fprintf(fo, "  gsave currentpoint translate /pix x 3 mul string def\n");
  fprintf(fo, "  0 q -1 mul translate x a mul y a mul scale x y 8 [x 0 0 y neg 0 y]\n");
  fprintf(fo, "  {currentfile x string readhexstring pop /line exch def \n");
  fprintf(fo, "   0 1 x 1 sub {/i exch def /col line i get 255 exch sub def\n");
  fprintf(fo, "   /j i 3 mul def pix j 255 col r mul add cvi put\n");
  fprintf(fo, "   pix j 1 add 255 col g mul add cvi put\n");
  fprintf(fo, "   pix j 2 add 255 col b mul add cvi put} for pix}\n");
  fprintf(fo, "  false 3 colorimage grestore} def\n");
#endif
  fprintf(fo, "%%%%Page: 1 1\n");
}

char * rgbcolor(unsigned int col)
{
  static char colorstr[32];
  sprintf(colorstr, "%g %g %g",
	  (col >>16)/255.0, ((col>>8)&255)/255.0, (col&255)/255.0);
  return colorstr;
}

int get_utf8_char_length(unsigned char utf8_char)
{
  if (utf8_char < 0x80) return 1;
  else if ((utf8_char & 0x20) == 0) return 2;
  else if ((utf8_char & 0x10) == 0) return 3;
  else if ((utf8_char & 0x08) == 0) return 4;
  else if ((utf8_char & 0x04) == 0) return 5;

  return 6;
}

char utf8_to_latin1_char(char *s, int *ind)
{
    int len = get_utf8_char_length((unsigned char)(s[*ind]));
    if (len == 1)
    {
        char c = s[*ind];
        (*ind)++;

        return c;
    }

    unsigned int v = (s[*ind] & (0xff >> (len + 1))) << ((len - 1) * 6);
    (*ind)++;
    for (len-- ; len > 0 ; len--)
    {
      v |= ((unsigned char)(s[*ind]) - 0x80) << ((len - 1) * 6);
        (*ind)++;
    }

    return (v > 0xff) ? 0 : (char)v;
}

char *utf8_to_ps_latin1(char *ws, char *s)
{
    int ind, wind;
    for (ind = 0, wind = 0 ; ; wind++)
    {
        if (s[ind] == 0)
        {
            ws[wind] = 0;
            break;
        }

        unsigned char c = (unsigned char) utf8_to_latin1_char(s, &ind);
        if (c == 0)
        {
            c = '_';
        }

	if (c <= 127) {
	    if (c == '\n') {
	      ws[wind++] = ')';
	      ws[wind++] = ' ';
	      ws[wind++] = 's';
	      ws[wind++] = '\n';
	      ws[wind] = '(';	      
	    } else
	    if (c == '(') {
	        ws[wind++] = '\\';
		if (tex_output) {
 	          ws[wind++] = 'b';
 	          ws[wind++] = 's';
		}
	        ws[wind] = '(';	        
	    } else
	    if (c == ')') {
	        ws[wind++] = '\\';
		if (tex_output) {
 	          ws[wind++] = 'b';
 	          ws[wind++] = 's';
		}
	        ws[wind] = ')';	        
	    } else  
	    if (c == '\\') {
	        ws[wind++] = '\\';
		if (tex_output) {
 	          ws[wind++] = 'b';
 	          ws[wind++] = 's';
		}
	        ws[wind++] = '1';
	        ws[wind++] = '3';
	        ws[wind] = '4';
	    } else
              ws[wind] = c;
	} else {
	    ws[wind++] = '\\';
	    if (tex_output) {
 	      ws[wind++] = 'b';
 	      ws[wind++] = 's';
	    }
	    ws[wind++] = '0' + c/64;
	    ws[wind++] = '0' + (c%64)/8;
	    ws[wind] =   '0' + c%8;	    
        }
    }

    return s;
}

void printcoords(int op)
{
  static unsigned int scolor1 = 0xffffffff, scolor2 = 0xffffffff;
  static double w0 = 0.0;
  char *ptr, *output;
  int i;
  double u, v, t, a;
  char c;
  char fillseq[32];
  
  if (op == 3 && brushmode == 1) {
    scolor1 = color1 | 0xc0c0c0;
    fprintf(fo, "%s rgb\n", rgbcolor(scolor1));
  } else
  if (color1 != scolor1) {
    fprintf(fo, "%s rgb\n", rgbcolor(color1));
    scolor1 = color1;
  }

  if (op == 10) {
    fprintf(fo, "%lg %lg m\n", x[0], canvash - y[0]);
    ptr = (char *)malloc(6*strlen(writing));
    utf8_to_ps_latin1(ptr, writing);
    fprintf(fo,  "%.3f F (%s) s\n", 41.2*w, ptr);
    free(ptr);
    wrlen = 0;
    return;
  }

  if (w != w0 || op == 3) {
    fprintf(fo, "%lg lw\n", ((op==3)? 24*w : w));
    if (op == 3) w0 = 0.0; else w0 = w;
  }

  if ((FILLOP >> op) & 1)
    sprintf(fillseq, "%s c", rgbcolor(color2));
  else
    strcpy(fillseq, "k");
  
  if (op == 8 && arcmode > 0) {
    a = -0.01 * M_PI / (64 * 180.0);
    x[1] = x[1] * 0.5;
    y[1] = y[1] * 0.5;
    x[0] = x[0] + x[1];
    y[0] = y[0] + y[1];
    y[2] = x[2] + y[2];
    c = 'm';
    for (i=0; i<=100; i++) {
      if (i == 1) {
	fprintf(fo, "1 0 0 t\n");
	c = 'd';
      }
      t = (i * y[2] + (100 - i)*x[2]) * a;
      u = x[0] + x[1] * cos(t);
      v = y[0] + y[1] * sin(t);
      fprintf(fo, "%lg %lg %c\n", u, canvash - v, c);
    }
    fprintf(fo, "%s\n", fillseq);
    n = 0;
    return;
  }
  if (op == 12 || op == 13) {
    fprintf(fo, "%lg %lg m\n", x[0], canvash - y[0]);
    if (boxmode & 2)
      fprintf(fo, "8 %d %g t\n", boxradius, boxratio);
    else
      fprintf(fo, "8 0 0 t\n");      
    fprintf(fo, "%lg %lg d\n", x[1], canvash - y[1]);
    fprintf(fo, "%s\n", fillseq);       
    n = 0;
    return;
  }
  if (op == 15 || op == 16) {
    n = ((y[1]-y[0])>0);
    /*    
    if (ellipsemode == 2) {
      x[0] = 2 * x[0] - x[1];
      y[0] = 2 * y[0] - y[1];      
    }
    */
    fprintf(fo, "%lg %lg m\n", (x[0]+x[1])*0.5, canvash - y[0]);
    fprintf(fo, "2 %d 0 t\n", 1-n);    
    fprintf(fo, "%lg %lg d\n", x[1], canvash - (y[0]+y[1])*0.5);
    fprintf(fo, "2 %d 0 t\n", n);    
    fprintf(fo, "%lg %lg d\n", (x[0]+x[1])*0.5, canvash - y[1]);
    fprintf(fo, "2 %d 0 t\n", n);    
    fprintf(fo, "%lg %lg d\n", x[0], canvash - (y[0]+y[1])*0.5);
    fprintf(fo, "2 %d 0 t\n", 1-n);        
    fprintf(fo, "%lg %lg d\n", (x[0]+x[1])/2, canvash - y[0]);
    fprintf(fo, "%s\n", fillseq);
    n = 0;
    return;
  }
  for (i=0; i<n; i++) {
    if (i == 0) {
      if (polygonmode && (op == 21 || op == 22)) {
	u = x[0];
	v = y[0];
	x[0] = x[1];
	y[0] = y[1];
	x[1] = 2 * u - x[0];
	y[1] = 2 * v - y[0];	  
      }
    }
    if (isnan(x[i])) {
      if (op == 24 || op == 25)
	fprintf(fo, "3 %d 0 t\n", splinemode);
      continue;
    }
    if (i == 1) {
      if (op == 6 && ticksmode) {
	fprintf(fo, "7 %d %d t\n", tt, tn);
	ticksmode = 0;
      } else
      if (op == 8) fprintf(fo, "1 0 0 t\n"); else
      if (op == 9) fprintf(fo, "6 %lg %lg t\n", angle, 4*arrowparam); else
      if (op == 21 || op == 22) {
	if (polygonmode == 2)
	  fprintf(fo, "4 %d %lg t\n", sides, ngonparam);
	else
	if (polygonmode == 3)
	  fprintf(fo, "5 %d %lg t\n", sides, ngonparam);
      } else
      if (op == 24 || op == 25)
	fprintf(fo, "3 %d 0 t\n", splinemode);
    }
    c = ((i==0)? 'm' : 'd');
    fprintf(fo, "%lg %lg %c\n", x[i], canvash - y[i], c);
  }
  fprintf(fo, "%s\n", fillseq);        
  n = 0;
}

void usage()
{
  printf("Usage: vxp2ps [-i] <inputfile> [-o <outputfile>] [-r <rescaling_factor>]\n");
  exit(0);
}

int main(int argc, char **argv)
{
  FILE *fd;
  char buf[1024], output[32];
  unsigned int ll;
  int i, j, op = -1, np, dash = 0, cap, join;
  double u;
  char *ptr;
  char *inputfile = NULL;

  inputfile = argv[1];

  if (argc <= 1) {
    printf("No input file has been specified !!\n");
    usage();
  }
  i = 1;  
  while (i < argc) {
    if (!strcmp(argv[i], "-h")) usage();
    else
    if (i == argc - 1) inputfile = argv[i];
    else
    if (!strcmp(argv[i], "-i")) inputfile = argv[++i];
    else
    if (!strcmp(argv[i], "-o")) psname = argv[++i];      
    else
    if (!strcmp(argv[i], "-r")) rescale = atof(argv[++i]);
    else
    inputfile = argv[i];
    ++i;
  }

  if (!psname) {
    psname = (char *)malloc(strlen(inputfile)+8);
    strcpy(psname, inputfile);
    ptr = strrchr(psname, '.');
    if (ptr) strcpy(ptr, ".ps"); else strcat(psname, ".ps");
  }
  
  fd = fopen(inputfile, "r");
  if (!fd) {
    fprintf(stderr, "File %s does not exist!\n", inputfile);
    exit(1);
  }

  if (strcmp(psname, "-")) {
    pdfname = (char *)malloc(strlen(psname)+16);
    strcpy(pdfname, psname);
    ptr = strrchr(pdfname, '.');
    if (ptr) strcpy(ptr, ".pdf"); else strcat(pdfname, ".pdf");
    fo = fopen(psname, "w");
  } else {
    fo = stdout;
  }
  
  if (!fo) {
    fprintf(stderr, "File %s cannot be created!\n", psname);
    exit(1);
  }

  fgets(buf, 1020, fo);
  if (!strcmp(buf, "#VXP")) {
    fprintf(stderr, "Not a VXP file. Aborting!\n");
    exit(1);
  }


  setup_tex_file(fd, buf);
  n = 0;
  fn = 1;
  ptr = NULL;
  rewind(fd);

  while (1) {
    if (feof(fd)) {
      buf[0] = '*';
      buf[1] = 0;
    } else
      fgets(buf, 1020, fd);
    i = strlen(buf) - 1;
    if (i >= 0 && buf[i] == '\n') buf[i] = '\0';    
    if (!strncmp(buf, "*canvas ", 8)) {
      sscanf(buf + 8, "%d,%d", &canvasx, &canvasy);
      width = (int)(canvasx * rescale + 0.5);
      height = (int)(canvasy * rescale + 0.5);
      canvash = canvasy;
      ps_init(fo);	
      fprintf(fo, "%g dup scale\n", rescale);	
      w = rescale * 596.0 / width;
    } else
    if (*buf == ':') {
      j = strlen(buf + 1);
      writing = realloc(writing, wrlen + j + 2);
      if (wrlen) writing[wrlen++] ='\n';
      strcpy(writing + wrlen, buf + 1);
      wrlen += j;
    } else
#ifdef HAVE_DVIPGM
    if (*buf == '=') {
      j = strlen(buf + 1);
      formula = realloc(formula, formlen + j + 2);
      if (formlen) formula[formlen++] ='\n';
      strcpy(formula + formlen, buf + 1);
      formlen += j;
    } else
#endif      
    if (buf[0] == '*') {      
      if (op >= 0 && ((FLAGOP >> op) & 1))
	printcoords(op);
      if (buf[1] == 0) break;
      if (buf[1] >= '0' && buf[1] <= '9') {
	op = atoi(buf+1);
	if (op == 6 && !strcmp(buf+3, "ticks")) ticksmode = 1;
      } else
	op = -1;
      n = 0;
      if (!strncmp(buf, "*color1 ", 8)) {
        sprintf(output, "0x%s", buf+8);
        color1 = strtol(output, NULL, 16);
      } else
      if (!strncmp(buf, "*color2 ", 8)) {
        sprintf(output, "0x%s", buf+8);
        color2 = strtol(output, NULL, 16);
      } else
      if (!strncmp(buf, "*brushmode ", 11)) {
	brushmode = atoi(buf+11);
      } else
      if (!strncmp(buf, "*arcmode ", 9)) {
	arcmode = atoi(buf+9);
      } else
      if (!strncmp(buf, "*ellipsemode ", 13)) {
	ellipsemode = atoi(buf+13);	
      } else
      if (!strncmp(buf, "*objectmode ", 12)) {
	objectmode = atoi(buf+12);
	fprintf(fo, "%d om\n", objectmode);	
      } else
      if (!strncmp(buf, "*boxmode ", 9)) {
	boxmode = atoi(buf+9);
      } else
      if (!strncmp(buf, "*splinemode ", 12)) {
	splinemode = atoi(buf+12);
      } else	
      if (!strncmp(buf, "*polygonmode ", 13)) {
	polygonmode = atoi(buf+13);
      } else	
      if (!strncmp(buf, "*boxparams ", 11)) {
	sscanf(buf+11, "%d %lg", &boxradius, &boxratio);
      } else
      if (!strncmp(buf, "*polygonparams ", 15)) {
	sscanf(buf+15, "%d %lg", &sides, &u);
	ngonparam = 8472 * u;
      } else
      if (!strncmp(buf, "*arrowheadparams ", 17)) {
	sscanf(buf+17, "%d %lg %lg", &ll, &u, &angle);
	arrowparam = 8 * u;
	fprintf(fo, "%d vp\n", ll);
      } else	
      if (!strncmp(buf, "*tickparams ", 12)) {
	int a, b;
	double c, d;
	sscanf(buf+12, "%d %d %d %d %lg %lg", &tt, &a, &b, &tn, &c, &d);
        fprintf(fo, "%d %d %lg %lg tp\n", a, b, c, d);
      } else	
      if (!strncmp(buf, "*switchpatterns", 15)) {
	ll = color2;
	color2 = color1;
	color1 = ll;
      } else	
      if (!strncmp(buf, "*texinput ", 10)) {
	sscanf(buf+10, "%d %d %d %06x", &dpi, &ascent, &opacity, &tcolor);
	wrlen = 0;
	formlen = 0;
      } else
      if (!strncmp(buf, "*textdata ", 10)) {
	sscanf(buf+10, "%06x", &tcolor);
	wrlen = 0;
	formlen = 0;
      } else	
      if (!strncmp(buf, "*textoutput ", 12)) {
	sscanf(buf+12, "%d,%d %d,%d", &text_x, &text_y, &text_w, &text_h);
        if (formlen) {
	  pgm_print();
          fn++;
	} else
	if (wrlen) {
	  fprintf(fo, "%s rgb %d %d m\n",
		  rgbcolor(tcolor), text_x, canvash - text_y);
	  ptr = (char *)malloc(6*strlen(writing));
          utf8_to_ps_latin1(ptr, writing);
          fprintf(fo,  "%.3f F (%s) s\n", 41.2*w, ptr);
          free(ptr);
          wrlen = 0;
	}
      } else
      if (!strncmp(buf, "*setlinestyle ", 14)) {
	ptr = strdup(buf+14);
	sscanf(buf+14, "%lg %d %d %[^\t\n]", &w, &cap, &join, ptr);
	w = w * 596.0 / canvasx;
	if (ptr && *ptr) {
          n = np = 0;
	  i = 0;
	  while (ptr[i]) {
	    if (ptr[i] == '=') ++n;
	    if (ptr[i] == '-') ++np;
	    ++i;
	  }
	  fprintf(fo, "[%d %d] 0 sd\n", n, np);
	  n = np = 0;
	}
	free(ptr);
      }
    } else {
      i = n + 1;
      x = (double *)realloc(x, i * sizeof(double));
      y = (double *)realloc(y, i * sizeof(double));
      if (buf[0] == '0' && buf[1] == '!') {
	x[n] = y[n] = NAN;
	n = i;
      } else
      if (sscanf(buf, "%lg,%lg", &x[n], &y[n]) == 2) n = i;      
    }
  }
    
  fprintf(fo, "%s", "showpage\n%%PageTrailer\n%%Trailer\n%%EOF\n");
  fclose(fo);
  if (pdfname) {
    sprintf(buf, "ps2pdf -dDEVICEWIDTHPOINTS=%d -dDEVICEHEIGHTPOINTS=%d %s %s",
	    width, height, psname, pdfname);
    if (system(buf));
  }
  if (dvifile) unlink(dvifile);
  return 0;
}
