/*	############################################################
	# @(#) par.c
	# @(#)
	# @(#) Copyright (c) 1995-2001 by Dirk Hagedorn
	# @(#) Dirk Hagedorn (udo@dirk-hagedorn.de)
	#
	# This program is free software; you can redistribute it and/or
	# modify it under the terms of the GNU General Public License
	# as published by the Free Software Foundation; either version 2
	# of the License, or (at your option) any later version.
	# 
	# This program is distributed in the hope that it will be useful,
	# but WITHOUT ANY WARRANTY; without even the implied warranty of
	# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	# GNU General Public License for more details.
	# 
	# You should have received a copy of the GNU General Public License
	# along with this program; if not, write to the Free Software
	# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
	############################################################	*/
#ifndef ID_PAR_C
#define ID_PAR_C
const char *id_par_c= "@(#) par.c       19.07.1999";
#endif

#include "import.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "portab.h"
#include "constant.h"
#include "udo_type.h"
#include "commands.h"
#include "chr.h"
#include "file.h"
#include "msg.h"
#include "str.h"
#include "sty.h"
#include "toc.h"
#include "udo.h"
#include "img.h"

#include "export.h"
#include "par.h"
#include "udomem.h"


/*	############################################################
	# lokale Variablen
	############################################################	*/

#define	MAX_PARAMETERS	9

LOCAL char Param[MAX_PARAMETERS+1][1024];
LOCAL char Space[MAX_PARAMETERS+1][64];

LOCAL HYPHEN	*hyphen[MAXHYPHEN];	/* Array mit Zeigern auf Trennregeln	*/

LOCAL MACROS	*macros[MAXMACROS];	/* Array auf Zeiger mit Makros			*/

LOCAL DEFS		*defs[MAXDEFS];		/* Array auf Zeiger mit defines			*/

LOCAL PLACEHOLDER	phold[MAXPHOLDS+1];	/* Platzhalter	*/
LOCAL int			phold_counter;

LOCAL SPECCMD		speccmd[MAXSPECCMDS+1];	/* Platzhalter	*/
LOCAL int			speccmd_counter;

/*	############################################################
	# lokale Funktionen
	############################################################	*/

LOCAL void del_param_quotes (char *s);
LOCAL int get_nr_of_parameters ( const char *cmd, char *s );
LOCAL void reset_parameters ( void );
LOCAL int extract_parameters ( char *s, const char *cmd, const int count );
LOCAL int get_parameters ( char *s, const char *search, const int count );

LOCAL void adjust_params_inside ( char * s);

LOCAL BOOLEAN convert_link_lds ( char *s, const char *p0, char *p1, char *p2, const char *link );
LOCAL BOOLEAN convert_link_stg ( char *s, const char *p0, char *p1, char *p2, const char *link );
LOCAL BOOLEAN convert_link_pch ( char *s, const char *p0, char *p1, char *p2, const char *link );
LOCAL BOOLEAN convert_link_tex ( char *s, const char *p0, char *p1, char *p2 );
LOCAL BOOLEAN convert_link_pdf ( char *s, const char *p0, char *p1, char *p2, const char *link );
LOCAL BOOLEAN convert_link_lyx ( char *s, const char *p0, char *p1, char *p2 );
LOCAL BOOLEAN convert_link_tvh ( char *s, const char *p0, char *p1, char *p2 );
LOCAL BOOLEAN convert_link_info ( char *s, const char *p0, char *p1, char *p2, const char *link );
LOCAL BOOLEAN convert_link_ipf ( char *s, const char *p0, char *p1, char *p2, const char *link );
LOCAL BOOLEAN convert_link_etc ( char *s, const char *p0, char *p1, char *p2, const char *link );

LOCAL void c_link ( char *s, BOOLEAN inside_b4_macro );
LOCAL void c_url ( char *s, BOOLEAN inside_b4_macro );
LOCAL void c_xlink ( char *s, BOOLEAN inside_b4_macro );
LOCAL void c_ilink ( char *s, const BOOLEAN inside_b4_macro );
LOCAL void c_plink ( char *s, const BOOLEAN inside_b4_macro );
LOCAL void c_nolink ( char *s, const BOOLEAN inside_b4_macro );
LOCAL void c_comment ( char *s, const BOOLEAN inside_b4_macro );

LOCAL BOOLEAN c_index ( char *s, const BOOLEAN inside_b4_macro);
LOCAL BOOLEAN c_single_index ( char *s, const BOOLEAN inside_b4_macro);
LOCAL BOOLEAN c_double_index ( char *s, const BOOLEAN inside_b4_macro );
LOCAL BOOLEAN c_tripple_index ( char *s, const BOOLEAN inside_b4_macro );
LOCAL BOOLEAN c_quadruple_index ( char *s, const BOOLEAN inside_b4_macro );

LOCAL void c_internal_image ( char *s, const BOOLEAN inside_b4_macro );

LOCAL BOOLEAN c_single_raw ( char *s, const BOOLEAN inside_b4_macro );
LOCAL BOOLEAN c_double_raw ( char *s, const BOOLEAN inside_b4_macro );
LOCAL void c_internal_raw ( char *s, const BOOLEAN inside_b4_macro );

LOCAL BOOLEAN md_uses_parameters ( const char *s );



/*	############################################################
	#
	#	Parameter aus einem String extrahieren, der die
	#	Syntax (!command [text] [text] [text]) besitzt
	#	->	s:	eine komplette Zeile
	#		cmd:		das Kommando ohne "(!": link, plink, xlink
	#		Param[0]:	Kompletter Aufbau des Kommandos in der Zeile (original)
	#		Param[i]:	i. Parameter (global)
	#	<-	TRUE:	Korrekter Aufbau
	#		FALSE:	Fehlerhafter Aufbau oder Kommando nicht
	#				gefunden
	#
	############################################################	*/

LOCAL void del_param_quotes (char *s)
{
	qreplace_all(s, "!)", 2, ")", 1);
	qreplace_all(s, "!]", 2, "]", 1);
}


/*	------------------------------------------------------------
	Anzahl der Parameter eines Kommandos ermitteln, das so
	aufgebaut ist: (!command [p1] [p2] [...])
	------------------------------------------------------------	*/
LOCAL int get_nr_of_parameters ( const char *cmd, char *s )
{
	int count= 0;
	char *pos;
	char search[128];
	
	sprintf(search, "(!%s", cmd);
		
	if ( (pos=strstr(s, search))==NULL )
	{	return 0;
	}

	pos+= strlen(search);
	
	/* Die erste geschlossene Klammer suchen, vor der kein ! steht */

	while( pos[0]!=')' || (pos[0]==')' && pos[-1]=='!') )
	{	switch(pos[0])
		{	case EOS:
				error_unexpected_eol();
				return 0;
			case ']':
				if (pos[-1]!='!')
				{	count++;
				}
				break;
		}
		pos++;
	}
	
	return count;
	
}	/* get_nr_of_parameters */


LOCAL void reset_parameters ( void )
{
	int i;
	
	for (i=0; i<MAX_PARAMETERS; Param[i++][0]= EOS) ;
	for (i=0; i<MAX_PARAMETERS; Space[i++][0]= EOS) ;

}	/* reset_parameters */



LOCAL int extract_parameters ( char *s, const char *cmd, const int count )
{
	int i;
	char *pos, search[128];

	sprintf(search, "(!%s", cmd);	/* PL3 */
	
	if ( (pos=strstr(s, search))==NULL )
	{	return 0;
	}

	reset_parameters();

	pos+= strlen(search);

	i= 0;

	while (i<count)		
	{	/* Anfang "[" des Parameters bestimmen		*/
		/* und die Zeichen ermitteln, die bis dahin	*/
		/* im Quelltext auftauchen					*/
		while( (pos[0]!='[') && (pos[0]!=EOS) )
		{	chrcat(Space[i], pos[0]);
			pos++;
		}
		if (pos[0]==EOS)
		{	error_unexpected_eol();
			return 0;
		}

		/* Pointer auf erstes Zeichen des Parameters setzen */
		/* und bis zur naechsten Klammer lesen, die nicht	*/
		/* duch ein Ausrufungszeichen gequotet ist.			*/
		pos++;

		while( (pos[0]!=']' || (pos[0]==']' && pos[-1]=='!')) && (pos[0]!=EOS) )
		{	chrcat(Param[i+1], pos[0]);
			pos++;
		}
		
		if (pos[0]==EOS)
		{	error_unexpected_eol();
			return 0;
		}
	
		pos++;
		i++;
	}

	/* Zeichen lesen, die bis zum Ende des Kommandos auftauchen */
	
#if 1
	while( (pos[0]!=')') && (pos[0]!=EOS) )
	{	chrcat(Space[count], pos[0]);
		pos++;
	}
#else
	while( (pos[0]!=')') && (pos[0]!=EOS) )
	{	chrcat(Space[count+1], pos[0]);
		pos++;
	}
#endif

	if (pos[0]==EOS)
	{	error_unexpected_eol();
		return 0;
	}

	return i ;	/* PL14: Anzahl der Parameter statt BOOLEAN */
}	/* extract_parameters */


LOCAL int get_parameters ( char *s, const char *search, const int count )
{
	int i, params;
	
	params=extract_parameters(s, search, count);
	
	if (params==0)
	{	return 0;
	}

#if 0
	if (params!=count)
	{	error "was nun?"
	}
#endif

	sprintf(Param[0], "(!%s%s", search, Space[0]);
	
	if (params>0)
	{	for(i=1; i<=params; i++)
		{	strcat(Param[0], "[");
			strcat(Param[0], Param[i]);
			strcat(Param[0], "]");
			strcat(Param[0], Space[i]);
			del_param_quotes(Param[i]);	
		}
	}
	
	strcat(Param[0], ")");

	return params;		/* PL14: Anzahl der Parameter statt BOOLEAN */
}	/* get_parameters */



/*	------------------------------------------------------------
	Diese Funktion dient zur Anpassung von Makros und Definitionen,
	die Variablen enthalten. Beispiel:

	!macro Maus (!1) (!2) @ (!3), (!1)_(!2)@(!3).maus.de
	MausNet:	(!Maus [Dirk] [Hagedorn] [MK2])

	cmd   =	Maus
	entry =	(!1) (!2) @ (!3), (!1)_(!2)@(!3).maus.de
	s     =	Der String mit dem Makro

	---->

	MausNet: Dirk Hagedorn @ MK2, Dirk_Hagedorn@MK2.maus.de
	------------------------------------------------------------	*/
GLOBAL void replace_variables ( char *s, const char *cmd, const char *entry)
{
	int parms, i;
	char p[16], without[128], *ptr;
	BOOLEAN flag;

	/* PL10: (!macro) vorher loeschen */
	sprintf(without, "(!%s)", cmd);
	delete_all(s, without);

	flag = TRUE;
	while ( flag && (parms= get_nr_of_parameters(cmd, s))>0 )
	{
		if (parms>MAX_PARAMETERS)
		{	error_too_many_parameters();
			return;
		}	

		get_parameters(s, cmd, parms);

		/* r6pl2: ptr statt s benutzen, damit die Parameter nur ab */
		/* der Stelle des/r Makros/Definition ersetzt werden und */
		/* nicht bereits davor. */
		/* Trotzdem werden auch (!1) etc. ersetzt, die nach den */
		/* Parameter-Befehle stehen. Dies wuerde aber einen */
		/* unheimlichen Umstand bedeuten (Ausschneiden, Ersetzen, */
		/* wieder Einfuegen: fuer jedes etwaige vorhandene Makro) */
		/* Da aber (!0) ... (!9) eh verboten sind, wird hier keine */
		/* Ruecksicht auf die Pappenheimer genommen, die UDO-Befehle */
		/* nicht quoten wollen, wie z.B. mit (!/0), (!/1) etc. */

		ptr= strstr(s, Param[0]);

		if ( replace_all(ptr, Param[0], entry) )	/* r6pl2: ptr statt s */
		{
			qdelete_all(ptr, "(!0)", 4);	/* r6pl2 */
			for (i=0; i<MAX_PARAMETERS; i++)
			{
				sprintf(p, "(!%d)", i+1);
				if (parms>i)
				{	auto_quote_chars(Param[i+1], TRUE);		/* <???> */
					replace_all(ptr, p, Param[i+1]);
				}
				else
				{
					qdelete_all(ptr, p, 4);
				}
			}
		}
		else
		{	flag= FALSE;
		}
	}

	if (!flag)
	{	sprintf(without, "!%s", cmd);
		error_replace_param(without);
	}

}	/* replace_variables */



