/*
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	dkfont.c	Font handling module.
*/



/**	Inside the dkfont module.
*/
#define DKFONT_C 1



#include "dk.h"
#include "dkerror.h"
#include "dkfont.h"
#include "dkmem.h"
#include "dkstr.h"
#include "dksto.h"
#include "dkstream.h"




#line 61 "dkfont.ctr"




/**	Font family name: Times.
*/
static char svg_name_times[] = { "Times" };

/**	Font family name: Palatino.
*/
static char svg_name_palatino[] = { "Palatino" };

/**	Font family name: AvantGarde.
*/
static char svg_name_avantgard[] = { "AvantGarde" };

/**	Font family name: Bookman.
*/
static char svg_name_bookman[] = { "Bookman" };

/**	Font family name: Courier.
*/
static char svg_name_courier[] = { "Courier" };

/**	Font family name: Helvetica.
*/
static char svg_name_helvetica[] = { "Helvetica" };

/**	Font family name: Helvetica Narrow.
*/
static char svg_name_helvnarrow[] = { "Helvetica Narrow" };

/**	Font family name: New Century Schoolbook.
*/
static char svg_name_newcent[] = { "New Century Schoolbook" };

/**	Font family name: Symbol.
*/
static char svg_name_symbol[] = { "Symbol" };

/**	Font family name: Zapf Chancery.
*/
static char svg_name_zapfchanc[] = { "Zapf Chancery" };

/**	Font family name: Zapf Dingbats.
*/
static char svg_name_zapfding[] = { "Zapf Dingbats" };



