/*
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	dkfigdt.c	Text handling.

This module contains tool functions to write TeX/LaTeX commands to an output
stream.
*/



/**	Inside the dkfigdt module.
*/
#define DKFIGDT_C 1



#include "dkfig.h"




#line 58 "dkfigdt.ctr"



#ifdef TRACE_DEBUG
#undef TRACE_DEBUG
#endif

#line 65 "dkfigdt.ctr"

#line 66 "dkfigdt.ctr"



/**	Do not include code to run latex/dvips.
*/
#define RUN_CMD_LATEX_DVIPS 0



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



/** Keywords used when writing LaTeX source.
*/
static char *kw[] = {
  /*   0 */ "\\font",
  /*   1 */ "\\newfont",
  /*   2 */ "\\fnt",
  /*   3 */ "{",
  /*   4 */ "}",
  /*   5 */ "=",
  /*   6 */ " at ",
  /*   7 */ "pt",
  /*   8 */ " scaled ",
  /*   9 */ ";",
  /*  10 */ "\\begin{document}\n",
  /*  11 */ "\\newcommand",
  /*  12 */ "\\def",
  /*  13 */ "\\reset@font",
  /*  14 */ "\\fontsize",
  /*  15 */ "\\fontfamily",
  /*  16 */ "\\familydefault",
  /*  17 */ "\\rmdefault",
  /*  18 */ "\\sfdefault",
  /*  19 */ "\\ttdefault",
  /*  20 */ "\\fontseries",
  /*  21 */ "\\fontshape",
  /*  22 */ "\\selectfont",
  /*  23 */ "%",
  /*  24 */ "  ",
  /*  25 */ "\n",
  /*  26 */ "\\mddefault",
  /*  27 */ "\\bfdefault",
  /*  28 */ "\\updefault",
  /*  29 */ "\\itdefault",
  /*  30 */ "\\def",
  /*  31 */ "\\fontencoding{T1}",
  /*  32 */ "\\begingroup\\makeatletter\\ifx",
  /*  33 */ "\\fi\\endgroup%\n",
  /*  34 */ "\\gdef",
  /*  35 */ "\\undefined%\n",
  /*  36 */ "\\end{document}\n",
  /*  37 */ "\\end\n",
  /*  38 */ "\\shipout\\hbox{%", /* "\\shipout\\hbox{\\smash{\\hbox{\\hbox{", */
  /*  39 */ "}",                 /* "}\\vrule width1sp}}}", */
  /*  40 */ "\\mbox{",
  /*  41 */ " ",
  /*  42 */ "\\renewcommand",
  /*  43 */ "\r\n",
};

/**	Number of elements in keywords array.
*/
static size_t array_size = sizeof(kw)/sizeof(CPTR);



/** LaTeX preamble: article document class.
*/
static char allp1[] = { "\\documentclass{article}" };

/** LaTeX preamble: Input is latin1 or utf8 encoded.
*/
static char allp2[] = { "\\usepackage[latin1]{inputenc}" };

/** LaTeX preamble: Use T1 font encoding.
*/
static char allp3[] = { "\\usepackage[T1]{fontenc}" };

/** LaTeX preamble: Additional text symbols.
*/
static char allp4[] = { "\\usepackage{textcomp}" };

/** LaTeX preamble: article document class, larger font.
*/
static char allp5[] = { "\\documentclass[12pt]{article}" };

/** LaTeX preamble: Use AMS math package.
*/
static char ams01[] = { "\\usepackage[intlimits]{amsmath}" };

/** LaTeX preamble: Use other AMS packages (fonts, symbols).
*/
static char ams02[] = { "\\usepackage{amsfonts,amssymb,amscd}" };



/** Default LaTeX preamble.
*/
static char *def_preamble[] = {
  allp1, allp2, allp3, allp4, ams01,
  NULL
};

/** Preamble using AMS fonts.
*/
static char *ams_preamble[] = {
  allp1, allp2, allp3, allp4, ams01, ams02,
  NULL
};

