/*
Copyright (c) 2004-2010, Dirk Krause
All rights reserved.

Redistribution and use in source and binary forms,
with or without modification, are permitted provided
that the following conditions are met:

* Redistributions of source code must retain the above
  copyright notice, this list of conditions and the
  following disclaimer.
* Redistributions in binary form must reproduce the above 
  opyright notice, this list of conditions and the following
  disclaimer in the documentation and/or other materials
  provided with the distribution.
* Neither the name of the Dirk Krause nor the names of
  contributors may be used to endorse or promote
  products derived from this software without specific
  prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
DAMAGE.
*/



/**	@file	dkfigsvg.c	SVG output driver module.
*/



/**	Inside the dkfigsvg module.
*/
#define DKFIGSVG_C 1



#include "dkfig.h"




#line 55 "dkfigsvg.ctr"




/**	Restrict number of decimal digits for double values.
*/
#define drd(v,o,w) dkfig_tool2_drd(v,o,w)



/**	Abbreviation.
*/
#define OI dkfig_svg_output_instruction

/**	Abbreviation.
*/
#define DRVE dk_fig_svg_drve

/**	Abbreviation.
*/
#define SVGPAT dk_fig_svg_pat

/**	Abbreviation.
*/
#define SVGSTY dk_fig_svg_style

/**	Abbreviation.
*/
#define OBJ dk_fig_object

/**	Abbreviation.
*/
#define AH dk_fig_arrow

/**	String pointer.
*/
typedef char *PCHAR;

/**	String array pointer.
*/
typedef PCHAR *PPCHAR;




/**	Output keywords.
*/
static char *kw[] = {
/*  00 */ "\n",
/*  01 */ " ",
/*  02 */ "<",
/*  03 */ ">",
/*  04 */ "/",
/*  05 */ "svg",
/*  06 */ "<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>",
/*  07 */ "!DOCTYPE svg PUBLIC",
/*  08 */ "\"-//W3C//DTD SVG 20010904//EN\"",
/*  09 */ "\"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd\"",
/*  10 */ "xmlns=\"http://www.w3.org/2000/svg\"",
/*  11 */ "xmlns:xlink=\"http://www.w3.org/1999/xlink\"",
/*  12 */ "\"-//W3C//DTD SVG 1.1//EN\"",
/*  13 */ "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\"",
/*  14 */ "x",
/*  15 */ "y",
/*  16 */ "width",
/*  17 */ "height",
/*  18 */ "viewBox",
/*  19 */ "=",
/*  20 */ "\"",
/*  21 */ "in",
/*  22 */ "px",
/*  23 */ "xmlns:svg=\"http://www.w3.org/2000/svg\"",
/*  24 */ ":",
/*  25 */ "title",
/*  26 */ "desc",
/*  27 */ "Converted by fig2vect, see http://dktools.sourceforge.net/fig2vect.html",
/*  28 */ "defs",
/*  29 */ "type=\"text/ecmascript\"",
/*  30 */ "<![CDATA[",
/*  31 */ "]]>",
/*  32 */ "script",
/*  33 */ "a",
/*  34 */ "g",
/*  35 */ "pattern",
/*  36 */ "id",
/*  37 */ "p",
/*  38 */ "style",
/*  39 */ "type=\"text/css\"",
/*  40 */ ".",
/*  41 */ "{",
/*  42 */ "}",
/*  43 */ ";",
/*  44 */ "c",
/*  45 */ "#",
/*  46 */ "font-family",
/*  47 */ "font-style",
/*  48 */ "font-weight",
/*  49 */ "font-size",
/*  50 */ "color",
/*  51 */ "text-anchor",
/*  52 */ "start",
/*  53 */ "middle",
/*  54 */ "end",
/*  55 */ ",",
/*  56 */ "serif",
/*  57 */ "sans-serif",
/*  58 */ "monospace",
/*  59 */ "normal",
/*  60 */ "italic",
/*  61 */ "bold",
/*  62 */ "fill",
/*  63 */ "stroke",
/*  64 */ "stroke-width",
/*  65 */ "none",
/*  66 */ "stroke-dasharray",
/*  67 */ "stroke-linecap",
/*  68 */ "butt",
/*  69 */ "round",
/*  70 */ "square",
/*  71 */ "stroke-linejoin",
/*  72 */ "miter",
/*  73 */ "bevel",
/*  74 */ "url",
/*  75 */ "(",
/*  76 */ ")",
/*  77 */ "text",
/*  78 */ "img",
/*  79 */ "rect",
/*  80 */ "class",
/*  81 */ "pt",
/*  82 */ "rx",
/*  83 */ "ry",
/*  84 */ "polygon",
/*  85 */ "polyline",
/*  86 */ "points",
/*  87 */ "cx",
/*  88 */ "cy",
/*  89 */ "r",
/*  90 */ "circle",
/*  91 */ "ellipse",
/*  92 */ "transform",
/*  93 */ "translate",
/*  94 */ "rotate",
/*  95 */ "rx",
/*  96 */ "ry",
/*  97 */ "-",
/*  98 */ "path",
/*  99 */ "d",
/* 100 */ "M",
/* 101 */ "L",
/* 102 */ "A",
/* 103 */ "0",
/* 104 */ "1",
/* 105 */ "z",
/* 106 */ "C",
/* 107 */ "'",
/* 108 */ "@font-face",
/* 109 */ "src: ",
/* 110 */ "format(svg)",
/* 111 */ "patternUnits=\"userSpaceOnUse\"",
/* 112 */ "image",
/* 113 */ "<!-- ",
/* 114 */ " -->",
/* 115 */ "line ",
/* 116 */ "layer ",
};

/**	Number of elements in the kw array.
*/
static size_t kw_num = sizeof(kw)/sizeof(PCHAR);




/**	Configuration option: js library
*/
static char *cmd00[] = { "js", "library", NULL };

/**	Configuration option: id
*/
static char *cmd01[] = { "id", NULL };

/**	Configuration option: onfocusin
*/
static char *cmd02[] = { "onfocusin", NULL };

/**	Configuration option: onfocusout
*/
static char *cmd03[] = { "onfocusout", NULL };

/**	Configuration option: onactivate
*/
static char *cmd04[] = { "onactivate", NULL };

/**	Configuration option: onclick
*/
static char *cmd05[] = { "onclick", NULL };

/**	Configuration option: onmousedown
*/
static char *cmd06[] = { "onmousedown", NULL };

/**	Configuration option: onmouseup
*/
static char *cmd07[] = { "onmouseup", NULL };

/**	Configuration option: onmouseover
*/
static char *cmd08[] = { "onmouseover", NULL };

/**	Configuration option: onmousemove
*/
static char *cmd09[] = { "onmousemove", NULL };

/**	Configuration option: onmouseout
*/
static char *cmd10[] = { "onmouseout", NULL };

/**	Configuration option: onload
*/
static char *cmd11[] = { "onload", NULL };

/**	Configuration option: onunload
*/
static char *cmd12[] = { "onunload", NULL };

/**	Configuration option: onabort
*/
static char *cmd13[] = { "onabort", NULL };

/**	Configuration option: onerror
*/
static char *cmd14[] = { "onerror", NULL };

/**	Configuration option: onresize
*/
static char *cmd15[] = { "onresize", NULL };

/**	Configuration option: onscroll
*/
static char *cmd16[] = { "onscroll", NULL };

/**	Configuration option: onzoom
*/
static char *cmd17[] = { "onzoom", NULL };

/**	Configuration option: onbegin
*/
static char *cmd18[] = { "onbegin", NULL };

/**	Configuration option: onend
*/
static char *cmd19[] = { "onend", NULL };

/**	Configuration option: onrepeat
*/
static char *cmd20[] = { "onrepeat", NULL };

/**	Configuration option: gs svg-font directory
*/
static char *cmd21[] = { "gs", "svg-font", "directory", NULL };



/**	Configuration options array.
*/
static char **cmds[] = {
  /*  00 */	cmd00,	/* js library */
  /*  01 */	cmd01,	/* id */
  /*  02 */	cmd02,	/* onfocusin */
  /*  03 */	cmd03,	/* onfocusout */
  /*  04 */	cmd04,	/* onactivate */
  /*  05 */	cmd05,	/* onclick */
  /*  06 */	cmd06,	/* onmousedown */
  /*  07 */	cmd07,	/* onmouseup */
  /*  08 */	cmd08,	/* onmouseover */
  /*  09 */	cmd09,	/* onmousemove */
  /*  10 */	cmd10,	/* onmouseout */
  /*  11 */	cmd11,	/* onload */
  /*  12 */	cmd12,	/* onunload */
  /*  13 */	cmd13,	/* onabort */
  /*  14 */	cmd14,	/* onerror */
  /*  15 */	cmd15,	/* onresize */
  /*  16 */	cmd16,	/* onscroll */
  /*  17 */	cmd17,	/* onzoom */
  /*  18 */	cmd18,	/* onbegin */
  /*  19 */	cmd19,	/* onend */
  /*  20 */	cmd20,	/* onrepeat */
  /*  21 */	cmd21,	/* urw font directory */
  NULL
};

/**	Numbeer of elements in the cmds array.
*/
static size_t sz_cmds = (sizeof(cmds)/sizeof(PPCHAR)) - 1;



/**	String exploder pattern. 
*/
static char exploder_pattern[] = { " \t\r\n." };


/**	File open mode.
*/
static char str_mode_open_read[] = { "r" };





/**	URW font family name: Nimbus Roman No9 L
*/
static char urw_svg_nimbus_roman_no9_l[] = {
  "Nimbus Roman No9 L"
};

/**	URW font family name: URW Gothic L
*/
static char urw_svg_urw_gothic_l[] = {
  "URW Gothic L"
};

/**	URW font family name: URW Bookman L
*/
static char urw_svg_urw_bookman_l[] = {
  "URW Bookman L"
};

/**	URW font family name: Nimbus Mono L
*/
static char urw_svg_nimbus_mono_l[] = {
  "Nimbus Mono L"
};

/**	URW font family name: Nimbus Sans L
*/
static char urw_svg_nimbus_sans_l[] = {
  "Nimbus Sans L"
};

/**	URW font family name: Nimbus Sans L
*/
static char urw_svg_nimbus_sans_condensed[] = {
  "Nimbus Sans L Condensed"
};

/**	URW font family name: Century Schoolbook L
*/
static char urw_svg_century_schoolbook_l[] = {
  "Century Schoolbook L"
};

/**	URW font family name: URW Palladio L
*/
static char urw_svg_urw_palladio_l[] = {
  "URW Palladio L"
};

/**	URW font family name: Standard Symbols L
*/
static char urw_svg_standard_symbols_l[] = {
  "Standard Symbols L"
};

/**	URW font family name: URW Chancery L
*/
static char urw_svg_urw_chancery_l[] = {
  "URW Chancery L"
};

/**	URW font family name: Dingbats
*/
static char urw_svg_dingbats[] = {
  "Dingbats"
};

/**	Names of URW font families.
*/
static char *urw_svg_font_families[] = {
/*  0 n021003l */	urw_svg_nimbus_roman_no9_l,
/*  1 n021023l */	urw_svg_nimbus_roman_no9_l,
/*  2 n021004l */	urw_svg_nimbus_roman_no9_l,
/*  3 n021004l */	urw_svg_nimbus_roman_no9_l,
/*  4 a021023l */	urw_svg_urw_gothic_l,
/*  5 a010033l */	urw_svg_urw_gothic_l,
/*  6 a010015l */	urw_svg_urw_gothic_l,
/*  7 a010035l */	urw_svg_urw_gothic_l,
/*  8 b018012l */	urw_svg_urw_bookman_l,
/*  9 b018032l */	urw_svg_urw_bookman_l,
/* 10 b018015l */	urw_svg_urw_bookman_l,
/* 11 b018035l */	urw_svg_urw_bookman_l,
/* 12 n022003l */	urw_svg_nimbus_mono_l,
/* 13 n022023l */	urw_svg_nimbus_mono_l,
/* 14 n022004l */	urw_svg_nimbus_mono_l,
/* 15 n022024l */	urw_svg_nimbus_mono_l,
/* 16 n019003l */	urw_svg_nimbus_sans_l,
/* 17 n019023l */	urw_svg_nimbus_sans_l,
/* 18 n019004l */	urw_svg_nimbus_sans_l,
/* 19 n019024l */	urw_svg_nimbus_sans_l,
/* 20 n019043l */	urw_svg_nimbus_sans_condensed,
/* 21 n019063l */	urw_svg_nimbus_sans_condensed,
/* 22 n019044l */	urw_svg_nimbus_sans_condensed,
/* 23 n019064l */	urw_svg_nimbus_sans_condensed,
/* 24 c059013l */	urw_svg_century_schoolbook_l,
/* 25 c059033l */	urw_svg_century_schoolbook_l,
/* 26 c059016l */	urw_svg_century_schoolbook_l,
/* 27 c059036l */	urw_svg_century_schoolbook_l,
/* 28 p052003l */	urw_svg_urw_palladio_l,
/* 29 p052023l */	urw_svg_urw_palladio_l,
/* 30 p052004l */	urw_svg_urw_palladio_l,
/* 31 p052024l */	urw_svg_urw_palladio_l,
/* 32 s050000l */	urw_svg_standard_symbols_l,
/* 33 z003034l */	urw_svg_urw_chancery_l,
/* 34 d050000l */	urw_svg_dingbats
};




/**	File name used when processing standard input.
*/
static char name_stdin[] = { "standard input" };




/**	Link keyword: xlink:href
*/
static char *xlc00[] = { "xlink:href", NULL };

/**	Link keyword: xlink:type
*/
static char *xlc01[] = { "xlink:type", NULL };

/**	Link keyword: xlink:role
*/
static char *xlc02[] = { "xlink:role", NULL };

/**	Link keyword: xlink:arcrole
*/
static char *xlc03[] = { "xlink:arcrole", NULL };

/**	Link keyword: xlink:title
*/
static char *xlc04[] = { "xlink:title", NULL };

/**	Link keyword: xlink:show
*/
static char *xlc05[] = { "xlink:show", NULL };

/**	Link keyword: xlink:actuate
*/
static char *xlc06[] = { "xlink:actuate", NULL };

/**	Array containing all link keywords.
*/
static char **xlcmds[] = {
  xlc00,
  xlc01,
  xlc02,
  xlc03,
  xlc04,
  xlc05,
  xlc06,
  NULL
};

/**	Number of elements in the xlcmds array.
*/
static size_t sz_xlcmds = (sizeof(xlcmds)/sizeof(PPCHAR)) - 1;

/**	Suffixes for compressed files.
*/
static char *suffix_types[] = {
  (char *)".gz",
  (char *)".bz2",
  NULL
};

/**	Hexadecimal digits.
*/
static char hex_digits[] = { "0123456789ABCDEF" };

/**	Conversion factor from pt to bp.
*/
static double pt_to_bp = DKFIG_BP_PER_INCH / DKFIG_PT_PER_INCH;

/**	Default text for hex encoded character output.
*/
static char default_encoding[] = { "&#x  ;" };

/**	Compare two values.
*/
#define COMPARE(a,b) ((a > b) ? 1 : ((a < b) ? -1 : 0))



/**	Restrict number of digits after decimal dot, use downward rounding.
	@param	x	Value to correct.
	@param	dig	Number of digits after decimal dot.
	@return	Rounding result.
*/
static
double
round_down_digits DK_P2(double,x,unsigned,dig)
{
  double back, newval;
  unsigned cc, didcc;
  int errc;
  
  newval = back = x; cc = dig; didcc = 0; errc = 0;
  while (cc--) {
    newval = dkma_mul_double_ok(back, 10.0, &errc);
    if (errc) {
      cc = 0;
    } else {
      back = newval; didcc++;
    }
  }
  back = floor(back);
  while (didcc--) {
    back = back / 10.0;
  }
  
  return back;
}



/**	Compare two pattern information structures.
	@param	l	Left pattern information structure.
	@param	r	Right pattern information structure.
	@param	cr	Comparison criteria (ignored).
	@return	Comparison result.
*/
int
dkfig_svg_comp_pat DK_P3(void *,l, void *,r, int,cr)
{
  int back = 0;
  SVGPAT *lp, *rp;
  
  lp = (SVGPAT *)l; rp = (SVGPAT *)r;
  switch(cr) {
    case 1: {
    } break;
    default: {
      if(l) {
        if(r) {
	  back = COMPARE((lp->flags),(rp->flags)) ;
	  if(!back) {
	    back = COMPARE((lp->pattp),(rp->pattp)) ;
	  }
	  /*
	  if(!back) {
	    back = COMPARE((lp->lw),(rp->lw)) ;
	  }
	  */
	  if(!back) {
	    back = COMPARE((lp->patrp),(rp->patrp)) ;
	  }
	  if(!back) {
	    back = COMPARE((lp->sred),(rp->sred)) ;
	  }
	  if(!back) {
	    back = COMPARE((lp->sgreen),(rp->sgreen)) ;
	  }
	  if(!back) {
	    back = COMPARE((lp->sblue),(rp->sblue)) ;
	  }
	  if((!back) && ((lp->flags) & 1UL)) {
	    back = COMPARE((lp->fred),(rp->fred)) ;
	  }
	  if((!back) && ((lp->flags) & 1UL)) {
	    back = COMPARE((lp->fgreen),(rp->fgreen)) ;
	  }
	  if((!back) && ((lp->flags) & 1UL)) {
	    back = COMPARE((lp->fblue),(rp->fblue)) ;
	  }
	} else {
	  back = 1;
	}
      } else {
        if(r) {
	  back = -1;
	}
      }
    } break;
  } 
  return back;
}



/**	Destroy pattern information structure.
	@param	p	Pattern information structure to destroy.
*/
static
void
svg_pat_del DK_P1(SVGPAT *,p)
{
  
  if(p) {
    
    
    
    
    
    
    
    
    
    
    DK_MEMRES(p,sizeof(SVGPAT)) ;
    dk_delete(p);
  } 
}



/**	Initialize pattern information structure.
	@param	p	Pattern information structure to initialize.
*/
static
void
svg_pat_null DK_P1(SVGPAT *,p)
{
  
  if(p) {
    DK_MEMRES(p,sizeof(SVGPAT)) ;
    
    
    
    
    
    
    
    
    
    
  } 
}



/**	Create a tolerance value to compare two double values.
	@param	d1	One value in comparison.
	@param	d2	Other value in comparison.
	@return	Comparison epsilon.
*/
static
double
create_epsilon DK_P2(double,d1, double,d2)
{
  double back = 0.000001;
  double x1, x2, min;
  x1 = fabs(d1); x2 = fabs(d2);
  min = x1;
  if(x2 < x1) { min = x2; }
  back = min * 0.000001;
  return back;
}



/**	Compare two style information structures.
	@param	l	Left style information structure.
	@param	r	Right style information structure.
	@param	cr	Comparison criteria (ignored).
	@return	Comparison result.
*/
int
dkfig_svg_comp_style DK_P3(void *,l, void *,r, int,cr)
{
  int back = 0;
  SVGSTY *lp, *rp;
  
  lp = (SVGSTY *)l; rp = (SVGSTY *)r;
  switch(cr) {
    case 1: {
      
    } break;
    default: {
      if(l) {
        if(r) {
	  
	  if(!back) {
	    back = COMPARE((lp->flags),(rp->flags)) ;
	  }
	  
	  
	  
	  
          if((lp->flags) & DKFIG_SVG_FL_TEXT) {
	    
	    if(!back) {
	      back = COMPARE((lp->sred),(rp->sred)) ;
	    }
	    if(!back) {
	      back = COMPARE((lp->sgreen),(rp->sgreen)) ;
	    }
	    if(!back) {
	      back = COMPARE((lp->sblue),(rp->sblue)) ;
	    }
	    /*
	      2004/11/22 Bugfix:
	      The following comparisons must be executed
	      only if there is no comparison result yet!
	    */
            if(!back) {
	      if(lp->fonth) {
	        if(rp->fonth) {
	          back = dkfig_fnt_comp_fonth(
		    (void *)(lp->fonth),(void *)(rp->fonth), 0
		  ); 
	        } else {
	          back = 1;
	        }
	      } else {
	        if(rp->fonth) {
	          back = -1;
	        }
	      }
	    }
	    if(!back) {
	      if(lp->talign > rp->talign) {
	        back = 1;
	      } else {
	        if(lp->talign < rp->talign) {
	          back = -1;
	        }
	      }
	    }
	  } else {
	    
	    if((lp->flags) & DKFIG_SVG_FL_STROKE) {
	      if(!back) {
	        back = COMPARE((lp->lw),(rp->lw)) ;
	      }
	      if(!back) {
	        back = COMPARE((lp->ls),(rp->ls)) ;
	      }
	      if(!back) {
	        back = COMPARE((lp->lc),(rp->lc)) ;
	      }
	      if(!back) {
	        back = COMPARE((lp->lj),(rp->lj)) ;
	      }
	      if(!back) {
	        back = COMPARE((lp->sred),(rp->sred)) ;
	      }
	      if(!back) {
	        back = COMPARE((lp->sgreen),(rp->sgreen)) ;
	      }
	      if(!back) {
	        back = COMPARE((lp->sblue),(rp->sblue)) ;
	      }
	      if(!back) {
	        double epsilon;
	        epsilon = create_epsilon(lp->sv, rp->sv);
	        if(lp->sv > (rp->sv + epsilon)) {
	          back = 1;
	        } else {
	          if(rp->sv > (lp->sv + epsilon)) {
		    back = -1;
		  }
	        }
	      }
	    }
	    if((!back) && ((lp->flags) & DKFIG_SVG_FL_FILL)) {
	      if(lp->pat) {
	        if(rp->pat) {
	          back = dkfig_svg_comp_pat((void *)(lp->pat),(void *)(rp->pat), 0);
	        } else {
	          back = 1;
	        }
	      } else {
	        if(rp->pat) {
	          back = -1;
	        } else {
	          back = COMPARE((lp->fred),(rp->fred)) ;
		  if(!back) {
		    back = COMPARE((lp->fgreen),(rp->fgreen)) ;
		  }
		  if(!back) {
		    back = COMPARE((lp->fblue),(rp->fblue)) ;
		  }
	        }
	      }
	    }
	  }
	} else { back = -1; }
      } else {
        if(r) { back = -1; }
      }
    } break;
  } 
  return back;
}



/**	Destroy style information structure.
	@param	s	Style information structure to destroy.
*/
static
void
svg_style_del DK_P1(SVGSTY *,s)
{
  
  if(s) {
    
    
    
    
    
    
    
    
    
    
    DK_MEMRES(s,sizeof(SVGSTY)) ;
    dk_delete(s);
  } 
}



/**	Initialize a style information structure.
	@param	s	Style information structure.
*/
static
void
svg_style_null DK_P1(SVGSTY *,s)
{
  if(s) {
    DK_MEMRES(s,sizeof(SVGSTY)) ;
    s->pat = NULL;
    s->fonth = NULL;
    s->sv = 1.0;
  }
}