/**	The 35 default PostScript fonts.
	Note: Do not change the sort order,
	it must be the same as used by XFig.
*/
dk_font_t dkfont_ps_35[] = {
  /*  0 */
  {
    (char *)"ptmr",
    (char *)"Times-Roman",
    DK_FONT_FEATURE_RM,
    svg_name_times,
    (char *)"NimbusRomNo9L-Regu",
    (char *)"n021003l",
    (char *)"NimbusRomanNo9L-Regu",
    (char *)"NimbusRomNo9L-Regu"
  },
  /*  1 */
  {
    (char *)"ptmri",
    (char *)"Times-Italic",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_IT),
    svg_name_times,
    (char *)"NimbusRomNo9L-ReguItal",
    (char *)"n021023l",
    (char *)"NimbusRomNo9L-ReguItal",
    (char *)"NimbusRomNo9L-ReguItal"
  },
  /*  2 */
  {
    (char *)"ptmb",
    (char *)"Times-Bold",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_BD),
    svg_name_times,
    (char *)"NimbusRomNo9L-Medi",
    (char *)"n021004l",
    (char *)"NimbusRomNo9L-Medi",
    (char *)"NimbusRomNo9L-Medi"
  },
  /*  3 */
  {
    (char *)"ptmbi",
    (char *)"Times-BoldItalic",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_BD | DK_FONT_FEATURE_IT),
    svg_name_times,
    (char *)"NimbusRomNo9L-MediItal",
    (char *)"n021024l",
    (char *)"NimbusRomNo9L-MediItal",
    (char *)"NimbusRomNo9L-MediItal"
  },
  /*  4 */
  {
    (char *)"pagk",
    (char *)"AvantGarde-Book",
    DK_FONT_FEATURE_SF,
    svg_name_avantgard,
    (char *)"URWGothicL-Book",
    (char *)"a010013l",
    (char *)"URWGothicL-Book",
    (char *)"URWGothicL-Book"
  },
  /*  5 */
  {
    (char *)"pagko",
    (char *)"AvantGarde-BookOblique",
    (DK_FONT_FEATURE_SF | DK_FONT_FEATURE_IT),
    svg_name_avantgard,
    (char *)"URWGothicL-BookObli",
    (char *)"a010033l",
    (char *)"URWGothicL-BookObli",
    (char *)"URWGothicL-BookObli"
  },
  /*  6 */
  {
    (char *)"pagd",
    (char *)"AvantGarde-Demi",
    (DK_FONT_FEATURE_SF | DK_FONT_FEATURE_BD),
    svg_name_avantgard,
    (char *)"URWGothicL-Demi",
    (char *)"a010015l",
    (char *)"URWGothicL-Demi",
    (char *)"URWGothicL-Demi"
  },
  /*  7 */
  {
    (char *)"pagdo",
    (char *)"AvantGarde-DemiOblique",
    (DK_FONT_FEATURE_SF | DK_FONT_FEATURE_BD | DK_FONT_FEATURE_IT),
    svg_name_avantgard,
    (char *)"URWGothicL-DemiObli",
    (char *)"a010035l",
    (char *)"URWGothicL-DemiObli",
    (char *)"URWGothicL-DemiObli"
  },
  /*  8 */
  {
    (char *)"pbkl",
    (char *)"Bookman-Light",
    DK_FONT_FEATURE_RM,
    svg_name_bookman,
    (char *)"URWBookmanL-Ligh",
    (char *)"b018012l",
    (char *)"URWBookmanL-Ligh",
    (char *)"URWBookmanL-Ligh"
  },
  /*  9 */
  {
    (char *)"pbkli",
    (char *)"Bookman-LightItalic",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_IT),
    svg_name_bookman,
    (char *)"URWBookmanL-LighItal",
    (char *)"b018032l",
    (char *)"URWBookmanL-LighItal",
    (char *)"URWBookmanL-LighItal"
  },
  /* 10 */
  {
    (char *)"pbkd",
    (char *)"Bookman-Demi",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_BD),
    svg_name_bookman,
    (char *)"URWBookmanL-Demi",
    (char *)"b018015l",
    (char *)"URWBookmanL-DemiBold",
    (char *)"URWBookmanL-DemiBold"
  },
  /* 11 */
  {
    (char *)"pbkdi",
    (char *)"Bookman-DemiItalic",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_IT | DK_FONT_FEATURE_BD),
    svg_name_bookman,
    (char *)"URWBookmanL-DemiItal",
    (char *)"b018035l",
    (char *)"URWBookmanL-DemiBoldItal",
    (char *)"URWBookmanL-DemiBoldItal"
  },
  /* 12 */
  {
    (char *)"pcrr",
    (char *)"Courier",
    DK_FONT_FEATURE_TT,
    svg_name_courier,
    (char *)"NimbusMonL-Regu",
    (char *)"n022003l",
    (char *)"NimbusMonL-Regu",
    (char *)"NimbusMonL-Regu"
  },
  /* 13 */
  {
    (char *)"pcrro",
    (char *)"Courier-Oblique",
    (DK_FONT_FEATURE_TT | DK_FONT_FEATURE_IT),
    svg_name_courier,
    (char *)"NimbusMonL-ReguObli",
    (char *)"n022023l",
    (char *)"NimbusMonL-ReguObli",
    (char *)"NimbusMonL-ReguObli"
  },
  /* 14 */
  {
    (char *)"pcrb",
    (char *)"Courier-Bold",
    (DK_FONT_FEATURE_TT | DK_FONT_FEATURE_BD),
    svg_name_courier,
    (char *)"NimbusMonL-Bold",
    (char *)"n022004l",
    (char *)"NimbusMonL-Bold",
    (char *)"NimbusMonL-Bold"
  },
  /* 15 */
  {
    (char *)"pcrbo",
    (char *)"Courier-BoldOblique",
    (DK_FONT_FEATURE_TT | DK_FONT_FEATURE_BD | DK_FONT_FEATURE_IT),
    svg_name_courier,
    (char *)"NimbusMonL-BoldObli",
    (char *)"n022024l",
    (char *)"NimbusMonL-BoldObli",
    (char *)"NimbusMonL-BoldObli"
  },
  /* 16 */
  {
    (char *)"phvr",
    (char *)"Helvetica",
    DK_FONT_FEATURE_SF,
    svg_name_helvetica,
    (char *)"NimbusSanL-Regu",
    (char *)"n019003l",
    (char *)"NimbusSansL-Regu",
    (char *)"NimbusSanL-Regu"
  },
  /* 17 */
  {
    (char *)"phvro",
    (char *)"Helvetica-Oblique",
    (DK_FONT_FEATURE_SF | DK_FONT_FEATURE_IT),
    svg_name_helvetica,
    (char *)"NimbusSanL-ReguItal",
    (char *)"n019023l",
    (char *)"NimbusSanL-ReguItal",
    (char *)"NimbusSanL-ReguItal"
  },
  /* 18 */
  {
    (char *)"phvb",
    (char *)"Helvetica-Bold",
    (DK_FONT_FEATURE_SF | DK_FONT_FEATURE_BD),
    svg_name_helvetica,
    (char *)"NimbusSanL-Bold",
    (char *)"n019004l",
    (char *)"NimbusSansL-Bold",
    (char *)"NimbusSanL-Bold"
  },
  /* 19 */
  {
    (char *)"phvbo",
    (char *)"Helvetica-BoldOblique",
    (DK_FONT_FEATURE_SF | DK_FONT_FEATURE_BD | DK_FONT_FEATURE_IT),
    svg_name_helvetica,
    (char *)"NimbusSanL-BoldItal",
    (char *)"n019024l",
    (char *)"NimbusSanL-BoldItal",
    (char *)"NimbusSanL-BoldItal"
  },
  /* 20 */
  {
    (char *)"phvrrn",
    (char *)"Helvetica-Narrow",
    DK_FONT_FEATURE_SF,
    svg_name_helvnarrow,
    (char *)"NimbusSanL-ReguCond",
    (char *)"n019043l",
    (char *)"NimbusSanL-ReguCond",
    (char *)"NimbusSanL-ReguCond"
  },
  /* 21 */
  {
    (char *)"phvron",
    (char *)"Helvetica-Narrow-Oblique",
    (DK_FONT_FEATURE_SF | DK_FONT_FEATURE_IT),
    svg_name_helvnarrow,
    (char *)"NimbusSanL-ReguCondItal",
    (char *)"n019063l",
    (char *)"NimbusSanL-ReguCondItal",
    (char *)"NimbusSanL-ReguCondItal"
  },
  /* 22 */
  {
    (char *)"phvbrn",
    (char *)"Helvetica-Narrow-Bold",
    (DK_FONT_FEATURE_SF | DK_FONT_FEATURE_BD),
    svg_name_helvnarrow,
    (char *)"NimbusSanL-BoldCond",
    (char *)"n019044l",
    (char *)"NimbusSanL-BoldCond",
    (char *)"NimbusSanL-BoldCond"
  },
  /* 23 */
  { 
    (char *)"phvbon",
    (char *)"Helvetica-Narrow-BoldOblique",
    (DK_FONT_FEATURE_SF | DK_FONT_FEATURE_BD | DK_FONT_FEATURE_IT),
    svg_name_helvnarrow,
    (char *)"NimbusSanL-BoldCondItal",
    (char *)"n019064l",
    (char *)"NimbusSanL-BoldCondItal",
    (char *)"NimbusSanL-BoldCondItal"
  },
  /* 24 */
  {
    (char *)"pncr",
    (char *)"NewCenturySchlbk-Roman",
    DK_FONT_FEATURE_RM,
    svg_name_newcent,
    (char *)"CenturySchL-Roma",
    (char *)"c059013l",
    (char *)"CenturySchL-Roma",
    (char *)"CenturySchL-Roma"
  },
  /* 25 */
  {
    (char *)"pncri",
    (char *)"NewCenturySchlbk-Italic",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_IT),
    svg_name_newcent,
    (char *)"CenturySchL-RomaItal",
    (char *)"c059033l",
    (char *)"CenturySchL-Ital",
    (char *)"CenturySchL-Ital"
  },
  /* 26 */
  {
    (char *)"pncb",
    (char *)"NewCenturySchlbk-Bold",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_BD),
    svg_name_newcent,
    (char *)"CenturySchL-Bold",
    (char *)"c059016l",
    (char *)"CenturySchL-Bold",
    (char *)"CenturySchL-Bold"
  },
  /* 27 */
  {
    (char *)"pncbi",
    (char *)"NewCenturySchlbk-BoldItalic",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_BD | DK_FONT_FEATURE_IT),
    svg_name_newcent,
    (char *)"CenturySchL-BoldItal",
    (char *)"c059036l",
    (char *)"CenturySchL-BoldItal",
    (char *)"CenturySchL-BoldItal"
  },
  /* 28 */
  {
    (char *)"pplr",
    (char *)"Palatino-Roman",
    DK_FONT_FEATURE_RM,
    svg_name_palatino,
    (char *)"URWPalladioL-Roma",
    (char *)"p052003l",
    (char *)"URWPalladioL-Roma",
    (char *)"URWPalladioL-Roma"
  },
  /* 29 */
  {
    (char *)"pplri",
    (char *)"Palatino-Italic",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_IT),
    svg_name_palatino,
    (char *)"URWPalladioL-Ital",
    (char *)"p052023l",
    (char *)"URWPalladioL-Ital",
    (char *)"URWPalladioL-Ital"
  },
  /* 30 */
  {
    (char *)"pplb",
    (char *)"Palatino-Bold",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_BD),
    svg_name_palatino,
    (char *)"URWPalladioL-Bold",
    (char *)"p052004l",
    (char *)"URWPalladioL-Bold",
    (char *)"URWPalladioL-Bold"
  },
  /* 31 */
  {
    (char *)"pplbi",
    (char *)"Palatino-BoldItalic",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_BD | DK_FONT_FEATURE_IT),
    svg_name_palatino,
    (char *)"URWPalladioL-BoldItal",
    (char *)"p052024l",
    (char *)"URWPalladioL-BoldItal",
    (char *)"URWPalladioL-BoldItal"
  },
  /* 32 */
  {
    (char *)"psyr",
    (char *)"Symbol",
    0,
    svg_name_symbol,
    (char *)"StandardSymL",
    (char *)"s050000l",
    (char *)"StandardSymL",
    (char *)"StandardSymL"
  },
  /* 33 */
  {
    (char *)"pzcmi",
    (char *)"ZapfChancery-MediumItalic",
    (DK_FONT_FEATURE_RM | DK_FONT_FEATURE_IT),
    svg_name_zapfchanc,
    (char *)"URWChanceryL-MediItal",
    (char *)"z003034l",
    (char *)"URWChanceryL-MediItal",
    (char *)"URWChanceryL-MediItal"
  },
  /* 34 */
  {
    (char *)"pzdr",
    (char *)"ZapfDingbats",
    0,
    svg_name_zapfding,
    (char *)"Dingbats",
    (char *)"d050000l",
    (char *)"Dingbats",
    (char *)"Dingbats"
  }
};




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