/** Preamble using AMS fonts and larger text size.
*/
static char *ams12_preamble[] = {
  allp5, allp2, allp3, allp4, ams01, ams02,
  NULL
};



/** LaTeX preamble: Use Times font.
*/
static char pdf01[] = { "\\usepackage{mathptmx}" };

/** LaTeX preamble: Use Helvetica font.
*/
static char pdf02[] = { "\\usepackage[scaled=.92]{helvet}" };

/** LaTeX preamble: Use Courier font.
*/
static char pdf03[] = { "\\usepackage{courier}" };



/** Preamble using Times, Helvetica and Courier.
*/
static char *pdf_preamble[] = {
  allp1, allp2, allp3, allp4, pdf01, pdf02, pdf03, ams01,
  NULL
};

/** Preamble using Times, Helvetica and Courier and larger text size.
*/
static char *pdf12_preamble[] = {
  allp5, allp2, allp3, allp4, pdf01, pdf02, pdf03, ams01,
  NULL
};



/** LaTeX preamble: Use New Century Schoolbook.
*/
static char new01[] = { "\\usepackage{newcent}" };

/** Preamble using New Century Schoolbook.
*/
static char *new_preamble[] = {
  allp1, allp2, allp3, allp4, new01, ams01,
  NULL
};

/** Preamble using New Century Schoolbook and larger text size.
*/
static char *new12_preamble[] = {
  allp5, allp2, allp3, allp4, new01, ams01,
  NULL
};



/** Default preamble for use with plain TeX.
*/
static char *plain_tex_preamble[] = {
  "\\font\\tenrm=cmr10 at 10.80pt \\font\\sevenrm=cmr7 at 7.56pt",
  "\\font\\fiverm=cmr5 at 5.40pt \\font\\teni=cmmi10 at 10.80pt",
  "\\font\\seveni=cmmi7 at 7.56pt \\font\\fivei=cmmi5 at 5.40pt",
  "\\font\\tensy=cmsy10 at 10.80pt \\font\\sevensy=cmsy7 at 7.56pt",
  "\\font\\fivesy=cmsy5 at 5.40pt \\textfont0\\tenrm",
  "\\scriptfont0\\sevenrm \\scriptscriptfont0\\fiverm",
  "\\textfont1\\teni \\scriptfont1\\seveni \\scriptscriptfont1\\fivei",
  "\\textfont2\\tensy \\scriptfont2\\sevensy \\scriptscriptfont2\\fivesy",
  NULL
};



/** Command to run TeX.
*/
static char texcmd[] = { "tex" };

/** Command to run LaTeX.
*/
static char latexcmd[] = { "latex" };

/** Command line arguments to TeX/LaTeX.
*/
static char options[] = { "-interaction=batchmode -file-line-error" };

/** Command line argument to enable write18.
*/
static char write18on[] = { "-shell-escape" };

/** Command line argument to disable write18.
*/
static char write18off[] = { "-no-shell-escape" };

#if RUN_CMD_LATEX_DVIPS
/** Command to run dvips.
*/
static char dvipscmd[] = { "dvips" };

/** Command line argument to enable execution of commands.
*/
static char dvipssec[] = { "-R" };

/** Command line argument to disable execution of commands.
*/
static char dvipsunsec[] = { "-R-" };
#endif



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

/** File open mode: Write.
*/
static char str_open_write_text[] = { "w" };



/**	Write one keyword to output stream.
	@param	os	Output stream to write to.
	@param	index	Index of keyword.
	@return	1 on success, 0 on error.
*/
static int
kw_to_stream DK_P2(dk_stream_t *,os, size_t,index)
{
  int back = 0;
  
  if(index < array_size) { 
    back = dkstream_puts(os, kw[index]);
  }
  
  return back;
}



