/*=============================================================================
   GNU UnRTF, a command-line program to convert RTF documents to other formats.
   Copyright (C) 2000,2001,2004 by Zachary Smith

   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 3 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

   The maintainer is reachable by electronic mail at daved@physiol.usyd.edu.au
=============================================================================*/


/*----------------------------------------------------------------------
 * Module name:    attr
 * Author name:    Zachary Smith
 * Create date:    01 Aug 01
 * Purpose:        Character attribute stack.
 *----------------------------------------------------------------------
 * Changes:
 * 01 Aug 01, tuorfa@yahoo.com: moved code over from convert.c
 * 06 Aug 01, tuorfa@yahoo.com: added several font attributes.
 * 18 Sep 01, tuorfa@yahoo.com: added AttrStack (stack of stacks) paradigm
 * 22 Sep 01, tuorfa@yahoo.com: added comment blocks
 * 29 Mar 05, daved@physiol.usyd.edu.au: changes requested by ZT Smith
 * 16 Dec 07, daved@physiol.usyd.edu.au: fixed fore/background_begin error
 *                       and updated to GPL v3
 * 09 Nov 08, arkadiusz.firus@gmail.com: adopt safe_printf
 * 07 Oct 11, jf@dockes.org, fix to add_to_collection()
 * 09 Jun 13, peterli@salk.edu, added code to cope with bold/italic
 			requests that are not properly nested
 * 27 Jun 13, peterli@salk.edu, improved efficiency of the unnested code
 * 09 Dec 14, nicosr@free.frl, fix to return in attr_get_param for clang
 *--------------------------------------------------------------------*/

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif

#ifdef HAVE_STRING_H
#include <string.h>
#endif

#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif

#ifndef HAVE_ATDARG_H
#include <stdarg.h>
#endif

#include <stddef.h>

#include "malloc.h"
#include "defs.h"
#include "error.h"
#include "attr.h"
#include "main.h"

extern void starting_body();
extern void starting_text();

extern int simulate_allcaps;
extern int simulate_smallcaps;


#define MAX_ATTRS 100


/* For each RTF text block (the text within braces) we must keep
 * an AttrStack which is a stack of attributes and their optional
 * parameter. Since RTF text blocks are nested, these make up a
 * stack of stacks. And, since RTF text blocks inherit attributes
 * from parent blocks, all new AttrStacks do the same from
 * their parent AttrStack.
 */
typedef struct _stack
{
	unsigned char attr_stack[MAX_ATTRS];
	char *attr_stack_params[MAX_ATTRS];
	int tos;
	struct _stack *prev;
} AttrStack;

/*@null@*/ static AttrStack *stack_of_stacks = NULL;
/*@null@*/ static AttrStack *stack_of_stacks_top = NULL;

static void attr_express_begin(int attr, char *param);
static void attr_express_end(int attr, char *param);


/* Iterate from top of given stack looking for findattr */
static int attr_find(AttrStack *stack, int findattr)
{
	int i;
	for (i = stack->tos; i >= 0; i--)
		if (stack->attr_stack[i] == findattr)
		{
			return i;
		}
	return -1;
}

/* Iterate all stacks looking for most recent value for attr */
static int attrstack_find_attr(int findattr, char **paramp)
{
	AttrStack *stack = stack_of_stacks_top;

	while (stack)
	{
		int index = attr_find(stack, findattr);
		if (index >= 0) 
		{
			*paramp = stack->attr_stack_params[index];
			return TRUE;
		}
		stack = stack->prev;
	}
	return FALSE;
}

/* Remove attribute at the given index, unexpressing and reexpressing
   the ones above in appropriate order. */
static void attr_pull_out(AttrStack *stack, int index)
{
	int j;
	/* Unexpress all newer attributes, and the one we'll remove */
	for (j = stack->tos; j >= index; j--)
	{
		attr_express_end(stack->attr_stack[j], stack->attr_stack_params[j]);
	}

	/* Delete target attribute and shift the stack down */
	if (stack->attr_stack_params[index]) 
		my_free(stack->attr_stack_params[index]);
	for (j = index; j < stack->tos; j++) 
	{
		stack->attr_stack[j] = stack->attr_stack[j + 1];
		stack->attr_stack_params[j] = stack->attr_stack_params[j + 1];
	}
	stack->tos--;

	/* Re-express unexpressed attributes */
	for (j = index; j <= stack->tos; j++) 
	{
		attr_express_begin(stack->attr_stack[j], stack->attr_stack_params[j]);
	}
	return;
}