/**	Font configuration file command: name.
*/
static char *cmd00[] = { (char *)"name",	NULL };

/**	Font configuration file command: source type.
*/
static char *cmd01[] = { (char *)"source",	(char *)"type",	NULL };

/**	Font configuration file command: directory.
*/
static char *cmd02[] = { (char *)"directory",	NULL };

/**	Font configuration file command: file name.
*/
static char *cmd03[] = { (char *)"file",	(char *)"name",	NULL };

/**	Font configuration file command: features.
*/
static char *cmd04[] = { (char *)"features",	NULL };

/**	Font configuration file command: family.
*/
static char *cmd05[] = { (char *)"family",	NULL };

/**	Font configuration file command: driver.
*/
static char *cmd06[] = { (char *)"driver",	NULL };

/**	Font configuration file command: font type.
*/
static char *cmd07[] = { (char *)"font",	(char *)"type",	NULL };

/**	Font configuration file command: tex name.
*/
static char *cmd08[] = { (char *)"tex",		(char *)"name",	NULL };

/**	Font configuration file command: pfb base.
*/
static char *cmd09[] = { (char *)"pfb",		(char *)"base", NULL};

/**	Font configuration file command: pfb file.
*/
static char *cmd10[] = { (char *)"pfb",		(char *)"file", NULL};