/**	Write newline (either nl or cr/nl).
	@param	c	Conversion job structure.
	@param	os	Output stream to write to.
*/
static void
newline_to_c DK_P2(dk_fig_conversion *,c, dk_stream_t *,os)
{
  if((c->opt2) & DKFIG_OPT_CRNL) {
    kw_to_stream(os, 43);
  } else {
    kw_to_stream(os, 25);
  }
}



/**	Classify file name suffix (find compression algorithm).
	@param	filename	File name.
	@return	0 for plain (uncompressed) file, 1 for gzip compression, 2 for bzip2 compression.
*/
static int
classify_suffix DK_P1(char *,filename)
{
  int back = 0;
  char *ptr;
  
  if(filename) {
    ptr = dksf_get_file_type_dot(filename);
    if(ptr) {
      if(strcmp(ptr, ".bz2") == 0) {
        back = 2;
      } else {
        if(strcmp(ptr, ".gz") == 0) {
	  back = 1;
	}
      }
    }
  }
  
  return back;
}



/**	Copy stream contents to another stream.
	@param	os	Output (destination) stream.
	@param	is	Input (source) stream.
	@return	1 on success, 0 on error.
*/
static int
copy_streams DK_P2(dk_stream_t *,os, dk_stream_t *,is)
{
  int back = 1;
  char buffer[512];
  size_t rb, wb;
  int cc;
  
  cc = 1;
  while(cc) {
    rb = dkstream_read(is, buffer, sizeof(buffer));
    if(rb) {
      wb = dkstream_write(os, buffer, rb);
      if(rb != wb) {
        back = 0;
      }
    } else {
      cc = 0;
    }
  }
  
  return back;
}



/**	Get preamble from named file and write it to output stream.
	The c->tpfn component contains the preamble file name.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@return	1 on success, 0 on error.
*/
static int
preamble_from_file DK_P2(dk_fig_conversion *,c, dk_stream_t *,os)
{
  int back = 0, ct = 0, reason = 0;
  size_t sz = 0;
  char *buffer = NULL;
  dk_stream_t *is = NULL;
  
  sz = (size_t)dksf_get_maxpathlen();
  buffer = dk_new(char,sz);
  if(buffer) {		
    if(c->app) {	
      back = dkapp_find_file(c->app, c->tpfn, buffer, sz);
      if(!back) {
        /* ERROR: Failed to find preamble file */
	dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 45, 46, c->tpfn);
      }
    } else {		
      if(strlen(c->tpfn) < sz) {	
        strcpy(buffer, c->tpfn);
	back = 1;
      }
      if(!back) {
        /* ERROR: Preamble file name too long! */
	dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 47, 48, c->tpfn);
      }
    }
    if(back) {		
      back = 0;
      ct = classify_suffix(buffer);
      is = NULL;
      switch(ct) {
        case 1: {
	  if(c->app) {
	    is = dkapp_stream_opengz(c->app, buffer, str_open_read_text);
	  } else {
	    is = dkstream_opengz(buffer, str_open_read_text, 0, &reason);
	  }
	} break;
	case 2: {
	  if(c->app) {
	    is = dkapp_stream_openbz2(c->app, buffer, str_open_read_text);
	  } else {
	    is = dkstream_openbz2(buffer, str_open_read_text, 0, &reason);
	  }
	} break;
	default: {
	  if(c->app) {
	    is = dkapp_stream_openfile(c->app, buffer, str_open_read_text);
	  } else {
	    is = dkstream_openfile(buffer, str_open_read_text, 0, &reason);
	  }
	} break;
      }
      if(is) {
	back = copy_streams(os, is);
        dkstream_close(is); is = NULL;
	if(!back) {
	  /* ERROR: Failed to copy preamble file */
	  dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 49, 50, buffer);
	}
      } else {
        if(c->app) {
	  /* ERROR: Failed to open preamble file! */
	  dkapp_err_fopenr(c->app, buffer);
	} else {
	}
      }
    }
    dk_delete(buffer); buffer = NULL;
  } else {
    /* ERROR: Memory */
    if(c->app) {
      dkapp_err_memory(c->app, sizeof(char), sz);
    }
  }
  
  return back;
}