/* Unexpress and remove top attr. Internal version, no checking of args */
static void attr_pop_internal(AttrStack *stack, int attr)
{
	if (stack->tos >= 0)
	{
		char *param = stack->attr_stack_params[stack->tos];

		attr_express_end(attr, param);

		if (param)
		{
			my_free(param);
		}

		stack->tos--;
	}
}


/*========================================================================
 * Name:	attr_express_begin
 * Purpose:	Print the HTML for beginning an attribute.
 * Args:	Attribute number, optional string parameter.
 * Returns:	None.
 *=======================================================================*/

static void attr_express_begin(int attr, char *param)
{
	switch (attr)
	{
	case ATTR_BOLD:
		if (safe_printf(0, op->bold_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "bold_begin");
		};
		break;
	case ATTR_ITALIC:
		if (safe_printf(0, op->italic_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "italic_begin");
		};
		break;

	/* Various underlines, they all resolve to HTML's <u> */
	case ATTR_THICK_UL:
	case ATTR_WAVE_UL:
	case ATTR_DASH_UL:
	case ATTR_DOT_UL:
	case ATTR_DOT_DASH_UL:
	case ATTR_2DOT_DASH_UL:
	case ATTR_WORD_UL:
	case ATTR_UNDERLINE:
		if (safe_printf(0, op->underline_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "underline_begin");
		};
		break;

	case ATTR_DOUBLE_UL:
		if (safe_printf(0, op->dbl_underline_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "dbl_underline_begin");
		};
		break;

	case ATTR_FONTSIZE:
		op_begin_std_fontsize(op, atoi(param));
		break;

	case ATTR_FONTFACE:
		if (safe_printf(1, op->font_begin, param))
		{
			fprintf(stderr, TOO_MANY_ARGS, "font_begin");
		};
		break;

	case ATTR_FOREGROUND:
		if (safe_printf(1, op->foreground_begin, param))
		{
			fprintf(stderr, TOO_MANY_ARGS, "foreground_begin");
		};
		break;

	case ATTR_BACKGROUND:
		if (!simple_mode)
			if (safe_printf(1, op->background_begin, param))
			{
				fprintf(stderr, TOO_MANY_ARGS, "background_begin");
			};
		break;

	case ATTR_SUPER:
		if (safe_printf(0, op->superscript_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "superscript_begin");
		};
		break;
	case ATTR_SUB:
		if (safe_printf(0, op->subscript_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "subscript_begin");
		};
		break;

	case ATTR_STRIKE:
		if (safe_printf(0, op->strikethru_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "strikethru_begin");
		};
		break;

	case ATTR_DBL_STRIKE:
		if (safe_printf(0, op->dbl_strikethru_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "dbl_strikethru_begin");
		};
		break;

	case ATTR_EXPAND:
		if (safe_printf(1, op->expand_begin, param))
		{
			fprintf(stderr, TOO_MANY_ARGS, "expand_begin");
		};
		break;

	case ATTR_OUTLINE:
		if (safe_printf(0, op->outline_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "outline_begin");
		};
		break;
	case ATTR_SHADOW:
		if (safe_printf(0, op->shadow_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "shadow_begin");
		};
		break;
	case ATTR_EMBOSS:
		if (safe_printf(0, op->emboss_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "emboss_begin");
		};
		break;
	case ATTR_ENGRAVE:
		if (safe_printf(0, op->engrave_begin))
		{
			fprintf(stderr, TOO_MANY_ARGS, "engrave_begin");
		};
		break;

	case ATTR_CAPS:
		if (op->simulate_all_caps)
		{
			simulate_allcaps = TRUE;
		}
		else
		{
			if (op->all_caps_begin)
				if (safe_printf(0, op->all_caps_begin))
				{
					fprintf(stderr, TOO_MANY_ARGS, "all_caps_begin");
				}
		}
		break;

	case ATTR_SMALLCAPS:
		if (op->simulate_small_caps)
		{
			simulate_smallcaps = TRUE;
		}
		else
		{
			if (op->small_caps_begin)
				if (safe_printf(0, op->small_caps_begin))
				{
					fprintf(stderr, TOO_MANY_ARGS, "small_caps_begin");
				};
		}
		break;
	}
}