/**	Font configuration file command: ttf base.
*/
static char *cmd11[] = { (char *)"ttf",		(char *)"base", NULL};

/**	Font configuration file command: ttf file.
*/
static char *cmd12[] = { (char *)"ttf",		(char *)"file", NULL};

/**	Font configuration file command: svg base.
*/
static char *cmd13[] = { (char *)"svg",		(char *)"base", NULL};

/**	Font configuration file command: svg file.
*/
static char *cmd14[] = { (char *)"svg",		(char *)"file", NULL};



/**	Commands in font configuration file.
*/
static char **cmds[] = {
  cmd00,
  cmd01,
  cmd02,
  cmd03,
  cmd04,
  cmd05,
  cmd06,
  cmd07,
  cmd08,
  cmd09,
  cmd10,
  cmd11,
  cmd12,
  cmd13,
  cmd14,
  NULL
};



/** Font feature settings keywords.
*/
static char *font_feature_strings[] = {
  (char *)"r$oman",
  (char *)"s$ans-serif",
  (char *)"t$ypewriter",
  (char *)"b$old",
  (char *)"i$talic",
  NULL
};



/** Source types keywords.
*/
static char *font_source_types[] = {
  (char *)"s$ystem",
  (char *)"d$ownload",
  NULL
};


/** Asterisk string for testing.
*/
static char str_asterisk[] = { "*" };



char *
dkfont_get_tex_name DK_P1(size_t, number)
{
  char *back = NULL;
  
  if(number < 35) {
    back = dkfont_ps_35[number].texname;
  }
  
  return back;
}



char *
dkfont_get_ps_name DK_P1(size_t, number)
{
  char *back = NULL;
  
  if(number < 35) {
    back = dkfont_ps_35[number].psname;
  }
  
  return back;
}




dk_font_t *
dkfont_get_ps_fonts DK_P0()
{
  return dkfont_ps_35;
}



int
dkfont_get_features DK_P1(size_t, number)
{
  int back = 0;
  
  if(number < 35) {
    back = dkfont_ps_35[number].features;
  }
  
  return back;
}



char *
dkfont_get_svg_font_id DK_P1(size_t,number)
{
  char *back = NULL;
  
  if(number < 35) {
    back = dkfont_ps_35[number].svgFontId;
  } 
  return back;
}



char *
dkfont_get_svg_family_name DK_P1(size_t,number)
{
  char *back = NULL;
  
  if(number < 35) {
    back = dkfont_ps_35[number].svgFontFamily;
  } 
  return back;
}



char *
dkfont_get_gs_alias_name DK_P1(size_t,number)
{
  char *back = NULL;
  
  if(number < 35) {
    back = dkfont_ps_35[number].gs_alias;
  } 
  return back;
}



char *
dkfont_get_gs_file_name DK_P1(size_t,number)
{
  char *back = NULL;
  
  if(number < 35) {
    back = dkfont_ps_35[number].gs_actual;
  } 
  return back;
}



char *
dkfont_get_new_gs_file_name DK_P1(size_t,number) {
  char *back = NULL;
  
  if(number < 35) {
    back = dkfont_ps_35[number].gs_new;
  } 
  return back;
}



/**	Abbreviation for dk_font_replacement_t.
*/
typedef dk_font_replacement_t FR;



/**	Abbreviation for char *.
*/
typedef char *PCHAR;



/**	Compare two strings.
	@param	l	Left string.
	@param	r	Right string.
	@param	cr	Comparison criteria (ignored).
	@return	Comparison result.
*/
static
int
compare_two_strings DK_P3(void *,l, void *,r, int,cr)
{
  int back = 0;
  if(l) {
    if(r) {
      back = strcmp((char *)l, (char *)r);
    } else { back = 1; }
  } else {
    if(r) { back = -1; }
  }
  return back;
}



/**	Compare two replacements by line number.
	@param	l	Left replacement.
	@param	r	Right replacement.
	@param	cr	Comparison criteria (ignored).
	@return	Comparison result.
*/
static
int
compare_replacement_by_number DK_P3(void *,l, void *,r, int,cr)
{
  int back = 0;
  dk_font_replacement_t *frl, *frr;
  if(l) {
    if(r) {
      frl = (dk_font_replacement_t *)l;
      frr = (dk_font_replacement_t *)r;
      if(frl->num > frr->num) { back =  1; }
      if(frl->num < frr->num) { back = -1; }
    } else {
      back = 1;
    }
  } else {
    if(r) {
      back = -1;
    }
  }
  return back;
}



/**	Compare two replacements by name.
	@param	l	Left replacement.
	@param	r	Right replacement.
	@param	cr	Comparison criteria (1=replacement/name, 0=replacement/replacement).
	@return	Comparison result.
*/
static
int
compare_replacement_by_name DK_P3(void *,l, void *,r, int,cr)
{
  int back = 0;
  dk_font_replacement_t *frl, *frr;
  if(l) {
    if(r) {
      frl = (dk_font_replacement_t *)l;
      frr = (dk_font_replacement_t *)r;
      switch(cr) {
        case 1: {
	  if(frl->n) {
	    back = strcmp(frl->n, (char *)r);
	  } else {
	    back = -1;
	  }
	} break;
	default: {
	  if(frl->n) {
	    if(frr->n) {
	      back = strcmp(frl->n, frr->n);
	    } else {
	      back = 1;
	    }
	  } else {
	    if(frr->n) {
	      back = -1;
	    }
	  }
	} break;
      }
    } else {
      back = 1;
    }
  } else {
    if(r) {
      back = -1;
    }
  }
  return back;
}