/**	Compare two attribute structures or compare one structure against a
	class id.
	@param	l	Left attribute to compare.
	@param	r	Right attribute to compare.
	@param	cr	Comparison criteria (ignored).
	@return	Comparison result.
*/
int
dkfig_svg_comp_attr DK_P3(void *,l, void *,r, int,cr)
{
  int back = 0;
  dk_fig_svg_attr *lp, *rp; int *ip;
  if(l) {
    if(r) {
      lp = (dk_fig_svg_attr *)l;
      switch(cr) {
        case 1: {	/* search for classid */
	  ip = (int *)r;
	  if((lp->classid) > *ip) {
	    back = 1;
	  } else {
	    if((lp->classid) < *ip) {
	      back = -1;
	    }
	  }
	} break;
	default: {	/* compare by classid */
	  rp = (dk_fig_svg_attr *)r;
	  if((lp->classid) > (rp->classid)) {
	    back = 1;
	  } else {
	    if((lp->classid) < (rp->classid)) {
	      back = -1;
	    }
	  }
	} break;
      }
    } else {
      back = 1;
    }
  } else {
    if(r) { back = -1; }
  }
  return back;
}



/**	Destroy attribute structure, release memory associated with it.
	@param	a	Attribute structure to destroy.
*/
static
void
dkfig_svg_attr_del DK_P1(dk_fig_svg_attr *,a)
{
  char *ptr;
  
  if(a) {
    if(a->value) {
      ptr = a->value; 
      dk_delete(ptr);
      a->value = NULL;
    }
    dk_delete(a);
  } 
}



/**	Create new attribute structure, initialize it.
	@param	clid	Class ID.
	@param	v	Attribute value.
	@return	Pointer to new structure on success, NULL on error.
*/
static
dk_fig_svg_attr *
dkfig_svg_attr_new DK_P2(int,clid, char *,v)
{
  dk_fig_svg_attr *back = NULL;
  
  if(v) {
    back = dk_new(dk_fig_svg_attr,1);
    if(back) {
      back->classid = clid;
      back->value = dkstr_dup(v);
      if(!(back->value)) {
        dkfig_svg_attr_del(back);
	back = NULL;
      }
    }
  } 
  return back;
}



/**	Write one keyword from the list.
	@param	oi	OI structure.
	@param	kn	Index of keyword in \arg kw array.
	@return	1 on success, 0 on error.
*/
static
int
kw_out DK_P2(OI *,oi,size_t,kn)
{
  int back = 0;
  if(kn < kw_num) {
    dkstream_puts(oi->s, kw[kn]);
    back = 1;
  }
  return back;
}



/**	Put double to output.
	@param	oi	OI structure.
	@param	x	Value to write.
	@param	w	Number of digits after decimal dot.
*/
static
void
put_double DK_P3(OI *,oi, double,x, int,w)
{
  dkstream_puts_double(oi->s, drd(x, oi->c, w));
}



/**	Convert double value coordinate x to SVG.
	@param	oi	OI structure.
	@param	x	Value to convert.
	@return	Converted value.
*/
static
double
ccdx DK_P2(OI *,oi, double,x)
{
  double back;
  back = dkma_add_double_ok(
    dkma_mul_double_ok(oi->mx, x, &(oi->me)),
    oi->nx,
    &(oi->me)
  );
  return back;
}



/**	Convert double value coordinate y to SVG.
	@param	oi	OI structure.
	@param	y	Value to convert.
	@return	Converted value.
*/
static
double
ccdy DK_P2(OI *,oi, double,y)
{
  double back;
  back = dkma_add_double_ok(
    dkma_mul_double_ok(oi->my, y, &(oi->me)),
    oi->ny,
    &(oi->me)
  );
  return back;
}



/**	Convert double value coordinate radius to SVG.
	@param	oi	OI structure.
	@param	r	Value to convert.
	@return	Converted value.
*/
static
double
ccdr DK_P2(OI *,oi, double,r)
{
  double back;
  back = dkma_mul_double_ok(oi->mx, r, &(oi->me));
  return back;
}



/**	Convert double value coordinate (line width) to SVG.
	@param	oi	OI structure.
	@param	w	Value to convert.
	@param	use_enl	Enlighten look (apply factor 1/2).
	@return	Converted value.
*/
static
double
ccdl DK_P3(OI *,oi, double,w, int,use_enl)
{
  double back;
  back = 0.9 * w;
  if(use_enl) {
    if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
      back = 0.5 * back;
    }
  }
  return back;
}



/**	Convert long value coordinate x to SVG.
	@param	oi	OI structure.
	@param	x	Value to convert.
	@return	Converted value.
*/
static
double
cclx DK_P2(OI *,oi, long,x)
{
  double back;
  back = ccdx(oi, dkma_l_to_double(x));
  return back;
}



/**	Convert long value coordinate y to SVG.
	@param	oi	OI structure.
	@param	y	Value to convert.
	@return	Converted value.
*/
static
double
ccly DK_P2(OI *,oi, long,y)
{
  double back;
  back = ccdy(oi, dkma_l_to_double(y));
  return back;
}



/**	Convert long value coordinate (radius) to SVG.
	@param	oi	OI structure.
	@param	r	Value to convert.
	@return	Converted value.
*/
static
double
cclr DK_P2(OI *,oi, long,r)
{
  double back;
  back = ccdr(oi, dkma_l_to_double(r));
  return back;
}



/**	Convert long value coordinate (line width) to SVG.
	@param	oi	OI structure.
	@param	w	Value to convert.
	@param	use_enl	Flag: Enlighten look (apply factor 1/2).
	@return	Converted value.
*/
static
double
ccll DK_P3(OI *,oi, long,w, int,use_enl)
{
  double back;
  back = ccdl(oi, dkma_l_to_double(w), use_enl);
  return back;
}



/**	Initialize DRVE structure.
	@param	p	Pointer to structure.
*/
static
void
svg_drve_init DK_P1(dk_fig_svg_drve *,p)
{
  
  if(p) {
    p->st1 = p->st2 = p->st3 = NULL;
    p->attr = NULL; p->attri = NULL;
    p->xl   = NULL; p->xli   = NULL;
  }
  
}


/**	Free memory, check pointer before freeing.
*/
#define MEMFREE(x) if(x) { ptr = x; dk_delete(ptr); } x = NULL;



/**	Destroy DRVE structure, release memory associated with it.
	@param	p	DRVE structure to destroy.
*/
static
void
svg_drve_delete DK_P1(dk_fig_svg_drve *,p)
{
  dk_fig_svg_attr *a;
  
  if(p) {
    p->st1 = p->st2 = p->st3 = NULL;
    if(p->attri) {
      
      dksto_it_reset(p->attri);
      while((a = (dk_fig_svg_attr *)dksto_it_next(p->attri)) != NULL) {
        dkfig_svg_attr_del(a);
      }
      dksto_it_close(p->attri);
    } p->attri = NULL;
    if(p->attr) {
      dksto_close(p->attr);
    } p->attr = NULL;
    if(p->xli) {
      
      dksto_it_reset(p->xli);
      while((a = (dk_fig_svg_attr *)dksto_it_next(p->xli)) != NULL) {
        dkfig_svg_attr_del(a);
      }
      dksto_it_close(p->xli);
    } p->xli = NULL;
    if(p->xl) {
      dksto_close(p->xl);
    } p->xl = NULL;
    dk_delete(p);
  } 
}



/**	Create new DRVE structure, initialize it.
	@return	Pointer to new DRVE structure on success, NULL on error.
*/
static
dk_fig_svg_drve *
svg_drve_new DK_P0()
{
  dk_fig_svg_drve *back = NULL;
  
  back = dk_new(dk_fig_svg_drve,1);
  if(back) {
    svg_drve_init(back);
  } 
  return back;
}



/**	Add a xlink:xxx="xxx" attribute to DRVE.
	@param	oi	OI structure.
	@param	dr	DRVE structure.
	@param	clid	Class ID.
	@param	v	Value for entry.
	@return	1 on success, 0 on error.
*/
static
int
svg_drve_add_xla DK_P4(OI *,oi, dk_fig_svg_drve *,dr, int,clid, char *,v)
{
  int back = 0; dk_fig_svg_attr *a; char *nn;
  
  if(dr) {
    if(!(dr->xl)) {
      dr->xl = dksto_open(0);
      if(dr->xl) {
        dksto_set_comp(dr->xl, dkfig_svg_comp_attr, 0);
      }
    }
    if(dr->xl) {
      if(!(dr->xli)) {
        dr->xli = dksto_it_open(dr->xl);
      }
      if(dr->xli) {
        if(v) {
	  a = (dk_fig_svg_attr *)dksto_it_find_like(
	    dr->xli, (void *)(&clid), 1
	  );
	  if(a) {
	    nn = dkstr_dup(v);
	    if(nn) {
	      if(a->value) {
	        char *ptr;
		ptr = a->value;
		/* WARNING: Already defined */
		dkfig_tool2_msg3(oi->c, DK_LOG_LEVEL_WARNING, 93, 92, (xlcmds[clid])[0]);
		dk_delete(ptr);
		a->value = NULL;
	      }
	      a->value = nn; back = 1;
	    }
	  } else {
            a = dkfig_svg_attr_new(clid, v);
	    if(a) {		
	      if(dksto_add(dr->xl, (void *)a)) {
	        back = 1;	
	      } else {	
	        dkfig_svg_attr_del(a);
	      }
	    }
	  }
	}
      }
    }
  } 
  return back;
}



/**	Add attribute to DRVE.
	@param	oi	OI structure.
	@param	dr	DRVE structure.
	@param	clid	Class ID.
	@param	v	Value for attribute.
	@return	1 on success, 0 on error.
*/
static
int
svg_drve_add_attr DK_P4(OI *,oi, dk_fig_svg_drve *,dr, int,clid, char *,v)
{
  int back = 0; dk_fig_svg_attr *a; char *nn;
  
  if(dr) {
    if(!(dr->attr)) {	
      dr->attr = dksto_open(0);
      if(dr->attr) {	
        dksto_set_comp(dr->attr, dkfig_svg_comp_attr, 0);
      }
    }
    if(dr->attr) {	
      if(!(dr->attri)) {	
        dr->attri = dksto_it_open(dr->attr);
      }
      if(dr->attri) {	
        if(v) {		
	  a = (dk_fig_svg_attr *)dksto_it_find_like(
	    dr->attri, (void *)(&clid), 1
	  );
	  if(a) {
	    nn = dkstr_dup(v);
	    if(nn) {
	      if(a->value) {
	        char *ptr;
		
		/* WARNING: Already defined */
		dkfig_tool2_msg3(oi->c, DK_LOG_LEVEL_WARNING, 93, 92, (cmds[clid])[0]);
		ptr = a->value;
		dk_delete(ptr);
		a->value = NULL;
	      }
	      a->value = nn;
	      back = 1;
	    }
	  } else {
            a = dkfig_svg_attr_new(clid, v);
	    if(a) {		
	      if(dksto_add(dr->attr, (void *)a)) {
	        back = 1;	
	      } else {	
	        dkfig_svg_attr_del(a);
	      }
	    }
	  }
        }
      }
    }
  } 
  return back;
}



/**	Start a new SVG tag.
	@param	oi	OI structure.
	@param	n	Index of tag name in kw array.
*/
static
void
begin_tag DK_P2(OI *,oi, size_t,n)
{
  
  kw_out(oi, 2);
  if(((oi->c)->opt1) & DKFIG_OPT_SVG_EMBEDDED) {
    kw_out(oi, 5);
    kw_out(oi, 24);
  }
  kw_out(oi, n);
  
}



/**	Finish an SVG tag.
	@param	oi	OI structure.
*/
static
void
finish_tag DK_P1(OI *,oi)
{
  
  kw_out(oi, 4);
  kw_out(oi, 3);
  kw_out(oi, 0);
  
}



/**	Write a closing SVG tag.
	@param	oi	OI structure.
	@param	n	Index of tag name in kw array.
*/
static
void
end_tag DK_P2(OI *,oi, size_t,n)
{
  
  kw_out(oi, 2); kw_out(oi, 4);
  if(((oi->c)->opt1) & DKFIG_OPT_SVG_EMBEDDED) {
    kw_out(oi, 5); kw_out(oi, 24);
  }
  kw_out(oi, n); kw_out(oi, 3); kw_out(oi, 0);
  
}



/**	Reset OI structure.
	@param	oi	OI structure.
*/
static
void
null_oi DK_P1(OI *,oi)
{
  
  oi->c = NULL;
  oi->d = NULL;
  oi->s = NULL;
  oi->dro = NULL;
  oi->xmin = oi->xmax = oi->ymin = oi->ymax = 0L;
  oi->mx = oi->nx = oi->my = oi->ny = 0.0;
  oi->me = 0;
  oi->fl = NULL;
  oi->fli = NULL;
  oi->pat = NULL;
  oi->pati = NULL;
  oi->sty = NULL;
  oi->styi = NULL;
  oi->o = NULL;
  oi->jsl = NULL; oi->jsli = NULL; oi->njsl = 0UL;
  oi->spcp = 0;
  oi->errprinted = 0;
  oi->npat = oi->nsty = 0UL;
  oi->lpat = oi->lsty = (size_t)0;
  oi->urw_dir = NULL;
  oi->fnused = NULL;
  oi->prep_mods = 0;
  oi->spcpass = 0;
  oi->fontmap = NULL;
  
}



/**	Calculate coefficients for transformations.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
establish_coord_transformation DK_P1(OI *,oi)
{
  int back = 1;
  double xmin, xmax, ymin, ymax, cxmin, cxmax, cymin, cymax;
  
  oi->me = 0;
  /*
    Get minima and maxima in Fig resolution.
  */
  xmin = dkfig_tool_bb_get_xmin(&(oi->d->dbb));
  xmax = dkfig_tool_bb_get_xmax(&(oi->d->dbb));
  ymin = dkfig_tool_bb_get_ymin(&(oi->d->dbb));
  ymax = dkfig_tool_bb_get_ymax(&(oi->d->dbb));
  /*
    Set scale factors to switch from Fig resolution
    to normal resolution.
  */
  oi->mx = dkma_div_double_ok( 72.0, (oi->d)->fres, &(oi->me));
  oi->my = oi->mx;
  if(!dkfig_tool_invert_y(oi->d)) {
    oi->my = 0.0 - oi->my;
  } 
  /*
    Calculate minima and maxima after resolution change.
  */
  xmin = dkma_mul_double_ok(xmin, oi->mx, &(oi->me));
  xmax = dkma_mul_double_ok(xmax, oi->mx, &(oi->me));
  ymin = dkma_mul_double_ok(ymin, oi->my, &(oi->me));
  ymax = dkma_mul_double_ok(ymax, oi->my, &(oi->me));
  /*
    Maximum/minimum swap if necessary.
  */
  if(xmax < xmin) {
    cxmin = xmin; xmin = xmax; xmax = cxmin;
  }
  if(ymax < ymin) {
    cxmin = ymin; ymin = ymax; ymax = cxmin;
  }
  /*
    Change to int values.
  */
  
  if(((oi->c)->svgs) == DKFIG_SVG_VP_INCHES) {
    /*
      Rounding in multiples of 9 produces 1/8 inch.
      So width/height specification in inches is restricted
      to 3 digits after decimal dot.
    */
    
    cxmin = dkma_mul_double_ok(9.0, floor(xmin/9.0), &(oi->me));
    cymin = dkma_mul_double_ok(9.0, floor(ymin/9.0), &(oi->me));
    cxmax = dkma_mul_double_ok(9.0, ceil(xmax/9.0), &(oi->me));
    cymax = dkma_mul_double_ok(9.0, ceil(ymax/9.0), &(oi->me));
    
  } else {
    /*
      Simple rounding if no inches.
    */
    cxmin = floor(xmin); cxmax = ceil(xmax);
    cymin = floor(ymin); cymax = ceil(ymax);
  }
  
  
  /*
    Calculate shiftings.
    First move xmin to 0, add half of the empty space to get
    figure centered in output file.
  */
  oi->nx = dkma_add_double_ok(
    dkma_sub_double_ok(0.0, xmin, &(oi->me)),
    (0.5 * dkma_sub_double_ok(
      dkma_sub_double_ok(cxmax, cxmin, &(oi->me)),
      dkma_sub_double_ok(xmax, xmin, &(oi->me)),
      &(oi->me)
    )),
    &(oi->me)
  );
  oi->ny = dkma_add_double_ok(
    dkma_sub_double_ok(0.0, ymin, &(oi->me)),
    (0.5 * dkma_sub_double_ok(
      dkma_sub_double_ok(cymax, cymin, &(oi->me)),
      dkma_sub_double_ok(ymax, ymin, &(oi->me)),
      &(oi->me)
    )),
    &(oi->me)
  );
  
  
  
  oi->xmin = 0L;
  oi->ymin = 0L;
  oi->xmax = dkma_double_to_l(ceil(dkma_sub_double_ok(cxmax, cxmin, &(oi->me))));
  oi->ymax = dkma_double_to_l(ceil(dkma_sub_double_ok(cymax, cymin, &(oi->me))));
  if(oi->me) { back = 0; }
  
  return back;
}



/**	Decide how to process an object.
	0 = "normal" object (polyline/polygon, spline, arc, ellipse)
	1 = text object
	2 = included image.
	@param	o	Fig object.
	@return	Selection how to process the object.
*/
static
int
get_how DK_P1(dk_fig_object *,o)
{
  int back = 0;
  if(o->objtype == DK_FIG_OBJ_TEXT) {
    back = 1;
  }
  if((o->objtype == DK_FIG_OBJ_POLYLINE) && (o->subtype == 5)) {
    back = 2;
  }
  return back;
}



/**	Register pattern. Return a pointer to an existing
	pattern in the pattern collection or add a new
	pattern to the collection.
	@param	oi	OI structure.
	@param	src	SVG pattern (source).
	@return	Pointer to existing or new pattern structure or NULL on error.
*/
static
SVGPAT *
svg_pat_register DK_P2(OI *,oi, SVGPAT *,src)
{
  SVGPAT *back = NULL;
  
  
  
  
  
  
  
  
  
  
  
  back = (dk_fig_svg_pat *)dksto_it_find_like(oi->pati, (void *)src, 0);
  if(!back) {	
    back = dk_new(SVGPAT,1);
    if(back) {	
      
      
      
      
      
      
      
      
      
      
      DK_MEMCPY(back,src,sizeof(SVGPAT)) ;
      
      
      
      
      
      
      
      
      
      
      if(!dksto_add(oi->pat, (void *)back)) {
        
        dk_delete(back); back = NULL;
      }
    }
  } 
  return back;
}



/**	Register an SVG style in the style collection.
	Create a new entry in the collection if necessary
	or return pointer to an existing entry.
	@param	oi	OI structure.
	@param	st	SVG style information structure.
	@return	Pointer to exisiting or new style information structure
	or NULL on error.
*/
static
SVGSTY *
svg_style_register DK_P2(OI *,oi, SVGSTY *,st)
{
  SVGSTY *back = NULL;
  
  back = (dk_fig_svg_style *)dksto_it_find_like(oi->styi, (void *)st, 0);
  if(!back) {	
    back = dk_new(SVGSTY,1);
    if(back) {	
      DK_MEMCPY(back,st,sizeof(SVGSTY)) ;
      if(!dksto_add(oi->sty, (void *)back)) {
        
        dk_delete(back); back = NULL;
      }
    }
  }
  
  
  if(back) {
    
    
  }
  
  return back;
}



/**	Attach a new driver-specific extension to each drawing object.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
attach_drve DK_P1(OI *,oi)
{
  int back = 1; 
  dk_fig_object *o;
  
  dksto_it_reset(oi->fli);
  while((o = (dk_fig_object *)dksto_it_next(oi->fli)) != NULL) {
    oi->o = o;
    
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, o->lineno);
    }
    o->drve = svg_drve_new();
    if(!(o->drve)) {
      back = 0;	
      /* MEMORY */
      dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 11);
    }
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, 0UL);
    }
  }
  if(!((oi->dro)->drve)) {
    (oi->dro)->drve = svg_drve_new();
    if(!((oi->dro)->drve)) {
      back = 0;
      /* MEMORY */
      dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 11);
    }
  }
  
  return back;
}



/**	Store the name of a file containing JavaScript code.
	@param	oi	OI structure.
	@param	vptr	File name.
	@return	1 on success, 0 on error.
*/
static
int
set_js_library DK_P2(OI *,oi, char *,vptr)
{
  int back = 0;
  dk_fig_opt *fo;
  
  if(vptr) {
    back = 1;
    if(!(oi->jsl)) {
      oi->jsl = dksto_open(0);
      if(oi->jsl) {
        dksto_set_comp(oi->jsl, dkfig_opt_compare, 0);
      }
    }
    if(oi->jsl) {
      if(!(oi->jsli)) {
        oi->jsli = dksto_it_open(oi->jsl);
      }
      if(oi->jsli) {
        fo = dkfig_opt_new(oi->njsl, vptr);
	oi->njsl += 1UL;
	if(fo) {
	  if(!dksto_add(oi->jsl, (void *)fo)) {
	    back = 0;
	    dkfig_opt_delete(fo); fo = NULL;
	    /* MEMORY */
	    dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 11);
	  }
	} else {
	  back = 0;
	  /* MEMORY */
	  dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 11);
	}
      } else {
        back = 0;
	/* MEMORY */
	dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 11);
      }
    } else {
      back = 0;
      /* MEMORY */
      dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 11);
    }
  } 
  return back;
}



/**	Save the name of the directory containing SVG fonts derived from the
	URW fonts.
	@param	oi	OI structure.
	@param	vptr	Directory name.
	@return	1 on success, 0 on error.
*/
static
int
set_urw_dir DK_P2(OI *,oi, char *,vptr)
{
  int back = 0;
  char *cptr, *nn;
  if(vptr) {
    nn = dkstr_dup(vptr);
    if(nn) {
      back = 1;
      if(oi->urw_dir) {
        cptr = oi->urw_dir;
	dk_delete(cptr);
	oi->urw_dir = NULL;
      }
      oi->urw_dir = nn;
    }
  }
  return back;
}



/**	Process one storage containing saved options from the configuration
	file to check for driver-specific options.
	There are separated storages for global options, for the base driver,
	the configuration-specific options and command line options.
	@param	oi	OI structure.
	@param	it	Iterator for storage to process.
	@return	1 on success, 0 on error.
*/
static
int
scan_it_options DK_P2(OI *,oi, dk_storage_iterator_t *,it)
{
  int back = 1;
  dk_fig_opt *fo;
  char *buffer, *sptr, *vptr; size_t sz;
  char *parts[16]; size_t xsz; int i;
  
  sz = 1 + ((oi->c)->lcfge);
  buffer = dk_new(char,sz);
  if(buffer) {
    dksto_it_reset(it);
    while((fo = (dk_fig_opt *)dksto_it_next(it)) != NULL) {
      if(fo->name) { 
        if((oi->c)->app) {
	  
	  dkapp_set_source_lineno((oi->c)->app, fo->number);
	}
        if(strlen(fo->name) < sz) {	
	  strcpy(buffer, fo->name);
	  vptr = sptr = NULL;
	  vptr = dkstr_chr(buffer, '=');
	  if(vptr) {			
	    *vptr++ = '\0';
	    vptr = dkstr_start(vptr, NULL);
	    if(vptr) { dkstr_chomp(vptr, NULL); }
	  }
	  sptr = dkstr_start(buffer, NULL);
	  if(sptr) {			
	    dkstr_chomp(sptr, NULL);
	    xsz = sizeof(parts)/sizeof(PCHAR);
            if(dkstr_explode(parts,xsz,sptr,exploder_pattern)) {
	      
	      i = dkstr_find_multi_part_abbr(parts, cmds, '$', 1);
	      
	      switch(i) {
	        case 0: {	/* js library */
		  back = set_js_library(oi, vptr);
		  fo->used = 0x01;
		  oi->prep_mods = 1;
		} break;
		case 21: {	/* URW font directory */
		  back = set_urw_dir(oi, vptr);
		  fo->used = 0x01;
		} break;
	      }
	    }
	  }
	}
      }
    }
    dk_delete(buffer); buffer = NULL; sz = 0;
  } else {
    back = 0;
    if((oi->c)->app) {
      dkapp_err_memory((oi->c)->app, 1, sz);
    }
  } 
  return back;
}