/*========================================================================
 * Name:	attr_express_end
 * Purpose:	Print HTML to complete an attribute.
 * Args:	Attribute number.
 * Returns:	None.
 *=======================================================================*/

static void attr_express_end(int attr, char *param)
{
	switch (attr)
	{
	case ATTR_BOLD:
		if (safe_printf(0, op->bold_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "bold_end");
		};
		break;
	case ATTR_ITALIC:
		if (safe_printf(0, op->italic_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "italic_end");
		};
		break;

	/* Various underlines, they all resolve to HTML's </u> */
	case ATTR_THICK_UL:
	case ATTR_WAVE_UL:
	case ATTR_DASH_UL:
	case ATTR_DOT_UL:
	case ATTR_DOT_DASH_UL:
	case ATTR_2DOT_DASH_UL:
	case ATTR_WORD_UL:
	case ATTR_UNDERLINE:
		if (safe_printf(0, op->underline_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "underline_end");
		};
		break;

	case ATTR_DOUBLE_UL:
		if (safe_printf(0, op->dbl_underline_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "dbl_underline_end");
		};
		break;

	case ATTR_FONTSIZE:
		op_end_std_fontsize(op, atoi(param));
		break;

	case ATTR_FONTFACE:
		if (safe_printf(0, op->font_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "font_end");
		};
		break;

	case ATTR_FOREGROUND:
		if (safe_printf(0, op->foreground_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "foreground_end");
		};
		break;
	case ATTR_BACKGROUND:
		if (!simple_mode)
			if (safe_printf(0, op->background_end))
			{
				fprintf(stderr, TOO_MANY_ARGS, "background_end");
			};
		break;

	case ATTR_SUPER:
		if (safe_printf(0, op->superscript_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "superscript_end");
		};
		break;
	case ATTR_SUB:
		if (safe_printf(0, op->subscript_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "subscript_end");
		};
		break;

	case ATTR_STRIKE:
		if (safe_printf(0, op->strikethru_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "strikethru_end");
		};
		break;

	case ATTR_DBL_STRIKE:
		if (safe_printf(0, op->dbl_strikethru_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "dbl_strikethru_end");
		};
		break;

	case ATTR_OUTLINE:
		if (safe_printf(0, op->outline_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "outline_end");
		};
		break;
	case ATTR_SHADOW:
		if (safe_printf(0, op->shadow_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "shadow_end");
		};
		break;
	case ATTR_EMBOSS:
		if (safe_printf(0, op->emboss_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "emboss_end");
		};
		break;
	case ATTR_ENGRAVE:
		if (safe_printf(0, op->engrave_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "engrave_end");
		};
		break;

	case ATTR_EXPAND:
		if (safe_printf(0, op->expand_end))
		{
			fprintf(stderr, TOO_MANY_ARGS, "expand_end");
		};
		break;

	case ATTR_CAPS:
		if (op->simulate_all_caps)
		{
			simulate_allcaps = FALSE;
		}
		else
		{
			if (op->all_caps_end)
				if (safe_printf(0, op->all_caps_end))
				{
					fprintf(stderr, TOO_MANY_ARGS, "all_caps_end");
				};
		}
		break;

	case ATTR_SMALLCAPS:
		if (op->simulate_small_caps)
		{
			simulate_smallcaps = FALSE;
		}
		else
		{
			if (op->small_caps_end)
				if (safe_printf(0, op->small_caps_end))
				{
					fprintf(stderr, TOO_MANY_ARGS, "small_caps_end");
				};
		}
		break;
	}
}



/*========================================================================
 * Name:	attr_push
 * Purpose:	Pushes an attribute onto the current attribute stack.
 * Args:	Attribute number, optional string parameter.
 * Returns:	None.
 *=======================================================================*/