/**	Destroy a replacement, release memory.
	@param	p	Replacement to destroy.
*/
static
void
destroy_replacement DK_P1(dk_font_replacement_t *,p)
{
  char *cp;
  
  if(p->d) {
    if(p->di) {
      
#line 869 "dkfont.ctr"
      
#line 870 "dkfont.ctr"
      
#line 871 "dkfont.ctr"
      
#line 872 "dkfont.ctr"
      
#line 873 "dkfont.ctr"
      
#line 874 "dkfont.ctr"
      
#line 875 "dkfont.ctr"
      
#line 876 "dkfont.ctr"
      
#line 877 "dkfont.ctr"
      
#line 878 "dkfont.ctr"
      dksto_it_close(p->di); p->di = NULL;
    }
    dksto_close(p->d); p->d = NULL;
  }
  if(p->tl) {
    cp = p->tl; dk_delete(cp); p->tl = NULL;
  }
  if(p->ts) {
    cp = p->ts; dk_delete(cp); p->ts = NULL;
  }
  if(p->pl) {
    cp = p->pl; dk_delete(cp); p->pl = NULL;
  }
  if(p->ps) {
    cp = p->ps; dk_delete(cp); p->ps = NULL;
  }
  if(p->tn) {
    
    cp = p->tn; dk_delete(cp); p->tn = NULL;
  }
  if(p->n) {
    
    cp = p->n; dk_delete(cp); p->n = NULL;
  }
  if(p->f) {
    
    cp = p->f; dk_delete(cp); p->f = NULL;
  }
  if(p->l) {
    
    cp = p->l; dk_delete(cp); p->l = NULL;
  }
  if(p->s) {
    
    cp = p->s; dk_delete(cp); p->s = NULL;
  }
  if(p->ft) {
    
    cp = p->ft; dk_delete(cp); p->ft = NULL;
  }
  
  p->ff = 0; p->t = 0; p->num = 0UL;
  dk_delete(p);
  
}




/**	Initialize a new font replacement.
	@param	p	Replacement to initialize.
	@param	n	Replacement name.
	@param	num	Line number of occurance.
	@return	1 on success, 0 on error.
*/
static
int
initialize_replacement DK_P3(FR *,p, char *,n, unsigned long,num)
{
  int back = 0;
  
  p->n = NULL; p->f = NULL; p->l = NULL; p->s = NULL; p->ft = NULL;
  p->ff = 0; p->t = 0; p->num = 0UL; p->tn = NULL;
  p->d = NULL; p->di = NULL; p->pl = NULL; p->ps = NULL;
  p->tl = NULL; p->ts = NULL;
  p->n = dkstr_dup(n);
  if(p->n) {
    p->num = num;
    p->d = dksto_open(0);
    if(p->d) {
      dksto_set_comp(p->d, compare_two_strings, 0);
      p->di = dksto_it_open(p->d);
      if(p->di) {
        back = 1;
      }
    }
  } 
  return back;
}



/**	Create a new font replacement.
	@param	n	Replacement name.
	@param	num	Line number in configuration file.
*/
static
dk_font_replacement_t *
create_replacement DK_P2(char *,n, unsigned long, num)
{
  dk_font_replacement_t *back = NULL;
  
  back = dk_new(dk_font_replacement_t,1);
  if(back) {
    if(!initialize_replacement(back,n,num)) {
      destroy_replacement(back); back = NULL;
    }
  } 
  return back;
}



/**	Initialize the mapping structure for one PS font.
	@param	p	Font mapping to initialize.
	@return	1 on success, 0 on error.
*/
static
int
initialize_one_font_mapping DK_P1(dk_one_font_mapping_t *,p)
{
  int back = 0;
  
  p->used = 0x00; p->noe = 0;
  p->r = NULL; p->ri = NULL; p->byname = NULL; p->bynamei = NULL;
  p->r = dksto_open(0);
  if(p->r) {
    dksto_set_comp(p->r, compare_replacement_by_number, 0);
    p->ri = dksto_it_open(p->r);
    if(p->ri) {
      p->byname = dksto_open(0);
      if(p->byname) {
        dksto_set_comp(p->byname, compare_replacement_by_name, 0);
        p->bynamei = dksto_it_open(p->byname);
	if(p->bynamei) {
	  back = 1;
	}
      }
    }
  } 
  return back;
}



/**	Destroy the mapping structure for one PS font, release memory.
	@param	p	Font mapping to destroy.
*/
static
void
destroy_one_font_mapping DK_P1(dk_one_font_mapping_t *,p)
{
  dk_font_replacement_t *ptr;
  
  if(p->r) {
    if(p->ri) {
      dksto_it_reset(p->ri);
      while((ptr = (FR *)dksto_it_next(p->ri)) != NULL) {
        destroy_replacement(ptr);
      }
      dksto_it_close(p->ri); p->ri = NULL;
    }
    dksto_close(p->r);
    p->r = NULL; p->used = 0x00;
  }
  if(p->byname) {
    if(p->bynamei) {
      dksto_it_close(p->bynamei); p->bynamei = NULL;
    }
    dksto_close(p->byname); p->byname = NULL;
  } 
}