/*	############################################################
	#
	# Spezielle Formatbefehle als Platzhalter im Text einbauen
	# Die Formatbefehle enthalten keinen sichtbaren Text!
	#
	############################################################	*/
GLOBAL void reset_speccmds ( void )
{
	int i;

	if (speccmd_counter>=0)
	{
		for (i=0; i<speccmd_counter; i++)
		{
			if ( speccmd[i].entry!=NULL )
			{	um_free(speccmd[i].entry);
				speccmd[i].entry= NULL;
			}
			
			speccmd[i].magic[0]= EOS;
		}
	}

	speccmd_counter= -1;

}	/* reset_speccmds */



GLOBAL BOOLEAN add_speccmd ( char *entry )
{
	size_t	sl;
	char	*ptr;
	
	if (speccmd_counter<MAXSPECCMDS)
	{
		speccmd_counter++;

		sl= strlen(entry);
		ptr= (char *) ( um_malloc(sl*sizeof(char)+1) );
		if (ptr==NULL)
		{	error_malloc_failed();
			speccmd_counter--;
			return FALSE;
		}
		
		if (speccmd_counter+OFFSET_SPECCMD==(int) '~')
		{	speccmd_counter++;
		}
		if (speccmd_counter+OFFSET_SPECCMD==(int) '\177')
		{	speccmd_counter++;
		}

		sprintf(speccmd[speccmd_counter].magic, "\033%c%c\033",
			C_SPECCMD_MAGIC, speccmd_counter+OFFSET_SPECCMD);
		
		
		speccmd[speccmd_counter].entry= ptr;
		
		strcpy(speccmd[speccmd_counter].entry, entry);

		return TRUE;
	}
	
	return FALSE;
}	/* add_speccmd */



GLOBAL BOOLEAN insert_speccmd ( char *s, const char *rep, char *entry )
{
	if ( add_speccmd(entry) )
	{	if ( replace_once(s, rep, speccmd[speccmd_counter].magic) )
		{	return TRUE;
		}
	}
	
	return FALSE;
}


GLOBAL void replace_speccmds ( char *s )
{
	register int i;
	int replaced= -1;

	if (speccmd_counter>=0)
	{
		if ( strstr(s, ESC_SPECCMD_MAGIC)==NULL)
		{	return;
		}	

#if 1
		/* PL10: Rueckwaerts ersetzen, da ein Platzhalter auch in	*/
		/* einem Platzhalter stecken kann!							*/
		for (i=speccmd_counter; i>=0; i--)
#else
		for (i=0; i<=speccmd_counter; i++)
#endif
		{	if ( replace_once(s, speccmd[i].magic, speccmd[i].entry) )
			{	speccmd[i].magic[0]= EOS;
				replaced++;
			}
		}
		if (replaced==speccmd_counter)
		{	reset_speccmds();
		}
	}

}	/* replace_speccmds */




/*	############################################################
	#
	# Links und andere interne Kommandos bearbeiten, was
	# VOR dem Tokenisieren passieren muss!
	# Aufbau: (!link [text] [destination])
	#
	############################################################	*/
GLOBAL void reset_placeholders ( void )
{
	int i;

	if (phold_counter>=0)
	{
		for (i=0; i<phold_counter; i++)
		{
			if ( phold[i].entry!=NULL )
			{	um_free(phold[i].entry);
				phold[i].entry= NULL;
			}
			
			if ( phold[i].text!=NULL )
			{	um_free(phold[i].text);
				phold[i].text= NULL;
			}
			
			phold[i].magic[0]= EOS;
		}
	}

	phold_counter= -1;

}	/* reset_placeholders */



GLOBAL BOOLEAN add_placeholder ( char *entry, char *rawtext )
{
	size_t	el, tl;
	char	*eptr, *tptr;
	
	if (phold_counter<MAXPHOLDS)
	{
		phold_counter++;

		el= strlen(entry);
		eptr= (char *) ( um_malloc(el*sizeof(char)+1) );
		if (eptr==NULL)
		{	error_malloc_failed();
			phold_counter--;
			return FALSE;
		}
		
		tl= strlen(rawtext);
		tptr= (char *) ( um_malloc (tl*sizeof(char)+1) );
		if (tptr==NULL)
		{	error_malloc_failed();
			um_free(eptr);
			phold_counter--;
			return FALSE;
		}

		if (phold_counter+OFFSET_PHOLD==(int) '~')		/* PL8 */
		{	phold_counter++;
		}
		if (phold_counter+OFFSET_PHOLD==(int) '\177')	/* PL8 */
		{	phold_counter++;
		}

		sprintf(phold[phold_counter].magic, "\033%c%c\033",
			C_PHOLD_MAGIC, phold_counter+OFFSET_PHOLD);
		
		
		phold[phold_counter].entry= eptr;
		phold[phold_counter].text= tptr;
		
		strcpy(phold[phold_counter].entry, entry);
		strcpy(phold[phold_counter].text, rawtext);

		return TRUE;
	}
	
	return FALSE;
}	/* add_placeholder */



GLOBAL BOOLEAN insert_placeholder ( char *s, const char *rep, char *entry, char *rawtext )
{
	if ( add_placeholder(entry, rawtext) )
	{	if ( replace_once(s, rep, phold[phold_counter].magic) )
		{	return TRUE;
		}
	}
	
	return FALSE;
}


GLOBAL void replace_placeholders ( char *s )
{
	register int i;
	int replaced= -1;

	if (phold_counter>=0)
	{
		if ( strstr(s, ESC_PHOLD_MAGIC)==NULL)
		{	return;
		}	

		/* PL10: Rueckwaerts ersetzen, da ein Platzhalter auch in	*/
		/* einem Platzhalter stecken kann!							*/
		for (i=phold_counter; i>=0; i--)
		{	if ( replace_once(s, phold[i].magic, phold[i].entry) )
			{	phold[i].magic[0]= EOS;
				replaced++;
			}
		}
		if (replaced==phold_counter)
		{	reset_placeholders();
		}
	}

}	/* replace_placeholders */


GLOBAL void replace_placeholders_text ( char *s )
{
	register int i;

	if (phold_counter>=0)
	{
		if ( strstr(s, ESC_PHOLD_MAGIC)==NULL)
		{	return;
		}	

		for (i=0; i<=phold_counter; i++)
		{	replace_once(s, phold[i].magic, phold[i].text);
		}
	}
}	/* replace_placeholders_text */


GLOBAL size_t pholdlen ( int i )
{
	if ( i>=0 && i<=MAXPHOLDS )
	{
		if ( phold[i].text!= NULL )
		{
			return(strlen(phold[i].text));
		}
	}
	
	return 0;
}	/* pholdlen */




LOCAL void adjust_params_inside ( char * s)
{
	replace_macros(s);
	c_divis(s);
	c_vars(s);
	c_styles(s);
}


LOCAL BOOLEAN convert_link_lds ( char *s, const char *p0, char *p1, char *p2, const char *link )
{
	char s_entry[1024], old_entry[1024];
	char *ptr;
	BOOLEAN flag;
	
	strcpy(s_entry, p2);
	c_tilde(s_entry);
	replace_udo_quotes(s_entry);

	convert_tilde(p1);
	convert_tilde(p2);
	replace_udo_quotes(p1);
	replace_udo_quotes(p2);
	strcpy(old_entry, p2);

	auto_references(s_entry, TRUE, "", 0, 0);		/* auch Links innerhalb der Seite ermoeglichen */
	/* Trick: Schauen, ob nun "> im Eintrag steht und dann */
	/* ab dort den Link einsetzen. */
	flag= FALSE;
	if ( (ptr=strstr(s_entry, "name=\"")) != NULL )
	{	flag= replace_once(ptr, old_entry, p1);
	}

	if (!flag)
	{	error_undefined_link(link);
		strcpy(s_entry, p1);	/* PL9 */
	}
	
	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return TRUE;
	}

	return FALSE;
}	/* convert_link_lds */


LOCAL BOOLEAN convert_link_stg ( char *s, const char *p0, char *p1, char *p2, const char *link )
{
	char nodename[256], s_entry[256];
	int ti, li;
	BOOLEAN isnode;
	BOOLEAN flag;

	c_tilde(p2);
	replace_udo_quotes(p2);
	
	flag= is_node_link(p2, nodename, &ti, &isnode, &li);

	replace_udo_tilde(p2);
	replace_udo_nbsp(p2);

	convert_tilde(p1);
	replace_udo_quotes(p1);

 	if (flag)
	{
		node2stg(p1);
		node2stg(p2);
		
		replace_2at_by_1at(p1);			/*r6pl2*/
		replace_2at_by_1at(p2);			/*r6pl2*/
		replace_2at_by_1at(nodename);	/*r6pl2*/

		/* r6pl15: links auf gleiche node mag ST-Guide nicht */
		if (isnode && is_current_node(ti))
		{
			strcpy(s_entry, p1);
		} else
		{
			if (!isnode)
			{	/* PL9: Links auf Labels sind etwas besonderes */
				sprintf(s_entry, "@{\"%s\" link \"%s\" \"%s\"}",
					p1, nodename, p2);
			}
			else
			{	sprintf(s_entry, "@{\"%s\" link \"%s\"}",
							p1, p2);
			}
		}
	}


	if (!flag)
	{	/* Node, Alias oder Label nicht definiert */
		error_undefined_link(link);
		strcpy(s_entry, p1);
	}
	
	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return TRUE;
	}

	return FALSE;

}	/* convert_link_stg */



LOCAL BOOLEAN convert_link_pch ( char *s, const char *p0, char *p1, char *p2, const char *link )
{
	char nodename[256], s_entry[256];
	int ti, li;
	BOOLEAN isnode;
	BOOLEAN flag;

	c_tilde(p2);
	replace_udo_quotes(p2);
	
	flag= is_node_link(p2, nodename, &ti, &isnode, &li);

	replace_udo_tilde(p2);
	replace_udo_nbsp(p2);

	convert_tilde(p1);
	replace_udo_quotes(p1);

	if (flag)
	{	node2pchelp(p2);
		sprintf(s_entry, "\\link(\"%s\")%s\\#", p2, p1);
	}
	else
	{	/* Node, Alias oder Label nicht definiert */
		error_undefined_link(link);
		strcpy(s_entry, p1);
	}
	
	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return TRUE;
	}

	return FALSE;

}	/* convert_link_pch */



LOCAL BOOLEAN convert_link_tex ( char *s, const char *p0, char *p1, char *p2 )
{
	char s_entry[1024];
	int li, ti;
	BOOLEAN isnode;
	char nodename[256];
	
	convert_tilde(p1);
	convert_tilde(p2);
	replace_udo_quotes(p1);
	replace_udo_quotes(p2);
	label2tex(p2);
	
	is_node_link(p2, nodename, &ti, &isnode, &li);

	sprintf(s_entry, "%s (%s \\ref{%s})", p1, lang.see, p2);

	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return TRUE;
	}

	return FALSE;
}	/* convert_link_tex */