void attr_push(int attr, char *param)
{
	AttrStack *stack = stack_of_stacks_top;
	int i;
	char *oldparam;

	/*fprintf(stderr, "attr_push: [%d] [%s]\n", attr, param);*/

	if (!stack)
	{
		warning_handler("No stack to push attribute onto");
		return;
	}

	/* Remove any current value of the same attr in the top stack */
	if ((i = attr_find(stack, attr)) != -1) 
	{
		attr_pull_out(stack, i);
	}

	if (stack->tos >= MAX_ATTRS - 1)
	{
		fprintf(stderr, "Too many attributes!\n");
		return;
	}

	/* Make sure it's understood we're in the <body> section. */
	/* KLUDGE */
	starting_body();
	starting_text();

	++stack->tos;
	stack->attr_stack[stack->tos] = attr;
	if (param)
	{
		stack->attr_stack_params[stack->tos] = my_strdup(param);
	}
	else
	{
		stack->attr_stack_params[stack->tos] = NULL;
	}

	attr_express_begin(attr, param);
}

/* Unexpress and remove an attribute which is not the top one */
int attr_find_pop(int findattr)
{
	int i;
	AttrStack *stack = stack_of_stacks_top;

	if (!stack)
	{
		warning_handler("no stack to pop attributes from");
		return FALSE;
	}

	/* Check whether findattr is on stack at all; if not, just give up */
	if ((i = attr_find(stack, findattr)) < 0)
	{
		return FALSE;
	}
	attr_pull_out(stack, i);
	return TRUE;
}

/*========================================================================
 * Name:	attr_get_param
 * Purpose:	Reads an attribute from the current attribute stack.
 * Args:	Attribute number
 * Returns:	string.
 *=======================================================================*/

char *
attr_get_param(int attr)
{
	int i;
	AttrStack *stack = stack_of_stacks_top;
	if (!stack)
	{
		if (attr != ATTR_ENCODING)
		{
			/*
			 * attr_get_param(ATTR_ENCODING) is always called
			 * called once without a stack being available.
			 */
			warning_handler("No stack to get attribute from");
		}
		return NULL;
	}

	if ((i = attr_find(stack, attr)) >= 0) {
		return stack->attr_stack_params[i];
	}
	return NULL;
}


/*========================================================================
 * Name:	attrstack_copy_all
 * Purpose:	Routine to copy all attributes from one stack to another.
 * Args:	Two stacks.
 * Returns:	None.
 *=======================================================================*/

void
attrstack_copy_all(AttrStack *src, AttrStack *dest)
{
	int i;

	CHECK_PARAM_NOT_NULL(src);
	CHECK_PARAM_NOT_NULL(dest);

	for (i = 0; i <= src->tos; i++)
	{
		dest->attr_stack[i] = src->attr_stack[i];

		char *param = src->attr_stack_params[i];
		if (param)
		{
			dest->attr_stack_params[i] = my_strdup(param);
		}
		else
		{
			dest->attr_stack_params[i] = NULL;
		}
	}

	dest->tos = src->tos;
}

/*========================================================================
 * Name:	attrstack_unexpress_all
 * Purpose:	Routine to un-express all attributes heretofore applied,
 * 		without removing any from the stack.
 * Args:	Stack whose contents should be unexpressed.
 * Returns:	None.
 * Notes:	This is needed by attrstack_push, but also for \cell, which
 * 		often occurs within a brace group, yet HTML uses <td></td>
 *		which clear attribute info within that block.
 *=======================================================================*/

void
attrstack_unexpress_all(AttrStack *stack)
{
	int i;

	CHECK_PARAM_NOT_NULL(stack);

	for (i = stack->tos; i >= 0; i--)
	{
		attr_express_end(stack->attr_stack[i], stack->attr_stack_params[i]);
	}
}


/*========================================================================
 * Name:	attrstack_push
 * Purpose:	Creates a new attribute stack, pushes it onto the stack
 *		of stacks, performs inheritance from previous stack.
 * Args:	None.
 * Returns:	None.
 *=======================================================================*/
void
attrstack_push()
{
	AttrStack *new_stack;

	new_stack = (AttrStack *) my_malloc(sizeof(AttrStack));

	if (new_stack == NULL) 
	{
		warning_handler("out of memory");
		return;
	}

	memset((void *) new_stack, 0, sizeof(AttrStack));

	if (!stack_of_stacks)
	{
		stack_of_stacks = new_stack;
		new_stack->tos = -1;
	} 
	else
	{
		/* Parent stack exists. Copy all attributes. This means that they
		   will be unexpressed when we exit this group, which is why there 
		 is a call to re-express the parent context in attrstack_drop */
		attrstack_copy_all(stack_of_stacks_top, new_stack);
	}
		
	/* stack_of_stacks_top is NULL if this is the first stack */
	new_stack->prev = stack_of_stacks_top;
	stack_of_stacks_top = new_stack;
}