/**	Close a complete mapping structure and release ressources.
	@param	p	Font mapping to close.
*/
void
dkfont_mapping_close DK_P1(dk_font_mapping_t *,p)
{
  size_t i; dk_one_font_mapping_t *ptr; char *cp;
  
  if(p) {
    p->error_code = 0; p->err_lineno = 0UL;
    if(p->m) {
      ptr = p->m;
      for(i = 0; i < 35; i++) {
	destroy_one_font_mapping(ptr);
        ptr++;
      }
    }
    if(p->d) {
      if(p->di) {
        dksto_it_reset(p->di);
	while((cp = (char *)dksto_it_next(p->di)) != NULL) {
	  
	  dk_delete(cp);
	}
        dksto_it_close(p->di); p->di = NULL;
      }
      dksto_close(p->d); p->d = NULL;
    }
  } 
}



/**	Initialize a new complete mapping structure.
	@param	p	Font mapping to initialize.
	@return	1 on success, 0 on error.
*/
static
int
initialize_mapping DK_P1(dk_font_mapping_t *,p)
{
  int back = 0;
  dk_one_font_mapping_t *ptr; size_t i;
  
  p->error_code = 0; p->err_lineno = 0UL;
  p->m = NULL; p->d = NULL; p->di = NULL;
  p->m = dk_new(dk_one_font_mapping_t,35);
  if(p->m) {
    p->d = dksto_open(0);
    if(p->d) {
      dksto_set_comp(p->d, compare_two_strings, 0);
      p->di = dksto_it_open(p->d);
      if(p->di) {
        back = 1;
	ptr = p->m;
	for(i = 0; i < 35; i++) {
	  if(!initialize_one_font_mapping(ptr)) {
	    
	    back = 0;
	  }
	  ptr++;
	}
      }
    }
  } 
  return back;
}



dk_font_mapping_t *
dkfont_mapping_open DK_P0()
{
  dk_font_mapping_t *back = NULL;
  
  back = dk_new(dk_font_mapping_t,1);
  if(back) {
    if(!initialize_mapping(back)) {
      dkfont_mapping_close(back);
      back = NULL;
    }
  } 
  return back;
}



/**	Get index (0...34) of a PS font name.
	@param	n	Font name.
	@return Numeric font id used by XFig.
*/
static
int
get_index_ps_35 DK_P1(char *,n)
{
  int back = -1; int i;
  dk_font_t *ptr;
  
  ptr = dkfont_ps_35;
  for(i = 0; ((i < 35) && (back == -1)); i++) {
    
    if(strcmp(ptr->psname, n) == 0) {
      back = i;
    }
    ptr++;
  }
  
  return back;
}