LOCAL BOOLEAN convert_link_pdf ( char *s, const char *p0, char *p1, char *p2, const char *link )
{
	char nodename[256], s_entry[256];
	int ti, li, dest;
	BOOLEAN isnode;
	BOOLEAN flag;

	c_tilde(p2);
	replace_udo_quotes(p2);
	
	flag= is_node_link(p2, nodename, &ti, &isnode, &li);

	convert_tilde(p1);
	replace_udo_quotes(p1);

	if (flag)
	{	if (isnode)
		{	dest= ti;
		}
		else
		{	dest= li;
		}
		/* Changed in r6.2pl1 [NHz] */
		sprintf(s_entry, "{\\pdfstartlink goto num %d\n%s\\pdfendlink}",
			dest, p1);
	}
	else
	{	/* Node, Alias oder Label nicht definiert */
		error_undefined_link(link);
		strcpy(s_entry, p1);
	}
	
	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return TRUE;
	}

	return FALSE;
}	/* convert_link_pdf */


LOCAL BOOLEAN convert_link_lyx ( char *s, const char *p0, char *p1, char *p2 )
{
	char s_entry[1024];
	int li, ti;
	BOOLEAN isnode;
	char nodename[256];
	
	is_node_link(p2, nodename, &ti, &isnode, &li);

	sprintf(s_entry,
		"%s (%s \n\\begin_inset LatexDel \\ref{%s}\n\n\\end_inset\n\n)",
		p1, lang.see, p2);
		
	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return TRUE;
	}
	
	return FALSE;
}


LOCAL BOOLEAN convert_link_tvh ( char *s, const char *p0, char *p1, char *p2 )
{
	char s_entry[1024];
	int li, ti;
	BOOLEAN isnode;
	char nodename[256];
	
	is_node_link(p2, nodename, &ti, &isnode, &li);

	node2vision(p2);
	sprintf(s_entry, "{%s:%s}", p1, p2);

	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return TRUE;
	}
	
	return FALSE;
}	/* convert_link_tvh */


LOCAL BOOLEAN convert_link_info ( char *s, const char *p0, char *p1, char *p2, const char *link )
{
	char nodename[256], s_entry[256];
	int ti, li;
	BOOLEAN isnode;
	BOOLEAN flag;

	c_tilde(p2);
	replace_udo_quotes(p2);
	
	flag= is_node_link(p2, nodename, &ti, &isnode, &li);

	convert_tilde(p1);
	replace_udo_quotes(p1);

	replace_udo_tilde(p2);
	replace_udo_nbsp(p2);
	node2texinfo(p2);

	if (flag)
	{
		if (isnode)
		{	strcpy(nodename, p2);
		}
		else
		{	node2texinfo(nodename);
		}

		sprintf(s_entry, "%s (@xref{%s})", p1, nodename);
	}
	else
	{	/* Node, Alias oder Label nicht definiert */
		error_undefined_link(link);
		strcpy(s_entry, p1);
	}
	
	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return TRUE;
	}

	return FALSE;

}	/* convert_link_info */


LOCAL BOOLEAN convert_link_ipf ( char *s, const char *p0, char *p1, char *p2, const char *link )
{
	char nodename[256], s_entry[256], s_id[256];
	int ti, li;
	BOOLEAN isnode;
	BOOLEAN flag;

	c_tilde(p2);
	replace_udo_quotes(p2);
	
	flag= is_node_link(p2, nodename, &ti, &isnode, &li);

	convert_tilde(p1);
	replace_udo_quotes(p1);

	if (flag)
	{	getLabelIndexFromTocIndex(&li, ti);
		node2NrIPF(s_id, li);
		sprintf(s_entry, ":link reftype=hd refid=%s.%s:elink.", s_id, p1);
	}
	else
	{	/* Node, Alias oder Label nicht definiert */
		error_undefined_link(link);
		strcpy(s_entry, p1);
	}
	
	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return TRUE;
	}

	return FALSE;

}	/* convert_link_ipf */


/* New in r6pl15 [NHz] */
LOCAL BOOLEAN convert_link_ps ( char *s, const char *p0, char *p1, char *p2, const char *link )
{
	char nodename[256], s_entry[256];
	int ti, li;
	BOOLEAN isnode;
	BOOLEAN flag;

	/* Internal Link for Postscript */
	flag= is_node_link(p2, nodename, &ti, &isnode, &li);


	convert_tilde(p1);
	if (flag)
	{	if (p2[0]==EOS)
		{	strcpy(p2, Param[1]);
		}
		replace_udo_quotes(p2);	/* r6pl2 */
		replace_udo_quotes(p1);	/* r6pl2 */
		/* Changed in V6.4.1 [NHz] */
		replace_all(p1, "(", "\\(");
		replace_all(p1, ")", "\\)");
		c_vars(p1);
		qreplace_all(p1, KPSPC_S, KPSPC_S_LEN, ")", 1);
		qreplace_all(p1, KPSPO_S, KPSPO_S_LEN, "(", 1);
		sprintf(s_entry, ") udoshow (%s) /%s 0 255 0 Link (", p1, p2);
	}

	else

	{	/* Node, Alias oder Label nicht definiert */
		error_undefined_link(link);
		strcpy(s_entry, p1);
	}

	

	if ( insert_placeholder(s, p0, s_entry, p1) )
	{	return(TRUE);
	}

	return FALSE;

}	/* convert_link_ps */


LOCAL BOOLEAN convert_link_etc ( char *s, const char *p0, char *p1, char *p2, const char *link )
{
	char nodename[256], s_entry[256];
	char lq[16], rq[16];
	int ti, li;
	BOOLEAN isnode;
	BOOLEAN flag;

	c_tilde(p2);
	replace_udo_quotes(p2);
	
	flag= is_node_link(p2, nodename, &ti, &isnode, &li);

	replace_udo_tilde(p2);
	replace_udo_nbsp(p2);

	/* Deleted in r6.2pl1 [NHz] / Bug #00000030 */
	/* 	convert_tilde(p1); */
	replace_udo_quotes(p1);

	if (flag)
	{
		if (no_links)
		{	/* r6pl6: Links unterdruecken */
			strcpy(s_entry, p1);
		}
		else
		{	if (desttype==TORTF)	/*r6pl6: die richtigen benutzen */
			{	strcpy(lq, "\\ldblquote ");
				strcpy(rq, "\\rdblquote");
			}
			else
			{	strcpy(lq, "\"");
				strcpy(rq, "\"");
			}

			if (!isnode)
			{	/* PL9: Links auf Labels sind etwas besonderes */
				sprintf(s_entry, "%s (%s %s%s%s)", p1, lang.see, lq, nodename, rq);
			}
			else
			{	sprintf(s_entry, "%s (%s %s%s%s)", p1, lang.see, lq, p2, rq);
			}
		}
	}


	if (!flag)
	{	/* Node, Alias oder Label nicht definiert */
		error_undefined_link(link);
		strcpy(s_entry, p1);
	}
	
	if ( replace_once(s, p0, s_entry) )
	{	return TRUE;
	}

	return FALSE;
	
}	/* convert_link_etc */



LOCAL void c_link ( char *s, BOOLEAN inside_b4_macro )
{
	int pnr=0;
	char s_entry[1024], old_entry[1024], link[1024];
	char *ptr;
	BOOLEAN linkerror;
	BOOLEAN flag;
	BOOLEAN	old_autorefoff;

	old_autorefoff= bDocAutorefOff;
	bDocAutorefOff= FALSE;
	
	linkerror = FALSE;
	while ( !linkerror && ((pnr=get_parameters(s, "link", 2))==2) )
	{
		strcpy(link, Param[2]);
		del_whitespaces(Param[1]);
		del_whitespaces(Param[2]);


		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);	
				auto_quote_chars(Param[2], TRUE);
			}
		
			adjust_params_inside(Param[1]);
			adjust_params_inside(Param[2]);
		}

		switch(desttype)
		{
			case TOHTM:
			case TOMHH:
				strcpy(s_entry, Param[2]);
				c_tilde(s_entry);
				replace_udo_quotes(s_entry);

				convert_tilde(Param[1]);
				convert_tilde(Param[2]);
				replace_udo_quotes(Param[1]);
				replace_udo_quotes(Param[2]);
				strcpy(old_entry, Param[2]);

				auto_references(s_entry, TRUE, "", 0, 0);		/* auch Links innerhalb der Seite ermoeglichen */

				/* Trick: Schauen, ob nun "> im Eintrag steht und dann */
				/* ab dort den Link einsetzen. */
				flag= FALSE;
				if ( (ptr=strstr(s_entry, "\">")) != NULL )
				{	flag= replace_once(ptr, old_entry, Param[1]);
				}

				if (!flag)
				{	error_undefined_link(link);
					strcpy(s_entry, Param[1]);	/* PL9 */
				}
				
				linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
				break;

			case TOWIN:	/* 0.41 */
			case TOWH4:
			case TOAQV:
				strcpy(s_entry, Param[2]);
				c_tilde(s_entry);
				replace_udo_quotes(s_entry);

				convert_tilde(Param[1]);
				convert_tilde(Param[2]);
				replace_udo_quotes(Param[1]);
				replace_udo_quotes(Param[2]);
				strcpy(old_entry, Param[2]);

				auto_references(s_entry, TRUE, "", 0, 0);		/* auch Links innerhalb der Seite ermoeglichen */

				/* Trick: Schauen, ob nun {\uldb im Eintrag steht und dann */
				/* ab dort den Link einsetzen. */
				flag= FALSE;

				ptr=strstr(s_entry, "{\\uldb");
				
				if ( ptr==NULL )	/* PL8: Links auf Popups erlauben */
				{	ptr=strstr(s_entry, "{\\ul");
				}

				if ( ptr != NULL )
				{	flag= replace_once(ptr, old_entry, Param[1]);
				}
				
				if (!flag)
				{	error_undefined_link(link);
					strcpy(s_entry, Param[1]);	/* PL9 */
				}
				
				linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
				break;
			case TOLDS:
				linkerror= !convert_link_lds(s, Param[0], Param[1], Param[2], link);
				break;
			case TOSTG:
			case TOAMG:
				linkerror= !convert_link_stg(s, Param[0], Param[1], Param[2], link);
				break;
			case TOTEX:
				linkerror= !convert_link_tex(s, Param[0], Param[1], Param[2]);
				break;
			case TOPDL:
				linkerror= !convert_link_pdf(s, Param[0], Param[1], Param[2], link);
				break;
			case TOLYX:
				linkerror= !convert_link_lyx(s, Param[0], Param[1], Param[2]);
				break;
			case TOTVH:
				linkerror= !convert_link_tvh(s, Param[0], Param[1], Param[2]);
				break;
			case TOPCH:	/* PL9 */
				linkerror= !convert_link_pch(s, Param[0], Param[1], Param[2], link);
				break;
			case TOINF:
				linkerror= !convert_link_info(s, Param[0], Param[1], Param[2], link);
				break;
			case TOIPF:
				linkerror= !convert_link_ipf(s, Param[0], Param[1], Param[2], link);
				break;

			/* New in r6pl15 [NHz] */
			/* Internal Link for Postscript */
			case TOKPS:
				linkerror= !convert_link_ps(s, Param[0], Param[1], Param[2], link);
				break;

			default:
				linkerror= !convert_link_etc(s, Param[0], Param[1], Param[2], link);
				break;
		}
	}
	
	if (linkerror)
	{	replace_once(s, Param[0], Param[1]);
		error_replace_param("!link");
	}
	
	if (pnr!=0 && pnr!=2)
	{	error_wrong_nr_parameters("!link");
	}

	bDocAutorefOff= old_autorefoff;
}	/*c_link*/