/**	Re-read the saved options from the configuration file to process the
	driver-specific options.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
scan_options DK_P1(OI *,oi)
{
  int back = 1;
  char *oldsrcfile; unsigned long oldsrcno;
  
  if((oi->c)->app) {
    oldsrcfile = dkapp_get_source_filename((oi->c)->app);
    oldsrcno = dkapp_get_source_lineno((oi->c)->app);
    dkapp_set_source_filename((oi->c)->app, (oi->c)->cfgfn);
    dkapp_set_source_lineno((oi->c)->app, 0UL);
  }
  if(((oi->c)->optg) && ((oi->c)->optgi)) {
    if(!scan_it_options(oi, (oi->c)->optgi)) { back = 0; }
  }
  if(((oi->c)->optb) && ((oi->c)->optbi)) {
    if(!scan_it_options(oi, (oi->c)->optbi)) { back = 0; }
  }
  if(((oi->c)->optd) && ((oi->c)->optdi)) {
    if(!scan_it_options(oi, (oi->c)->optdi)) { back = 0; }
  }
  if((oi->c)->app) {
    dkapp_set_source_filename((oi->c)->app, NULL);
  }
  if(((oi->c)->opt) && ((oi->c)->opti)) {
    if(!scan_it_options(oi, (oi->c)->opti)) { back = 0; }
  }
  if((oi->c)->app) {
    dkapp_set_source_filename((oi->c)->app, oldsrcfile);
    dkapp_set_source_lineno((oi->c)->app, oldsrcno);
  }
  
  return back;
}



/**	Handle special comments attached to an object.
	@param	oi	OI structure.
	@param	obj	Current object.
	@param	it	Iterator for special comments storage.
	@param	docroot	Flag: Processing document level comments (1).
	@param	use_svg_spec	Flag: Use SVG related special comments.
	@return	1 on success, 0 on error.
*/
static
int
handle_spc_for_object DK_P5(OI *,oi, dk_fig_object *,obj, dk_storage_iterator_t *,it, int,docroot, int,use_svg_spec)
{
  int back = 1;
  dk_fig_opt *fo;
  char mybuffer[128], *parts[16], *myline, *lptr, *cptr, *vptr;
  size_t sz; int i;
  int handled;
  unsigned long oldsrcno = 0UL;
  
  if((oi->c)->app) {
    oldsrcno = dkapp_get_source_lineno((oi->c)->app);
  }
  if(it) {
    dksto_it_reset(it);
    while((fo = (dk_fig_opt *)dksto_it_next(it)) != NULL) {
      if((oi->c)->app) {
        dkapp_set_source_lineno((oi->c)->app, fo->number);
      }
      myline = NULL; handled = 0;
      if(fo->name) {
        sz = strlen(fo->name);
	if(sz < sizeof(mybuffer)) {
	  strcpy(mybuffer, fo->name);
	  lptr = mybuffer;
	} else {
	  myline = dkstr_dup(fo->name);
	  lptr = myline;
	}
	if(lptr) {
	  cptr = dkfig_opt_special_comment_contents(lptr, kw[5]);
	  if((cptr) && (use_svg_spec)) {
	    vptr = dkstr_chr(cptr, '=');
	    if(vptr) {
	      *(vptr++) = '\0';
	      vptr = dkstr_start(vptr, NULL);
	      if(vptr) { dkstr_chomp(vptr, NULL); }
	      cptr = dkstr_start(cptr, NULL);
	      if(cptr) {
	        dkstr_chomp(cptr, NULL);
		sz = sizeof(parts)/sizeof(PCHAR);
		if(dkstr_explode(parts,sz,cptr,exploder_pattern)) {
		  i = dkstr_find_multi_part_abbr(parts,cmds,'$',1);
		  switch(i) {
		    case -1: {	/* not in cmds list */
		      int j;
		      j = dkstr_find_multi_part_abbr(parts,xlcmds,'$',1);
		      if(j > -1) {
		        if(svg_drve_add_xla(oi, (DRVE *)(obj->drve), j, vptr)) {
			  handled = 1;
			} else {
			  back = 0;
			  /* ERROR: MEMORY */
			  dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 11);
			}
		      }
		    } break;
		    case 0: {	/* js library */
		      handled = 1;
		      if(docroot) {
		        
		        back = set_js_library(oi, vptr);
			oi->prep_mods = 1;
		      } else {
		        /* ERROR: Only in document level comments */
			dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_WARNING, 94);
		      }
		    } break;
		    case 21: {	/* URW font directory */
		      back = set_urw_dir(oi, vptr);
		      handled = 1;
		    } break;
		    default: {
		      if(svg_drve_add_attr(oi, (DRVE *)(obj->drve), i, vptr)) {
		        handled = 1;
		      } else {
		        back = 0;
			/* ERROR: MEMORY */
			dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 11);
		      }
		      if((i >= 2) && (i <= 20)) {
		        oi->prep_mods = 1;
		      }
		    } break;
		  }
		}
	      }
	    }
	  }
	}
      }
      if(myline) {
        dk_delete(myline); myline = NULL;
      }
      if(!handled) {
        i = dkfig_opt_process_special_comment(oi->c, fo->name, kw[5], docroot);
	if((oi->spcpass) == 0) {
	  dkfig_tool2_report_special_comment(oi->c, fo, i);
	}
      }
    }
  }
  if((oi->c)->app) {
    dkapp_set_source_lineno((oi->c)->app, oldsrcno);
  }
  
  return back;
}



/**	Process the document level special comments.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
use_dlspc DK_P1(OI *,oi)
{
  int back = 1;
  
  back = handle_spc_for_object(oi, oi->dro, (oi->d)->dlsci, 1, 1);
  
  return back;
}



/**	Prepare each object for output.
	Create references to patterns and styles in the pattern and style
	collections, create new collection entries if necessary.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
prepare_objects DK_P1(OI *,oi)
{
  int back = 1;
  unsigned long backupopt1, backupopt2;
  int how, must_draw, backupia;
  dk_fig_object *o;
  SVGSTY style, *pstyle; SVGPAT pattern, *ppattern;
  dk_fig_dcc dcc;
  
  dksto_it_reset(oi->fli);
  while((oi->o = (dk_fig_object *)dksto_it_next(oi->fli)) != NULL) {
    o = oi->o;
    if(back) {
      backupopt1 = (oi->c)->opt1;
      backupopt2 = (oi->c)->opt2;
      backupia = (oi->c)->image_align;
      if((oi->c)->app) {
        dkapp_set_source_lineno((oi->c)->app, (oi->o)->lineno);
      }
      oi->me = 0;
      if((oi->o)->osci) {
        if(!handle_spc_for_object(oi, oi->o, (oi->o)->osci, 0, 1)) {
          back = 0;	
        }
      }
      if(back) {
        how = 0; must_draw = 1;
        if(o->drve) {
          svg_style_null(&style);
          svg_pat_null(&pattern);
          how = get_how(o);
          switch(how) {
            case 1: {	/* text */
  	    dk_fig_text *t;
  	    svg_style_null(&style);
  	    style.flags = DKFIG_SVG_FL_TEXT;
  	    dkfig_tool_fill_dcc(oi->d, &dcc, (o->fpd).pc);
	    /*
	      2004/11/22
	      style.fred = ...
	      Fig files store the text color as pen color,
	      SVG needs it as fill color.
	    */
  	    style.fred = style.sred = dcc.ired;
  	    style.fgreen = style.sgreen = dcc.igreen;
  	    style.fblue = style.sblue = dcc.iblue;
	    
  	    t = (dk_fig_text *)(o->data);
  	    if(t) {
  	      style.fonth = t->font_handling;
  	    }
  	    switch((style.fonth)->handling) {
  	      case 2: case 3: case 4: case 5: {
  	        if(!((oi->errprinted) & 1)) {
  	          dkfig_tool2_svg_error_message(oi, 85);
  		  if(!(((oi->c)->opt1) & DKFIG_OPT_REPORT_MULTIPLE)) {
  		    oi->errprinted |= 1;
  		  }
  	        }
  	      } break;
  	      default: {
  	        style.talign = o->subtype;
  	        if((style.fonth)->fontno < 0) {
  	          (style.fonth)->fontno = 0;
  	        }
  	        if((style.fonth)->fontno > 35) {
  	          (style.fonth)->fontno = 35;
  	        }
		(oi->fnused)[(style.fonth)->fontno] = '+';
  	        ((dk_fig_svg_drve *)(o->drve))->st1
  	        = svg_style_register(oi, &style);
  	        if(!(((dk_fig_svg_drve *)(o->drve))->st1)) {
  	          back = 0; 
  	        } else {
		  SVGSTY *stptr;
		  stptr = ((dk_fig_svg_drve *)(o->drve))->st1;
		  
		}
  	      } break;
  	    }
  	  } break;
  	  case 2: {	/* included image */
  	    svg_style_null(&style);
  	    /* filling */
            if(((oi->c)->opt1) & DKFIG_OPT_FILL_BITMAP_AREA) {
              if(dkfig_tool_must_fill((o->fpd).af, (oi->c)->opt1)
                 || dkfig_tool_must_pattern((o->fpd).af, (oi->c)->opt1))
              {
  	        style.flags |= DKFIG_SVG_FL_FILL;
  	        dkfig_tool_fill_dcc(oi->d, &dcc, (o->fpd).fc);
  	        dkfig_tool_correct_dcc(&dcc, (o->fpd).fc, (o->fpd).af);
  	        if(dkfig_tool_must_pattern((o->fpd).af, (oi->c)->opt1)
  	           && ((o->fpd).pc != (oi->d)->transparent)
		   && (((oi->c)->opt1) & DKFIG_OPT_FILL_PATTERNS))
  	        {
  	          /* fill patterns */
  	          svg_pat_null(&pattern);
                    pattern.pattp = (o->fpd).af;
  	          /* pattern.lw = (o->fpd).lt; */
  	          pattern.patrp = (oi->c)->patrp;
  	          if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
  	            pattern.flags |= DKFIG_SVG_FL_ENLIGHTEN;
  	          }
  	          if((o->fpd).fc != (oi->d)->transparent) {
  	            pattern.flags |= DKFIG_SVG_FL_FILL;
  	            pattern.fred = dcc.ired;
  		    pattern.fgreen = dcc.igreen;
  		    pattern.fblue = dcc.iblue;
  	          }
  	          pattern.flags |= DKFIG_SVG_FL_STROKE;
  	          dkfig_tool_fill_dcc(oi->d, &dcc, (o->fpd).pc);
  	          pattern.sred = dcc.ired;
  	          pattern.sgreen = dcc.igreen;
  	          pattern.sblue = dcc.iblue;
  	          style.pat = svg_pat_register(oi, &pattern);
  	          if(!(style.pat)) {
  	            back = 0;	
  	          }
  	        } else {
  	          /* color fill */
  	          style.fred = dcc.ired;
  	          style.fgreen = dcc.igreen;
  	          style.fblue = dcc.iblue;
  	        }
  	        ((dk_fig_svg_drve *)(o->drve))->st1
  	        = svg_style_register(oi, &style);
  	        if(!(((dk_fig_svg_drve *)(o->drve))->st1)) {
  	          back = 0;	
  	        }
              }
	    }
  	    svg_style_null(&style);
  	    /* stroking */
  	    must_draw = 1;
  	    if(o->objtype == DK_FIG_OBJ_POLYLINE) {
  	      if(o->subtype == 5) {
  	        if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BITMAP_BORDER) {
  	          must_draw = 0;
  	        }
  	      }
  	    }
  	    if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_THIN_BORDERS) {
  	      if((o->fpd).lt == 0L) {
  	        if((o->fpd).cl) {
  	          if(dkfig_tool_must_fill((o->fpd).af, (oi->c)->opt1)) {
  	            must_draw = 0;
  	          }
  	          if(dkfig_tool_must_pattern((o->fpd).af, (oi->c)->opt1)) {
  	            must_draw = 0;
  	          }
  	        }
  	      }
  	    }
  	    if((o->fpd).pc == (oi->d)->transparent) {
  	      must_draw = 0;
  	    }
            if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BG_RECTANGLE) {
	      int wbgr = 0;
	      if(((oi->c)->opt2) & DKFIG_OPT_WHITE_BGRECT) {
	        wbgr = 1;
	      }
              if(dkfig_tool2_obj_is_bg_rect(oi->o, wbgr)) { must_draw = 0; }
            } 
  	    if(must_draw) {
  	      dkfig_tool_fill_dcc(oi->d, &dcc, (o->fpd).pc);
  	      style.ls = (o->fpd).ls;	
  	      style.lw = (o->fpd).lt;
  	      style.sred = dcc.ired;
  	      style.sgreen = dcc.igreen;
  	      style.sblue = dcc.iblue;
  	      style.flags |= DKFIG_SVG_FL_STROKE;
  	      if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
  	        style.flags |= DKFIG_SVG_FL_ENLIGHTEN;
  	      }
  	      style.sv = (o->fpd).sv;
	      style.lc = (o->fpd).cs;
	      style.lj = (o->fpd).js;
  	      ((dk_fig_svg_drve *)(o->drve))->st2
  	      = svg_style_register(oi, &style);
  	      if(!(((dk_fig_svg_drve *)(o->drve))->st2)) {
  	        back = 0; 
  	      }
  	    }
  	  } break;
  	  default: {	/* regular path object */
  	    svg_style_null(&style);
  	    /* filling */
            if(dkfig_tool_must_fill((o->fpd).af, (oi->c)->opt1)
               || dkfig_tool_must_pattern((o->fpd).af, (oi->c)->opt1))
            {
  	      style.flags |= DKFIG_SVG_FL_FILL;
  	      dkfig_tool_fill_dcc(oi->d, &dcc, (o->fpd).fc);
  	      dkfig_tool_correct_dcc(&dcc, (o->fpd).fc, (o->fpd).af);
  	      if(dkfig_tool_must_pattern((o->fpd).af, (oi->c)->opt1)
  	         && ((o->fpd).pc != (oi->d)->transparent))
  	      {
  	        /* fill patterns */
  	        svg_pat_null(&pattern);
                pattern.pattp = (o->fpd).af;
  	        /* pattern.lw = (o->fpd).lt; */
  	        pattern.patrp = (oi->c)->patrp;
  	        if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
  	          pattern.flags |= DKFIG_SVG_FL_ENLIGHTEN;
  	        }
  	        if((o->fpd).fc != (oi->d)->transparent) {
  	          pattern.flags |= DKFIG_SVG_FL_FILL;
  	          pattern.fred = dcc.ired;
  		  pattern.fgreen = dcc.igreen;
  		  pattern.fblue = dcc.iblue;
  	        }
  	        pattern.flags |= DKFIG_SVG_FL_STROKE;
  	        dkfig_tool_fill_dcc(oi->d, &dcc, (o->fpd).pc);
  	        pattern.sred = dcc.ired;
  	        pattern.sgreen = dcc.igreen;
  	        pattern.sblue = dcc.iblue;
  	        style.pat = svg_pat_register(oi, &pattern);
  	        if(!(style.pat)) {
  	          back = 0;	
  	        }
  	      } else {
  	        /* color fill */
  	        style.fred = dcc.ired;
  	        style.fgreen = dcc.igreen;
  	        style.fblue = dcc.iblue;
  	      }
            }
  	    /* stroking */
  	    must_draw = 1;
  	    if(o->objtype == DK_FIG_OBJ_POLYLINE) {
  	      if(o->subtype == 5) {
  	        if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BITMAP_BORDER) {
  	          must_draw = 0; 
  	        }
  	      }
  	    }
  	    if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_THIN_BORDERS) {
  	      if((o->fpd).lt == 0L) {
  	        if((o->fpd).cl) {
  	          if(dkfig_tool_must_fill((o->fpd).af, (oi->c)->opt1)) {
  	            must_draw = 0; 
  	          }
  	          if(dkfig_tool_must_pattern((o->fpd).af, (oi->c)->opt1)) {
  	            must_draw = 0; 
  	          }
  	        }
  	      }
  	    }
  	    if((o->fpd).pc == (oi->d)->transparent) {
  	      must_draw = 0;	
  	    }
            if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BG_RECTANGLE) {
	      int wbgr = 0;
	      if(((oi->c)->opt2) & DKFIG_OPT_WHITE_BGRECT) {
	        wbgr = 1;
	      }
              if(dkfig_tool2_obj_is_bg_rect(oi->o, wbgr)) { must_draw = 0; }
            } 
  	    if(must_draw) {	
  	      dkfig_tool_fill_dcc(oi->d, &dcc, (o->fpd).pc);
  	      style.ls = (o->fpd).ls;	
  	      style.lw = (o->fpd).lt;
  	      style.sred = dcc.ired;
  	      style.sgreen = dcc.igreen;
  	      style.sblue = dcc.iblue;
  	      style.flags |= DKFIG_SVG_FL_STROKE;
  	      if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
  	        style.flags |= DKFIG_SVG_FL_ENLIGHTEN;
  	      }
  	      style.sv = (o->fpd).sv;
	      style.lc = (o->fpd).cs;
	      style.lj = (o->fpd).js;
  	    }
  	    ((dk_fig_svg_drve *)(o->drve))->st1
  	    = svg_style_register(oi, &style);
  	    if(!(((dk_fig_svg_drve *)(o->drve))->st1)) {
  	      back = 0;	
  	    }
  	    if(((o->fpd).ar) & 1) {	/* forward arrowhead */
              svg_style_null(&style);
  	      dkfig_tool_fill_dcc(oi->d, &dcc, (o->fpd).pc);
  	      style.lw = (o->fpd).lt;
  	      style.sred = dcc.ired;
  	      style.sgreen = dcc.igreen;
  	      style.sblue = dcc.iblue;
  	      style.flags |= DKFIG_SVG_FL_STROKE;
  	      if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
  	        style.flags |= DKFIG_SVG_FL_ENLIGHTEN;
  	      }
  	      if(((o->fpd).ahf).type > 0) {
	        style.flags |= DKFIG_SVG_FL_FILL;
  	        if(((o->fpd).ahf).style > 0) {
  		  style.fred = style.sred;
  		  style.fgreen = style.sgreen;
  		  style.fblue = style.sblue;
  	        } else {
		  style.fred = style.fgreen = style.fblue = 255;
		}
  	      }
	      style.lj = (oi->c)->ahlj;
  	      ((dk_fig_svg_drve *)(o->drve))->st2
  	      = svg_style_register(oi, &style);
  	      if(!(((dk_fig_svg_drve *)(o->drve))->st2)) {
  	        back = 0;	
  	      }
  	    }
  	    if(((o->fpd).ar) & 2) {	/* backward arrowhead */
  	      svg_style_null(&style);
  	      dkfig_tool_fill_dcc(oi->d, &dcc, (o->fpd).pc);
  	      style.lw = (o->fpd).lt;
  	      style.sred = dcc.ired;
  	      style.sgreen = dcc.igreen;
  	      style.sblue = dcc.iblue;
  	      style.flags |= DKFIG_SVG_FL_STROKE;
  	      if(((oi->c)->opt1) & DKFIG_OPT_ENLIGHTEN_LOOK) {
  	        style.flags |= DKFIG_SVG_FL_ENLIGHTEN;
  	      }
  	      if(((o->fpd).ahb).type > 0) {
	        style.flags |= DKFIG_SVG_FL_FILL;
  	        if(((o->fpd).ahb).style > 0) {
  		  style.fred = style.sred;
  		  style.fgreen = style.sgreen;
  		  style.fblue = style.sblue;
  	        } else {
		  style.fred = style.fgreen = style.fblue = 255;
		}
  	      }
	      style.lj = (oi->c)->ahlj;
  	      ((dk_fig_svg_drve *)(o->drve))->st3
  	      = svg_style_register(oi, &style);
  	      if(!(((dk_fig_svg_drve *)(o->drve))->st3)) {
  	        back = 0;	
  	      }
  	    }
  	  } break;
          }
        } else {
          back = 0;	
          /* MEMORY */
	  dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 11);
        }
      }
      if(oi->me) {
        /* MATH PROBLEM */
	dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 13);
      } oi->me = 0;
      if((oi->c)->app) {
        dkapp_set_source_lineno((oi->c)->app, 0UL);
      }
      (oi->c)->opt1 = backupopt1;
      (oi->c)->opt2 = backupopt2;
      (oi->c)->image_align = backupia;
    }
  }
  oi->spcpass = 1;
  if(back) {
    oi->npat = 0UL;
    dksto_it_reset(oi->pati);
    while((ppattern = (SVGPAT *)dksto_it_next(oi->pati)) != NULL) {
      ppattern->patno = oi->npat;
      oi->npat += 1UL;
    }
    oi->nsty = 0UL;
    dksto_it_reset(oi->styi);
    while((pstyle = (SVGSTY *)dksto_it_next(oi->styi)) != NULL) {
      pstyle->classno = oi->nsty;
      oi->nsty += 1UL;
    }
    oi->lpat = dkfig_dt_needed_alpha(oi->npat);
    
    oi->lsty = dkfig_dt_needed_alpha(oi->nsty);
    
  }
  
  return back;
}



/**	Find compression type for file name.
	@param	n	File name.
	@return	-1=not compressed, 0=gzip, 1=bzip2.
*/
static
int
compression_type DK_P1(char *,n)
{
  int back = -1; char *suffixptr;
  suffixptr = dksf_get_file_type_dot(n);
  if(n) {
    back = dkstr_array_index(suffix_types, suffixptr, 0);
  }
  return back;
}