int
dkfont_mapping_add_stream DK_P2(dk_font_mapping_t *,fm, dk_stream_t *,st)
{
  int back = 0;
  int cc;
  char inputline[1024], *ls, *le, *vptr;
  dk_one_font_mapping_t	*cofm = NULL;
  dk_font_replacement_t	*cfr = NULL;
  
  if(fm) {	
    if(st) {	
      back = 1; cc = 1; fm->error_code = 0; fm->err_lineno = 0UL;
      while((cc == 1) && (fm->error_code == 0)) {
        if(dkstream_gets(st, inputline, sizeof(inputline))) {
	  fm->err_lineno += 1UL;
	  dkstr_delcomm(inputline, '#');
	  ls = dkstr_start(inputline, NULL);
	  if(ls) {
	    dkstr_chomp(ls, NULL);
	    
	    if(*ls == '[') {	/* new font number */
	      ls++; ls = dkstr_start(ls, NULL);
	      if(ls) {
	        le = dkstr_chr(ls, ']');
		if(le) {
		  *le = '\0';
		  ls = dkstr_start(ls, NULL);
		  if(ls) {
		    int i;
		    dkstr_chomp(ls, NULL);
		    i = get_index_ps_35(ls);
		    
		    if((i >= 0) && (i < 35)) {
		      cofm = &((fm->m)[i]); cfr = NULL;
		    } else {
		      fm->error_code = DK_ERR_SYNTAX;
		      
		    }
		  } else {
		    fm->error_code = DK_ERR_SYNTAX;
		    
		  }
		} else {
		  fm->error_code = DK_ERR_SYNTAX;
		  
		}
	      } else {
	        fm->error_code = DK_ERR_SYNTAX;
		
	      }
	    } else {		/* continue editing current font */
	      
	      if(cofm) {
	        vptr = dkstr_chr(ls, '=');
		if(vptr) {
		  *(vptr++) = '\0';
		  vptr = dkstr_start(vptr, NULL);
		  if(vptr) {
		    ls = dkstr_start(ls, NULL);
		    if(ls) {
		      char *parts[32]; size_t xsz;
		      dkstr_chomp(ls, NULL);
		      dkstr_chomp(vptr, NULL);
		      
		      xsz = sizeof(parts)/sizeof(PCHAR);
		      if(dkstr_explode(parts, xsz, ls, explode_pattern)) {
		        int i;
		        i = dkstr_find_multi_part_abbr(parts, cmds, '$', 1);
			switch(i) {
			  case 0: {	/* name */
			    
			    cfr = dksto_it_find_like(cofm->bynamei, vptr, 1);
			    if(!cfr) {
			      int ok;
			      cfr = create_replacement(vptr, cofm->noe);
			      cofm->noe += 1;
			      if(cfr) {
			        ok = 0;
				if(dksto_add(cofm->r, (void *)cfr)) {
				  if(dksto_add(cofm->byname, (void *)cfr)) {
				    ok = 1;
				  }
				} else {
				  destroy_replacement(cfr); cfr = NULL;
				}
				if(!ok) {
				  fm->error_code = DK_ERR_NOMEM;
				  
				}
			      }
			    }
			    if(!cfr) {
                              fm->error_code = DK_ERR_NOMEM;
			      
			    }
			  } break;
			  case 1: {	/* source type */
			    
			    if(cfr) {
			      cfr->t = dkstr_array_abbr(font_source_types, vptr, '$', 0);
			      if(cfr->t < 0) {
			        fm->error_code = DK_ERR_SYNTAX;
				
			      }
			    } else {
			      fm->error_code = DK_ERR_SYNTAX;
			      
			    }
			  } break;
			  case 2: case 13: {	/* directory */
			    
			    if(cfr->l) {
			      fm->error_code = DK_ERR_SYNTAX;
			      
			    } else {
			      cfr->l = dkstr_dup(vptr);
			      if(!(cfr->l)) {
			        fm->error_code = DK_ERR_NOMEM;
				
			      }
			    }
			  } break;
			  case 3: case 14: {	/* file name */
			    
			    if(cfr->s) {
			      fm->error_code = DK_ERR_SYNTAX;
			      
			    } else {
			      cfr->s = dkstr_dup(vptr);
			      if(!(cfr->s)) {
			        fm->error_code = DK_ERR_NOMEM;
				
			      }
			    }
			  } break;
			  case 4: {	/* features */
			    char *p1, *p2;
			    
			    p1 = dkstr_start(vptr, NULL);
			    while(p1) {
			      p2 = dkstr_next(p1, NULL);
			      switch(dkstr_array_abbr(
			                 font_feature_strings, p1, '$', 0
			                             )
			      )
			      {
			        case 0: {	/* roman */
				  cfr->ff = DK_FONT_FEATURE_RM
				  	  | ((cfr->ff) & (~(DK_FONT_FEATURE_FAMILY)));
				} break;
				case 1: {	/* sans-serif */
				  cfr->ff = DK_FONT_FEATURE_SF
				  	  | ((cfr->ff) & (~(DK_FONT_FEATURE_FAMILY)));
				} break;
				case 2: {	/* typewriter */
				  cfr->ff = DK_FONT_FEATURE_TT
				  	  | ((cfr->ff) & (~(DK_FONT_FEATURE_FAMILY)));
				} break;
				case 3: {	/* bold */
				  cfr->ff = cfr->ff | DK_FONT_FEATURE_BD;
				} break;
				case 4: {	/* italic */
				  cfr->ff = cfr->ff | DK_FONT_FEATURE_IT;
				} break;
				default: {
				  fm->error_code = DK_ERR_SYNTAX;
				  
				} break;
			      }
			      p1 = p2;
			    }
			  } break;
			  case 5: {	/* family */
			    
			    if(cfr->f) {
			      fm->error_code = DK_ERR_SYNTAX;
			      
			    } else {
			      cfr->f = dkstr_dup(vptr);
			      if(!(cfr->f)) {
			        fm->error_code = DK_ERR_NOMEM;
				
			      }
			    }
			  } break;
			  case 6: {	/* driver */
			    char *p1, *p2, *p3;
			    
			    p1 = dkstr_start(vptr, NULL);
			    while(p1) {
			      p2 = dkstr_next(p1, NULL);
			      p3 = dksto_it_find_like(fm->di, p1, 0);
			      if(p3) {
			        if(!dksto_add(cfr->d, (void *)p3)) {
				  fm->error_code = DK_ERR_NOMEM;
				  
				}
			      } else {
			        p3 = dkstr_dup(p1);
				if(p3) {
				  if(dksto_add(fm->d, (void *)p3)) {
				    if(!dksto_add(cfr->d, (void *)p3)) {
				      fm->error_code = DK_ERR_NOMEM;
				      
				    }
				  } else {
				    dk_delete(p3);
				  }
				} else {
				  fm->error_code = DK_ERR_NOMEM;
				  
				}
			      }
			      p1 = p2;
			    }
			  } break;
			  case 7: {	/* font type */
			    if(cfr->ft) {
			      fm->error_code = DK_ERR_SYNTAX;
			      
			    } else {
			      cfr->ft = dkstr_dup(vptr);
			      if(!(cfr->ft)) {
			        fm->error_code = DK_ERR_NOMEM;
				
			      }
			    }
			  } break;
			  case 8: {
			    if(cfr->tn) {
			      fm->error_code = DK_ERR_SYNTAX;
			      
			    } else {
			      cfr->tn = dkstr_dup(vptr);
			      if(!(cfr->tn)) {
			        fm->error_code = DK_ERR_NOMEM;
				
			      }
			    }
			  } break;
			  case 9: {
			    if(cfr->pl) {
			      fm->error_code = DK_ERR_SYNTAX; 
			    } else {
			      cfr->pl = dkstr_dup(vptr);
			      if(!(cfr->pl)) {
			        fm->error_code = DK_ERR_NOMEM; 
			      }
			    }
			  } break;
			  case 10: {
			    if(cfr->ps) {
			       fm->error_code = DK_ERR_SYNTAX; 
			    } else {
			      cfr->ps = dkstr_dup(vptr);
			      if(!(cfr->ps)) {
			        fm->error_code = DK_ERR_NOMEM; 
			      }
			    }
			  } break;
			  case 11: {
			    if(cfr->tl) {
			      fm->error_code = DK_ERR_SYNTAX; 
			    } else {
			      cfr->tl = dkstr_dup(vptr);
			      if(!(cfr->tl)) {
			        fm->error_code = DK_ERR_NOMEM; 
			      }
			    }
			  } break;
			  case 12: {
			    if(cfr->ts) {
			       fm->error_code = DK_ERR_SYNTAX; 
			    } else {
			      cfr->ts = dkstr_dup(vptr);
			      if(!(cfr->ts)) {
			        fm->error_code = DK_ERR_NOMEM; 
			      }
			    }
			  } break;
			  default: {
                            fm->error_code = DK_ERR_SYNTAX;
			    
			  } break;
			}
		      } else {
		        fm->error_code = DK_ERR_SYNTAX;
			
		      }
		    } else {
		      fm->error_code = DK_ERR_SYNTAX;
		      
		    }
		  } else {
		    fm->error_code = DK_ERR_SYNTAX;
		    
		  }
		} else {
		  fm->error_code = DK_ERR_SYNTAX;
		  
		}
	      } else {		
	        fm->error_code = DK_ERR_SYNTAX;
		
	      }
	    }
	  }
	} else {
	  cc = 0;
	}
      }
      if(fm->error_code) { back = 0; }
    } else {
      
    }
  } else {
    
  } 
  return back;
}