LOCAL void c_url ( char *s, BOOLEAN inside_b4_macro )
{
	int pnr=0, url_len, i;
	/* Changed in r6pl17 [NHz] / s_entry (1024 to 4096 bytes), url_rtf (512 to 2048 bytes) */
	char s_entry[4096], url_rtf[2048], rtf0[4];

	char rtf1[]="00d0c9ea79f9bace118c8200aa004ba90b0200000003000000";
	char rtf2[]="e0c9ea79f9bace118c8200aa004ba90b";
	char rtf3[]="000000";
	char rtf4[]="0000";
	BOOLEAN linkerror= FALSE;

	while ( !linkerror && ((pnr=get_parameters(s, "url", 2))==2) )
	{
		del_whitespaces(Param[1]);	/* PL9 */

		/* Wird ein leerer Parameter benutzt, den	*/
		/* den ersten auch als zweiten verwenden.	*/
		if (Param[2][0]==EOS)
		{	um_strcpy(Param[2], Param[1], 1024, "c_url[1]");
		}

		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);
			}

			adjust_params_inside(Param[1]);
		}
		
		if (no_urls)
		{	replace_all(s, Param[0], Param[1]);
		}
		else
		{
 			switch(desttype)
 			{
 				case TOHTM:
				case TOMHH:
 					convert_tilde(Param[1]);
					if (Param[2][0]==EOS)
					{	um_strcpy(Param[2], Param[1], 1024, "c_url[TOHTM|1]");
					}
					replace_udo_quotes(Param[2]);	/* r6pl2 */
					replace_udo_quotes(Param[1]);	/* r6pl2 */
					if (html_frames_layout)
					{	sprintf(s_entry, "<a href=\"%s\" target=\"_top\">%s</a>", Param[2], Param[1]);
					}
					else
					{	sprintf(s_entry, "<a href=\"%s\">%s</a>", Param[2], Param[1]);
					}
					if (strlen(s_entry)>=4096) /* vj: For debugging reasons */
					{
						printf("c_url: s_entry buffer overrus after sprintf\n");
					}
 					linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
 					break;

					/* New in r6pl15 [NHz] */
					/* Weblink for Postscript/PDF */
				case TOKPS:
  				convert_tilde(Param[1]);
					if (Param[2][0]==EOS)
					{	strcpy(Param[2], Param[1]);
					}
					replace_udo_quotes(Param[2]);
					replace_udo_quotes(Param[1]);
					/* Changed in V6.4.1 [NHz] */
					c_divis(Param[1]);
					c_vars(Param[1]);
					/* Changed: Fixed bug #0000062 in V 6.4.1 [NHz] */
					node2postscript(Param[1], KPS_CONTENT);
					replace_all(Param[1], KPSPO_S, "(");
					replace_all(Param[1], KPSPC_S, ")");
					sprintf(s_entry, ") udoshow (%s) (%s) 0 0 255 WebLink (", Param[1], Param[2]);
   				linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
					break;

					/* Deleted bug in V6.4.1 [NHz] */
					/* Weblink for WinHelp4 */
				case TOWH4:
  				convert_tilde(Param[1]);
					if (Param[2][0]==EOS)
					{	strcpy(Param[2], Param[1]);
					}
					replace_udo_quotes(Param[2]);
					replace_udo_quotes(Param[1]);
					sprintf(s_entry, "{\\ul %s}{\\v !ExecFile(%s)}", Param[1], Param[2]);
   				linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
					break;

					/* New in r6pl15 [NHz] */
					/* Weblink for Richtext Format */
				case TORTF:
  				convert_tilde(Param[1]);

					/* New in r6.2pl1 [NHz] / Bug #00000029 */
					c_rtf_quotes(Param[1]);

					if (Param[2][0]==EOS)
					{	strcpy(Param[2], Param[1]);
					}
					replace_udo_quotes(Param[2]);
					replace_udo_quotes(Param[1]);

					/* Changed in r6.2pl1 [NHz] */ 					auto_quote_chars(Param[2], TRUE); 					url_len = (int)strlen(Param[2]);

					rtf0[0]=EOS;
					url_rtf[0]=EOS;

					for(i=0;i<url_len;i++)
					{	if(Param[2][i] == '\\') 						{	i += 2;
							rtf0[0]=EOS;
							strncpy(rtf0, Param[2]+i, 2);
							i++; 						} 						else 							sprintf(rtf0, "%x", (int)Param[2][i]); 
						strcat(url_rtf, rtf0);
						strcat(url_rtf, "00");
					}

					sprintf(s_entry, "{\\field{\\*\\fldinst {HYPERLINK \"%s\"}{{\\*\\datafield %s%s%x%s%s%s}}}\n{\\fldrslt {\\cs15\\ul\\cf2 %s}}}", Param[2], rtf1, rtf2, (url_len+1)*2, rtf3, url_rtf, rtf4, Param[1]);

   				linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
					break;

   			default:
   				convert_tilde(Param[1]);
					replace_udo_quotes(Param[1]);	/* r6pl2 */
					replace_udo_quotes(Param[2]);	/* r6pl2 */
					linkerror= !insert_placeholder(s, Param[0], Param[1], Param[1]);
 					break;
   			}	/*switch*/
   		}	/* if (no_urls) */

	}	/* while */

	if (linkerror)
	{	replace_once(s, Param[0], Param[1]);
		error_replace_param("!url");
	}

	if (pnr!=0 && pnr!=2)
	{	error_wrong_nr_parameters("!url");
	}

}	/*c_url*/


LOCAL void c_xlink ( char *s, BOOLEAN inside_b4_macro )
{
	int pnr=0;
	char s_entry[1024];
	char wnode[1024], wfile[1024], *ptr;
	BOOLEAN linkerror= FALSE;

	while ( !linkerror && ((pnr=get_parameters(s, "xlink", 2))==2) )
	{
		del_whitespaces(Param[1]);	/* PL9 */

		/* PL6: Wird ein leerer Parameter benutzt, den	*/
		/* den ersten auch als zweiten verwenden.		*/
		if (Param[2][0]==EOS && desttype!=TOHTM && desttype!=TOMHH)
		{	strcpy(Param[2], Param[1]);
		}


		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);
			}

			adjust_params_inside(Param[1]);
		}
		
		if (no_xlinks)
		{	replace_all(s, Param[0], Param[1]);
		}
		else
		{
   			switch(desttype)
   			{
				case TOSTG:
				case TOAMG:
   					convert_tilde(Param[1]);
   					convert_tilde(Param[2]);
   					replace_2at_by_1at(Param[2]);
   					replace_2at_by_1at(Param[1]);
					replace_udo_quotes(Param[2]);	/* r6pl2 */
					replace_udo_quotes(Param[1]);	/* r6pl2 */
   					node2stg(Param[2]);
   					node2stg(Param[1]);
   					sprintf(s_entry, "@{\"%s\" link \"%s\"}", Param[1], Param[2]);
   					
   					linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
   					break;
   				case TOHTM:
				case TOMHH:
   					convert_tilde(Param[1]);
					if (Param[2][0]==EOS)
					{	strcpy(Param[2], Param[1]);
					}
					replace_udo_quotes(Param[2]);	/* r6pl2 */
					replace_udo_quotes(Param[1]);	/* r6pl2 */
					if (html_frames_layout)
					{	sprintf(s_entry, "<a href=\"%s\" target=\"_top\">%s</a>", Param[2], Param[1]);
					}
					else
					{	sprintf(s_entry, "<a href=\"%s\">%s</a>", Param[2], Param[1]);
					}
   					linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
   					break;
   				case TOLDS:
   					convert_tilde(Param[1]);
   					convert_tilde(Param[2]);
					replace_udo_quotes(Param[1]);	/* r6pl2 */
					replace_udo_quotes(Param[2]);	/* r6pl2 */
   					sprintf(s_entry, "<htmlurl url=\"%s\" name=\"%s\">", Param[2], Param[1]);
   					linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
   					break;
   				case TOPCH:
   					convert_tilde(Param[1]);
   					convert_tilde(Param[2]);
					replace_udo_quotes(Param[1]);	/* r6pl2 */
					replace_udo_quotes(Param[2]);	/* r6pl2 */
   					sprintf(s_entry, "\\#%s\\#", Param[1]);
   					linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
   					break;
   				case TOWIN:
				case TOWH4:
   				case TOAQV:
   					/* PL8: Der erste Teil muss auch angepasst werden */
   					convert_tilde(Param[1]);
   					convert_tilde(Param[2]);
					replace_udo_quotes(Param[1]);	/* r6pl2 */
					replace_udo_quotes(Param[2]);	/* r6pl2 */
   					ptr= strchr(Param[2], '@');
   					if (ptr!=NULL)
	   				{	ptr[0]= EOS;
	   					strcpy(wnode, Param[2]);
	   					strcpy(wfile, ptr+1);
	   					if (wnode[0]!=EOS && wfile[0]!=EOS)
	   					{	node2winhelp(wnode);
		   					sprintf(s_entry, "{\\uldb %s}{\\v %s@%s}", Param[1], wnode, wfile);
		   					linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
	   					}
	   					else
	   					{	if (wnode[0]!=EOS)
	   						{	error_xlink_win_topic();
			   					linkerror= !replace_once(s, Param[0], Param[1]);
	   						}
	   						if (wfile[0]!=EOS)
	   						{	error_xlink_win_file();
			   					linkerror= !replace_once(s, Param[0], Param[1]);
	   						}
	   					}
	   				}
	   				else
	   				{	error_xlink_win_syntax();
	   					linkerror= !replace_once(s, Param[0], Param[1]);
	   				}
  					break;

					/* New in r6pl15 [NHz] */
					/* Filelink for Postscript */
					case TOKPS:
   					convert_tilde(Param[1]);
						if (Param[2][0]==EOS)
						{	strcpy(Param[2], Param[1]);
						}
						replace_udo_quotes(Param[2]);	/* r6pl2 */
						replace_udo_quotes(Param[1]);	/* r6pl2 */
						/* Changed in V6.4.1 [NHz] */
						c_divis(Param[1]);
						c_vars(Param[1]);
						auto_quote_chars(Param[1], TRUE);
						sprintf(s_entry, ") udoshow (%s) (%s) %s 255 0 0 FileLink (", Param[1], Param[2], "/Null");
   					linkerror= !insert_placeholder(s, Param[0], s_entry, Param[1]);
						break;

   				default:
   					convert_tilde(Param[1]);
						replace_udo_quotes(Param[1]);	/* r6pl2 */
						replace_udo_quotes(Param[2]);	/* r6pl2 */
						linkerror= !insert_placeholder(s, Param[0], Param[1], Param[1]);
   					break;
   			}	/*switch*/
   		}	/* if (no_xlinks) */

	}	/* while */

	if (linkerror)
	{	replace_once(s, Param[0], Param[1]);
		error_replace_param("!xlink");
	}

	if (pnr!=0 && pnr!=2)
	{	error_wrong_nr_parameters("!xlink");
	}

}	/*c_xlink*/



/*	--------------------------------------------------------------
	c_ilink()
	Umwandeln des (!ilink [] [] []) Kommandos in einer Zeile.
	->	inside_b4_macro:	Sind bereits Makros in dieser Zeile
							umgewandelt worden?
	<->	s:					komplette Zeile
	--------------------------------------------------------------
	Kommandosyntax: (!ilink [filename] [alternativtext] [linkziel])
	--------------------------------------------------------------	*/