/**	Write one of the built-in preambles to the output stream.
	The c->latfs component chooses a preamble.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@return	1 on success, 0 on error.
*/
static int
preamble_from_settings DK_P2(dk_fig_conversion *,c, dk_stream_t *,os)
{
  int back = 1;
  
  if(!((c->opt1) & DKFIG_OPT_OLD_TEX)) {
    switch(c->latfs) {
      case 0: {
        dkstream_puts_array(os, ams_preamble);
      } break;
      case 1: {
        dkstream_puts_array(os, pdf_preamble);
      } break;
      case 2: {
        dkstream_puts_array(os, new_preamble);
      } break;
      case 3: {
        dkstream_puts_array(os, ams12_preamble);
      } break;
      case 4: {
        dkstream_puts_array(os, pdf12_preamble);
      } break;
      case 5: {
        dkstream_puts_array(os, new12_preamble);
      } break;
      default: {
        dkstream_puts_array(os, def_preamble);
      } break;
    }
  } else {
    dkstream_puts_array(os, plain_tex_preamble);
  }
  
  return back;
}



/**	Write LaTeX preamble to a stream.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@return	1 on success, 0 on error.
*/
int
dkfig_dt_tex_preamble DK_P2(dk_fig_conversion *,c, dk_stream_t *,os)
{
  int back = 0;
  
  if(c && os) {
    if(c->tpfn) {
      back = preamble_from_file(c, os);
    } else {
      back = preamble_from_settings(c, os);
    }
  }
  
  return back;
}



/**	Check whether or not the font handling requires LaTeX/TeX.
	@param	fhptr	Font handling structure.
	@return	1 if LaTeX or TeX is needed, 0 if not.
*/
int
dkfig_dt_is_latex_text DK_P1(dk_fig_fonth_t *,fhptr)
{
  int back = 0;
  
  if(fhptr) {
    switch(fhptr->handling) {
      case 2: case 3: case 4: case 5: {
        back = 1;
      } break;
    }
  }
  
  return back;
}



/**	Find number of characters needed to string encode
	a number.
	@param	num	Number to encode.
	@return	Needed string length.
*/
size_t
dkfig_dt_needed_alpha DK_P1(unsigned long, num)
{
  size_t back = 0; unsigned long n = 0UL;
  
  n = num;
  while(num) {
    back++;
    num = num / 26UL;
  }
  
  return back;
}