/**	Open the font mapping file.
	@param	oi	OI structure.
	@param	n	File name of font mapping file.
	@return	Pointer to stream structure to read file on success,
	NULL on error.
*/
static
dk_stream_t *
open_the_mapping_file DK_P2(OI *,oi, char *,n)
{
  dk_stream_t *back = NULL;
  switch(compression_type(n)) {
    case 0: {
#if DK_HAVE_ZLIB_H
      if((oi->c)->app) {
        back = dkapp_stream_opengz((oi->c)->app, n, str_mode_open_read);
      } else {
        back = dkstream_opengz(n, str_mode_open_read, 0, NULL);
      }
#else
      dkapp_err_no_zlib_support_for((oi->c)->app, n);
#endif
    } break;
    case 1: {
#if DK_HAVE_BZLIB_H
      if((oi->c)->app) {
        back = dkapp_stream_openbz2((oi->c)->app, n, str_mode_open_read);
      } else {
        back = dkstream_openbz2(n, str_mode_open_read, 0, NULL);
      }
#else
     dkapp_err_no_bzlib_support_for((oi->c)->app, n);
#endif
    } break;
    default: {
      if((oi->c)->app) {
        back = dkapp_stream_openfile((oi->c)->app, n, str_mode_open_read);
      } else {
        back = dkstream_openfile(n, str_mode_open_read, 0, NULL);
      }
    } break;
  }
  return back;
}



/**	Read font mapping.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
get_fontmap DK_P1(OI *,oi)
{
  int back = 0; dk_stream_t *st;
  char *fmname; size_t szfmname;
  
  szfmname = (size_t)dksf_get_maxpathlen();
  fmname = dk_new(char,szfmname);
  if(fmname) {
    if((oi->c)->app) {
      if(dkapp_find_file((oi->c)->app, (oi->c)->fcfg, fmname, szfmname)) {
        
        oi->fontmap = dkfont_mapping_open();
        if(oi->fontmap) {
          st = open_the_mapping_file(oi, fmname);
	  if(st) {
	    if(dkfont_mapping_add_stream(oi->fontmap, st)) {
	      back = 1;	
	    } else {
	      char *oldsourcefilename; unsigned long oldsourcelineno;
	      oldsourcefilename = dkapp_get_source_filename((oi->c)->app);
	      oldsourcelineno = dkapp_get_source_lineno((oi->c)->app);
	      dkapp_set_source_filename((oi->c)->app, fmname);
	      dkapp_set_source_lineno((oi->c)->app, dkfont_get_error_lineno(oi->fontmap));
	      switch(dkfont_get_error_code(oi->fontmap)) {
	        case DK_ERR_NOMEM: {
		  dkfig_tool2_simple_error_message(oi->c, 11);
		} break;
		default: {
		  dkfig_tool2_simple_error_message(oi->c, 12);
		} break;
	      }
	      dkapp_set_source_lineno((oi->c)->app, oldsourcelineno);
	      dkapp_set_source_filename((oi->c)->app, oldsourcefilename);
	      dkfont_mapping_close(oi->fontmap); oi->fontmap = NULL;
	    }
	    dkstream_close(st);
	  } else {
	    dkapp_err_fopenr((oi->c)->app, fmname);
	  }
        } else {
	  dkapp_err_memory((oi->c)->app, 1, 1);
        }
        back = 1;
      } else {
	dkapp_err_matchfile((oi->c)->app, (oi->c)->fcfg);
      }
    } else {
      oi->fontmap = dkfont_mapping_open();
      if(oi->fontmap) {
        st = open_the_mapping_file(oi, (oi->c)->fcfg);
	if(st) {
	  if(dkfont_mapping_add_stream(oi->fontmap, st)) {
	    back = 1;
	  } else {
	    dkfont_mapping_close(oi->fontmap); oi->fontmap = NULL;
	  }
	  dkstream_close(st);
	} else {
	}
      } else {
      }
    }
    dk_delete(fmname);
  } else {
    if((oi->c)->app) {
      dkapp_err_memory((oi->c)->app, 1, szfmname);
    }
  } 
  return back;
}



/**	Prepare for output.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
preparation_pass DK_P1(OI *,oi)
{
  int back = 0;
  
  oi->fl = dkfig_flat_list(oi->c, (oi->c)->drwng);
  oi->pat = dksto_open(0);
  oi->sty = dksto_open(0);
  if((oi->fl) && (oi->pat) && (oi->sty)) {
    dksto_set_comp(oi->pat, dkfig_svg_comp_pat, 0);
    dksto_set_comp(oi->sty, dkfig_svg_comp_style, 0);
    oi->fli = dksto_it_open(oi->fl);
    oi->pati = dksto_it_open(oi->pat);
    oi->styi = dksto_it_open(oi->sty);
    if((oi->fli) && (oi->pati) && (oi->styi)) {
      if(attach_drve(oi)) {	
        if(scan_options(oi)) {
	  if(establish_coord_transformation(oi)) {
	    if(use_dlspc(oi)) {	
              dkfig_tool2_report_unused_options(oi->c);
	      back = prepare_objects(oi);
	      if((oi->c)->fcfg) {	
	        back = get_fontmap(oi);
	      } else {			
	        back = 1;
	      }
	    } else {		
	    }
	  } else {		
	  }
	} else {		
	}
      } else {			
      }
    }
  }
  
  return back;
}



/**	Write the SVG document type.
	@param	oi	OI structure.
*/
static
void
svg_document_type DK_P1(OI *,oi)
{
  
  switch((oi->c)->svgv) {
    case DKFIG_SVG_VERS_12: /* HIER NOCH SCHAUEN, WIE DEFINIERT ##### */
    case DKFIG_SVG_VERS_10: {
      kw_out(oi, 6); kw_out(oi, 0); kw_out(oi, 2); kw_out(oi, 7);
      kw_out(oi, 1); kw_out(oi, 8); kw_out(oi, 0); kw_out(oi, 9);
      kw_out(oi, 0); kw_out(oi, 3); kw_out(oi, 0);
    } break;
    default: {
      kw_out(oi, 6); kw_out(oi, 0); kw_out(oi, 2); kw_out(oi, 7);
      kw_out(oi, 1); kw_out(oi, 12); kw_out(oi, 0); kw_out(oi, 13);
      kw_out(oi, 0); kw_out(oi, 3); kw_out(oi, 0);
    } break;
  } 
}



/**	Print a length, maybee either in inches or pixels.
	@param	oi	OI structure.
	@param	v	Value to print.
	@param	h	Choose units (DKFIG_SVG_VP_xxx).
	@param	w	Index of "what" in kw array.
*/
static
void
print_lgt DK_P4(OI *,oi, double,v, int,h, size_t,w)
{
  
  kw_out(oi, w);
  kw_out(oi, 19);
  kw_out(oi, 20);
  put_double(oi, v, 1);
  switch(h) {
    case DKFIG_SVG_VP_PIXELS: {
      kw_out(oi, 22);
    } break;
    case DKFIG_SVG_VP_INCHES: {
      kw_out(oi, 21);
    } break;
  }
  kw_out(oi, 20); 
}



/**	Print width of SVG either in inches or in pixels (without unit).
	@param	oi	OI structure.
	@param	v	Value to print.
	@param	h	Choose unit.
*/
static
void
print_width DK_P3(OI *,oi, double,v, int,h)
{
  print_lgt(oi,v,h,16);
  
}



/**	Print height of SVG either in inches or in pixels (without unit).
	@param	oi	OI structure.
	@param	v	Value to print.
	@param	h	Choose units.
*/
static
void
print_height DK_P3(OI *,oi, double,v, int,h)
{
  print_lgt(oi,v,h,17);
  
}



/**	Write data attached to the entire drawing.
	@param	oi	OI structure.
	@param	o	Fig object for entire drawing.
	@param	drve	Driver-specific extension data for entire drawing.
	@param	isroot	Flag: Is root object.
	@return	1 on success, 0 on error.
*/
static
int
svg_drve_write DK_P4(OI *,oi, dk_fig_object *,o, DRVE *,drve, int,isroot)
{
  int back = 1;
  int i, is_first;
  dk_fig_svg_attr *a;
  char *ptr, **pptr;
  
  is_first = 1;
  if(drve->attri) {
    for(i = 1; i < (int)sz_cmds; i++) {
      a = (dk_fig_svg_attr *)dksto_it_find_like(drve->attri, (void *)(&i), 1);
      if(a) {
        if(a->value) {
	  if(is_first) {
	    if(!isroot) {
	      kw_out(oi, 0);
	    }
	  }
	  pptr = cmds[i];
	  ptr = *pptr;
	  dkstream_puts(oi->s, ptr);
	  kw_out(oi, 19);
	  kw_out(oi, 20);
	  dkstream_puts(oi->s, a->value);
	  kw_out(oi, 20);
	  kw_out(oi, 0);
	  is_first = 0;
	}
      }
    }
  }
  
  return back;
}



/**	Write opening SVG tag.
	@param	oi	OI structure.
*/
static
void
svg_start_tag DK_P1(OI *,oi)
{
  double w, h, wp, hp;
  
  begin_tag(oi, 5); kw_out(oi, 1);
  wp = dkma_sub_double_ok(
    dkma_l_to_double(oi->xmax),
    dkma_l_to_double(oi->xmin),
    &(oi->me)
  );
  hp = dkma_sub_double_ok(
    dkma_l_to_double(oi->ymax),
    dkma_l_to_double(oi->ymin),
    &(oi->me)
  );
  h = hp; w = wp;
  if(((oi->c)->svgs) == DKFIG_SVG_VP_INCHES) {
    h = h / 72.0; w = w / 72.0;
  }
  hp = dkma_double_restrict_digits(hp, 0);
  wp = dkma_double_restrict_digits(wp, 0);
  h  = drd(h, oi->c, 1);
  w  = drd(w, oi->c, 1);
  print_width(oi, w, (oi->c)->svgs); kw_out(oi, 1);
  print_height(oi, h, (oi->c)->svgs); kw_out(oi, 1);
  kw_out(oi, 18); kw_out(oi, 19); kw_out(oi, 20);
  dkstream_puts_ul(oi->s, 0UL); kw_out(oi, 1);
  dkstream_puts_ul(oi->s, 0UL); kw_out(oi, 1);
  dkstream_puts_long(oi->s, dkma_double_to_l(wp));
  kw_out(oi, 1);
  dkstream_puts_long(oi->s, dkma_double_to_l(hp));
  kw_out(oi, 20);
  if(!(((oi->c)->opt1) & DKFIG_OPT_SVG_EMBEDDED)) {
    kw_out(oi, 0);
    switch((oi->c)->svgv) {
      case DKFIG_SVG_VERS_10: {
        if(((oi->c)->opt1) & DKFIG_OPT_SVG_EMBEDDED) {
          kw_out(oi, 23);
        } else {
          kw_out(oi, 10);
        }
        kw_out(oi, 0); kw_out(oi, 11); kw_out(oi, 0);
      } break;
      case DKFIG_SVG_VERS_11: {
        if(((oi->c)->opt1) & DKFIG_OPT_SVG_EMBEDDED) {
          kw_out(oi, 23);
        } else {
          kw_out(oi, 10);
        }
        kw_out(oi, 0); kw_out(oi, 11); kw_out(oi, 0);
      } break;
    }
  }
  svg_drve_write(oi, oi->dro, (DRVE *)((oi->dro)->drve), 1);
  kw_out(oi, 3); kw_out(oi, 0); 
}



/**	Finish svg output.
	@param	oi	OI structure.
*/
static
void
svg_end_tag DK_P1(OI *,oi)
{
  end_tag(oi, 5); 
}




/**	Write a byte as two hex digits.
	@param	oi	OI structure.
	@param	i	Byte to print.
*/
static
void
hex_out DK_P2(OI *,oi, int,i)
{
  size_t sz;
  char buffer[3];
  sz = (i >> 4) & 15;
  buffer[0] = hex_digits[sz];
  sz = i & 15;
  buffer[1] = hex_digits[sz];
  buffer[2] = '\0';
  dkstream_puts(oi->s, buffer);
}



/**	Calculate grey value.
	@param	r	Red component.
	@param	g	Green component.
	@param	b	Blue component.
	@return	Grey value.
*/
static unsigned
ntsc DK_P3(unsigned, r, unsigned, g, unsigned, b)
{
  unsigned long l1, l2, l3, l4;
  l1 =  54UL * (unsigned long)r;
  l2 = 183UL * (unsigned long)g;
  l3 =  19UL * (unsigned long)b;
  l4 = l1 + l2 + l3;
  l4 = (l4 >> 8) & 0x000000FFUL;
  return((unsigned)l4);
}


/**	Write a color in hexadecimal notation, i.e. "#FF0000".
	@param	oi	OI structure
	@param	r	Red.
	@param	g	Green.
	@param	b	Blue.
*/
static
void
color_out DK_P4(OI *,oi, int,r, int,g, int,b)
{
  int use_color = 1;
  int grayvalue;
  if(oi->c) {
    if(!(((oi->c)->opt2) & DKFIG_OPT_COLOR)) {
      use_color = 0;
    }
  }
  if(use_color) {
    kw_out(oi, 45);
    hex_out(oi, r);
    hex_out(oi, g);
    hex_out(oi, b);
  } else {
    grayvalue = (int)ntsc((unsigned)r, (unsigned)g, (unsigned)b);
    kw_out(oi, 45);
    hex_out(oi, grayvalue); hex_out(oi, grayvalue); hex_out(oi, grayvalue);
  }
}



/**	Write style information for pattern stroke.
	@param	oi	OI structure.
	@param	pat	SVG pattern information structure.
	@param	st
*/
static
void
pattern_style DK_P3(OI *,oi, SVGPAT *,pat, int,st)
{
  double dlw;
  /* if(st) { dlw = ccll(oi, ((pat->lw) ? pat->lw : 1L), 1); } */
  if(st) { dlw = ccll(oi, 1L, 1); }
  kw_out(oi, 38);
  kw_out(oi, 19);
  dkstream_set_double_no_exponent(oi->s, 1);
  kw_out(oi, 20);
  kw_out(oi, (st ? 62 : 63)); kw_out(oi, 24); kw_out(oi, 1);
  kw_out(oi, 65); kw_out(oi, 43);
  kw_out(oi, 1);
  kw_out(oi, (st ? 63 : 62)); kw_out(oi, 24); kw_out(oi, 1);
  color_out(oi, pat->sred, pat->sgreen, pat->sblue);
  kw_out(oi, 43);
  if(st) {
    kw_out(oi, 1);
    kw_out(oi, 64); kw_out(oi, 24); kw_out(oi, 1);
    put_double(oi, dlw, 1);
    kw_out(oi, 43);
    kw_out(oi, 1);
    kw_out(oi, 67); kw_out(oi, 24); kw_out(oi, 1);
    kw_out(oi, 69);
    kw_out(oi, 43);
  }
  kw_out(oi, 20);
  dkstream_set_double_no_exponent(oi->s, 0);
}



/**	Write points="xxx" for polyline/polygon.
	@param	oi	OI structure.
	@param	co	Coordinates array.
	@param	n	Size of array (even number).
	@param	cl	Flag: Closed path.
*/
static
void
points_out DK_P4(OI *,oi, double *,co, size_t,n, int,cl)
{
  size_t max;
  size_t i;
  max = 2 * n;
  kw_out(oi, 86);
  kw_out(oi, 19);
  kw_out(oi, 20);
  for(i = 0; i < max; i++) {
    if(i) { kw_out(oi, ((i % 2) ? 55 : 0)); }
    put_double(oi, co[i], 1);
  }
  kw_out(oi, 20);
}



/**	Draw and fill operations for pattern strokes.
	@param	oi	OI structure.
	@param	co	Coordinates array.
	@param	np	Number of points.
	@param	cl	Flag: Closed path.
	@param	pat	SVG pattern information structure.
	@param	lof	Flag: Line (0) or fill (1).
*/
static
void
pattern_line_or_fill DK_P6(OI *,oi, double *,co, size_t,np, int,cl, SVGPAT *,pat, int,lof)
{
  begin_tag(oi, ((lof && cl) ? 84 : 85));
  kw_out(oi, 0);
  pattern_style(oi, pat, lof);
  kw_out(oi, 0);
  points_out(oi, co, np, cl);
  kw_out(oi, 0);
  kw_out(oi, 4);
  kw_out(oi, 3);
  kw_out(oi, 0);
}



/**	Write pattern strokes as a polyline/polygon.
	@param	oi	OI structure.
	@param	co	Coordinates.
	@param	np	Number of points.
	@param	cl	Flag: Closed path.
	@param	pat	SVG pattern information structure.
*/
static
void
pattern_line DK_P5(OI *,oi, double *,co, size_t,np, int,cl, SVGPAT *,pat)
{
  pattern_line_or_fill(oi, co, np, cl, pat, 1);
}



/**	Write pattern strokes as a filled polygon.
	@param	oi	OI structure.
	@param	co	Coordinates.
	@param	np	Number of points.
	@param	cl	Flag: Closed path.
	@param	pat	SVG pattern information structure.
*/
static
void
pattern_area DK_P5(OI *,oi, double *,co, size_t,np, int,cl, SVGPAT *,pat)
{
  pattern_line_or_fill(oi, co, np, cl, pat, 0);
}



/**	Write strokes for the fish scales patterns.
	@param	oi	OI structure.
	@param	pat	Pattern information structure.
	@param	xstep	Repeat distance in x direction.
	@param	ystep	Repeat distance in y direction.
	@param	x1	Start point x.
	@param	y1	Start point y.
	@param	r	Radius of fishscale.
*/
static
void
do_fish_scales DK_P7(OI *,oi, SVGPAT *,pat, double,xstep, double,ystep, double,x1, double,y1, double,r)
{
  begin_tag(oi, 98);
  kw_out(oi, 0);
  pattern_style(oi, pat, 1);
  kw_out(oi, 0);
  kw_out(oi, 99);
  kw_out(oi, 19);
  kw_out(oi, 20);
  kw_out(oi, 100);
  kw_out(oi, 103);
  kw_out(oi, 55);
  kw_out(oi, 103);
  kw_out(oi, 102);
  put_double(oi, r, 2);
  kw_out(oi, 1);
  put_double(oi, r, 1);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  put_double(oi, xstep, 1);
  kw_out(oi, 55);
  put_double(oi, 0.0, 1);
  kw_out(oi, 20);
  kw_out(oi, 0);
  kw_out(oi, 4);
  kw_out(oi, 3);
  kw_out(oi, 0);
  begin_tag(oi, 98);
  kw_out(oi, 0);
  pattern_style(oi, pat, 1);
  kw_out(oi, 0);
  kw_out(oi, 99);
  kw_out(oi, 19);
  kw_out(oi, 20);
  kw_out(oi, 100);
  kw_out(oi, 103);
  kw_out(oi, 55);
  put_double(oi, ystep, 1);
  kw_out(oi, 102);
  put_double(oi, r, 1);
  kw_out(oi, 1);
  put_double(oi, r, 1);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  put_double(oi, x1, 1);
  kw_out(oi, 55);
  put_double(oi, y1, 1);
  kw_out(oi, 20);
  kw_out(oi, 0);
  kw_out(oi, 4);
  kw_out(oi, 3);
  kw_out(oi, 0);
  begin_tag(oi, 98);
  kw_out(oi, 0);
  pattern_style(oi, pat, 1);
  kw_out(oi, 0);
  kw_out(oi, 99);
  kw_out(oi, 19);
  kw_out(oi, 20);
  kw_out(oi, 100);
  put_double(oi, x1, 1);
  kw_out(oi, 55);
  put_double(oi, y1, 1);
  kw_out(oi, 102);
  put_double(oi, r, 1);
  kw_out(oi, 1);
  put_double(oi, r, 1);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  put_double(oi, xstep, 1);
  kw_out(oi, 55);
  put_double(oi, ystep, 1);
  kw_out(oi, 20);
  kw_out(oi, 0);
  kw_out(oi, 4);
  kw_out(oi, 3);
  kw_out(oi, 0);

  begin_tag(oi, 98);
  kw_out(oi, 0);
  pattern_style(oi, pat, 1);
  kw_out(oi, 0);
  kw_out(oi, 99);
  kw_out(oi, 19);
  kw_out(oi, 20);
  kw_out(oi, 100);
  kw_out(oi, 103);
  kw_out(oi, 55);
  kw_out(oi, 103);
  kw_out(oi, 102);
  put_double(oi, r, 1);
  kw_out(oi, 1);
  put_double(oi, r, 1);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  put_double(oi, x1, 1);
  kw_out(oi, 55);
  put_double(oi, (0.0 - y1), 1);
  kw_out(oi, 20);
  kw_out(oi, 0);
  kw_out(oi, 4);
  kw_out(oi, 3);
  kw_out(oi, 0);
  begin_tag(oi, 98);
  kw_out(oi, 0);
  pattern_style(oi, pat, 1);
  kw_out(oi, 0);
  kw_out(oi, 99);
  kw_out(oi, 19);
  kw_out(oi, 20);
  kw_out(oi, 100);
  put_double(oi, x1, 1);
  kw_out(oi, 55);
  put_double(oi, (0.0 - y1), 1);
  kw_out(oi, 102);
  put_double(oi, r, 1);
  kw_out(oi, 1);
  put_double(oi, r, 1);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  kw_out(oi, 103);
  kw_out(oi, 1);
  put_double(oi, xstep, 1);
  kw_out(oi, 55);
  kw_out(oi, 103);
  kw_out(oi, 20);
  kw_out(oi, 0);
  kw_out(oi, 4);
  kw_out(oi, 3);
  kw_out(oi, 0);
}