LOCAL void c_ilink ( char *s, const BOOLEAN inside_b4_macro )
{
	int pnr=0;
	char s_entry[1024], img_entry[1024], old_entry[1024], link[1024];
	char *ptr;
	BOOLEAN flag;
	BOOLEAN linkerror;
	BOOLEAN	old_autorefoff;

	old_autorefoff= bDocAutorefOff;
	bDocAutorefOff= FALSE;

	linkerror = FALSE;
	while ( !linkerror && ((pnr=get_parameters(s, "ilink", 3))==3) )
	{
		strcpy(link, Param[3]);
		del_whitespaces(Param[1]);
		del_whitespaces(Param[2]);
		del_whitespaces(Param[3]);
		
		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[2], TRUE);	
				auto_quote_chars(Param[3], TRUE);	
			}
		
			adjust_params_inside(Param[1]);
			adjust_params_inside(Param[2]);
			adjust_params_inside(Param[3]);
		}

		fsplit(Param[1], tmp_driv, tmp_path, tmp_name, tmp_suff);

		replace_udo_quotes(Param[2]);
		replace_udo_quotes(Param[3]);

		switch(desttype)
		{
			case TOHTM:
			case TOMHH:
				strcpy(tmp_suff, sDocImgSuffix);
				sprintf(Param[1], "%s%s%s%s", tmp_driv, tmp_path, tmp_name, tmp_suff);
				replace_char(Param[1], "\\", "/");

				strcpy(s_entry, Param[3]);
				c_tilde(s_entry);
				replace_udo_quotes(s_entry);

				convert_tilde(Param[2]);
				convert_tilde(Param[3]);
				replace_udo_quotes(Param[2]);
				replace_udo_quotes(Param[3]);
				strcpy(old_entry, Param[3]);

				auto_references(s_entry, TRUE, "", 0, 0);		/* auch innerhalb des Nodes linken (TRUE)! */

				/* Trick/Hack: Schauen, ob nun "> im Eintrag steht und dann */
				/* ab dort den Image-Eintrag setzen. */

				flag= FALSE;

				if ( (ptr=strstr(s_entry, "\">")) != NULL )
				{	if (no_images)	/* r6pl2 */
					{	strcpy(img_entry, Param[2]);
					}
					else
					{	sprintf(img_entry, "<img src=\"%s\" alt=\"%s\" border=\"0\">",
							Param[1], Param[2]);
					}
					flag= replace_once(ptr, old_entry, img_entry);
				}
				
				if (!flag)
				{	error_undefined_link(link);
					strcpy(s_entry, Param[2]);	/* PL9 */
				}
				
				linkerror= !insert_placeholder(s, Param[0], s_entry, Param[2]);
				break;

			case TOWIN:
			case TOWH4:
			case TOAQV:
				strcpy(tmp_suff, ".bmp");
				sprintf(Param[1], "%s%s%s%s", tmp_driv, tmp_path, tmp_name, tmp_suff);
				replace_char(Param[1], "\\", "/");

				strcpy(s_entry, Param[3]);
				c_tilde(s_entry);
				replace_udo_quotes(s_entry);

				convert_tilde(Param[2]);
				convert_tilde(Param[3]);
				replace_udo_quotes(Param[2]);
				replace_udo_quotes(Param[3]);
				strcpy(old_entry, Param[3]);

				auto_references(s_entry, TRUE, "", 0, 0);		/* auch innerhalb des Nodes linken (TRUE)! */

				/* Trick: Schauen, ob nun {\uldb im Eintrag steht und dann */
				/* ab dort den Image-Text einsetzen. */
				flag= FALSE;
				if ( (ptr=strstr(s_entry, "{\\uldb")) != NULL )
				{	if (no_images)	/*r6pl2*/
					{	strcpy(img_entry, Param[2]);
					}
					else
					{	sprintf(img_entry, "\\{bmc %s\\}", Param[1]);
					}
					flag= replace_once(ptr, old_entry, img_entry);
				}
				
				if (!flag)
				{	error_undefined_link(link);
					strcpy(s_entry, Param[2]);	/* PL9 */
				}
				
				linkerror= !insert_placeholder(s, Param[0], s_entry, Param[2]);
				break;

			case TOLDS:
				linkerror= !convert_link_lds(s, Param[0], Param[2], Param[3], link);
				break;
			case TOSTG:
			case TOAMG:
				linkerror= !convert_link_stg(s, Param[0], Param[2], Param[3], link);
				break;
			case TOTEX:
			case TOPDL:
				linkerror= !convert_link_tex(s, Param[0], Param[2], Param[3]);
				break;
			case TOLYX:
				linkerror= !convert_link_lyx(s, Param[0], Param[2], Param[3]);
				break;
			case TOTVH:
				linkerror= !convert_link_tvh(s, Param[0], Param[2], Param[3]);
				break;
			/* New in V6.4.1 [NHz] */
			case TOKPS:
				linkerror= !convert_link_ps(s, Param[0], Param[2], Param[3], link);
				break;
			default:
				linkerror= !convert_link_etc(s, Param[0], Param[2], Param[3], link);
				break;
		}
	}
	
	if (linkerror)
	{	replace_once(s, Param[0], Param[2]);
		error_replace_param("!ilink");
	}

	if (pnr!=0 && pnr!=3)
	{	error_wrong_nr_parameters("!ilink");
	}

	bDocAutorefOff= old_autorefoff;

}	/*c_ilink*/



LOCAL void c_plink ( char *s, const BOOLEAN inside_b4_macro )
{
	int pnr=0;
	char s_entry[1024];
	BOOLEAN linkerror= FALSE;

	while ( !linkerror && (pnr=get_parameters(s, "plink", 2))==2 )
	{

		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);	
				auto_quote_chars(Param[2], TRUE);	
			}
			adjust_params_inside(Param[1]);
			adjust_params_inside(Param[2]);
		}

		switch (desttype)
		{
			case TOTEX:
			case TOPDL:
				label2tex(Param[2]);
				sprintf(s_entry, "%s (%s %s \\pageref{%s})",
					Param[1], lang.see, lang.page, Param[2]);
				linkerror= !replace_once(s, Param[0], s_entry);
				break;
			case TOLYX:
				sprintf(s_entry,
					"%s (%s %s \n\\begin_inset LatexDel \\pageref{%s}\n\n\\end_inset\n\n)",
					Param[1], lang.see, lang.page, Param[2]);
				if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
				{	linkerror= TRUE;
					replace_once(s, Param[0], s_entry);
				}
				break;
			default:
				linkerror= !replace_once(s, Param[0], Param[1]);
		}
	}

	if (pnr!=0 && pnr!=2)
	{	error_wrong_nr_parameters("!plink");
	}

	if (linkerror)
	{	error_replace_param("!plink");
	}

}	/*c_plink*/


LOCAL void c_nolink ( char *s, const BOOLEAN inside_b4_macro )
{
	int pnr=0;
	char s_entry[1024];
	BOOLEAN linkerror= FALSE;

	while ( !linkerror && (pnr=get_parameters(s, "nolink", 1))==1 )
	{
		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);	
				auto_quote_chars(Param[2], TRUE);	
			}
			adjust_params_inside(Param[1]);
			adjust_params_inside(Param[2]);
		}

		switch (desttype)
		{
			case TOSTG:
			case TOAMG:
				replace_2at_by_1at(Param[1]);
				sprintf(s_entry, "@{\"%s\" ignore}", Param[1]);
				if (!insert_placeholder(s, Param[0], s_entry, Param[1]))
				{	linkerror= TRUE;
					replace_once(s, Param[0], Param[1]);
				}
				break;

			default:
				if (!insert_placeholder(s, Param[0], Param[1], Param[1]))
				{	linkerror= TRUE;
					replace_once(s, Param[0], Param[1]);
				}
				break;
		}
	}

	if (pnr!=0 && pnr!=1)
	{	error_wrong_nr_parameters("!nolink");
	}

	if (linkerror)
	{	error_replace_param("!nolink");
	}

}	/*c_nolink*/



LOCAL void c_comment ( char *s, const BOOLEAN inside_b4_macro )
{
	int pnr=0;
	char s_entry[1024];
	BOOLEAN linkerror= FALSE;

	while ( !linkerror && (pnr=get_parameters(s, "comment", 1))==1 )
	{
		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);	
				auto_quote_chars(Param[2], TRUE);	
			}
			adjust_params_inside(Param[1]);
			adjust_params_inside(Param[2]);
		}

		switch (desttype)
		{
			case TOHTM:
			case TOMHH:
				sprintf(s_entry, "<!-- %s -->", Param[1]);
				if (!insert_placeholder(s, Param[0], s_entry, Param[1]))
				{	linkerror= TRUE;
					replace_once(s, Param[0], Param[1]);
				}
				break;

			case TOSRC:
			case TOSRP:
				sprintf(s_entry, "%s %s %s", sSrcRemOn, Param[1], sSrcRemOff);
				if (!insert_placeholder(s, Param[0], s_entry, Param[1]))
				{	linkerror= TRUE;
					replace_once(s, Param[0], Param[1]);
				}
				break;

			case TOWIN:
			case TOWH4:
			case TORTF:
			case TOAQV:
				sprintf(s_entry, "{\\*\\%s}", Param[1]);
				if (!insert_placeholder(s, Param[0], s_entry, Param[1]))
				{	linkerror= TRUE;
					replace_once(s, Param[0], Param[1]);
				}
				break;

			default:
				if (use_comments)
				{	sprintf(s_entry, "(%s)", Param[1]);
					if (!replace_once(s, Param[0], s_entry))
					{	linkerror= TRUE;
						replace_once(s, Param[0], Param[1]);
					}
				}
				else
				{	if (!delete_once(s, Param[0]))
					{	linkerror= TRUE;
					}
				}
				break;
		}
	}

	if (pnr!=0 && pnr!=1)
	{	error_wrong_nr_parameters("comment");
	}

	if (linkerror)
	{	error_replace_param("comment");
	}

}	/*c_comment*/



LOCAL BOOLEAN c_index ( char *s, const BOOLEAN inside_b4_macro )
{
	char s_tidx[256], s_entry[256], upr_entry[512];
	char keyword[256];
	BOOLEAN ret= TRUE;

	if ( get_parameters(s, "index", 1) )
	{
		strcpy(s_tidx, Param[1]);

		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);	
				auto_quote_chars(s_tidx, TRUE);	
			}
		
			adjust_params_inside(Param[1]);
		}

		/* New in r6pl15 [NHz] */

		/* Set index in project file */

		sprintf(upr_entry, "%s", Param[1]); 

		save_upr_entry_index ( 1, sCurrFileName, upr_entry, uiCurrFileLine );

		if (no_index)
		{	ret= replace_once(s, Param[0], Param[1]);
		}
		else
		{
			bCalledIndex= TRUE;	/* PL9 */
			
			switch (desttype)
			{
				case TOTEX:
				case TOPDL:
					auto_quote_texindex(s_tidx);
					sprintf(s_entry, "\\index{%s}", s_tidx);
					ret= delete_once(s, Param[0]);
					break;
				case TORTF:
					sprintf(s_entry, "{\\xe\\v %s}", Param[1]);
					/* Changed in r6pl15 [NHz] */

					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					/* ret= delete_once(s, Param[0]);*/
					break;
				case TOWIN:
				case TOWH4:
				case TOAQV:
					convert_tilde(Param[1]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					strcpy(keyword, Param[1]);
					winspecials2ascii(keyword);	/* PL9 */
					sprintf(s_entry, "{K{\\footnote K %s}}", keyword);
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOSTG:
				case TOAMG:
					delete_all_divis(Param[1]);
					convert_tilde(Param[1]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					if (iUdopass==PASS2 && bInsideDocument)
					{	index2stg(Param[1]);
						voutlnf("@index \"%s\"", Param[1]);
					}
					ret= delete_once(s, Param[0]);	/*r6pl9: Soll nicht angezeigt werden*/
					break;
				case TOINF:
					if (iUdopass==PASS2 && bInsideDocument)
					{	voutlnf("@cindex %s", Param[1]);
						add_idxlist_item(Param[1], "", "");
					}
					ret= delete_once(s, Param[0]);
					break;
				case TOHPH:
					sprintf(s_entry, "<idx>%s<\\idx>", Param[1]);
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOASC:
					delete_all_divis(Param[1]);
					convert_tilde(Param[1]);
					replace_udo_quotes(Param[1]);
					if (iUdopass==PASS2)
					{	add_idxlist_item(Param[1], "", "");
					}
					ret= delete_once(s, Param[0]);
					break;
				case TOMHH:
					if (iUdopass==PASS2)
					{	output_htmlhelp_index(1, Param[1], "", "");
					}
					ret= delete_once(s, Param[0]);
					break;

				default:
					ret= delete_once(s, Param[0]);
					break;
			}

		}
	}

	if (!ret)
	{	error_replace_param("!index");
		return FALSE;
	}
	
	return TRUE;
}	/*c_index */