/**	Write command to define one font to output stream.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@param	fhptr	Font handling structure.
	@return	1 on success, 0 on error.
*/
static int
write_one_font_def DK_P3(dk_fig_conversion *,c, dk_stream_t *,os, dk_fig_fonth_t *,fhptr)
{
  int back = 1;
  int me = 0;
  kw_to_stream(c->ostrm, 3);
  kw_to_stream(c->ostrm, 23);
  newline_to_c(c, c->ostrm);
  /* kw_to_stream(c->ostrm, 24); */
  if((c->opt1) & DKFIG_OPT_OLD_TEX) {
    kw_to_stream(c->ostrm, 13);
    kw_to_stream(c->ostrm, 31);
  }
  if(fhptr->handling == 4) {		
    kw_to_stream(c->ostrm, 14);
    kw_to_stream(c->ostrm, 3);
    dkstream_puts_double(
      c->ostrm,
      dkma_mul_double_ok(fhptr->fontsize,c->fsf,&me)
    );
    kw_to_stream(c->ostrm, 4);
    kw_to_stream(c->ostrm, 3);
    dkstream_puts_double(
      c->ostrm,
      dkma_mul_double_ok(
        1.25,
	dkma_mul_double_ok(fhptr->fontsize,c->fsf,&me),
	&me
      )
    );
    kw_to_stream(c->ostrm, 7);
    kw_to_stream(c->ostrm, 4);
    kw_to_stream(c->ostrm, 23);
    newline_to_c(c, c->ostrm);
    /* kw_to_stream(c->ostrm, 24); */
  }
  kw_to_stream(c->ostrm, 15); kw_to_stream(c->ostrm, 3);
  switch((fhptr->fontno) & DK_FONT_FEATURE_FAMILY) {
    case DK_FONT_FEATURE_RM : {
      kw_to_stream(c->ostrm, 17);
    } break;
    case DK_FONT_FEATURE_SF : {
      kw_to_stream(c->ostrm, 18);
    } break;
    case DK_FONT_FEATURE_TT : {
      kw_to_stream(c->ostrm, 19);
    } break;
    default: {
      kw_to_stream(c->ostrm, 16);
    } break;
  } kw_to_stream(c->ostrm, 4);
  kw_to_stream(c->ostrm, 23);
  newline_to_c(c, c->ostrm);
  /* kw_to_stream(c->ostrm, 24); */
  kw_to_stream(c->ostrm, 20); kw_to_stream(c->ostrm, 3);
  kw_to_stream(c->ostrm,
    (((fhptr->fontno) & DK_FONT_FEATURE_BD) ? 27 : 26)
  );
  kw_to_stream(c->ostrm, 4);
  kw_to_stream(c->ostrm, 23);
  newline_to_c(c, c->ostrm);
  /* kw_to_stream(c->ostrm, 24); */
  kw_to_stream(c->ostrm, 21); kw_to_stream(c->ostrm, 3);
  kw_to_stream(c->ostrm,
    (((fhptr->fontno) & DK_FONT_FEATURE_IT) ? 29 : 28)
  );
  kw_to_stream(c->ostrm, 4);
  kw_to_stream(c->ostrm, 23);
  newline_to_c(c, c->ostrm);
  /* kw_to_stream(c->ostrm, 24); */
  kw_to_stream(c->ostrm, 22);
  kw_to_stream(c->ostrm, 23);
  newline_to_c(c, c->ostrm);
  kw_to_stream(c->ostrm, 4);
  kw_to_stream(c->ostrm, 23);
  newline_to_c(c, c->ostrm);
  if(me) { back = 0; }
  return back;
}



/**	Write a font name to output stream. The font number
	is encoded as character sequence.
	@param	os	Output stream.
	@param	drw	Fig drawing structure.
	@param	fhptr	Font handling structure.
*/
void
dkfig_dt_write_fontname DK_P3(dk_stream_t *,os, dk_fig_drawing *,drw, dk_fig_fonth_t *,fhptr)
{
  kw_to_stream(os, 2);
  dkfig_tool_num_as_string(os, fhptr->fonthno, drw->numlatalpha);
}