/**	Write one pattern.
	@param	oi	OI structure.
	@param	pat	Pattern information structure.
*/
static
void
pattern_out DK_P2(OI *,oi, SVGPAT *,pat)
{
  double patrp, xstep, ystep, a, b, dlw;
  double x1, y1, x2, y2, x3, y3, x4, y4;
  double co[32];
  
  xstep = ystep = 10.0; a = b = 0.0;
  /* dlw = ccll(oi, ((pat->lw) ? pat->lw : 1L), 1); */
  dlw = ccll(oi, 1L, 1);
  if((oi->c)->patrp) {
    patrp = 0.9 * dkma_l_to_double((oi->c)->patrp);
  } else {
    patrp = 3.6;
  } patrp = fabs(patrp);
  xstep = ystep = patrp;
  switch(pat->pattp) {
    case 41: case 42: case 43: {
      xstep = dkma_mul_double_ok(patrp, 2.0, &(oi->me));
      ystep = dkma_mul_double_ok(patrp, sqrt(4.0/3.0), &(oi->me));
    } break;
    case 44: case 45: case 46: {	/* FourtyFiveLeft */
      xstep = dkma_mul_double_ok(patrp, sqrt(2.0), &(oi->me));
      ystep = xstep;
    } break;
    case 47: {	/* HorizontalBricks */
      x1    = patrp;
      patrp = dkma_mul_double_ok(patrp, 2.0, &(oi->me));
      x2    = dkma_add_double_ok(x1, patrp, &(oi->me));
      x3    = dkma_add_double_ok(x2, patrp, &(oi->me));
      x4    = dkma_add_double_ok(x3, patrp, &(oi->me));
      y1    = patrp;
      ystep = dkma_mul_double_ok(patrp, 2.0, &(oi->me));
      xstep = dkma_mul_double_ok(ystep, 2.0, &(oi->me));
    } break;
    case 48: {	/* VerticalBricks */
      y1    = patrp;
      patrp = dkma_mul_double_ok(patrp, 2.0, &(oi->me));
      y2    = dkma_add_double_ok(y1, patrp, &(oi->me));
      y3    = dkma_add_double_ok(y2, patrp, &(oi->me));
      y4    = dkma_add_double_ok(y3, patrp, &(oi->me));
      x1    = patrp;
      xstep = dkma_mul_double_ok(patrp, 2.0, &(oi->me));
      ystep = dkma_mul_double_ok(xstep, 2.0, &(oi->me));
    } break;
    case 49: {	/* HorizontalLines */
    } break;
    case 50: {	/* VerticalLines */
    } break;
    case 51: {	/* CrossHatch */
    } break;
    case 52: case 53: {	/* HorizShinglesRight, Left... */
      ystep = dkma_mul_double_ok(patrp, 8.0, &(oi->me));
      xstep = dkma_mul_double_ok(patrp, 4.0, &(oi->me));
      x1 = patrp;
      x2 = dkma_mul_double_ok(patrp, 2.0, &(oi->me));
      x3 = dkma_mul_double_ok(patrp, 3.0, &(oi->me));
      a  = 0.5 * dlw;
      y1 = x2;
      y2 = xstep;
      y3 = dkma_mul_double_ok(patrp, 6.0, &(oi->me));
    } break;
    case 54: case 55: {	/* VertShinglesOne */
      ystep = dkma_mul_double_ok(patrp, 4.0, &(oi->me));
      xstep = dkma_mul_double_ok(patrp, 8.0, &(oi->me));
      y1 = patrp;
      y2 = dkma_mul_double_ok(patrp, 2.0, &(oi->me));
      y3 = dkma_mul_double_ok(patrp, 3.0, &(oi->me));
      a  = 0.5 * dlw;
      x1 = y2;
      x2 = ystep;
      x3 = dkma_mul_double_ok(patrp, 6.0, &(oi->me));
    } break;
    case 56: {	/* FishScales */
      a = dkma_mul_double_ok(patrp, 2.5, &(oi->me));
      b = 1.881618;
      xstep = dkma_mul_double_ok(
        2.0,
	dkma_mul_double_ok(a, sin(0.5*b), &(oi->me)),
	&(oi->me)
      );
      ystep = dkma_mul_double_ok(
        (1.0 - cos(0.5*b)),
	a,
	&(oi->me)
      );
      ystep = dkma_mul_double_ok(ystep, 2.0, &(oi->me));
      xstep = round_down_digits(xstep, 4);
      ystep = round_down_digits(ystep, 4);
      x1 = 0.5 * xstep; y1 = 0.5 * ystep;
    } break;
    case 57: {	/* SmallFishScales */
      a = patrp;
      b = M_PI;
      xstep = dkma_mul_double_ok(
        2.0,
	dkma_mul_double_ok(a, sin(0.5*b), &(oi->me)),
	&(oi->me)
      );
      ystep = dkma_mul_double_ok(
        (1.0 - cos(0.5*b)),
	a,
	&(oi->me)
      );
      ystep = dkma_mul_double_ok(ystep, 2.0, &(oi->me));
      xstep = round_down_digits(xstep, 4);
      ystep = round_down_digits(ystep, 4);
      x1 = 0.5 * xstep; y1 = 0.5 * ystep;
    } break;
    case 58: {	/* Circles */
      a = dkma_mul_double_ok(patrp, 2.0, &(oi->me));
      xstep = ystep = dkma_mul_double_ok(patrp, 4.0, &(oi->me));
    } break;
    case 59: {	/* Hexagons */
      xstep = dkma_mul_double_ok(patrp, 6.0, &(oi->me));
      y1 = ystep = dkma_mul_double_ok(patrp, sqrt(3.0), &(oi->me));
      ystep = dkma_mul_double_ok(ystep, 2.0, &(oi->me));
      x1 = patrp;
      x2 = dkma_mul_double_ok(patrp, 3.0, &(oi->me));
      x3 = dkma_mul_double_ok(patrp, 4.0, &(oi->me));
      x4 = dkma_add_double_ok(xstep, patrp, &(oi->me));
    } break;
    case 60: {	/* Octagons */
      patrp = dkma_mul_double_ok(patrp, 4.0, &(oi->me));
      xstep = ystep = patrp;
      a = xstep / (2.0+sqrt(2.0));
    } break;
    case 61: case 62: {	/* HorizontalTireTreads, Vertical... */
      xstep = ystep = dkma_mul_double_ok(patrp, 2.0, &(oi->me));
    } break;
  }
  begin_tag(oi, 35);
  kw_out(oi, 1);
  kw_out(oi, 36);
  kw_out(oi, 19);
  kw_out(oi, 20);
  kw_out(oi, 37);
  dkfig_tool_num_as_string(oi->s, pat->patno, oi->lpat);
  kw_out(oi, 20);
  kw_out(oi, 1);
  kw_out(oi, 14);
  kw_out(oi, 19);
  kw_out(oi, 20);
  kw_out(oi, 103);
  kw_out(oi, 20);
  kw_out(oi, 1);
  kw_out(oi, 15);
  kw_out(oi, 19);
  kw_out(oi, 20);
  kw_out(oi, 103);
  kw_out(oi, 20);
  kw_out(oi, 1);
  kw_out(oi, 16);
  kw_out(oi, 19);
  kw_out(oi, 20);
  put_double(oi, xstep, 1);
  kw_out(oi, 20);
  kw_out(oi, 1);
  kw_out(oi, 17);
  kw_out(oi, 19);
  kw_out(oi, 20);
  put_double(oi, ystep, 1);
  kw_out(oi, 20);
  kw_out(oi, 0);
  kw_out(oi, 111);
  kw_out(oi, 0);
  kw_out(oi, 3); kw_out(oi, 0);
  if((pat->flags) & DKFIG_SVG_FL_FILL) {
    begin_tag(oi, 79);
    kw_out(oi, 1);
    kw_out(oi, 14);
    kw_out(oi, 19);
    kw_out(oi, 20);
    kw_out(oi, 103);
    kw_out(oi, 20);
    kw_out(oi, 1);
    kw_out(oi, 15);
    kw_out(oi, 19);
    kw_out(oi, 20);
    kw_out(oi, 103);
    kw_out(oi, 20);
    kw_out(oi, 1);
    kw_out(oi, 16);
    kw_out(oi, 19);
    kw_out(oi, 20);
    put_double(oi, xstep, 1);
    kw_out(oi, 20);
    kw_out(oi, 1);
    kw_out(oi, 17);
    kw_out(oi, 19);
    kw_out(oi, 20);
    put_double(oi, ystep, 1);
    kw_out(oi, 20);
    kw_out(oi, 0);
    kw_out(oi, 38);
    kw_out(oi, 19);
    dkstream_set_double_no_exponent(oi->s, 1);
    kw_out(oi, 20);
    kw_out(oi, 62); kw_out(oi, 24); kw_out(oi, 1);
    color_out(oi, pat->fred, pat->fgreen, pat->fblue);
    kw_out(oi, 43);
    kw_out(oi, 1);
    kw_out(oi, 63); kw_out(oi, 24); kw_out(oi, 1);
    kw_out(oi, 65);
    kw_out(oi, 43);
    kw_out(oi, 20);
    dkstream_set_double_no_exponent(oi->s, 0);
    kw_out(oi, 0);
    kw_out(oi, 4);
    kw_out(oi, 3);
    kw_out(oi, 0);
  }
  if((pat->flags) & DKFIG_SVG_FL_STROKE) {
    switch(pat->pattp) {
      case 41: {	/* ThirtyLeft */
	a = dlw; b = dlw / sqrt(3.0);
	co[0] = 0.0; co[1] = 0.0; co[2] = a; co[3] = 0.0;
	co[4] = xstep;
	co[5] = dkma_sub_double_ok(ystep, b, &(oi->me));
	co[6] = xstep; co[7] = ystep;
	co[8] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[9] = ystep; co[10] = 0.0; co[11] = b;
	pattern_area(oi, co, 6, 0, pat);
	co[0] = 0.0;
	co[1] = dkma_sub_double_ok(ystep, b, &(oi->me));
	co[2] = a; co[3] = ystep; co[4] = 0.0; co[5] = ystep;
	pattern_area(oi, co, 3, 0, pat);
	co[0] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[1] = 0.0; co[2] = xstep; co[3] = b; co[4] = xstep;
	co[5] = 0.0;
	pattern_area(oi, co, 3, 0, pat);
      } break;
      case 42: {	/* ThirtyRight */
	a = dlw; b = dlw / sqrt(3.0);
	co[0] = 0.0; co[1] = ystep; co[2] = a; co[3] = ystep;
	co[4] = xstep; co[5] = b; co[6] = xstep; co[7] = 0.0;
	co[8] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[9] = 0.0; co[10] = 0.0;
	co[11] = dkma_sub_double_ok(ystep, b, &(oi->me));
	pattern_area(oi, co, 6, 0, pat);
	co[0] = 0.0; co[1] = b; co[2] = a; co[3] = 0.0;
	co[4] = 0.0; co[5] = 0.0;
	pattern_area(oi, co, 3, 0, pat);
	co[0] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[1] = ystep; co[2] = xstep; co[3] = ystep;
	co[4] = xstep;
	co[5] = dkma_sub_double_ok(ystep, b, &(oi->me));
	pattern_area(oi, co, 3, 0, pat);
      } break;
      case 43: case 46: {	/* ThirtyHatch, FourtyFiveHatch */
        co[0] = 0.0; co[1] = 0.0; co[2] = xstep; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0; co[1] = ystep; co[2] = xstep; co[3] = 0.0;
	pattern_line(oi, co, 2, 0, pat);
      } break;
      case 44: {	/* FourtyFiveLeft */
	a = dlw / sqrt(2.0); b = dlw / sqrt(2.0);
	co[0] = 0.0; co[1] = 0.0; co[2] = a; co[3] = 0.0;
	co[4] = xstep;
	co[5] = dkma_sub_double_ok(ystep, b, &(oi->me));
	co[6] = xstep; co[7] = ystep;
	co[8] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[9] = ystep; co[10] = 0.0; co[11] = b;
	pattern_area(oi, co, 6, 0, pat);
	co[0] = 0.0;
	co[1] = dkma_sub_double_ok(ystep, b, &(oi->me));
	co[2] = a; co[3] = ystep; co[4] = 0.0; co[5] = ystep;
	pattern_area(oi, co, 3, 0, pat);
	co[0] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[1] = 0.0; co[2] = xstep; co[3] = b; co[4] = xstep;
	co[5] = 0.0;
	pattern_area(oi, co, 3, 0, pat);
      } break;
      case 45: {	/* FourtyFiveRight */
	a = dlw / sqrt(2.0); b = dlw / sqrt(2.0);
	co[0] = 0.0; co[1] = ystep; co[2] = a; co[3] = ystep;
	co[4] = xstep; co[5] = b; co[6] = xstep; co[7] = 0.0;
	co[8] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[9] = 0.0; co[10] = 0.0;
	co[11] = dkma_sub_double_ok(ystep, b, &(oi->me));
	pattern_area(oi, co, 6, 0, pat);
	co[0] = 0.0; co[1] = b; co[2] = a; co[3] = 0.0;
	co[4] = 0.0; co[5] = 0.0;
	pattern_area(oi, co, 3, 0, pat);
	co[0] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[1] = ystep; co[2] = xstep; co[3] = ystep;
	co[4] = xstep;
	co[5] = dkma_sub_double_ok(ystep, b, &(oi->me));
	pattern_area(oi, co, 3, 0, pat);
      } break;
      case 47: {	/* HorizontalBricks */
        co[0] = x1; co[1] = 0.0; co[2] = x1; co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = x3; co[1] = 0.0; co[2] = x3; co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = x2; co[1] = y1; co[2] = x2; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = x4; co[1] = y1; co[2] = x4; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = 0.0; co[1] = 0.0; co[2] = xstep; co[3] = 0.0;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = 0.0; co[1] = ystep; co[2] = xstep; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = 0.0; co[1] = y1; co[2] = xstep; co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
      } break;
      case 48: {	/* VerticalBricks */
        co[0] = 0.0; co[1] = y1; co[2] = x1; co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = 0.0; co[1] = y3; co[2] = x1; co[3] = y3;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = x1; co[1] = y2; co[2] = xstep; co[3] = y2;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = x1; co[1] = y4; co[2] = xstep; co[3] = y4;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = 0.0; co[1] = 0.0; co[2] = 0.0; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = x1; co[1] = 0.0; co[2] = x1; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = xstep; co[1] = 0.0; co[2] = xstep; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);

      } break;
      case 49: {	/* HorizontalLines */
        co[0] = 0.0; co[1] = 0.0;
	co[2] = xstep; co[3] = 0.0;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0; co[1] = ystep;
	co[2] = xstep; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
      } break;
      case 50: {	/* VerticalLines */
        co[0] = 0.0; co[1] = 0.0;
	co[2] = 0.0; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = xstep; co[1] = 0.0;
	co[2] = xstep; co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
      } break;
      case 51: {	/* CrossHatch */
        co[0] = 0.0; co[1] = 0.0;
	co[2] = 0.0; co[3] = ystep;
	co[4] = xstep; co[5] = ystep;
	co[6] = xstep; co[7] = 0.0;
	pattern_line(oi, co, 4, 1, pat);
      } break;
      case 52: {	/* HorizShinglesRight */
        co[0] = a;
	co[1] = y1;
	co[2] = dkma_sub_double_ok(x1, a, &(oi->me));
	co[3] = 0.0;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = dkma_add_double_ok(x1, a, &(oi->me));
	co[1] = y2;
	co[2] = dkma_sub_double_ok(x2, a, &(oi->me));
	co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = dkma_add_double_ok(x2, a, &(oi->me));
	co[1] = y3;
	co[2] = dkma_sub_double_ok(x3, a, &(oi->me));
	co[3] = y2;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = dkma_add_double_ok(x3, a, &(oi->me));
	co[1] = ystep;
	co[2] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[3] = y3;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = 0.0;
	co[2] = xstep;
	co[3] = 0.0;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = y1;
	co[2] = xstep;
	co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = y2;
	co[2] = xstep;
	co[3] = y2;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = y3;
	co[2] = xstep;
	co[3] = y3;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = ystep;
	co[2] = xstep;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
      } break;
      case 53: {	/* HorizShinglesLeft */
        co[0] = 0.0;
	co[1] = 0.0;
	co[2] = x1;
	co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x3;
	co[1] = y1;
	co[2] = xstep;
	co[3] = y2;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x2;
	co[1] = y2;
	co[2] = x3;
	co[3] = y3;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x1;
	co[1] = y3;
	co[2] = x2;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = 0.0;
	co[2] = xstep;
	co[3] = 0.0;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = y1;
	co[2] = xstep;
	co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = y2;
	co[2] = xstep;
	co[3] = y2;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = y3;
	co[2] = xstep;
	co[3] = y3;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = ystep;
	co[2] = xstep;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
      } break;
      case 54: {	/* VertShinglesOne */
        co[0] = 0.0;
	co[1] = y3;
	co[2] = x1;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x1;
	co[1] = y2;
	co[2] = x2;
	co[3] = y3;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x2;
	co[1] = y1;
	co[2] = x3;
	co[3] = y2;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x3;
	co[1] = 0.0;
	co[2] = xstep;
	co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = 0.0;
	co[2] = 0.0;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x1;
	co[1] = 0.0;
	co[2] = x1;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x2;
	co[1] = 0.0;
	co[2] = x2;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x3;
	co[1] = 0.0;
	co[2] = x3;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = xstep;
	co[1] = 0.0;
	co[2] = xstep;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
      } break;
      case 55: {	/* VertShinglesOther */
        co[0] = 0.0;
	co[1] = ystep;
	co[2] = x1;
	co[3] = y3;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x1;
	co[1] = y1;
	co[2] = x2;
	co[3] = 0.0;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x2;
	co[1] = y2;
	co[2] = x3;
	co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x3;
	co[1] = y3;
	co[2] = xstep;
	co[3] = y2;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = 0.0;
	co[1] = 0.0;
	co[2] = 0.0;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x1;
	co[1] = 0.0;
	co[2] = x1;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x2;
	co[1] = 0.0;
	co[2] = x2;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = x3;
	co[1] = 0.0;
	co[2] = x3;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
        co[0] = xstep;
	co[1] = 0.0;
	co[2] = xstep;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
      } break;
      case 56: {	/* FishScales */
        do_fish_scales(oi, pat, xstep, ystep, x1, y1, a);
      } break;
      case 57: {	/* SmallFishScales */
        do_fish_scales(oi, pat, xstep, ystep, x1, y1, a);
      } break;
      case 58: {	/* Circles */
        begin_tag(oi, 90);
	kw_out(oi, 1);
        kw_out(oi, 87);
	kw_out(oi, 19);
	kw_out(oi, 20);
        put_double(oi, a, 1);
	kw_out(oi, 20);
	kw_out(oi, 1);
	kw_out(oi, 88);
	kw_out(oi, 19);
	kw_out(oi, 20);
        put_double(oi, a, 1);
	kw_out(oi, 20);
	kw_out(oi, 1);
	kw_out(oi, 89);
	kw_out(oi, 19);
	kw_out(oi, 20);
        put_double(oi, a, 1);
	kw_out(oi, 20);
	kw_out(oi, 0);
	pattern_style(oi, pat, 1);
	kw_out(oi, 0);
        kw_out(oi, 4);
	kw_out(oi, 3);
	kw_out(oi, 0);
      } break;
      case 59: {	/* Hexagons */
        co[0] = x1;
	co[1] = 0.0;
	co[2] = 0.0;
	co[3] = y1;
	co[4] = x1;
	co[5] = ystep;
	co[6] = x2;
	co[7] = ystep;
	co[8] = x3;
	co[9] = y1;
	co[10] = x2;
	co[11] = 0.0;
	pattern_line(oi, co, 6, 1, pat);
	co[0] = x3;
	co[1] = y1;
	co[2] = xstep;
	co[3] = y1;
	pattern_line(oi, co, 2, 0, pat);
	/* for the line ends at the right border */
	co[0] = xstep;
	co[1] = y1;
	co[2] = x4;
	co[3] = 0.0;
	pattern_line(oi, co, 2, 0, pat);
	co[0] = xstep;
	co[1] = y1;
	co[2] = x4;
	co[3] = ystep;
	pattern_line(oi, co, 2, 0, pat);
      } break;
      case 60: {	/* Octagons */
        co[0] = 0.0; co[1] = a;
	co[2] = a; co[3] = 0.0;
	co[4] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[5] = 0.0;
	co[6] = xstep; co[7] = a;
	co[8] = xstep;
	co[9] = dkma_sub_double_ok(ystep, a, &(oi->me));
	co[10] = dkma_sub_double_ok(xstep, a, &(oi->me));
	co[11] = ystep;
	co[12] = a; co[13] = ystep;
	co[14] = 0.0;
	co[15] = dkma_sub_double_ok(ystep, a, &(oi->me));
	pattern_line(oi, co, 8, 1, pat);
      } break;
      case 61: {	/* HorizontalTireTreads */
        y1 = 0.5 * patrp;
	y2 = dkma_mul_double_ok(patrp, 1.5, &(oi->me));
	co[0] = 0.0;
	co[1] = y1;
	co[2] = patrp;
	co[3] = y2;
	co[4] = xstep;
	co[5] = y1;
	pattern_line(oi, co, 3, 0, pat);
      } break;
      case 62: {	/* VerticalTireTreads */
        x1 = 0.5 * patrp;
	x2 = dkma_mul_double_ok(patrp, 1.5, &(oi->me));
	co[0] = x1;
	co[1] = 0.0;
	co[2] = x2;
	co[3] = patrp;
	co[4] = x1;
	co[5] = ystep;
	pattern_line(oi, co, 3, 0, pat);
      } break;
    }
  }
  end_tag(oi, 35);
  
}



/**	Write a font size.
	@param	oi	OI structure.
	@param	sty	Style information structure.
*/
static
void
put_font_size DK_P2(OI *,oi, SVGSTY *,sty)
{
  if(((oi->c)->opt2) & DKFIG_OPT_SVG_FONTSIZE_UNIT) {
    switch((oi->c)->svgs) {
      case DKFIG_SVG_VP_INCHES: {
        dkstream_puts_double(
          oi->s,
          drd(
	    dkma_mul_double_ok((sty->fonth)->fontsize, (oi->c)->fsf, &(oi->me)),
	    oi->c, 1
          )
        );
	kw_out(oi, 81);
      } break;
      case DKFIG_SVG_VP_PIXELS: {
        dkstream_puts_double(
          oi->s,
          drd(
            (pt_to_bp *
	     dkma_mul_double_ok((sty->fonth)->fontsize, (oi->c)->fsf, &(oi->me))
	    ),
	    oi->c, 1
          )
        );
	kw_out(oi, 22);
      } break;
      default: {
        dkstream_puts_double(
          oi->s,
          drd(
            (pt_to_bp *
	     dkma_mul_double_ok((sty->fonth)->fontsize, (oi->c)->fsf, &(oi->me))
	    ),
	    oi->c, 1
          )
        );
      } break;
    }
  } else {
    dkstream_puts_double(
      oi->s,
      drd(
        (pt_to_bp *
	 dkma_mul_double_ok((sty->fonth)->fontsize, (oi->c)->fsf, &(oi->me))
	),
	oi->c, 1
      )
    );
  }
}