/* PL15: Die Nummer des Pass wird geprueft, damit bei Formaten, die die */
/* Indexbefehle direkt ausgeben, nicht am Anfang der Zieldatei die */
/* gesamten Indizes landen. */
/* r6pl2: Stilbefehle und Umlaute werden umgewandelt */

LOCAL BOOLEAN c_single_index ( char *s, const BOOLEAN inside_b4_macro )
{
	char s_tidx[256], s_entry[256], upr_entry[512];
	char keyword[256];
	BOOLEAN ret= TRUE;

	if ( get_parameters(s, "idx", 1) )
	{
		strcpy(s_tidx, Param[1]);

		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);	
				auto_quote_chars(s_tidx, TRUE);	
			}
		
			adjust_params_inside(Param[1]);
		}

		/* New in r6pl15 [NHz] */

		/* Set index in project file */

		sprintf(upr_entry, "%s", Param[1]); 

		save_upr_entry_index ( 1, sCurrFileName, upr_entry, uiCurrFileLine );

		if (no_index)
		{	ret= replace_once(s, Param[0], Param[1]);
		}
		else
		{
			bCalledIndex= TRUE;	/* PL9 */
			
			switch (desttype)
			{
				case TOTEX:
				case TOPDL:
					auto_quote_texindex(s_tidx);
					sprintf(s_entry, "%s\\index{%s}", Param[1], s_tidx);
					ret= replace_once(s, Param[0], s_entry);
					break;
				case TORTF:
					sprintf(s_entry, "{\\xe\\v %s}%s", Param[1], Param[1]);
					ret= replace_once(s, Param[0], s_entry);
					break;
				case TOWIN:
				case TOWH4:
				case TOAQV:
					convert_tilde(Param[1]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					strcpy(keyword, Param[1]);
					winspecials2ascii(keyword);	/* PL9 */
					sprintf(s_entry, "{K{\\footnote K %s}}%s", keyword, Param[1]);
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOSTG:
				case TOAMG:
					delete_all_divis(Param[1]);
					convert_tilde(Param[1]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					if (iUdopass==PASS2 && bInsideDocument)
					{	index2stg(Param[1]);
						voutlnf("@index \"%s\"", Param[1]);
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOINF:
					if (iUdopass==PASS2 && bInsideDocument)
					{	voutlnf("@cindex %s", Param[1]);
						add_idxlist_item(Param[1], "", "");
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOHPH:
					sprintf(s_entry, "<idx>%s<\\idx>%s", Param[1], Param[1]);
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOASC:
					delete_all_divis(Param[1]);
					convert_tilde(Param[1]);
					replace_udo_quotes(Param[1]);
					if (iUdopass==PASS2)
					{	add_idxlist_item(Param[1], "", "");
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOMHH:
					if (iUdopass==PASS2)
					{	output_htmlhelp_index(1, Param[1], "", "");
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				default:
					ret= replace_once(s, Param[0], Param[1]);
					break;
			}

		}
	}

	if (!ret)
	{	error_replace_param("!idx");
		return FALSE;
	}
	
	return TRUE;
}	/*c_single_index */


LOCAL BOOLEAN c_double_index ( char *s, const BOOLEAN inside_b4_macro )
{
	char s_entry[1024], upr_entry[512];
	BOOLEAN ret= TRUE;

	if ( get_parameters(s, "idx", 2) )
	{

		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);	
				auto_quote_chars(Param[2], TRUE);	
			}	
			
			adjust_params_inside(Param[1]);
			adjust_params_inside(Param[2]);
		}

		/* New in r6pl15 [NHz] */

		/* Set index in project file */

		sprintf(upr_entry, "%s:%s", Param[1], Param[2]); 

		save_upr_entry_index ( 2, sCurrFileName, upr_entry, uiCurrFileLine );

		if (no_index)
		{	ret= replace_once(s, Param[0], Param[1]);
		}
		else
		{
			bCalledIndex= TRUE;	/* PL9 */

			switch (desttype)
			{
				case TOTEX:
				case TOPDL:
					auto_quote_texindex(Param[2]);
					sprintf(s_entry, "%s\\index{%s}", Param[1], Param[2]);
					ret= replace_once(s, Param[0], s_entry);
					break;
				case TORTF:	/* PL9 */
					sprintf(s_entry, "{\\xe\\v %s}%s", Param[2], Param[1]);
					ret= replace_once(s, Param[0], s_entry);
					break;
				case TOWIN:
				case TOWH4:
				case TOAQV:
					convert_tilde(Param[1]);
					convert_tilde(Param[2]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					del_internal_styles(Param[2]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					replace_udo_quotes(Param[2]);
					winspecials2ascii(Param[2]);	/* PL9 */
					sprintf(s_entry, "{K{\\footnote K %s}}%s", Param[2], Param[1]);
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOSTG:	/* PL 9 */
				case TOAMG:
					delete_all_divis(Param[1]);
					delete_all_divis(Param[2]);
					convert_tilde(Param[1]);
					convert_tilde(Param[2]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					del_internal_styles(Param[2]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					replace_udo_quotes(Param[2]);
					if (iUdopass==PASS2 && bInsideDocument)
					{	index2stg(Param[2]);
						voutlnf("@index \"%s\"", Param[2]);
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOINF:	/* PL 9 */
					if (iUdopass==PASS2 && bInsideDocument)
					{	voutlnf("@cindex %s", Param[2]);
						add_idxlist_item(Param[2], "", "");
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOHPH:
					sprintf(s_entry, "<idx>%s<\\idx>%s", Param[2], Param[1]);
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOASC:
					delete_all_divis(Param[1]);
					delete_all_divis(Param[2]);
					convert_tilde(Param[1]);
					convert_tilde(Param[2]);
					replace_udo_quotes(Param[1]);
					replace_udo_quotes(Param[2]);
					if (iUdopass==PASS2)
					{	add_idxlist_item(Param[2], "", "");
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOMHH:
					if (iUdopass==PASS2)
					{	output_htmlhelp_index(1, Param[2], "", "");
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				default:
					ret= replace_once(s, Param[0], Param[1]);
					break;
			}
		}
	}

	if (!ret)
	{	error_replace_param("!idx");
		return FALSE;
	}

	return TRUE;
}	/*c_double_index */


LOCAL BOOLEAN c_tripple_index ( char *s, const BOOLEAN inside_b4_macro )
{
	char s_entry[1024], upr_entry[512];
	BOOLEAN ret= TRUE;

	if ( get_parameters(s, "idx", 3) )
	{
		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);	
				auto_quote_chars(Param[2], TRUE);	
				auto_quote_chars(Param[3], TRUE);	
			}
		
			adjust_params_inside(Param[1]);
			adjust_params_inside(Param[2]);
			adjust_params_inside(Param[3]);
		}

		/* New in r6pl15 [NHz] */

		/* Set index in project file */

		sprintf(upr_entry, "%s:%s:%s", Param[1], Param[2], Param[3]); 

		save_upr_entry_index ( 3, sCurrFileName, upr_entry, uiCurrFileLine );

		if (no_index)
		{	ret= replace_once(s, Param[0], Param[1]);
		}
		else
		{
			bCalledIndex= TRUE;	/* PL9 */

			switch (desttype)
			{
				case TOTEX:
				case TOPDL:
					auto_quote_texindex(Param[2]);
					auto_quote_texindex(Param[3]);
					if (use_mirrored_indices)
					{	sprintf(s_entry, "%s\\index{%s!%s}\\index{%s!%s}",
							Param[1], Param[2], Param[3], Param[3], Param[2]);
					}
					else
					{	sprintf(s_entry, "%s\\index{%s!%s}", Param[1], Param[2], Param[3]);
					}
					ret= replace_once(s, Param[0], s_entry);
					break;
				case TORTF:
					if (use_mirrored_indices)
					{	sprintf(s_entry, "{\\xe\\v %s\\:%s}{\\xe\\v %s\\:%s}%s",
							Param[2], Param[3], Param[3], Param[2], Param[1]);
					}
					else
					{	sprintf(s_entry, "{\\xe\\v %s\\:%s}%s", Param[2], Param[3], Param[1]);
					}
					ret= replace_once(s, Param[0], s_entry);
					break;
				case TOWIN:
				case TOWH4:
				case TOAQV:
					convert_tilde(Param[1]);
					convert_tilde(Param[2]);
					convert_tilde(Param[3]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					del_internal_styles(Param[2]);	/*r6pl2*/
					del_internal_styles(Param[3]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					replace_udo_quotes(Param[2]);
					replace_udo_quotes(Param[3]);
					winspecials2ascii(Param[2]);
					winspecials2ascii(Param[3]);
					if (use_mirrored_indices)
					{	sprintf(s_entry, "{K{\\footnote K %s, %s}}{K{\\footnote K %s, %s}}%s",
							Param[2], Param[3], Param[3], Param[2], Param[1]);
					}
					else
					{	sprintf(s_entry, "{K{\\footnote K %s, %s}}%s", Param[2], Param[3], Param[1]);
					}
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOSTG:	/* PL 9 */
				case TOAMG:
					delete_all_divis(Param[1]);
					delete_all_divis(Param[2]);
					delete_all_divis(Param[3]);
					convert_tilde(Param[1]);
					convert_tilde(Param[2]);
					convert_tilde(Param[3]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					del_internal_styles(Param[2]);	/*r6pl2*/
					del_internal_styles(Param[3]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					replace_udo_quotes(Param[2]);
					replace_udo_quotes(Param[3]);
					if (iUdopass==PASS2 && bInsideDocument)
					{	index2stg(Param[2]);
						index2stg(Param[3]);
						voutlnf("@index \"%s, %s\"", Param[2], Param[3]);
						if (use_mirrored_indices)
						{	voutlnf("@index \"%s, %s\"", Param[3], Param[2]);
						}
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOINF:
					if (iUdopass==PASS2 && bInsideDocument)
					{
						voutlnf("@cindex %s, %s", Param[2], Param[3]);
						add_idxlist_item(Param[2], Param[3], "");
						if (use_mirrored_indices)
						{	voutlnf("@cindex %s, %s", Param[3], Param[2]);
							add_idxlist_item(Param[3], Param[2], "");
						}
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOHPH:
					sprintf(s_entry, "<idx>%s, %s<\\idx>%s", Param[2], Param[3], Param[1]);
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOASC:
					delete_all_divis(Param[1]);
					delete_all_divis(Param[2]);
					delete_all_divis(Param[3]);
					convert_tilde(Param[1]);
					convert_tilde(Param[2]);
					convert_tilde(Param[3]);
					replace_udo_quotes(Param[1]);
					replace_udo_quotes(Param[2]);
					replace_udo_quotes(Param[3]);
					if (iUdopass==PASS2)
					{	add_idxlist_item(Param[2], Param[3], "");
						if (use_mirrored_indices)
						{	add_idxlist_item(Param[3], Param[2], "");
						}
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOMHH:
					if (iUdopass==PASS2)
					{	output_htmlhelp_index(2, Param[2], Param[3], "");
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				default:
					ret= replace_once(s, Param[0], Param[1]);
					break;
			}
		}
	}

	if (!ret)
	{	error_replace_param("!idx");
		return FALSE;
	}
	
	return TRUE;

}	/*c_tripple_index */


LOCAL BOOLEAN c_quadruple_index ( char *s, const BOOLEAN inside_b4_macro )
{
	char s_entry[1024], upr_entry[512];
	BOOLEAN ret= TRUE;

	if ( get_parameters(s, "idx", 4) )
	{
		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[1], TRUE);	
				auto_quote_chars(Param[2], TRUE);
				auto_quote_chars(Param[3], TRUE);
				auto_quote_chars(Param[4], TRUE);
			}

			adjust_params_inside(Param[1]);
			adjust_params_inside(Param[2]);
			adjust_params_inside(Param[3]);
			adjust_params_inside(Param[4]);
		}

		/* New in r6pl15 [NHz] */

		/* Set index in project file */

		sprintf(upr_entry, "%s:%s:%s:%s", Param[1], Param[2], Param[3], Param[4]); 

		save_upr_entry_index ( 4, sCurrFileName, upr_entry, uiCurrFileLine );

		if (no_index)
		{	ret= replace_once(s, Param[0], Param[1]);
		}
		else
		{
			bCalledIndex= TRUE;	/* PL9 */

			switch (desttype)
			{
				case TOTEX:
				case TOPDL:
					auto_quote_texindex(Param[2]);
					auto_quote_texindex(Param[3]);
					auto_quote_texindex(Param[4]);
					sprintf(s_entry, "%s\\index{%s!%s!%s}", Param[1], Param[2], Param[3], Param[4]);
					ret= replace_once(s, Param[0], s_entry);
					break;
				case TORTF:	/* PL9 */
					sprintf(s_entry, "{\\xe\\v %s\\:%s\\:%s}%s", Param[2], Param[3], Param[4], Param[1]);
					ret= replace_once(s, Param[0], s_entry);
					break;
				case TOWIN:
				case TOWH4:
				case TOAQV:
					convert_tilde(Param[1]);
					convert_tilde(Param[2]);
					convert_tilde(Param[3]);
					convert_tilde(Param[4]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					del_internal_styles(Param[2]);	/*r6pl2*/
					del_internal_styles(Param[3]);	/*r6pl2*/
					del_internal_styles(Param[4]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					replace_udo_quotes(Param[2]);
					replace_udo_quotes(Param[3]);
					replace_udo_quotes(Param[4]);
					winspecials2ascii(Param[2]);	/* PL9 */
					winspecials2ascii(Param[3]);	/* PL9 */
					winspecials2ascii(Param[4]);	/* PL9 */
					sprintf(s_entry, "{K{\\footnote K %s, %s, %s}}%s", Param[2], Param[3], Param[4], Param[1]);
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOSTG:	/* PL 9 */
				case TOAMG:
					delete_all_divis(Param[1]);
					delete_all_divis(Param[2]);
					delete_all_divis(Param[3]);
					delete_all_divis(Param[4]);
					convert_tilde(Param[1]);
					convert_tilde(Param[2]);
					convert_tilde(Param[3]);
					convert_tilde(Param[4]);
					del_internal_styles(Param[1]);	/*r6pl2*/
					del_internal_styles(Param[2]);	/*r6pl2*/
					del_internal_styles(Param[3]);	/*r6pl2*/
					del_internal_styles(Param[4]);	/*r6pl2*/
					replace_udo_quotes(Param[1]);
					replace_udo_quotes(Param[2]);
					replace_udo_quotes(Param[3]);
					replace_udo_quotes(Param[4]);
					if (iUdopass==PASS2 && bInsideDocument)
					{	index2stg(Param[2]);
						index2stg(Param[3]);
						index2stg(Param[4]);
						voutlnf("@index \"%s, %s, %s\"", Param[2], Param[3], Param[4]);
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOINF:	/* PL 9 */
					if (iUdopass==PASS2 && bInsideDocument)
					{	voutlnf("@cindex %s, %s, %s", Param[2], Param[3], Param[4]);
						add_idxlist_item(Param[2], Param[3], Param[4]);
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOHPH:
					sprintf(s_entry, "<idx>%s, %s, %s<\\idx>%s", Param[2], Param[3], Param[4], Param[1]);
					if ( !insert_placeholder(s, Param[0], s_entry, s_entry) )
					{	ret= FALSE;
						replace_once(s, Param[0], s_entry);
					}
					break;
				case TOASC:
					delete_all_divis(Param[1]);
					delete_all_divis(Param[2]);
					delete_all_divis(Param[3]);
					delete_all_divis(Param[4]);
					convert_tilde(Param[1]);
					convert_tilde(Param[2]);
					convert_tilde(Param[3]);
					convert_tilde(Param[4]);
					replace_udo_quotes(Param[1]);
					replace_udo_quotes(Param[2]);
					replace_udo_quotes(Param[3]);
					replace_udo_quotes(Param[4]);
					if (iUdopass==PASS2)
					{	add_idxlist_item(Param[2], Param[3], Param[4]);
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				case TOMHH:
					if (iUdopass==PASS2)
					{	output_htmlhelp_index(3, Param[2], Param[3], Param[4]);
					}
					ret= replace_once(s, Param[0], Param[1]);
					break;
				default:
					ret= replace_once(s, Param[0], Param[1]);
					break;
			}
		}
	}

	if (!ret)
	{	error_replace_param("!idx");
		return FALSE;
	}
	
	return TRUE;
}	/*c_quadruple_index */


GLOBAL void c_internal_index ( char *s, const BOOLEAN inside_b4_macro )
{
	int nr;
	BOOLEAN flag;
	BOOLEAN has_idx, has_index;

	
	has_idx = (strstr(s, "(!idx")!=NULL);
	has_index = (strstr(s, "(!index")!=NULL);

	if (has_idx)
	{
		do
		{	
			nr=get_nr_of_parameters(CMD_IDX, s);
			
			switch(nr)
			{
				case 0:		flag= FALSE;
							break;
				case 1:		flag= c_single_index(s, inside_b4_macro);
							break;
				case 2: 	flag= c_double_index(s, inside_b4_macro);
							break;
				case 3: 	flag= c_tripple_index(s, inside_b4_macro);
							break;
				case 4: 	flag= c_quadruple_index(s, inside_b4_macro);
							break;
				default:	error_wrong_nr_parameters("!idx");
							flag= FALSE;
							break;
			}

		}	while (flag==TRUE);
	}

	if (has_index)	/* r6pl6: Unterstuetzung fuer (!index [...]) */
	{
		do
		{	
			nr=get_nr_of_parameters("index", s);
			
			switch (nr)
			{
				case 0:		flag= FALSE;
							break;
				case 1:		flag= c_index(s, inside_b4_macro);
							break;
				default:	error_wrong_nr_parameters("!index");
							flag= FALSE;
							break;
			}

		}	while (flag==TRUE);
	}

}	/* c_internal_index */


LOCAL void c_internal_image ( char *s, const BOOLEAN inside_b4_macro )
{
	int pnr=0;
	char s_entry[1024], sGifSize[80], sGifName[512];
	BOOLEAN flag;
	unsigned int uiW, uiH;

	flag = FALSE;
	while ( !flag && ((pnr=get_parameters(s, "img", 2))==2) )
	{
		if (inside_b4_macro)
		{
			if (desttype!=TOSTG)
			{	auto_quote_chars(Param[2], TRUE);	
			}
		
			adjust_params_inside(Param[1]);
			adjust_params_inside(Param[2]);
		}

		fsplit(Param[1], tmp_driv, tmp_path, tmp_name, tmp_suff);
		
		replace_udo_quotes(Param[2]);

		switch(desttype)
		{
			case TOHTM:
			case TOMHH:
				strcpy(tmp_suff, sDocImgSuffix);
				sprintf(Param[1], "%s%s%s%s", tmp_driv, tmp_path, tmp_name, tmp_suff);
				path_adjust_separator(Param[1]);
				uiW= uiH= 0;
				sGifSize[0]= EOS;
				if (!no_img_size)
				{
					if (my_stricmp(tmp_suff, ".gif")==0)
					{
						strcpy(sGifName, Param[1]);
						strinsert(sGifName, old_outfile.path);
						strinsert(sGifName, old_outfile.driv);
						path_adjust_separator(sGifName);

						if (!get_gif_size(sGifName, &uiW, &uiH))
						{	error_read_gif(sGifName);
						}
					}
				}
				if (uiW!=0 && uiH!=0)
				{	sprintf(sGifSize, " width=\"%u\" height=\"%u\"", uiW, uiH);
				}
				replace_char(Param[1], "\\", "/");
				if (no_images)	/*r6pl2*/
				{	strcpy(s_entry, Param[2]);
				}
				else
				{	sprintf(s_entry, "<img src=\"%s\" alt=\"%s\"%s>",
						Param[1], Param[2], sGifSize);
				}
				flag= !insert_placeholder(s, Param[0], s_entry, Param[2]);
				break;
			case TOHPH:
				strcpy(tmp_suff, sDocImgSuffix);
				sprintf(Param[1], "%s%s%s%s", tmp_driv, tmp_path, tmp_name, tmp_suff);
				replace_char(Param[1], "\\", "/");
				if (no_images)	/*r6pl2*/
				{	strcpy(s_entry, Param[2]);
				}
				else
				{	sprintf(s_entry, "<graphic>%s<\\graphic>", Param[1]);
				}
				flag= !insert_placeholder(s, Param[0], s_entry, Param[2]);
				break;
			case TOWIN:
			case TOWH4:
			case TOAQV:
				strcpy(tmp_suff, ".bmp");
				sprintf(Param[1], "%s%s%s%s", tmp_driv, tmp_path, tmp_name, tmp_suff);
				replace_char(Param[1], "\\", "/");
				if (no_images)	/*r6pl2*/
				{	strcpy(s_entry, Param[2]);
				}
				else
				{	sprintf(s_entry, " \\{bmc %s\\}", Param[1]);
				}
				flag= !insert_placeholder(s, Param[0], s_entry, Param[2]);
				break;
			case TOIPF:	/*r6pl8*/
				strcpy(tmp_suff, ".bmp");
				sprintf(Param[1], "%s%s%s%s", tmp_driv, tmp_path, tmp_name, tmp_suff);
				if (no_images)	/*r6pl2*/
				{	strcpy(s_entry, Param[2]);
				}
				else
				{	sprintf(s_entry, "\n:artwork runin name='%s'.\n", Param[1]);
				}
				flag= !insert_placeholder(s, Param[0], s_entry, Param[2]);
				break;
			/* New in r6.3pl3 [NHz] */
			case TORTF:
				strcpy(s_entry, "");
				flag= !insert_placeholder(s, Param[0], s_entry, Param[2]);
				break;
			/* New in V6.4.1 [NHz] */
			case TOKPS:
				strcpy(s_entry, Param[2]);
				c_vars(s_entry);
				replace_all(s_entry, KPSPC_S, ")");
				replace_all(s_entry, KPSPO_S, "(");
				flag= !insert_placeholder(s, Param[0], s_entry, Param[2]);
				break;
			default:
				strcpy(s_entry, Param[2]);
				flag= !insert_placeholder(s, Param[0], s_entry, Param[2]);
				break;
		}
	}
	
	if (flag)
	{	replace_once(s, Param[0], Param[2]);
		error_replace_param("!img");
	}

	if (pnr!=0 && pnr!=2)
	{	error_wrong_nr_parameters("!img");
	}

}	/*c_internal_image*/


#if 0 /* alte Version */
LOCAL void c_internal_raw ( char *s, const BOOLEAN inside_b4_macro )
{
	int pnr;
	BOOLEAN flag;

	UNUSED(inside_b4_macro);
	flag = FALSE;
	while ( !flag && ((pnr=get_parameters(s, "raw", 1))==1) )
	{
		flag= !insert_placeholder(s, Param[0], Param[1], Param[1]);
	}
	
	if (flag)
	{	replace_once(s, Param[0], Param[1]);
		error_replace_param("!raw");
	}

	if (pnr!=0 && pnr!=2)
	{	error_wrong_nr_parameters("!raw");
	}

}
#endif


LOCAL BOOLEAN c_single_raw ( char *s, const BOOLEAN inside_b4_macro )
{
	BOOLEAN flag;

	UNUSED(inside_b4_macro);
	if ( get_parameters(s, "raw", 1) )
	{
		flag= insert_placeholder(s, Param[0], Param[1], Param[1]);

		if (!flag)
		{	replace_once(s, Param[0], Param[1]);
			error_replace_param("!raw");
			return FALSE;
		}

	}

	return TRUE;

}	/* c_single_raw */


LOCAL BOOLEAN c_double_raw ( char *s, const BOOLEAN inside_b4_macro )
{
	BOOLEAN flag;

	UNUSED(inside_b4_macro);
	if ( get_parameters(s, "raw", 2) )
	{
		if (str_for_desttype(Param[1]))
		{
			flag= insert_placeholder(s, Param[0], Param[2], Param[2]);

			if (!flag)
			{	delete_once(s, Param[0]);
				error_replace_param("!raw");
				return FALSE;
			}
		}
		else
		{
			delete_once(s, Param[0]);
		}
	}

	return TRUE;

}	/* c_double_raw */


LOCAL void c_internal_raw ( char *s, const BOOLEAN inside_b4_macro )
{
	int nr;
	BOOLEAN flag;
	BOOLEAN has_raw;
	
	has_raw = (strstr(s, "(!raw")!=NULL);

	if (has_raw)
	{
		do
		{	
			nr=get_nr_of_parameters("raw", s);
			
			switch(nr)
			{
				case 0:		flag= FALSE;
							break;
				case 1:		flag= c_single_raw(s, inside_b4_macro);
							break;
				case 2: 	flag= c_double_raw(s, inside_b4_macro);
							break;
				default:	error_wrong_nr_parameters("!raw");
							flag= FALSE;
							break;
			}

		}	while (flag);
	}

}	/* c_internal_raw */


GLOBAL void c_commands_inside ( char *s, const BOOLEAN inside_b4_macro )
{
	if ( strstr(s, "(!")==NULL )
	{	/* Optimierung */
		return;
	}
	
	c_link(s, inside_b4_macro);
	c_url(s, inside_b4_macro);
	c_xlink(s, inside_b4_macro);
	c_ilink(s, inside_b4_macro);
	c_plink(s, inside_b4_macro);
	c_nolink(s, inside_b4_macro);
	c_comment(s, inside_b4_macro);
	c_internal_index(s, inside_b4_macro);
	c_internal_image(s, inside_b4_macro);
	c_internal_raw(s, inside_b4_macro);

}	/* c_commands_inside */



/*	################################################################
	#
	# Silbentrennregeln hinzufuegen und im Text ersetzen
	#
	################################################################	*/
GLOBAL void replace_hyphens ( char *s )
{
	UINT h;
	
	if (hyphen_counter<=0)	return;

	for (h=0; h<hyphen_counter; h++)
	{
		if (hyphen[h]!=NULL)
		{
			replace_all(s, hyphen[h]->solo, hyphen[h]->hyphen);
		}
	}
}	/* replace_hyphens */


GLOBAL void add_hyphen ( void )
{
	HYPHEN *p;
	
	switch(desttype)
	{
		case TOWIN:
		case TOWH4:
		case TOAQV:
		case TORTF:
		case TOHTM:
		case TOMHH:
			return;	/* Hier werden keine Trennregeln benoetigt */
	}
	
	if (hyphen_counter>=MAXHYPHEN)
	{	error_too_many_hyphens();
		return;
	}
	
	if (token_counter<=1)
	{	error_missing_parameter("!hyphen");
		return;
	}
	
	p= (HYPHEN *) um_malloc(sizeof(HYPHEN));
	
	if (p==NULL)
	{	error_malloc_failed();
		return;
	}

	tokcpy2(p->hyphen, HYPHEN_LEN+1);
	tokcpy2(p->solo, HYPHEN_LEN+1);

	if (desttype==TOTEX || desttype==TOPDL)
	{	/* Die Tokens sind leider vorher schon durch c_vars gelaufen */
		/* Dabei wurden auch (!ck) usw. bereits in "ck umgewandelt */
		/* Problem: replace_hyphens() findet Dru"cker dann nicht */
		qdelete_all(p->solo, "\\-", 2);
	}
	else
	{	delete_all_divis(p->solo);
	}

	hyphen[hyphen_counter]= p;
	
	hyphen_counter++;

}	/* add_hyphen */



/*	############################################################
	# Testen, ob Makro/Definition Parameter benutzt
	############################################################	*/
LOCAL BOOLEAN md_uses_parameters ( const char *s )
{
	if (strstr(s, "(!0)")!=NULL)	return TRUE;	/* r6pl2 */
	if (strstr(s, "(!1)")!=NULL)	return TRUE;
	if (strstr(s, "(!2)")!=NULL)	return TRUE;
	if (strstr(s, "(!3)")!=NULL)	return TRUE;
	if (strstr(s, "(!4)")!=NULL)	return TRUE;
	if (strstr(s, "(!5)")!=NULL)	return TRUE;
	if (strstr(s, "(!6)")!=NULL)	return TRUE;
	if (strstr(s, "(!7)")!=NULL)	return TRUE;
	if (strstr(s, "(!8)")!=NULL)	return TRUE;
	if (strstr(s, "(!9)")!=NULL)	return TRUE;

	return FALSE;
}

/*	############################################################
	#
	# Ein Makro hinzufuegen
	#
	############################################################	*/
GLOBAL void replace_macros ( char *s )
{
	UINT i;

	if (strstr(s, "(!")==NULL)
	{	return;
	}
	
	for (i=0; i<macro_counter; i++)
	{	if (macros[i]!=NULL)
		{
			if (macros[i]->vars)
			{	replace_variables(s, macros[i]->name, macros[i]->entry);
			}
			else
			{	replace_all(s, macros[i]->name, macros[i]->entry);
			}
		}
	}

}	/*replace_macros*/


GLOBAL BOOLEAN add_macro ( void )
{
	int i;
	MACROS *p;
	char entry[512];

	/* Die Daten stehen in token[] */
	
	if (macro_counter>=MAXMACROS)
	{	error_too_many_macros();
		return FALSE;
	}

	/* Nur !macro in der Zeile? */	
	if (token_counter<=1)
	{	error_missing_parameter(CMD_MACRO);
		return FALSE;
	}

	/* PL10: Makro-Name zu lang? */	
	if (strlen(token[1])>MACRO_NAME_LEN)
	{	error_long_macro_name(MACRO_NAME_LEN);
		return FALSE;
	}

	p= (MACROS *) um_malloc(sizeof(MACROS));
	
	if (p==NULL)
	{	error_malloc_failed();
		return FALSE;
	}

	entry[0]= EOS;

	if (token_counter>=2)
	{	for (i=2; i<token_counter; i++)
		{	um_strcat(entry, token[i], 512, "add_macro[1]");
			if (i<token_counter-1)
			{	um_strcat(entry, " ", 512, "add_macro[2]");
			}
		}
	}

	auto_quote_chars(entry, FALSE);
	replace_macros(entry);
	replace_defines(entry);
	c_divis(entry);
	c_vars(entry);


	/* PL10: Inhalt zu lang? */
	if (strlen(entry)>MACRO_CONT_LEN)
	{	error_long_macro_cont(MACRO_CONT_LEN);
		um_free(p);
		return FALSE;
	}

	um_strcpy(p->entry, entry, MACRO_CONT_LEN+1, "add_macro[3]");

	if ( md_uses_parameters(p->entry) )	/* PL8 */
	{	/* Makro mit Parametern */
		um_strcpy(p->name, token[1], MACRO_NAME_LEN+1, "add_macro[4]");
		p->vars= TRUE;
	}
	else
	{	/* normales Makros */
		sprintf(p->name, "(!%s)", token[1]);
		token[1][0]= EOS;
		p->vars= FALSE;
	}
	
	macros[macro_counter]= p;
	macro_counter++;

	return TRUE;	
}	/* add_macro */



/*	############################################################
	#
	# Eine Definition hinzufuegen
	#
	############################################################	*/
GLOBAL void replace_defines ( char *s )
{
	UINT	i;

	if (strstr(s, "(!")==NULL)
	{	return;
	}
	
	for (i=0; i<define_counter; i++)
	{	if (defs[i]!=NULL)
		{	if (defs[i]->vars)
			{	replace_variables(s, defs[i]->name, defs[i]->entry);
			}
			else
			{	replace_all(s, defs[i]->name, defs[i]->entry);
			}
		}
	}
	
}	/*replace_defines*/


GLOBAL BOOLEAN add_define ( void )
{
	int i;
	DEFS *p;
	char entry[512];

	/* Die Daten stehen in token[] */
	
	if (define_counter>=MAXDEFS)
	{	error_too_many_defines();
		return FALSE;
	}

	/* Nur !define in der Zeile? */	
	if (token_counter<=1)
	{	error_missing_parameter(CMD_DEFINE);
		return FALSE;
	}

	/* PL10: Definitions-Name zu lang? */	
	if (strlen(token[1])>DEFINE_NAME_LEN)
	{	error_long_define_name(DEFINE_NAME_LEN);
		return FALSE;
	}


	p= (DEFS *) um_malloc(sizeof(DEFS));
	
	if (p==NULL)
	{	error_malloc_failed();
		return FALSE;
	}

	entry[0]= EOS;

	if (token_counter>=2)
	{	for (i=2; i<token_counter; i++)
		{	um_strcat(entry, token[i], 512, "add_define[1]");
			if (i<token_counter-1)
			{	um_strcat(entry, " ", 512, "add_define[2]");
			}
		}
	}
	
	/* PL10: Inhalt zu lang? */
	if (strlen(entry)>DEFINE_CONT_LEN)
	{	error_long_define_cont(DEFINE_CONT_LEN);
		um_free(p);
		return FALSE;
	}
	
	um_strcpy(p->entry, entry, MACRO_CONT_LEN+1, "add_define[3]");

	/* Schauen, ob der !define Parameter enthalten soll */

	if ( md_uses_parameters(p->entry) )	/* PL12 */
	{	/* Definition mit Parametern */
		um_strcpy(p->name, token[1], MACRO_NAME_LEN+1, "add_define[4]");
		p->vars= TRUE;
	}
	else
	{	/* normale Definition */
		sprintf(p->name, "(!%s)", token[1]);
		token[1][0]= EOS;
		p->vars= FALSE;
	}
	
	defs[define_counter]= p;
	define_counter++;

	return TRUE;	
}	/* add_define */




/*	############################################################
	#
	# Modulinit
	#
	############################################################	*/
GLOBAL void init_module_par ( void )
{
	int i;
	
	/* Dafuer sorgen, dass alle geleert werden */
	phold_counter= -1;
	for (i=0; i<MAXPHOLDS; i++)
	{	phold[i].magic[0]= EOS;
		phold[i].entry= NULL;
		phold[i].text= NULL;
	}

	hyphen_counter= 0;
	for (i=0; i<MAXHYPHEN; hyphen[i++]= NULL) ;

	macro_counter= 0;
	for (i=0; i<MAXMACROS; macros[i++]= NULL) ;

	define_counter= 0;
	for (i=0; i<MAXDEFS; defs[i++]= NULL) ;

}	/* init_module_par */


GLOBAL void exit_module_par ( void )
{
	/*
        r6.3.19[vj]: Der folgende Code wurde auskommentiert, um zu überprüfen,
        ob sich hieraus ein Geschwindigkeitsvorteil erlangen läßt. Wird der
        Speicher hier nicht freigegeben, wird das später um_exit tun,
        das die Speicherbereiche viel effizienter freigeben kann.
        Bitte nicht löschen, da er später vielleicht wieder rein kommt!

        int	i;

	for (i=MAXMACROS-1; i>=0; i--)
	{	if (macros[i]!=NULL)
		{	um_free(macros[i]);
		}
	}

	for (i=MAXDEFS-1; i>=0; i--)
	{	if (defs[i]!=NULL)
		{	um_free(defs[i]);
		}
	}

	for (i=MAXHYPHEN-1; i>=0; i--)
	{	if (hyphen[i]!=NULL)
		{	um_free(hyphen[i]);
		}
	}*/

	reset_placeholders();

}	/* exit_module_par */


/*	############################################################
	# par.c
	############################################################	*/