/*========================================================================
 * Name:	attr_pop
 * Purpose:	Removes and undoes the effect of the top attribute of
 *		the current AttrStack.
 * Args:	The top attribute's number, for verification.
 * Returns:	Success/fail flag.
 *=======================================================================*/

int
attr_pop(int attr)
{
	AttrStack *stack = stack_of_stacks_top;

	if (!stack)
	{
		warning_handler("no stack to pop attribute from");
		return FALSE;
	}

	if (stack->tos >= 0 && stack->attr_stack[stack->tos] == attr)
	{
		attr_pop_internal(stack, attr);
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}



/*========================================================================
 * Name:	attr_read
 * Purpose:	Reads but leaves in place the top attribute of the top
 * 		attribute stack.
 * Args:	None.
 * Returns:	Attribute number.
 *=======================================================================*/

int
attr_read()
{
	AttrStack *stack = stack_of_stacks_top;
	if (!stack)
	{
		warning_handler("no stack to read attribute from");
		return FALSE;
	}

	if (stack->tos >= 0)
	{
		int attr = stack->attr_stack [stack->tos];
		return attr;
	}
	else
	{
		return ATTR_NONE;
	}
}


/*========================================================================
 * Name:	attr_drop_all
 * Purpose:	Empty top attr stack without unexpressing attributes.
 * Args:	None.
 * Returns:	None.
 *=======================================================================*/

void
attr_drop_all()
{
	AttrStack *stack = stack_of_stacks_top;
	if (!stack)
	{
		warning_handler("no stack to drop all attributes from");
		return;
	}

	while (stack->tos >= 0)
	{
		char *param = stack->attr_stack_params [stack->tos];
		if (param)
		{
			my_free(param);
		}
		stack->tos--;
	}
}


/*========================================================================
 * Name:	attrstack_drop
 * Purpose:	Removes the top AttrStack from the stack of stacks, undoing
 *		all attributes that it had in it.
 * Args:	None.
 * Returns:	None.
 *=======================================================================*/

void
attrstack_drop()
{
	AttrStack *stack = stack_of_stacks_top;
	if (!stack)
	{
		warning_handler("no attr-stack to drop");
		return;
	}

	attr_pop_all();

	if (stack->prev == NULL)
	{
		stack_of_stacks = NULL;
	}
	stack_of_stacks_top = stack->prev;

	my_free((void *) stack);

	/* Re-set attributes for parent state */
	if (stack_of_stacks_top)
	{
		attrstack_express_all(/*stack_of_stacks_top*/);
	}
}

/*========================================================================
 * Name:	attr_pop_all
 * Purpose:	Routine to undo all attributes heretofore applied,
 *		also reversing the order in which they were applied.
 * Args:	None.
 * Returns:	None.
 *=======================================================================*/

void
attr_pop_all()
{
	AttrStack *stack = stack_of_stacks_top;
	if (!stack)
	{
		warning_handler("no stack to pop from");
		return;
	}

	while (stack->tos >= 0)
	{
		attr_pop_internal(stack, stack->attr_stack[stack->tos]);
	}
}

/*========================================================================
 * Name:	attrstack_express_all
 * Purpose:	Routine to re-express all attributes heretofore applied.
 * Args:	None.
 * Returns:	None.
 * Notes:	This is needed by attrstack_push, but also for \cell, which
 * 		often occurs within a brace group, yet HTML uses <td></td>
 *		which clear attribute info within that block.
 *=======================================================================*/

void
attrstack_express_all()
{
	AttrStack *stack = stack_of_stacks_top;
	int i;

	if (!stack)
	{
		warning_handler("no stack to pop from");
		return;
	}

	for (i = 0; i <= stack->tos; i++)
	{
		attr_express_begin(stack->attr_stack[i], stack->attr_stack_params[i]);
	}
}

/*========================================================================
 * Name:	safe_printf
 * Purpose:	Prevents format string attack and writes empty string
		instead of NULL.
 * Args:	Number of parameters (without a string), string to write,
		additional parameters to print (have to be strings).
 * Returns:	Returns 0 if number of not escaped '%' in string
		 is not greater than nr, else returns -1
 *=======================================================================*/


int
safe_printf(int nr, char *string, ...)
{

	char *s;
	int i = 0, ret_code = 0;
	va_list arguments;

	if (string == NULL)
		;
	else
	{
		va_start(arguments, string);

		for (; nr > 0; nr--)
		{
			while (string[i] != '\0' && (string[i] != '%' || (string[i] == '%' && (i != 0 && string[i - 1] == '\\'))))
			{
				if (string[i] != '\\' || string[i + 1] != '%')
				{
					printf("%c", string[i]);
				}
				i++;
			}

			if (string[i] != '\0')
			{
				s = va_arg(arguments, char *);
				printf("%s", s);
				i++;
			}
		}
		va_end(arguments);

		while (string[i] != '\0')
		{
			if (string[i] != '\\' || (string[i] == '\\' && string[i + 1] != '%'))
			{
				if (string[i] != '%' || (string[i] == '%' && (i != 0 && string[i - 1] == '\\')))
				{
					printf("%c", string[i]);
				}
				else
				{
					ret_code = -1;
				}
			}
			i++;
		}
	}

	return ret_code;
}

/*========================================================================
 * Name:	assemble_string
 * Purpose:	See Returns
 * Args:	String to return and int to put into first parameter.
 * Returns:	Returns first parameter where first not escaped
		character % is substituted with second parameter.
 *=======================================================================*/

char *
assemble_string(char *string, int nr)
{

	char *s, tmp[12];/* Number of characters that can be in int type (including '\0') - AF */
	int i = 0, j = 0;

	if (string == NULL)
	{
		return NULL;
	}
	else
	{
		s = my_malloc(strlen(string) + 1 + 12/* Number of characters that can be in int type (including '\0') - AF */);
		while (string[i] != '\0' && (string[i] != '%' || (string[i] == '%' && (i != 0 && string[i - 1] == '\\'))))
		{
			if (string[i] != '\\' || string[i + 1] != '%')
			{
				s[j] = string[i];
				j++;
			}
			i++;
		}

		if (string[i] != '\0')
		{
			sprintf(tmp, "%d", nr);
			strcpy(&s[j], tmp);
			j = j + strlen(tmp);
		}

		while (string[i] != '\0')
		{
			if (string[i] != '\\' || (string[i] == '\\' && string[i + 1] != '%'))
			{
				if (string[i] != '%' || (string[i] == '%' && (i != 0 && string[i - 1] == '\\')))
				{
					s[j] = string[i];
					j++;
				}
				else
				{
					/* More than one char % occured */
				}
			}
			i++;
		}
	}

	s[j] = '\0';

	return s;
}


/*========================================================================
 * Name:	add_to_collection
 * Purpose:	Adds (substitutes) element under index nr.
 * Args:	Collection, index, text to add.
 * Returns:	Collection.
 *=======================================================================*/

Collection *
add_to_collection(Collection *col, int nr, const char *text)
{
	Collection *c = col;

	if (col == NULL)
	{
		col = (Collection *)my_malloc(sizeof(Collection));
		col->nr = nr;
		col->text = text;
		col->next = NULL;
	}
	else
	{
		do
		{
			if (c->nr == nr)
			{
				/* Here is a memory leak but not heavy. Do we need to care about this?
								my_free(a->alias.text);
				*/
				c->text = text;

				return col;
			}

			if (c->next == NULL)
			{
				break;
			}
			c = c->next;
		}
		while (1);

		c->next = (Collection *)my_malloc(sizeof(Collection));
		c->next->nr = nr;
		c->next->text = text;
		c->next->next = NULL;
	}

	return col;
}

/*========================================================================
 * Name:	get_from_collection
 * Purpose:	Search for element under index nr.
 * Args:	Collection, index.
 * Returns:	NULL or found elemet.
 *=======================================================================*/

const char *
get_from_collection(Collection *c, int nr)
{
	while (c != NULL)
	{
		if (c->nr == nr)
		{
			return c->text;
		}

		c = c->next;
	}

	return NULL;
}

/*========================================================================
 * Name:	free_collection
 * Purpose:	Release memory used by collection.
 * Args:	Needless collection.
 * Returns:
 *=======================================================================*/

void
free_collection(Collection *c)
{
	Collection *c2;

	while (c != NULL)
	{
		c2 = c->next;
		my_free((void *)c);
		c = c2;
	}
}