/**	Write style information (style contents).
	The iscss flag indicates whether we are in
	a style type="text/css" section or in
	a style="..." string.
	@param	oi	OI structure.
	@param	sty	Style information structure.
	@param	iscss	Flag: Write CSS style definition (1) or
	attribute set (0).
*/
static
void
style_out DK_P3(OI *,oi, SVGSTY *,sty, int,iscss)
{
  double dotlgt;
  int had_entry;
  dk_one_font_mapping_t	*pofm;
  dk_font_replacement_t *pfr;
  char *fontfamilyname;
  
  dotlgt = 0.0;
  if(oi->prep_mods) {
    if(!iscss) {
      if((sty->flags) & DKFIG_SVG_FL_TEXT) {
        if(sty->fonth) {
          switch((sty->fonth)->handling) {
            case 2: case 3: case 4: case 5: { } break;
  	  default: {
  	    char *ptr; int ft;
            /* font-family */
  	    if(iscss) { kw_out(oi, 0); }
  	    kw_out(oi, 46); kw_out(oi, 19); kw_out(oi, 20);
            ptr = dkfont_get_svg_family_name((size_t)((sty->fonth)->fontno));
	    
  	    if(oi->urw_dir) {
  	      if(((sty->fonth)->fontno) >= 0) {
  	        if(((sty->fonth)->fontno) < 35) {
  	          ptr = urw_svg_font_families[(sty->fonth)->fontno];
		  
  	        }
  	      }
  	    }
  	    ft = dkfont_get_features((size_t)((sty->fonth)->fontno));
	    had_entry = 0;
	    if(oi->fontmap) {
	      pofm = dkfont_get_one_font(oi->fontmap, (sty->fonth)->fontno);
	      if(pofm) {
	        dkfont_one_font_reset(pofm);
		while((pfr = dkfont_one_font_get(pofm)) != NULL) {
		  if(dkfont_rep_check_driver(pfr, kw[5])) {
		    fontfamilyname = dkfont_rep_get_family(pfr);
		    if(fontfamilyname) {
		      if(had_entry) {
		        kw_out(oi, 55);
		      }
  	              kw_out(oi, (iscss ? 20 : 107));
		      dkstream_puts(oi->s, fontfamilyname);
  	              kw_out(oi, (iscss ? 20 : 107));
		      had_entry = 1;
		    }
		  }
		}
	      }
	    } else {
  	      if(ptr) {
	        
  	        kw_out(oi, (iscss ? 20 : 107));
  	        dkstream_puts(oi->s, ptr);
  	        kw_out(oi, (iscss ? 20 : 107));
		had_entry = 1;
  	      }
	    }
	    if(had_entry) {
	      kw_out(oi, 55);
	    }
  	    switch(ft & DK_FONT_FEATURE_FAMILY) {
  	      case DK_FONT_FEATURE_TT: {
  	        kw_out(oi, 58);
  	      } break;
  	      case DK_FONT_FEATURE_SF: {
  	        kw_out(oi, 57);
  	      } break;
  	      default: {
  	        kw_out(oi, 56);
  	      } break;
  	    }
  	    kw_out(oi, 20);


  	    kw_out(oi, 0);
  	    kw_out(oi, 47); kw_out(oi, 19); kw_out(oi, 20);
  	    kw_out(oi, ((ft & DK_FONT_FEATURE_IT) ? 60 : 59));
  	    kw_out(oi, 20);
  	    kw_out(oi, 1);
  	    kw_out(oi, 48); kw_out(oi, 19); kw_out(oi, 20);
  	    kw_out(oi, ((ft & DK_FONT_FEATURE_BD) ? 61 : 59));
  	    kw_out(oi, 20);
  	    kw_out(oi, 1);
  	    kw_out(oi, 49); kw_out(oi, 19); kw_out(oi, 20);
	    /*
	      font size
	    */
	    put_font_size(oi, sty);
  	    /* kw_out(oi, 81); */
  	    kw_out(oi, 20);
  	    kw_out(oi, 0);
              /* align */
  	    kw_out(oi, 51); kw_out(oi, 19); kw_out(oi, 20);
  	    switch(sty->talign) {
  	      case 1: {
  	        kw_out(oi, 53);
  	      } break;
  	      case 2: {
  	        kw_out(oi, 54);
  	      } break;
  	      default: {
  	        kw_out(oi, 52);
  	      } break;
  	    }
  	    kw_out(oi, 20);
  	    kw_out(oi, 1);
              /* color */
  	    /* kw_out(oi, 50); */
  	    kw_out(oi, 62); kw_out(oi, 19); kw_out(oi, 20);
  	    color_out(oi, sty->sred, sty->sgreen, sty->sblue);
  	    kw_out(oi, 20);
	    kw_out(oi, 0);
  	  } break;
          }
        }
      } else {
        if(iscss) { kw_out(oi, 0); }
        kw_out(oi, 62); kw_out(oi, 19); kw_out(oi, 20);
        if((sty->flags) & DKFIG_SVG_FL_FILL) {
          if(sty->pat) {
            kw_out(oi, 74);
  	    kw_out(oi, 75);
  	    kw_out(oi, 45);
            kw_out(oi, 37);
            dkfig_tool_num_as_string(oi->s, (sty->pat)->patno, oi->lpat);
  	    kw_out(oi, 76);
          } else {
            color_out(oi, sty->fred, sty->fgreen, sty->fblue);
          }
        } else {
          kw_out(oi, 65);
        }
        kw_out(oi, 20);
        kw_out(oi, 1);
        kw_out(oi, 63); kw_out(oi, 19); kw_out(oi, 20);
        if((sty->flags) & DKFIG_SVG_FL_STROKE) {
          double mylw;
          color_out(oi, sty->sred, sty->sgreen, sty->sblue);
          kw_out(oi, 20);
          kw_out(oi, 1);
          mylw = ccll(oi, sty->lw, 1);
          /*
          mylw = dkma_l_to_double(sty->lw);
          mylw = dkma_mul_double_ok(mylw, oi->mx, &(oi->me));
          if((sty->flags) & DKFIG_SVG_FL_ENLIGHTEN) {
            mylw = mylw * 0.5;
          }
          */
          kw_out(oi, 64); kw_out(oi, 19); kw_out(oi, 20);
          put_double(oi, mylw, 1);
          kw_out(oi, 20);
          if(sty->lc) {
            kw_out(oi, 0);
            kw_out(oi, 67); kw_out(oi, 19); kw_out(oi, 20);
            switch(sty->lc) {
              case 2: {
  	      kw_out(oi, 70);
  	    } break;
  	    case 1: {
  	      kw_out(oi, 69);
  	    } break;
  	    default: {
  	      kw_out(oi, 68);
  	    } break;
            }
            kw_out(oi, 20);
          }
          if(sty->lj) {
            kw_out(oi, 0);
            kw_out(oi, 71); kw_out(oi, 19); kw_out(oi, 20);
            switch(sty->lj) {
              case 2: {
  	      kw_out(oi, 73);
  	    } break;
  	    case 1: {
  	      kw_out(oi, 69);
  	    } break;
  	    default: {
  	      kw_out(oi, 72);
  	    } break;
            }
            kw_out(oi, 20);
          }
          if((sty->ls) > 0) {
            /* double mylw; */
  	  kw_out(oi, 0);
  	  mylw = ccdl(oi, sty->sv, 0);
	  dotlgt = 0.0;
	  if(((oi->c)->opt1) & DKFIG_OPT_DP_DOT_LW) {
	    dotlgt = ccll(oi, ((sty->lw) ? sty->lw : 1L), 1);
	    dotlgt = drd(dotlgt, oi->c, 1);
	  }
  	  /*
            mylw = dkma_l_to_double(sty->sv);
            mylw = dkma_mul_double_ok(mylw, oi->mx, &(oi->me));
  	  */
            mylw = drd(mylw, oi->c, 1);
            kw_out(oi, 66); kw_out(oi, 19); kw_out(oi, 20);
            switch(sty->ls) {
              case 1: {
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	    } break;
  	    case 2: {
  	      dkstream_puts_double(oi->s,dotlgt);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	    } break;
  	    case 3: {
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s,dotlgt);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	    } break;
  	    case 4: {
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s,dotlgt);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s,dotlgt);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	    } break;
  	    case 5: {
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s,dotlgt);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s,dotlgt);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s,dotlgt);
  	      kw_out(oi, 55);
  	      dkstream_puts_double(oi->s, mylw);
  	    } break;
            }
            kw_out(oi, 20);
          }
        } else {
          kw_out(oi, 65); kw_out(oi, 20);
        }
	kw_out(oi, 0);
      }
    }
  } else {
    if(iscss) {
      kw_out(oi, 40);
      kw_out(oi, 44);
      
      dkfig_tool_num_as_string(oi->s, sty->classno, oi->lsty);
      
      kw_out(oi, 1);
      kw_out(oi, 41);
    } else {
      kw_out(oi, 38);
      kw_out(oi, 19);
      dkstream_set_double_no_exponent(oi->s, 1);
      kw_out(oi, 20);
    }
    if((sty->flags) & DKFIG_SVG_FL_TEXT) {
      if(sty->fonth) {
        switch((sty->fonth)->handling) {
          case 2: case 3: case 4: case 5: { } break;
  	default: {
  	  char *ptr; int ft;
          /* font-family */
  	  if(iscss) { kw_out(oi, 0); }
  	  kw_out(oi, 46); kw_out(oi, 24); kw_out(oi, 1);
          ptr = dkfont_get_svg_family_name((size_t)((sty->fonth)->fontno));
	  
  	  if(oi->urw_dir) {
  	    if(((sty->fonth)->fontno) >= 0) {
  	      if(((sty->fonth)->fontno) < 35) {
  	        ptr = urw_svg_font_families[(sty->fonth)->fontno];
		
  	      }
  	    }
  	  }
  	  ft = dkfont_get_features((size_t)((sty->fonth)->fontno));
	  had_entry = 0;
	  if(oi->fontmap) {
	    pofm = dkfont_get_one_font(oi->fontmap, (sty->fonth)->fontno);
	    if(pofm) {
	        dkfont_one_font_reset(pofm);
		while((pfr = dkfont_one_font_get(pofm)) != NULL) {
		  if(dkfont_rep_check_driver(pfr, kw[5])) {
		    fontfamilyname = dkfont_rep_get_family(pfr);
		    if(fontfamilyname) {	
		      if(had_entry) {
		        kw_out(oi, 55);
		      }
  	              kw_out(oi, (iscss ? 20 : 107));
		      dkstream_puts(oi->s, fontfamilyname);
  	              kw_out(oi, (iscss ? 20 : 107));
		      had_entry = 1;
		    }
		  }
		}
	    }
	  } else {
  	    if(ptr) {
	        
  	        kw_out(oi, (iscss ? 20 : 107));
  	        dkstream_puts(oi->s, ptr);
  	        kw_out(oi, (iscss ? 20 : 107));
		had_entry = 1;
  	    }
	  }
	  if(had_entry) {
	      kw_out(oi, 55);
	  }
  	  switch(ft & DK_FONT_FEATURE_FAMILY) {
  	      case DK_FONT_FEATURE_TT: {
  	        kw_out(oi, 58);
  	      } break;
  	      case DK_FONT_FEATURE_SF: {
  	        kw_out(oi, 57);
  	      } break;
  	      default: {
  	        kw_out(oi, 56);
  	      } break;
  	  }
  	  kw_out(oi, 43);
  	  kw_out(oi, (iscss ? 0 : 1));
  	  kw_out(oi, 47); kw_out(oi, 24); kw_out(oi, 1);
  	  kw_out(oi, ((ft & DK_FONT_FEATURE_IT) ? 60 : 59));
  	  kw_out(oi, 43);
  	  kw_out(oi, (iscss ? 0 : 1));
  	  kw_out(oi, 48); kw_out(oi, 24); kw_out(oi, 1);
  	  kw_out(oi, ((ft & DK_FONT_FEATURE_BD) ? 61 : 59));
  	  kw_out(oi, 43);
  	  kw_out(oi, 0);
  	  kw_out(oi, 49); kw_out(oi, 24); kw_out(oi, 1);
	  /*
	    font size
	  */
	  put_font_size(oi, sty);
  	  /* kw_out(oi, 81); */
  	  kw_out(oi, 43);
  	  kw_out(oi, (iscss ? 0 : 1));
            /* align */
  	  kw_out(oi, 51); kw_out(oi, 24); kw_out(oi, 1);
  	  switch(sty->talign) {
  	    case 1: {
  	      kw_out(oi, 53);
  	    } break;
  	    case 2: {
  	      kw_out(oi, 54);
  	    } break;
  	    default: {
  	      kw_out(oi, 52);
  	    } break;
  	  }
  	  kw_out(oi, 43);
  	  kw_out(oi, (iscss ? 0 : 1));
            /* color */
  	  /* kw_out(oi, 50); */
  	  kw_out(oi, 62); kw_out(oi, 24); kw_out(oi, 1);
  	  color_out(oi, sty->sred, sty->sgreen, sty->sblue);
  	  kw_out(oi, 43);
  	} break;
        }
      }
    } else {
      if(iscss) { kw_out(oi, 0); }
      kw_out(oi, 62); kw_out(oi, 24); kw_out(oi, 1);
      if((sty->flags) & DKFIG_SVG_FL_FILL) {
        if(sty->pat) {
          kw_out(oi, 74);
  	  kw_out(oi, 75);
  	  kw_out(oi, 45);
          kw_out(oi, 37);
          dkfig_tool_num_as_string(oi->s, (sty->pat)->patno, oi->lpat);
  	  kw_out(oi, 76);
        } else {
          color_out(oi, sty->fred, sty->fgreen, sty->fblue);
        }
      } else {
        kw_out(oi, 65);
      }
      kw_out(oi, 43);
      kw_out(oi, (iscss ? 0 : 1));
      kw_out(oi, 63); kw_out(oi, 24); kw_out(oi, 1);
      if((sty->flags) & DKFIG_SVG_FL_STROKE) {
        double mylw;
        color_out(oi, sty->sred, sty->sgreen, sty->sblue);
        kw_out(oi, 43);
        kw_out(oi, (iscss ? 0 : 1));
        mylw = ccll(oi, sty->lw, 1);
        /*
        mylw = dkma_l_to_double(sty->lw);
        mylw = dkma_mul_double_ok(mylw, oi->mx, &(oi->me));
        if((sty->flags) & DKFIG_SVG_FL_ENLIGHTEN) {
          mylw = mylw * 0.5;
        }
        */
        kw_out(oi, 64); kw_out(oi, 24); kw_out(oi, 1);
        put_double(oi, mylw, 1);
        kw_out(oi, 43);
        if(sty->lc) {
          kw_out(oi, (iscss ? 0 : 1));
          kw_out(oi, 67); kw_out(oi, 24); kw_out(oi, 1);
          switch(sty->lc) {
            case 2: {
  	    kw_out(oi, 70);
  	  } break;
  	  case 1: {
  	    kw_out(oi, 69);
  	  } break;
  	  default: {
  	    kw_out(oi, 68);
  	  } break;
          }
          kw_out(oi, 43);
        }
        if(sty->lj) {
          kw_out(oi, 0);
          kw_out(oi, 71); kw_out(oi, 24); kw_out(oi, 1);
          switch(sty->lj) {
            case 2: {
  	    kw_out(oi, 73);
  	  } break;
  	  case 1: {
  	    kw_out(oi, 69);
  	  } break;
  	  default: {
  	    kw_out(oi, 72);
  	  } break;
          }
          kw_out(oi, 43);
        }
        if((sty->ls) > 0) {
          /* double mylw; */
  	kw_out(oi, 0);
  	mylw = ccdl(oi, sty->sv, 0);
	dotlgt = 0.0;
	if(((oi->c)->opt1) & DKFIG_OPT_DP_DOT_LW) {
	  dotlgt = ccll(oi, ((sty->lw) ? sty->lw : 1L), 1);
	  dotlgt = drd(dotlgt, oi->c, 1);
	}
  	/*
          mylw = dkma_l_to_double(sty->sv);
          mylw = dkma_mul_double_ok(mylw, oi->mx, &(oi->me));
  	*/
          mylw = drd(mylw, oi->c, 1);
          kw_out(oi, 66); kw_out(oi, 24); kw_out(oi, 1);
          switch(sty->ls) {
            case 1: {
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	  } break;
  	  case 2: {
  	    dkstream_puts_double(oi->s,dotlgt);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	  } break;
  	  case 3: {
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s,dotlgt);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	  } break;
  	  case 4: {
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s,dotlgt);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s,dotlgt);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	  } break;
  	  case 5: {
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s,dotlgt);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s,dotlgt);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s,dotlgt);
  	    kw_out(oi, 55);
  	    dkstream_puts_double(oi->s, mylw);
  	  } break;
          }
          kw_out(oi, 43);
        }
      } else {
        kw_out(oi, 65); kw_out(oi, 43);
      }
    }
    if(iscss) {
      kw_out(oi, 0);
      kw_out(oi, 42);
      kw_out(oi, 0);
    } else {
      kw_out(oi, 20);
      dkstream_set_double_no_exponent(oi->s, 0);
      kw_out(oi, 0);
    }
  }
  
}



/**	Check whether or not an object has a link attached.
	@param	drve	Driver-specific extension to a Fig object.
	@return	1=link attached, 0=no link.
*/
static
int
check_link DK_P1(DRVE *,drve)
{
  int back = 0;
  if(drve) {
    if(drve->xli) {
      dksto_it_reset(drve->xli);
      if(dksto_it_next(drve->xli)) {
        back = 1;
      }
    }
  }
  return back;
}



/**	Write the hyperlink for an object.
	@param	oi	OI structure.
	@param	drve	Driver-specific extension to Fig object.
*/
static
void
print_a_contents DK_P2(OI *,oi, DRVE *,drve)
{
  dk_fig_svg_attr *a;
  if(drve->xli) {
    dksto_it_reset(drve->xli);
    while((a = (dk_fig_svg_attr *)dksto_it_next(drve->xli)) != NULL) {
      if((a->classid >= 0) && ((size_t)(a->classid) < sz_xlcmds) && (a->value)) {
        kw_out(oi, 0);
        dkstream_puts(oi->s, *(xlcmds[a->classid]));
	kw_out(oi, 19);
	kw_out(oi, 20);
	dkstream_puts(oi->s, a->value);
	kw_out(oi, 20);
      }
    }
  }
}



/**	Check whether we need to create a group for an object.
	This is usefull if SVGs are imported into a
	drawing application. In this case we want to
	copy/move not only lines/splines/arcs but also the
	arrowheads attached to them.
	@param	oi	OI structure.
	@return	1=group necessary, 0=no group necessary.
*/
static
int
check_group DK_P1(OI *,oi)
{
  int back = 0, how;
  how = get_how(oi->o);
  switch(how) {
    case 1: {
    } break;
    case 2: {
      if(((DRVE *)((oi->o)->drve))->st1) {
        back = 1;
      }
      if(((DRVE *)((oi->o)->drve))->st2) {
        back = 1;
      }
    } break;
    default: {
      if(!(((oi->o)->fpd).cl)) {
        if((((oi->o)->fpd).ar) & 3) {
	  back = 1;
	}
      }
    } break;
  }
  return back;
}



/**	Transfer text contents to output, encode characters if necessary.
	@param	oi	OI structure.
	@param	s	UTF-8 encoded text to print.
*/
static
void
print_utf8_encoded DK_P2(OI *,oi, char,*s)
{
  /*
  char buffer[10], c, *ptr;
  unsigned char uc; size_t sz;
  int must_encode;
  ptr = s;
  while(*ptr) {
    c = *ptr;
    must_encode = 1;
    if((c >= 'a') && (c <= 'z')) {
      must_encode = 0;
    } else {
      if((c >= 'A') && (c <= 'Z')) {
        must_encode = 0;
      } else {
        if((c >= '0') && (c <= '9')) {
	  must_encode = 0;
	} else {
	  switch(c) {
	    case '|':
	    case '@':
	    case '^':
	    case '!':
	    case '$':
	    case '%':
	    case '/':
	    case '(':
	    case ')':
	    case '=':
	    case '?':
	    case '~':
	    case '*':
	    case '#':
	    case '_':
	    case '+':
	    case '-':
	    case ':':
	    case ';':
	    case ',':
	    case '.':
	    case ' ': {
	      must_encode = 0;
	    } break;
	  }
	}
      }
    }
    if(must_encode) {
      uc = (unsigned char)c; sz = (size_t)uc;
      strcpy(buffer, default_encoding);
      buffer[3] = hex_digits[(sz >> 4) & 15];
      buffer[4] = hex_digits[sz & 15];
      dkstream_puts(oi->s, buffer);
    } else {
      buffer[0] = c;
      buffer[1] = '\0';
      dkstream_puts(oi->s, buffer);
    }
    ptr++;
  }
  */

  dk_udword ucb; unsigned char uc; char chr; int i;
  int cc, must_encode;
  char buffer[16];
  size_t max, used, avail, step;
  cc = 1; max = strlen(s); avail = max; used = 0;
  while(cc) {
    cc = 0;
    if(avail) {
      step = 0;
      cc = dkenc_utf82uc(&ucb, (unsigned char *)(&(s[used])), avail, &step);
      if(cc) {
        used += step;
	if(avail > step) {
	  avail = avail - step;
	} else {
	  avail = 0;
	}
	uc = (unsigned char)ucb; chr = (char)uc; i = (int)chr;
	must_encode = 1;
	if((chr >= 'a') && (chr <= 'z')) {
	  must_encode = 0;
	} else {
	  if((chr >= 'A') && (chr <= 'Z')) {
	    must_encode = 0;
	  } else {
	    if((chr >= '0') && (chr <= '9')) {
	      must_encode = 0;
	    } else {
	      switch(chr) {
	        case '|':
	        case '@':
	        case '^':
	        case '!':
	        case '$':
	        case '%':
	        case '/':
	        case '(':
	        case ')':
	        case '=':
	        case '?':
	        case '~':
	        case '*':
	        case '#':
	        case '_':
	        case '+':
	        case '-':
	        case ':':
	        case ';':
	        case ',':
	        case '.':
	        case ' ': {
	          must_encode = 0;
	        } break;
	      }
	    }
	  }
	}
	if(must_encode) {
	  /*
	  sz = size_t uc;
	  strcpy(buffer, default_encoding);
	  buffer[3] = hex_digits[(sz >> 4) & 15];
	  buffer[4] = hex_digits[sz & 15];
	  */
	  if(ucb > 0x000000FFUL) {
	    if(ucb > 0x0000FFFFUL) {
	      if(ucb > 0x00FFFFFFUL) {
#if DK_HAVE_SNPRINTF
	        snprintf(buffer, sizeof(buffer), "&#x%08lX;", ucb);
		buffer[sizeof(buffer)-1] = '\0';
#else
	        sprintf(buffer, "&#x%08lX;", ucb);
#endif
	      } else {	/* 6 */
#if DK_HAVE_SNPRINTF
	        snprintf(buffer, sizeof(buffer), "&#x%06lX;", ucb);
		buffer[sizeof(buffer)-1] = '\0';
#else
	        sprintf(buffer, "&#x%06lX;", ucb);
#endif
	      }
	    } else {	/* 4 */
#if DK_HAVE_SNPRINTF
              snprintf(buffer, sizeof(buffer), "&#x%04lX;", ucb);
	      buffer[sizeof(buffer)-1] = '\0';
#else
	      sprintf(buffer, "&#x%04lX;", ucb);
#endif
	    }
	  } else {	/* 2 */
#if DK_HAVE_SNPRINTF
            snprintf(buffer, sizeof(buffer), "&#x%02lX;", ucb);
	    buffer[sizeof(buffer)-1] = '\0';
#else
            sprintf(buffer, "&#x%02lX;", ucb);
#endif
	  }
	} else {
	  buffer[0] = chr; buffer[1] = '\0';
	}
	dkstream_puts(oi->s, buffer);
      }
    }
  }
}



/**	Transfer text contents to output, encode characters if necessary.
	@param	oi	OI structure.
	@param	s	Text to print.
*/
static
void
print_text_encoded DK_P2(OI *,oi, char,*s)
{
  char buffer[10], c, *ptr;
  unsigned char uc; size_t sz;
  int must_encode;
  ptr = s;
  while(*ptr) {
    c = *ptr;
    must_encode = 1;
    if((c >= 'a') && (c <= 'z')) {
      must_encode = 0;
    } else {
      if((c >= 'A') && (c <= 'Z')) {
        must_encode = 0;
      } else {
        if((c >= '0') && (c <= '9')) {
	  must_encode = 0;
	} else {
	  switch(c) {
	    case '|':
	    case '@':
	    case '^':
	    case '!':
	    case '$':
	    case '%':
	    case '/':
	    case '(':
	    case ')':
	    case '=':
	    case '?':
	    case '~':
	    case '*':
	    case '#':
	    case '_':
	    case '+':
	    case '-':
	    case ':':
	    case ';':
	    case ',':
	    case '.':
	    case ' ': {
	      must_encode = 0;
	    } break;
	  }
	}
      }
    }
    if(must_encode) {
      uc = (unsigned char)c; sz = (size_t)uc;
      strcpy(buffer, default_encoding);
      buffer[3] = hex_digits[(sz >> 4) & 15];
      buffer[4] = hex_digits[sz & 15];
      dkstream_puts(oi->s, buffer);
    } else {
      buffer[0] = c;
      buffer[1] = '\0';
      dkstream_puts(oi->s, buffer);
    }
    ptr++;
  }
}