/**	Write LaTeX commands to define all fonts to output stream.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@param	drw	Fig drawing structure.
	@param	r	Flag: Use renewcommand instead of newcommand.
	@return	1 on success, 0 on error.
*/
static int
write_font_defs DK_P4(dk_fig_conversion *,c, dk_stream_t *,os, dk_fig_drawing *,drw, int,r)
{
  int back = 0;
  int me = 0;
  dk_fig_fonth_t *fhptr = NULL;
  
  if(drw->fonthi) {
    back = 1;
    if(drw->numlatfonts) {
      dksto_it_reset(drw->fonthi);
      while((fhptr = (dk_fig_fonth_t *)dksto_it_next(drw->fonthi)) != NULL) {
        
	/* wird jetzt zentral erledigt
	if((c->opt1) & DKFIG_OPT_OLD_TEX) {
	  correct_fonth_for_plain_tex(fhptr);
	}
	*/
        switch(fhptr->handling) {
	  case 3: {	/* exact font */
	    /* /font/fntAA=ptmr at 12 pt; */
	    /* /newfont{/fntAA}{ptmr scaled 12pt;} */
	    if((c->opt1) & DKFIG_OPT_OLD_TEX) {
	      kw_to_stream(c->ostrm, 0);
	      kw_to_stream(c->ostrm, 2);
	      dkfig_tool_num_as_string(
	        c->ostrm, fhptr->fonthno, drw->numlatalpha
	      );
	      kw_to_stream(c->ostrm, 5);
	      dkstream_puts(c->ostrm, dkfont_get_tex_name(fhptr->fontno));
	      kw_to_stream(c->ostrm, 6);
	      dkstream_puts_double(
	        c->ostrm,
		dkma_mul_double_ok(fhptr->fontsize, c->fsf, &me)
	      );
	      kw_to_stream(c->ostrm, 7);
	      kw_to_stream(c->ostrm, 23);
	      newline_to_c(c, c->ostrm);
	    } else {
	      kw_to_stream(c->ostrm, 1);
	      kw_to_stream(c->ostrm, 3);
	      kw_to_stream(c->ostrm, 2);
	      dkfig_tool_num_as_string(
	        c->ostrm, fhptr->fonthno, drw->numlatalpha
	      );
	      kw_to_stream(c->ostrm, 4);
	      kw_to_stream(c->ostrm, 3);
	      dkstream_puts(c->ostrm, dkfont_get_tex_name(fhptr->fontno));
	      kw_to_stream(c->ostrm, 6);
	      dkstream_puts_double(
	        c->ostrm,
		dkma_mul_double_ok(fhptr->fontsize,c->fsf,&me)
	      );
	      kw_to_stream(c->ostrm, 7);
	      kw_to_stream(c->ostrm, 4);
	      kw_to_stream(c->ostrm, 23);
	      newline_to_c(c, c->ostrm);
	    }
	  } break;
	  case 4: case 5: {	/* features and size */
	    if((c->opt1) & DKFIG_OPT_OLD_TEX) {
	      kw_to_stream(c->ostrm, 32);
	      kw_to_stream(c->ostrm,  2);
              dkfig_tool_num_as_string(
	        c->ostrm, fhptr->fonthno, drw->numlatalpha
	      );
	      kw_to_stream(c->ostrm, 35);
	      kw_to_stream(c->ostrm, 34);
	      kw_to_stream(c->ostrm, 2);
	      dkfig_tool_num_as_string(
	        c->ostrm, fhptr->fonthno, drw->numlatalpha
	      );
	      back = write_one_font_def(c, c->ostrm, fhptr);
	      kw_to_stream(c->ostrm, 33);
	    } else {
	      if((c->opt2) & DKFIG_OPT_TEX_DRIVER) {
	        kw_to_stream(c->ostrm, 12);
		kw_to_stream(c->ostrm,  2);
		dkfig_tool_num_as_string(
		  c->ostrm, fhptr->fonthno, drw->numlatalpha
		);
	      } else {
	        if(r) {
	          kw_to_stream(c->ostrm, 42);
	        } else {
	          kw_to_stream(c->ostrm, 11);
	        }
	        kw_to_stream(c->ostrm, 3);
	        kw_to_stream(c->ostrm, 2);
	        dkfig_tool_num_as_string(
	          c->ostrm, fhptr->fonthno, drw->numlatalpha
	        );
	        kw_to_stream(c->ostrm, 4);
	      }
	      back = write_one_font_def(c, c->ostrm, fhptr);
	    }
	  } break;
#if TRACE_DEBUG
	  default: { 
	  } break;
#endif
	}
      }
    }
  }
  if(me) { back = 0; }
  
  return back;
}



/**	Write LaTeX commands for font definitions to
	output stream.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@param	r	Flag: redefinition (1) or definition (0).
	@return	1 on success, 0 on error.
*/
int
dkfig_dt_font_redef DK_P3(dk_fig_conversion *,c, dk_stream_t *,os, int,r)
{
  int back = 0;
  /* dk_fig_output_mp *mpo = NULL; */
  dk_fig_object    *dro = NULL;
  dk_fig_drawing   *drw = NULL;
  
  if(c && os) {
    /* mpo = (dk_fig_output_mp *)(c->outds); */
    dro = c->drwng;
    /* if(mpo && dro) { */
    if(dro) {
      drw = (dk_fig_drawing *)(dro->data);
      if(drw) {
        back = write_font_defs(c, os, drw, r);
      }
    }
  }
  
  return back;
}