int
dkfont_get_error_code DK_P1(dk_font_mapping_t *,fm)
{
  int back = 0;
  if(fm) {
    back = fm->error_code;
  }
  return back;
}




unsigned long
dkfont_get_error_lineno DK_P1(dk_font_mapping_t *,fm)
{
  unsigned long back = 0UL;
  if(fm) {
    back = fm->err_lineno;
  }
  return back;
}



dk_one_font_mapping_t *
dkfont_get_one_font DK_P2(dk_font_mapping_t *,fm, size_t,n)
{
  dk_one_font_mapping_t *back = NULL;
  if(fm) {
    if(n < 35) {
      back = &((fm->m)[n]);
    }
  }
  return back;
}



void
dkfont_set_used DK_P3(dk_font_mapping_t *,fm, size_t,n, int,b)
{
  if(fm) {
    if(n < 35) {
      if(b) {
        ((fm->m)[n]).used = 1;
      } else {
        ((fm->m)[n]).used = 0;
      }
    }
  }
}



int
dkfont_get_used DK_P2(dk_font_mapping_t *,fm, size_t,n)
{
  int back = 0;
  if(fm) {
    if(n < 35) {
      if(((fm->m)[n]).used) {
        back = 1;
      }
    }
  }
  return back;
}



void
dkfont_one_font_reset DK_P1(dk_one_font_mapping_t *,o)
{
  if(o) {
    dksto_it_reset(o->ri);
  }
}



dk_font_replacement_t *
dkfont_one_font_get DK_P1(dk_one_font_mapping_t *,o)
{
  dk_font_replacement_t *back = NULL;
  if(o) {
    back = (dk_font_replacement_t *)dksto_it_next(o->ri);
  }
  return back;
}



char *
dkfont_rep_get_name DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->n;
  }
  return back;
}



char *
dkfont_rep_get_family DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->f;
  }
  return back;
}



char *
dkfont_rep_get_location DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->l;
  }
  return back;
}



char *
dkfont_rep_get_source_name DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->s;
  }
  return back;
}



char *
dkfont_rep_get_pfb_location DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->pl;
  }
  return back;
}



char *
dkfont_rep_get_pfb_source_name DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->ps;
  }
  return back;
}



char *
dkfont_rep_get_ttf_location DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->tl;
  }
  return back;
}



char *
dkfont_rep_get_ttf_source_name DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->ts;
  }
  return back;
}



char *
dkfont_rep_get_font_type DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->ft;
  }
  return back;
}



char *
dkfont_rep_get_tex_name DK_P1(dk_font_replacement_t *,r)
{
  char *back = NULL;
  if(r) {
    back = r->tn;
  } return back;
}



int
dkfont_rep_get_features DK_P1(dk_font_replacement_t *,r)
{
  int back = 0;
  if(r) {
    back = r->ff;
  }
  return back;
}



int
dkfont_rep_get_source_type DK_P1(dk_font_replacement_t *,r)
{
  int back = 0;
  if(r) {
    back = r->t;
  }
  return back;
}



int
dkfont_rep_check_driver DK_P2(dk_font_replacement_t *,r, char *,n)
{
  int back = 0;
  int found = 0;
  char *ptr;
  if(r) {
  if(n) {
    dksto_it_reset(r->di);
    while((ptr = (char *)dksto_it_next(r->di)) != NULL) {
      if(strcmp(ptr, str_asterisk) == 0) { back = 1; }
      if(strcmp(ptr,n) == 0) { back = 1; }
      found = 1;
    }
  }
  }
  if(!found) { back = 1; }
  return back;
}