/**	Write either style="xxx" parameter or class="xxx" reference.
	@param	oi	OI structure.
	@param	s	SVG style information structure.
*/
static
void
style_or_class DK_P2(OI *,oi, SVGSTY *,s)
{
  if(oi->prep_mods) {
    kw_out(oi, 0);
    style_out(oi, s, 0);
  } else {
    if(((oi->c)->opt1) & DKFIG_OPT_USE_CSS) {
      kw_out(oi, 1);
      kw_out(oi, 80);
      kw_out(oi, 19);
      kw_out(oi, 20);
      kw_out(oi, 44);
      dkfig_tool_num_as_string(oi->s, s->classno, oi->lsty);
      kw_out(oi, 20);
      kw_out(oi, 0);
    } else {
      kw_out(oi, 0);
      style_out(oi, s, 0);
    }
  }
}



/**	Generate output for a text.
	@param	oi	OI structure.
	@param	ug	Flag: Use group.
	@return	1 on success, 0 on error.
*/
static
int
print_text DK_P2(OI *,oi, int,ug)
{
  int back = 0;
  dk_fig_text *t = NULL;
  dk_fig_fonth_t *f = NULL;
  DRVE *d = NULL;
  SVGSTY *s = NULL;
  t = (dk_fig_text *)((oi->o)->data);
  d = (DRVE *)((oi->o)->drve);
  if(d) {
    s = d->st1;
  }
  if((t) && (s)) {
    if(t->text) {
      f = t->font_handling;
      switch(f->handling) {
        case 2: case 3: case 4: case 5: {} break;
        default: {
          back = 1;
          begin_tag(oi, 77);
	  kw_out(oi, 1);
	  if(fabs(t->angle) > DKFIG_EPSILON) {
	    kw_out(oi, 92); kw_out(oi, 19);
	    kw_out(oi, 20);
	    kw_out(oi, 93);
            kw_out(oi, 75);
	    put_double(oi, cclx(oi, t->x), 1);
	    kw_out(oi, 1);
	    put_double(oi, ccly(oi, t->y), 1);
	    kw_out(oi, 76);
	    kw_out(oi, 1);
            kw_out(oi, 94);
	    kw_out(oi, 75);
	    kw_out(oi, 97);
	    dkstream_puts_double(oi->s, 
	      drd(
	        dkma_div_double_ok(
		  dkma_mul_double_ok(180.0, t->angle, &(oi->me)),
		  M_PI,
		  &(oi->me)
		),
	        oi->c, 1
	      )
	    );
	    kw_out(oi, 76);
	    kw_out(oi, 20);
	    kw_out(oi, 1);
	    kw_out(oi, 14);
	    kw_out(oi, 19);
	    kw_out(oi, 20);
	    kw_out(oi, 103);
	    kw_out(oi, 20);
	    kw_out(oi, 1);
	    kw_out(oi, 15);
	    kw_out(oi, 19);
	    kw_out(oi, 20);
	    kw_out(oi, 103);
	    kw_out(oi, 20);
	  } else {
	    kw_out(oi, 14);
	    kw_out(oi, 19);
	    kw_out(oi, 20);
	    put_double(oi, cclx(oi, t->x), 1);
	    kw_out(oi, 20);
	    kw_out(oi, 1);
	    kw_out(oi, 15);
	    kw_out(oi, 19);
	    kw_out(oi, 20);
	    put_double(oi, ccly(oi, t->y), 1);
	    kw_out(oi, 20);
	  }
	  style_or_class(oi, s);
	  if(!ug) {
	    svg_drve_write(oi, oi->o, (DRVE *)((oi->o)->drve), 0);
	  }
          kw_out(oi, 3);
	  if(((oi->c)->opt2) & DKFIG_OPT_UTF_8) {
	    /* UTF-8 encoded */
	    print_utf8_encoded(oi, t->text);
	  } else {
	    print_text_encoded(oi, t->text);
	  }
          end_tag(oi, 77);
        } break;
      }
    }
  }
  return back;
}



/**	Write point specified by double coordinates in Fig space.
	@param	oi	OI structure.
	@param	x	X position.
	@param	y	Y position.
	@param	w	Number of digits after decimal dot.
*/
static
void
point_double DK_P4(OI *,oi, double,x, double,y, int,w)
{
  put_double(
    oi,
    ccdx(oi, x),
    w
  );
  kw_out(oi, 55);
  put_double(
    oi,
    ccdy(oi, y),
    w
  );
}



/**	Write point specified by long coordinates in Fig space.
	@param	oi	OI structure.
	@param	x	X position.
	@param	y	Y position.
*/
static
void
point_long DK_P3(OI *,oi, long,x, long,y)
{
  point_double(
    oi,
    dkma_l_to_double(x),
    dkma_l_to_double(y),
    1
  );
}



/**	Print rectangle/arc box specified by bounding box information b.
	If da is non-zero, we have an arc box, radius is a.
	b and a are in output space.
	@param	oi	OI structure.
	@param	b	Bounding box.
	@param	s	Style information structure.
	@param	da	Flag: Arc box.
	@param	a	Radius for arc box.
*/
static
void
print_rect_arc_bb DK_P5(OI *,oi, dk_fig_bb *,b, SVGSTY *,s, int,da, double,a)
{
  begin_tag(oi, 79);
  kw_out(oi, 1);
  kw_out(oi, 14);
  kw_out(oi, 19);
  kw_out(oi, 20);
  put_double(oi, b->xmin, 1);
  kw_out(oi, 20);
  kw_out(oi, 1);
  kw_out(oi, 15);
  kw_out(oi, 19);
  kw_out(oi, 20);
  put_double(oi, b->ymin, 1);
  kw_out(oi, 20);
  kw_out(oi, 1);
  kw_out(oi, 16);
  kw_out(oi, 19);
  kw_out(oi, 20);
  put_double(oi, (b->xmax - b->xmin), 1);
  kw_out(oi, 20);
  kw_out(oi, 1);
  kw_out(oi, 17);
  kw_out(oi, 19);
  kw_out(oi, 20);
  put_double(oi, (b->ymax - b->ymin), 1);
  kw_out(oi, 20);
  if(da) {
    kw_out(oi, 0);
    kw_out(oi, 82);
    kw_out(oi, 19);
    kw_out(oi, 20);
    put_double(oi, a, 1);
    kw_out(oi, 20);
    kw_out(oi, 1);
    kw_out(oi, 83);
    kw_out(oi, 19);
    kw_out(oi, 20);
    put_double(oi, a, 1);
    kw_out(oi, 20);
  }
  style_or_class(oi, s);
  finish_tag(oi);
}



/**	Draw a rectangle as specified in the bounding-box structure b
	(specified in output space).
	@param	oi	OI structure.
	@param	b	Bounding box.
	@param	s	SVG style information structure.
*/
static
void
print_rect_bb DK_P3(OI *,oi, dk_fig_bb *,b, SVGSTY *,s)
{
  print_rect_arc_bb(oi,b,s,0,0.0);
}



/**	Draw included image.
	@param	oi	OI structure.
	@param	ug	Flag: Use group.
	@return	1 on success, 0 on error.
*/
static
int
print_image DK_P2(OI *,oi, int,ug)
{
  int back = 0;
  dk_fig_bb ibb;
  dk_fig_polyline *p;
  long *xptr, *yptr; size_t i;
  SVGSTY *s;
  double xmin, xmax, ymin, ymax;
  double ori_width, ori_height, xstart, ystart;
  double new_width, new_height;
  unsigned long w, h;
  int res;

  p = (dk_fig_polyline *)((oi->o)->data);
  if(p) {
    if(p->imagename) {
      dkfig_tool_bb_reset(&ibb);
      xptr = p->xvalues; yptr = p->yvalues;
      for(i = 0; i < p->npoints; i++) {
        dkfig_tool_bb_add_x(&ibb, cclx(oi, *xptr));
        dkfig_tool_bb_add_y(&ibb, ccly(oi, *yptr));
        xptr++; yptr++;
      }
      if(p->npoints > 0) {
        back = 1;
        if(((DRVE *)((oi->o)->drve))->st1) {
          s = ((DRVE *)((oi->o)->drve))->st1;
          print_rect_bb(oi, &ibb, s);
        }
        xmin = dkfig_tool_bb_get_xmin(&ibb);
        xmax = dkfig_tool_bb_get_xmax(&ibb);
        ymin = dkfig_tool_bb_get_ymin(&ibb);
        ymax = dkfig_tool_bb_get_ymax(&ibb);
        if(((DRVE *)((oi->o)->drve))->st2) {
          double lwh;
	  lwh = 0.5 * ccll(oi, (((DRVE *)((oi->o)->drve))->st2)->lw, 1);
	  xmin = dkma_add_double_ok(xmin, lwh, &(oi->me));
	  xmax = dkma_sub_double_ok(xmax, lwh, &(oi->me));
	  ymin = dkma_add_double_ok(ymin, lwh, &(oi->me));
	  ymax = dkma_sub_double_ok(ymax, lwh, &(oi->me));
        }
        ori_width = dkma_sub_double_ok(xmax, xmin, &(oi->me));
        ori_height = dkma_sub_double_ok(ymax, ymin, &(oi->me));
	new_width = ori_width; new_height = ori_height;
	xstart = xmin; ystart = ymin;
	
        res = dkfig_tool2_get_image_size(oi->c, p->imagename, &w, &h);
	if(res) {
	  if(((oi->c)->opt1) & DKFIG_OPT_KEEP_BITMAP_WH_RATIO) {
	    double ls, rs;
	    
	    ls = dkma_div_double_ok(
	      dkma_l_to_double(h),
	      dkma_l_to_double(w),
	      &(oi->me)
	    );
	    rs = dkma_div_double_ok(ori_height, ori_width, &(oi->me));
	    if(ls > rs) {
	      new_width = dkma_mul_double_ok(
	        new_height,
		dkma_div_double_ok(
		  dkma_l_to_double(w),
		  dkma_l_to_double(h),
		  &(oi->me)
		),
		&(oi->me)
	      );
	      switch(((oi->c)->image_align) & 3) {
	        case DKFIG_ALIGN_H_CENTERED: {
	          xstart = dkma_add_double_ok(
	            xstart,
		    (0.5 * dkma_sub_double_ok(ori_width, new_width, &(oi->me))),
		    &(oi->me)
	          );
		} break;
		case DKFIG_ALIGN_H_RIGHT: {
	          xstart = dkma_add_double_ok(
	            xstart,
		    dkma_sub_double_ok(ori_width, new_width, &(oi->me)),
		    &(oi->me)
	          );
		} break;
	      }
	    } else {
	      new_height = dkma_mul_double_ok(
	        new_width,
		dkma_div_double_ok(
		  dkma_l_to_double(h),
		  dkma_l_to_double(w),
		  &(oi->me)
		),
		&(oi->me)
	      );
	      switch((((oi->c)->image_align) >> 2) & 3) {
	        case DKFIG_ALIGN_V_CENTERED: {
	          ystart = dkma_add_double_ok(
	            ystart,
		    (0.5 * dkma_sub_double_ok(ori_height, new_height, &(oi->me))),
		    &(oi->me)
	          );
		} break;
		case DKFIG_ALIGN_V_BOTTOM: {
	          ystart = dkma_add_double_ok(
	            ystart,
		    dkma_sub_double_ok(ori_height, new_height, &(oi->me)),
		    &(oi->me)
	          );
		} break;
	      }
	    }
	  }
	} else {
	  dkfig_tool2_msg3(oi->c, DK_LOG_LEVEL_WARNING, 95, 92, p->imagename);
	}
	
	begin_tag(oi, 112);
	kw_out(oi, 1);
        kw_out(oi, 14);
	kw_out(oi, 19);
	kw_out(oi, 20);
	put_double(oi, xstart, 1);
	kw_out(oi, 20);
	kw_out(oi, 1);
        kw_out(oi, 15);
	kw_out(oi, 19);
	kw_out(oi, 20);
	put_double(oi, ystart, 1);
	kw_out(oi, 20);
        kw_out(oi, 1);
        kw_out(oi, 16);
	kw_out(oi, 19);
	kw_out(oi, 20);
	put_double(oi, new_width, 1);
	kw_out(oi, 20);
        kw_out(oi, 1);
        kw_out(oi, 17);
	kw_out(oi, 19);
	kw_out(oi, 20);
	put_double(oi, new_height, 1);
	kw_out(oi, 20);
	kw_out(oi, 0);
	dkstream_puts(oi->s, xlc00[0]);
	kw_out(oi, 19);
	kw_out(oi, 20);
	dkstream_puts(oi->s, p->imagename);
	kw_out(oi, 20);
	kw_out(oi, 0);
	kw_out(oi, 4);
	kw_out(oi, 3);
	kw_out(oi, 0);
        if(((DRVE *)((oi->o)->drve))->st2) {
	  s = ((DRVE *)((oi->o)->drve))->st2;
	  print_rect_bb(oi, &ibb, s);
        }
      }
    }
  }
  return back;
}



/**	Check the corner radius for arc boxes, correct (decrease) radius if
	necessary.
	@param	rx	Original corner radius.
	@param	oi	OI structure.
	@param	mini	Minimum side length.
	@param	maxi	Maximum side length.
	@return	Corner radius.
*/
static
double
check_rx DK_P4(double,rx, OI *,oi, double,mini, double,maxi)
{
  double back, distance;
  back = rx;
  if(back < 0.0) { back = 0.0 - back; }
  distance = fabs(dkma_sub_double_ok(maxi, mini, &(oi->me)));
  if(back > (0.5 * distance)) {
    back = 0.5 * distance;
  }
  return back;
}



/**	Eraw a polyline/polygon, spline, ellipse or arc.
	(Everything except text or included image)
	@param	oi	OI structure.
	@param	ug	Flag: Use group.
	@return	1 on success, 0 on error.
*/
static
int
print_path_object DK_P2(OI *,oi, int,ug)
{
  int back = 0;
  dk_fig_arc *pa;
  dk_fig_spline *ps;
  dk_fig_polyline *pp;
  dk_fig_ellipse *pe;
  DRVE *d = NULL; SVGSTY *s = NULL;
  d = (DRVE *)((oi->o)->drve);
  if(d) {
    s = d->st1;
    if(s) {
      switch((oi->o)->objtype) {
        case DK_FIG_OBJ_ARC: {
          pa = (dk_fig_arc *)((oi->o)->data);
          if(pa) {
	    double aa, ae, p1x, p1y, p2x, p2y, r;
	    int    islong;
	    aa = ae = p1x = p1y = p2x = p2y = 0.0;
	    islong = 0;
	    r = ccdr(oi, (pa->calc).ra);
	    aa = (pa->calc).astart;
	    if((!(((oi->o)->fpd).cl)) && ((((oi->o)->fpd).ar) & 2)) {
	      aa = dkma_add_double_ok(aa, pa->lba, &(oi->me));
	    }
	    ae = dkma_add_double_ok(
	      (pa->calc).astart, (pa->calc).alength, &(oi->me)
	    );
	    if((!(((oi->o)->fpd).cl)) && ((((oi->o)->fpd).ar) & 1)) {
	      ae = dkma_sub_double_ok(ae, pa->rba, &(oi->me));
	    }
	    p1x = dkma_add_double_ok(
	      (pa->calc).xm,
	      (((pa->calc).ra) * cos(aa)),
	      &(oi->me)
	    );
	    p2x = dkma_add_double_ok(
	      (pa->calc).xm,
	      (((pa->calc).ra) * cos(ae)),
	      &(oi->me)
	    );
	    if(dkfig_tool_invert_y(oi->d)) {
	      p1y = dkma_sub_double_ok(
	        (pa->calc).ym,
		(((pa->calc).ra) * sin(aa)),
		&(oi->me)
	      );
	      p2y = dkma_sub_double_ok(
	        (pa->calc).ym,
		(((pa->calc).ra) * sin(ae)),
		&(oi->me)
	      );
	    } else {
	      p1y = dkma_add_double_ok(
	        (pa->calc).ym,
		(((pa->calc).ra) * sin(aa)),
		&(oi->me)
	      );
	      p2y = dkma_add_double_ok(
	        (pa->calc).ym,
		(((pa->calc).ra) * sin(ae)),
		&(oi->me)
	      );
	    }
	    while(ae < aa) {
	      ae = dkma_add_double_ok(ae, (2.0 * M_PI), &(oi->me));
	    }
	    if(dkma_sub_double_ok(ae, aa, &(oi->me)) >= M_PI) {
	      islong = 1;
	    } else {
	      islong = 0;
	    }
	    back = 1;
	    begin_tag(oi, 98);
	    style_or_class(oi, s);
	    kw_out(oi, 99);
	    kw_out(oi, 19);
	    kw_out(oi, 20);
	    if(((oi->o)->fpd).cl) {	/* pie-wedge */
	      kw_out(oi, 100);
	      point_double(oi, (pa->calc).xm, (pa->calc).ym, 1);
	      kw_out(oi, 1);
	      kw_out(oi, 101);
	      point_double(oi, p1x, p1y, 1);
	      kw_out(oi, 0);
	    } else {			/* open arc */
	      kw_out(oi, 100);
	      point_double(oi, p1x, p1y, 1);
	    }
	    kw_out(oi, 1);
	    kw_out(oi, 102);
	    put_double(oi, r, 1);
	    kw_out(oi, 1);
	    put_double(oi, r, 1);
	    kw_out(oi, 1);
	    kw_out(oi, 103);
	    kw_out(oi, 1);
	    kw_out(oi, (islong ? 104 : 103));
	    kw_out(oi, 1);
	    kw_out(oi, 103);
	    kw_out(oi, 1);
	    point_double(oi, p2x, p2y, 1);
	    if(((oi->o)->fpd).cl) {	/* pie-wedge */
	      kw_out(oi, 0);
	      kw_out(oi, 101);
	      point_double(oi, (pa->calc).xm, (pa->calc).ym, 1);
	      kw_out(oi, 105);
	    }
	    kw_out(oi, 20);
	    kw_out(oi, 0);
	    finish_tag(oi);
          }
        } break;
        case DK_FIG_OBJ_SPLINE: {
	  dk_fig_bezier_point *bpptr;
          size_t nsegs, li, ri, maxli;
          ps = (dk_fig_spline *)((oi->o)->data);
          if(ps) {
	    if((ps->nbpoints) >= 2) {
              begin_tag(oi, 98);
	      style_or_class(oi, s);
	      kw_out(oi, 99);
	      kw_out(oi, 19);
	      kw_out(oi, 20);
	      bpptr = ps->bpoints;
	      nsegs = ps->nbpoints - 1;
	      if(((oi->o)->fpd).cl) { nsegs = ps->nbpoints; }
	      if((!(((oi->o)->fpd).cl)) && ((((oi->o)->fpd).ar) & 2)) {
	        /* moveto point pa */
		kw_out(oi, 100);
		point_double(oi,(ps->pa).value.x,(ps->pa).value.y, 1);
		kw_out(oi, 0);
		/* bezier to point pa2 */
		kw_out(oi, 106);
		point_double(oi, (ps->pa).rcontrol.x, (ps->pa).rcontrol.y, 1);
		kw_out(oi, 1);
		point_double(oi, (ps->pa2).lcontrol.x, (ps->pa2).lcontrol.y, 1);
		kw_out(oi, 1);
		point_double(oi, (ps->pa2).value.x, (ps->pa2).value.y, 1);
		li = ps->normals;
	      } else {
	        /* moveto point 0 */
		kw_out(oi, 100);
		point_double(oi,bpptr[0].value.x,bpptr[0].value.y, 1);
		li = 0;
	      }
	      kw_out(oi, 0);
              if((ps->normale > 0)||(((oi->o)->fpd).cl)||(!((((oi->o)->fpd).ar) & 1))) 
	      {
                maxli = ps->nbpoints - 2;
                if(((oi->o)->fpd).cl) { maxli = ps->nbpoints - 1; }
                if((!(((oi->o)->fpd).cl)) && (((oi->o)->fpd).ar & 1)) {
                  maxli = ps->normale - 1;
                }
		while(li <= maxli) {
		  ri = li + 1;
		  if(ri >= ps->nbpoints) { ri = 0; }
		  kw_out(oi, 106);
		  point_double(oi, bpptr[li].rcontrol.x, bpptr[li].rcontrol.y, 1);
		  kw_out(oi, 1);
		  point_double(oi, bpptr[ri].lcontrol.x, bpptr[ri].lcontrol.y, 1);
		  kw_out(oi, 1);
		  point_double(oi, bpptr[ri].value.x, bpptr[ri].value.y, 1);
		  kw_out(oi, 0);
		  li++;
		}
              }
	      if(((oi->o)->fpd).cl) {
	        kw_out(oi, 105);
	      } else {
	        if((((oi->o)->fpd).ar) & 1) {
		  kw_out(oi, 106);
		  point_double(oi, (ps->pe2).rcontrol.x, (ps->pe2).rcontrol.y, 1);
		  kw_out(oi, 1);
		  point_double(oi, (ps->pe).lcontrol.x, (ps->pe).lcontrol.y, 1);
		  kw_out(oi, 1);
		  point_double(oi, (ps->pe).value.x, (ps->pe).value.y, 1);
		  kw_out(oi, 0);
		}
	      }
	      kw_out(oi, 20);
	      kw_out(oi, 0);
	      finish_tag(oi);
	    }
          }
        } break;
        case DK_FIG_OBJ_POLYLINE: {
          pp = (dk_fig_polyline *)((oi->o)->data);
          if(pp) {
	    long *xptr, *yptr; size_t i, npoints;
	    double rx; int urx, wr_nl, wr_no;
            dk_fig_bb ibb;
	    urx = 0; rx = 0.0;
	    switch((oi->o)->subtype) {
	      case 5: {	/* image, handled somewhere else */
	      } break;
	      case 2:	/* box */
	      case 4: {	/* arc-box */
                dkfig_tool_bb_reset(&ibb);
                xptr = pp->xvalues; yptr = pp->yvalues;
                for(i = 0; i < pp->npoints; i++) {
                  dkfig_tool_bb_add_x(&ibb, cclx(oi, *xptr));
                  dkfig_tool_bb_add_y(&ibb, ccly(oi, *yptr));
                  xptr++; yptr++;
                }
		if(pp->npoints > 0) {
		  if((oi->o)->subtype == 4) {
		    if(pp->radius > 0L) {
		      urx = 1;
		      rx = ccll(oi, pp->radius, 0);
		      rx = check_rx(rx, oi, ibb.xmin, ibb.xmax);
		      rx = check_rx(rx, oi, ibb.ymin, ibb.ymax);
		    }
		  }
		  print_rect_arc_bb(oi, &ibb, s, urx, rx);
		  back = 1;
		}
	      } break;
	      case 3: {	/* polygon */
	        xptr = pp->xvalues; yptr = pp->yvalues;
		npoints = pp->npoints;
		if(npoints) {
		  back = 1;
		  if(xptr[0] == xptr[npoints-1]) {
		    if(yptr[0] == yptr[npoints-1]) {
		      npoints--;
		    }
		  }
		  begin_tag(oi, 84);
		  style_or_class(oi, s);
		  kw_out(oi, 86);
		  kw_out(oi, 19);
		  kw_out(oi, 20);
		  wr_nl = 0; wr_no = 0;
		  for(i = 0; i < npoints; i++) {
		    if(i) {
		      /*
		      kw_out(oi, (wr_nl ? 0 : 1));
		      if(wr_nl) { wr_nl = 0; }
		      if(wr_no >= 3) {
		        wr_no = 0; wr_nl = 1;
		      } else {
		        wr_no++;
		      }
		      */
		      kw_out(oi, 0);
		    }
		    point_long(oi, xptr[i], yptr[i]);
		  }
		  kw_out(oi, 20);
		  kw_out(oi, 0);
		  finish_tag(oi);
		}
	      } break;
	      case 1: {	/* polyline */
	        xptr = pp->xvalues; yptr = pp->yvalues;
		npoints = pp->npoints;
		if(npoints) {
		  back = 1;
		  begin_tag(oi, 85);
		  style_or_class(oi, s);
		  kw_out(oi, 86);
		  kw_out(oi, 19);
		  kw_out(oi, 20);
		  wr_nl = 0; wr_no = 0;
		  for(i = 0; i < npoints; i++) {
		    if(i) {
		      /* 
		      kw_out(oi, (wr_nl ? 0 : 1));
		      if(wr_nl) { wr_nl = 0; }
		      if(wr_no >= 3) {
		        wr_no = 0; wr_nl = 1;
		      } else {
		        wr_no++;
		      }
		      */
		      kw_out(oi, 0);
		    }
		    if((i == 0) && ((((oi->o)->fpd).ar) & 2)) {
		      point_double(oi, (pp->pa).x, (pp->pa).y, 1);
		    } else {
		      if((i == (npoints - 1)) && ((((oi->o)->fpd).ar) & 1)) {
		        point_double(oi, (pp->pe).x, (pp->pe).y, 1);
		      } else {
		        point_long(oi, xptr[i], yptr[i]);
		      }
		    }
		  }
		  kw_out(oi, 20);
		  kw_out(oi, 0);
		  finish_tag(oi);
		}
	      } break;
	    }
          }
        } break;
        case DK_FIG_OBJ_ELLIPSE: {
          pe = (dk_fig_ellipse *)((oi->o)->data);
          if(pe) {
	    if((pe->radiusx) == (pe->radiusy)) {
	      begin_tag(oi, 90);
	      kw_out(oi, 1);
	      kw_out(oi, 87);
	      kw_out(oi, 19);
	      kw_out(oi, 20);
	      put_double(oi, cclx(oi, pe->centerx), 1);
	      kw_out(oi, 20);
	      kw_out(oi, 1);
	      kw_out(oi, 88);
	      kw_out(oi, 19);
	      kw_out(oi, 20);
	      /* cy */
	      put_double(oi, ccly(oi, pe->centery), 1);
	      kw_out(oi, 20);
	      kw_out(oi, 1);
	      kw_out(oi, 89);
	      kw_out(oi, 19);
	      kw_out(oi, 20);
	      /* r */
	      put_double(oi, cclr(oi, pe->radiusx), 1);
	      kw_out(oi, 20);
	      style_or_class(oi, s);
	      if(!ug) {
	        svg_drve_write(oi, oi->o, (DRVE *)((oi->o)->drve), 0);
	      }
	      finish_tag(oi);
	    } else {
	      begin_tag(oi, 91);
	      kw_out(oi, 1);
	      kw_out(oi, 92);
	      kw_out(oi, 19);
	      kw_out(oi, 20);
              kw_out(oi, 93);
	      kw_out(oi, 75);
	      put_double(oi, cclx(oi, pe->centerx), 1);
	      kw_out(oi, 1);
	      put_double(oi, ccly(oi, pe->centery), 1);
	      kw_out(oi, 76);
	      if(fabs(pe->angle) > DKFIG_EPSILON) {
	        kw_out(oi, 1);
		kw_out(oi, 94);
		kw_out(oi, 75);
		kw_out(oi, 97);
		put_double(
		  oi,
		  dkma_mul_double_ok(
		    pe->angle,
		    dkma_div_double_ok(180.0, M_PI, &(oi->me)),
		    &(oi->me)
		  ),
		  1
		);
		kw_out(oi, 76);
	      }
	      kw_out(oi, 20);
	      kw_out(oi, 0);
	      kw_out(oi, 95);
	      kw_out(oi, 19);
	      kw_out(oi, 20);
	      put_double(oi, cclr(oi, pe->radiusx), 1);
	      kw_out(oi, 20);
	      kw_out(oi, 1);
	      kw_out(oi, 96);
	      kw_out(oi, 19);
	      kw_out(oi, 20);
	      put_double(oi, cclr(oi, pe->radiusy), 1);
	      kw_out(oi, 20);
	      style_or_class(oi, s);
	      if(!ug) {
	        svg_drve_write(oi, oi->o, (DRVE *)((oi->o)->drve), 0);
	      }
	      finish_tag(oi);
	    }
          }
        } break;
      }
    }
  }
  return back;
}