/**	Write LaTeX commands for font definitions to
	output stream.
	@param	c	Conversion job structure.
	@param	os	Output stream.
	@return	1 on success, 0 on error.
*/
int
dkfig_dt_font_defs DK_P2(dk_fig_conversion *,c, dk_stream_t *,os)
{
  int back;
  back = dkfig_dt_font_redef(c, os, 0); 
  return back;
}



/**	Write end{document} sequence to output stream.
	@param	c	Conversion job structure.
	@param	os	Output stream.
*/
void
dkfig_dt_end_document DK_P2(dk_fig_conversion *,c, dk_stream_t *,os)
{
  if((c) && (os)) {
    if(!((c->opt1) & DKFIG_OPT_OLD_TEX)) {
      kw_to_stream(os, 36);
    } else {
      kw_to_stream(os, 37);
    }
  }
}



/**	Write begin{document} to output stream.
	@param	c	Conversion job structure.
	@param	os	Output stream.
*/
void
dkfig_dt_begin_document DK_P2(dk_fig_conversion *,c, dk_stream_t *,os)
{
  if((c) && (os)) {
    if(!((c->opt1) & DKFIG_OPT_OLD_TEX)) {
      kw_to_stream(os, 10);
    }
  }
}



/**	Check whether or not there is any text in the drawing
	requiring the use of LaTeX/TeX.
	@param	c	Conversion job structure.
	@return	Test result (1=LaTeX/TeX needed, 0=not needed).
*/
int
dkfig_dt_need_tex_file DK_P1(dk_fig_conversion *,c)
{
  int back = 0;
  dk_fig_object *o = NULL;
  dk_fig_drawing *drw = NULL;
  dk_fig_fonth_t *fhptr = NULL;
  
  if(c) {
    o = c->drwng;
    if(o) {
      drw = (dk_fig_drawing *)(o->data);
      if(drw) {
       if(drw->fonthi) {
        dksto_it_reset(drw->fonthi);
        while(((fhptr = (dk_fig_fonth_t *)dksto_it_next(drw->fonthi)) != NULL)
	      && (!back))
	{
	 switch(fhptr->handling) {
	  case 2: case 3: case 4: case 5: back = 1; break;
	 }
        }
       }
      }
    }
  }
  
  return back;
}



/**	Write LaTeX/TeX file and run LaTeX/TeX.
	@param	c	Conversion job structure.
	@param	d	Fig drawing structure.
	@param	it	Iterator to flattened Fig objects container.
	@return	1 on success, 0 on error.
*/
int
dkfig_dt_run_tex DK_P3(dk_fig_conversion *,c, dk_fig_drawing *,d, dk_storage_iterator_t *,it)
{
  int back = 0;
  dk_stream_t *os = NULL;
  FILE *of = NULL;
  dk_fig_object *o;
  dk_fig_text   *t;
  dk_fig_fonth_t *f;
  if(c && it) {
    if(c->texn) {
      if(c->app) {
        of = dkapp_fopen(c->app, c->texn, str_open_write_text);
      } else {
        of = dksf_fopen(c->texn, str_open_write_text);
      }
      if(of) {
        os = dkstream_for_file(of);
	if(os) {
	  if(dkfig_dt_tex_preamble(c, os)) {
	    dkfig_dt_begin_document(c, os);
	    back = 1;
	    dksto_it_reset(it);
	    while((o = (dk_fig_object *)dksto_it_next(it)) != NULL) {
	      if(o->objtype == DK_FIG_OBJ_TEXT) {
	        t = (dk_fig_text *)(o->data);
		if(t) {
		  f = t->font_handling;
		  if(f) {
		    switch(f->handling) {
		      case 2: case 3: case 4: case 5: {
		        kw_to_stream(os, 38);
			newline_to_c(c, os);
			if((c->special_text) & DKFIG_TH_MBOX) {
			  kw_to_stream(os, 40);
			}
                        if(f->handling != 2) {
                          dkfig_dt_write_fontname(os, d, f);
	                  kw_to_stream(os, 41);
                        }
			dkstream_puts(os, t->text);
			if((c->special_text) & DKFIG_TH_MBOX) {
			  kw_to_stream(os, 4);
			}
			kw_to_stream(os, 39);
			newline_to_c(c, os);
		      } break;
		    }
		  }
		}
	      }
	    }
	    dkfig_dt_end_document(c, os);
	  }
	  dkstream_close(os); os = NULL;
	} else {	
	  dkfig_tool2_msg1(c, DK_LOG_LEVEL_ERROR, 59);
	}
        fclose(of); of = NULL;
	if(back) {
	  char *tc, *to, *tw;
#if RUN_CMD_LATEX_DVIPS
          char *cmdline;
#endif
	  size_t sz;
	  back = 0;
	  tc = to = tw = NULL;
	  tc = (((c->opt1) & DKFIG_OPT_OLD_TEX) ? texcmd : latexcmd);
	  to = options;
	  if((c->opt1) & DKFIG_OPT_SPECIFY_WRITE18) {
	    tw = (((c->opt1) & DKFIG_OPT_ENABLE_WRITE18)
	         ? write18on : write18off);
	  }
	  sz = strlen(tc) + strlen(c->texn) + strlen(to) + 3;
	  if(tw) {
	    sz += (1 + strlen(tw));
	  }
#if RUN_CMD_LATEX_DVIPS
	  cmdline = dk_new(char,sz);
	  if(cmdline) {
	    strcpy(cmdline, tc);
	    strcat(cmdline, kw[41]);
	    strcat(cmdline, to);
	    if(tw) {
	      strcat(cmdline, kw[41]);
	      strcat(cmdline, tw);
	    }
	    strcat(cmdline, kw[41]);
	    strcat(cmdline, c->texn);
	    
	    if(system(cmdline) == 0) {
	      back = 1;
	    } else {	
	      dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 60, 61, cmdline);
	    }
	    dk_delete(cmdline); cmdline = NULL;
	    if(back) {
	      back = 0;
	      tc = to = tw = NULL;
	      tc = dvipscmd;
	      if((c->opt1) & DKFIG_OPT_SPECIFY_WRITE18) {
	        tw = (((c->opt1) & DKFIG_OPT_ENABLE_WRITE18)
	             ? dvipsunsec : dvipssec);
	      }
	      sz = strlen(tc) + strlen(c->dvin) + 2;
	      if(tw) {
	        sz += (1 + strlen(tw));
	      }
	      cmdline = dk_new(char,sz);
	      if(cmdline) {
	        strcpy(cmdline, tc);
		strcat(cmdline, kw[41]);
		if(tw) {
		  strcat(cmdline, tw);
		  strcat(cmdline, kw[41]);
		}
		strcat(cmdline, c->dvin);
		
		if(system(cmdline) == 0) {
		  back = 1;
		} else {
		  dkfig_tool2_msg3(c, DK_LOG_LEVEL_ERROR, 60, 61, cmdline);
		}
	        dk_delete(cmdline); cmdline = NULL;
	      } else {	
		if(c->app) {
		  dkapp_err_memory(c->app, sizeof(char), sz);
		}
	      }
	    }
	  } else {	
	    if(c->app) {
	      dkapp_err_memory(c->app, sizeof(char), sz);
	    }
	  }
#else
          back = 1;
#endif
	}
      } else {		
	if(c->app) {
	  dkapp_err_fopenw(c->app, c->texn);
	}
      }
    } else {		
    }
  } else {		
  }
  return back;
}