/**	Draw arrowhead, this is typically done after drawing the line.
	@param	oi	OI structure.
	@param	o	Current object.
	@param	ah	Arrowhead structure.
	@param	d	Driver-specific extension data for Fig object.
	@param	s	SVG style information structure for object.
*/
static
void
arrow_head DK_P5(OI *,oi, OBJ *,o, AH *,ah, DRVE *,d, SVGSTY *,s)
{
  if((ah->type) > 0) {
    begin_tag(oi, 84);
  } else {
    begin_tag(oi, 85);
  }
  style_or_class(oi, s);
  kw_out(oi, 86);
  kw_out(oi, 19);
  kw_out(oi, 20);
  point_double(oi, (ah->p1).x, (ah->p1).y, 1);
  kw_out(oi, 1);
  point_double(oi, (ah->p2).x, (ah->p2).y, 1);
  kw_out(oi, 1);
  point_double(oi, (ah->p3).x, (ah->p3).y, 1);
  if((ah->numpoints) > 3) {
    kw_out(oi, 1);
    point_double(oi, (ah->p4).x, (ah->p4).y, 1);
  }
  kw_out(oi, 20);
  kw_out(oi, 0);
  finish_tag(oi);
}



/**	Handle one graphics object.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
output_object DK_P1(OI *,oi)
{
  int back = 1;
  unsigned long backupopt1, backupopt2;
  int use_link, use_group, how, backupia;
  DRVE *d; SVGSTY *s;
  
  backupopt1 = (oi->c)->opt1;
  backupopt2 = (oi->c)->opt2;
  backupia = (oi->c)->image_align;
  /* handle special comments */
  if((oi->o)->osci) {
    (void)handle_spc_for_object(oi, oi->o, (oi->o)->osci, 0, 0);
  }
  use_link = use_group = how = 0;
  use_link = check_link((DRVE *)((oi->o)->drve));
  use_group = check_group(oi);
  if(((oi->c)->opt1) & DKFIG_OPT_VERBOSE_OUTPUT) {
    kw_out(oi, 113);
    kw_out(oi, 115);
    dkstream_puts_ul(oi->s, (oi->o)->lineno);
    kw_out(oi, 55);
    kw_out(oi, 1);
    kw_out(oi, 116);
    dkstream_puts_ul(oi->s, (unsigned long)((oi->o)->layer));
    kw_out(oi, 114);
    kw_out(oi, 0);
  }
  if(use_link) {
    begin_tag(oi, 33);
    print_a_contents(oi, (DRVE *)((oi->o)->drve));
    kw_out(oi, 0); kw_out(oi, 3); kw_out(oi, 0);
  }
  if(use_group) {
    begin_tag(oi, 34);
    if(how != 2) {
      svg_drve_write(oi, oi->o, (DRVE *)((oi->o)->drve), 0);
    }
    kw_out(oi, 3); kw_out(oi, 0);
  }
  /* print object */
  how = get_how(oi->o);
  switch(how) {
    case 1: {	/* text */
      print_text(oi, use_group);
    } break;
    case 2: {	/* included image */
      print_image(oi, use_group);
    } break;
    default: {	/* path object */
      int must_draw = 1;
      if(((oi->c)->opt1) & DKFIG_OPT_REMOVE_BG_RECTANGLE) {
        int wbgr = 0;
	if(((oi->c)->opt2) & DKFIG_OPT_WHITE_BGRECT) {
	  wbgr = 1;
	}
	if(dkfig_tool2_obj_is_bg_rect(oi->o, wbgr)) {
	  must_draw = 0;
	}
      }
      if(must_draw) {
        print_path_object(oi, use_group);
      }
    } break;
  }
  /* forward arrow */
  if((!(((oi->o)->fpd).cl)) && ((((oi->o)->fpd).ar) & 1)) {
    d = (DRVE *)((oi->o)->drve);
    if(d) {
      s = d->st2;
      if(s) {
        arrow_head(oi, oi->o, &(((oi->o)->fpd).ahf), d, s);
      }
    }
  }
  /* backward arrow */
  if((!(((oi->o)->fpd).cl)) && ((((oi->o)->fpd).ar) & 2)) {
    d = (DRVE *)((oi->o)->drve);
    if(d) {
      s = d->st3;
      if(s) {
        arrow_head(oi, oi->o, &(((oi->o)->fpd).ahb), d, s);
      }
    }
  }
  if(use_group) {
    end_tag(oi, 34);
  }
  if(use_link) {
    end_tag(oi, 33);
  }
  (oi->c)->opt1 = backupopt1;
  (oi->c)->opt2 = backupopt2;
  (oi->c)->image_align = backupia;
  
  return back;
}



/**	Write title and desc sections.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
svg_title_and_desc DK_P1(OI *,oi)
{
  int back = 1;
  
  begin_tag(oi, 25); kw_out(oi, 3);
  dkstream_puts(oi->s, (((oi->c)->ifn2) ? ((oi->c)->ifn2) : (name_stdin)));
  end_tag(oi, 25);
  begin_tag(oi, 26); kw_out(oi, 3);
  kw_out(oi, 27);
  end_tag(oi, 26); 
  return back;
}



/**	Write JavaScript code from the named library files into the
	defs section.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
write_js_libraries DK_P1(OI *,oi)
{
  int back = 1; int is_first;
  dk_fig_opt *fo;
  FILE *fipo;
  char inputline[512], *sptr;
  
  if((oi->jsl) && (oi->jsli)) {
    is_first = 1;
    dksto_it_reset(oi->jsli);
    while((fo = (dk_fig_opt *)dksto_it_next(oi->jsli)) != NULL) {
      if(fo->name) {
        if((oi->c)->app) {
	  fipo = dkapp_fopen((oi->c)->app, fo->name, str_mode_open_read);
	} else {
	  fipo = dksf_fopen(fo->name, str_mode_open_read);
	}
	if(fipo) {
	  if(is_first) {
	    begin_tag(oi, 32); kw_out(oi, 1);
	    kw_out(oi, 29); kw_out(oi, 3);
	    kw_out(oi, 30); kw_out(oi, 0);
	    is_first = 0;
	  }
	  while(fgets(inputline, sizeof(inputline), fipo)) {
	    sptr = dkstr_start(inputline, NULL);
	    if(sptr) {
	      dkstr_chomp(sptr, NULL);
	      dkstream_puts(oi->s, inputline);
	    }
	    kw_out(oi, 0);
	  }
	  fclose(fipo);
	} else {
	  /* Warning: Failed to read file */
	  if((oi->c)->app) {
	    dkapp_err_fopenr((oi->c)->app, fo->name);
	  }
	}
      }
    }
    if(!is_first) {
      kw_out(oi, 31); end_tag(oi, 32);
    }
  } 
  return back;
}



/**	Write file the defs section which consists of patterns, fonts,
	styles and JavaScript code.
	@param	oi	OI structure.
*/
static
int
svg_defs DK_P1(OI *,oi)
{
  int back = 1;
  int is_first;
  size_t i, ft;
  SVGPAT *pat; SVGSTY *sty;
  dk_one_font_mapping_t	*pofm;
  dk_font_replacement_t *pfr;
  char *fontfamilyname;
  char *fontlocation;
  char *fontfilename;
  char *fontid;
  char *fontformat;
  
  back = write_js_libraries(oi);
  begin_tag(oi, 28); kw_out(oi, 3); kw_out(oi, 0);
  if(oi->pati) {
    dksto_it_reset(oi->pati);
    while((pat = (SVGPAT *)dksto_it_next(oi->pati)) != NULL) {
      pattern_out(oi, pat);
    }
  }
  is_first = 1;
  if((oi->urw_dir) || (oi->fontmap)) {
    
    for(i = 0; i < 35; i++) {
      if((oi->fnused)[i]) {
        if(is_first) {
	  begin_tag(oi, 38);
	  kw_out(oi, 1);
	  kw_out(oi, 39);
	  kw_out(oi, 3);
	  kw_out(oi, 30);
	  kw_out(oi, 0);
	  is_first = 0;
          dkstream_set_double_no_exponent(oi->s, 1);
        }
	if(oi->fontmap) {		
	  pofm = dkfont_get_one_font(oi->fontmap, i);
	  if(pofm) {			
	    dkfont_one_font_reset(pofm);
	    while((pfr = dkfont_one_font_get(pofm)) != NULL) {
	      
	      if(dkfont_rep_check_driver(pfr, kw[5])) {
	        
	        fontfamilyname = dkfont_rep_get_family(pfr);
		fontlocation = dkfont_rep_get_location(pfr);
		fontfilename = dkfont_rep_get_source_name(pfr);
		fontid = dkfont_rep_get_name(pfr);
		fontformat = dkfont_rep_get_font_type(pfr);
		if(fontfamilyname) {	
		if(fontlocation) {	
		if(fontfilename) {	
		if(fontid)  {		
		if(fontformat) {	
	          kw_out(oi, 108);
	          kw_out(oi, 1);
	          kw_out(oi, 41);
	          kw_out(oi, 0);
	          kw_out(oi, 46); kw_out(oi, 24); kw_out(oi, 1);
	          kw_out(oi, 107);
	          dkstream_puts(oi->s, fontfamilyname);
	          kw_out(oi, 107);
	          kw_out(oi, 43);
	          kw_out(oi, 0);
	          ft = dkfont_get_features(i);
	          kw_out(oi, 47); kw_out(oi, 24); kw_out(oi, 1);
	          kw_out(oi, ((ft & DK_FONT_FEATURE_IT) ? 60 : 59));
	          kw_out(oi, 43);
	          kw_out(oi, 0);
	          kw_out(oi, 48); kw_out(oi, 24); kw_out(oi, 1);
	          kw_out(oi, ((ft & DK_FONT_FEATURE_BD) ? 61 : 59));
	          kw_out(oi, 43);
	          kw_out(oi, 0);
	          kw_out(oi, 109);
	          kw_out(oi, 74);
	          kw_out(oi, 75);
	          kw_out(oi, 20);
	          dkstream_puts(oi->s, fontlocation);
	          kw_out(oi, 4);
	          dkstream_puts(oi->s, fontfilename);
	          kw_out(oi, 45);
	          dkstream_puts(oi->s, fontid);
	          kw_out(oi, 20);
	          kw_out(oi, 76);
	          kw_out(oi, 1);
	          kw_out(oi, 110);
	          kw_out(oi, 43);
	          kw_out(oi, 0);
	          kw_out(oi, 42);
	          kw_out(oi, 0);
		} else {		
		}
		} else {		
		}
		} else {		
		}
		} else {		
		}
		} else {		
		}
	      } else {			
	      }
	    }
	  } else {			
	  }
	} else {
	  kw_out(oi, 108);
	  kw_out(oi, 1);
	  kw_out(oi, 41);
	  kw_out(oi, 0);
	  kw_out(oi, 46); kw_out(oi, 24); kw_out(oi, 1);
	  kw_out(oi, 107);
	  dkstream_puts(oi->s, urw_svg_font_families[i]);
	  kw_out(oi, 107);
	  kw_out(oi, 43);
	  kw_out(oi, 0);
	  ft = dkfont_get_features(i);
	  kw_out(oi, 47); kw_out(oi, 24); kw_out(oi, 1);
	  kw_out(oi, ((ft & DK_FONT_FEATURE_IT) ? 60 : 59));
	  kw_out(oi, 43);
	  kw_out(oi, 0);
	  kw_out(oi, 48); kw_out(oi, 24); kw_out(oi, 1);
	  kw_out(oi, ((ft & DK_FONT_FEATURE_BD) ? 61 : 59));
	  kw_out(oi, 43);
	  kw_out(oi, 0);
	  kw_out(oi, 109);
	  kw_out(oi, 74);
	  kw_out(oi, 75);
	  kw_out(oi, 20);
	  dkstream_puts(oi->s, oi->urw_dir);
	  kw_out(oi, 4);
	  dkstream_puts(
	    oi->s,
	    dkfont_get_gs_file_name(i)
	  );
	  kw_out(oi, 40);
	  kw_out(oi, 5);
	  kw_out(oi, 45);
	  dkstream_puts(
	    oi->s,
	    dkfont_get_svg_font_id(i)
	  );
	  kw_out(oi, 20);
	  kw_out(oi, 76);
	  kw_out(oi, 1);
	  kw_out(oi, 110);
	  kw_out(oi, 43);
	  kw_out(oi, 0);
	  kw_out(oi, 42);
	  kw_out(oi, 0);
	}
      }
    }
  }
  if(!(oi->prep_mods)) {
    if(((oi->c)->opt1) & DKFIG_OPT_USE_CSS) {
      if(oi->styi) {
        dksto_it_reset(oi->styi);
        while((sty = (SVGSTY *)dksto_it_next(oi->styi)) != NULL) {
          if(is_first) {
	    begin_tag(oi, 38);
	    kw_out(oi, 1);
	    kw_out(oi, 39);
	    kw_out(oi, 3);
	    kw_out(oi, 30);
	    kw_out(oi, 0);
            dkstream_set_double_no_exponent(oi->s, 1);
          }
	  style_out(oi, sty, 1);
          is_first = 0;
        }
      }
    }
  }
  if(!is_first) {
    kw_out(oi, 31);
    end_tag(oi, 38);
    dkstream_set_double_no_exponent(oi->s, 0);
  }
  end_tag(oi, 28);
  
  return back;
}



/**	Write output.
	@param	oi	OI structure.
*/
static
int
output_pass DK_P1(OI *,oi)
{
  int back = 1;
  
  if(!(((oi->c)->opt1) & DKFIG_OPT_SVG_EMBEDDED)) {
    svg_document_type(oi);
  }
  svg_start_tag(oi);
  svg_title_and_desc(oi);
  svg_defs(oi);
  dksto_it_reset(oi->fli);
  while((oi->o = (dk_fig_object *)dksto_it_next(oi->fli)) != NULL) {
    
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, (oi->o)->lineno);
    }
    oi->me = 0;
    if(!output_object(oi)) {
      back = 0;
    }
    if(oi->me) {
      /* MATH PROBLEM */
      dkfig_tool2_msg1(oi->c, DK_LOG_LEVEL_ERROR, 13);
    } oi->me = 0;
    if((oi->c)->app) {
      dkapp_set_source_lineno((oi->c)->app, 0UL);
    }
  }
  svg_end_tag(oi);
  
  return back;
}



/**	Clean up after writing output.
	This function releases the pattern and style
	information gathered in the preparation_pass().
	The collection of JavaScript library file
	names is released too.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
cleanup_pass DK_P1(OI *,oi)
{
  int back = 0; char *cptr;
  dk_fig_opt *fo; SVGSTY *s; SVGPAT *p;
  
  if(oi->fontmap) {
    dkfont_mapping_close(oi->fontmap); oi->fontmap = NULL;
  }
  if(oi->styi) {
    dksto_it_reset(oi->styi);
    while((s = (SVGSTY *)dksto_it_next(oi->styi)) != NULL) {
      svg_style_del(s);
    }
    dksto_it_close(oi->styi);
  } oi->styi = NULL;
  if(oi->sty) {
    dksto_close(oi->sty);
  } oi->sty = NULL;
  if(oi->pati) {
    dksto_it_reset(oi->pati);
    while((p = (SVGPAT *)dksto_it_next(oi->pati)) != NULL) {
      svg_pat_del(p);
    }
    dksto_it_close(oi->pati);
  } oi->pati = NULL;
  if(oi->pat) {
    dksto_close(oi->pat);
  } oi->pat = NULL;
  if(oi->fli) {
    dk_fig_object *o;
    dksto_it_reset(oi->fli);
    while((o = (dk_fig_object *)dksto_it_next(oi->fli)) != NULL) {
      if(o->drve) {
        svg_drve_delete((dk_fig_svg_drve *)(o->drve)); o->drve = NULL;
      }
    }
    dksto_it_close(oi->fli); oi->fli = NULL;
  }
  if((oi->dro)->drve) {
    svg_drve_delete((DRVE *)((oi->dro)->drve));
    (oi->dro)->drve = NULL;
  }
  if(oi->fl) {
    dksto_close(oi->fl); oi->fl = NULL;
  }
  if(oi->jsli) {
    dksto_it_reset(oi->jsli);
    while((fo = (dk_fig_opt *)dksto_it_next(oi->jsli)) != NULL) {
      
      dkfig_opt_delete(fo);
    }
  } oi->jsli = NULL;
  if(oi->jsl) {
    dksto_close(oi->jsl);
  } oi->jsl = NULL;
  if(oi->urw_dir) {
    cptr = oi->urw_dir; 
    dk_delete(cptr);
  } oi->urw_dir = NULL;
  
  return back;
}



/**	The preparation/output/cleanup sequence.
	@param	oi	OI structure.
	@return	1 on success, 0 on error.
*/
static
int
run_the_passes DK_P1(OI *,oi)
{
  int back = 0;
  
  if(preparation_pass(oi)) {
    back = output_pass(oi);
  }
  cleanup_pass(oi);
  
  return back;
}



/**	SVG output driver function.
	@param	c	Conversion job structure.
	@return	1 on success, 0 on error.
*/
int
dkfig_output_svg DK_P1(dk_fig_conversion *,c)
{
  int back = 0;
  char fnused[35]; size_t i;
  OI oi;
  
  if(c) {
    null_oi(&oi);
    if((c->opt1) & DKFIG_OPT_PREPARE_FOR_MODS) {
      oi.prep_mods = 1;
    }
    for(i = 0; i < 35; i++) { fnused[i] = 0x00; };
    oi.fnused = fnused;
    oi.c = c;
    oi.s = c->ostrm;
    if(c->ostrm) {
      oi.dro = c->drwng;
      if(c->drwng) {
        oi.d = (dk_fig_drawing *)((oi.dro)->data);
	if((oi.dro)->data) {
	  back = run_the_passes(&oi);
	}
      }
    }
  } 
  return back;
}


