/*****************************************************************************/
/* parser.cpp - 21/07/99 - By Christophe LOREK - CRYO-NETWORKS               */
/*                                                                           */
/* This is the parser code for the libHTML designed for SCOL.                */
/*                                                                           */
/* last modified on 13/08/99 By Christophe LOREK                             */
/*****************************************************************************/

#ifdef HTML_INCLUDE

#include "parser.h"

//TagStruct **fatherlist;																			// stack of father pointer


int freeParamList(Param **paramlist)
{
	int i = 0;

	while (paramlist[i] != NULL)
	{
		free(paramlist[i]->name);
		free(paramlist[i]->value);
		free(paramlist[i]);
		i++;
	}
	free(paramlist);
	return 0;
}

/*
 * SkipBlank :
 *	In						:	string		(char *)	pointer to the beginning of the string in the inbuf.
 *	Out						:	SkipBlank	(char *)	pointer to the first non blank character in the stringin the inbuf.
 *	Side Effects	:	none.
 */
char *SkipBlank(char *string)
{
	char *currentpos;
	currentpos = string;

	while (*currentpos == ' '  ||															// eating preceding spaces, tabs, and returns
				 *currentpos == '\t' ||
				 *currentpos == '\r' ||
				 *currentpos == '\n')
		currentpos++;
	return currentpos;
}

/*
 * FindTagName :
 *	In						:	tagstring		(char *)	pointer to the beginning of the name in the inbuf.
 *	Out						:	FindTagName	(char *)	pointer to the beginning of the name in the inbuf.
 *									namelen			(int	*)	pointer to the length of the name.
 *	Side Effects	:	none.
 */
char *FindTagName(char *tagstring, int *namelen)
{
	char *currentpos;

	currentpos = tagstring;
    *namelen = 0;
	while (*currentpos != '\0' &&
				 *currentpos != ' '  &&
				 *currentpos != '\t' &&
				 *currentpos != '\r' &&
				 *currentpos != '\n')
	{
		currentpos++;
		(*namelen)++;
	}
	if (*namelen == 0) return NULL;
	else return tagstring;
}

/*
 * GetParam :
 *	In						:	paramstring			(char *)	pointer to the beginning of the string in the inbuf.
 *	Out						:	paramname				(char **)	pointer to a variable, which will contain the pointer
 *																						to the allocated memory for the name string.
 *									paramvalue			(char	**)	pointer to a variable, which will contain the pointer
 *																						to the allocated memory for the value string.
 *									nextparamstring	(char	**)	pointer to a variable, which will contain the pointer
 *																						to the next string in the inbuf.
 *									GetParam				(int)			status (0 == successful;0 != error).
 *	Side Effects	:	none.
 */
int GetParam(char *paramstring,char **paramname,char **paramvalue, char **nextparamstring)
{
	char	*currentpos;
	char	*currentparamname;
	char	*currentparamvalue;
	char	*opendoublequotes;
	char	*closedoublequotes;
	char	*equalpos;
	int		namelen=0;
	int		valuelen=0;

	currentpos = SkipBlank(paramstring);

	currentparamname = currentpos;														// counting number of characters in the param name
	while (*currentpos != '\0'	&&
				 *currentpos != ' '		&&
				 *currentpos != '\t'	&&
				 *currentpos != '='		&&
				 *currentpos != '>'		&&
				 *currentpos != '\r'	&&
				 *currentpos != '\n')
	{
		currentpos++;
		namelen++;
	}
	if (namelen == 0) return 1;
	equalpos = strchr(currentpos,'=');	
	if (equalpos == NULL) return 1;
	currentpos=SkipBlank(equalpos+1);
	if ((*currentpos)=='"')
	{
		opendoublequotes = strchr(currentpos,'"');		
		if (opendoublequotes == NULL) return 1;
		closedoublequotes = strchr(opendoublequotes+1,'"');	
		if (closedoublequotes == NULL) return 1;
		currentparamvalue = opendoublequotes+1;
		valuelen = closedoublequotes - opendoublequotes - 1;
	}
	else
	{
		currentparamvalue = currentpos;
		while (*currentpos != '\0' &&
					 *currentpos != ' '  &&
					 *currentpos != '>'  &&
					 *currentpos != '\t' &&
					 *currentpos != '\r' &&
					 *currentpos != '\n')
		{
			currentpos++;
			valuelen++;
		}
	}
	(*paramname) = (char*) malloc ((namelen+1)*sizeof(char));
	if ((*paramname) == NULL)
	{
		MMechostr(MSKDEBUG,"libHTML : GetParam, could not allocate memory for paramname...\n");
		return 1;
	}
	memcpy((*paramname),currentparamname,namelen*sizeof(char));
	(*paramname)[namelen]='\0';

	(*paramvalue) = (char*) malloc ((valuelen+1)*sizeof(char));
	if ((*paramvalue) == NULL)
	{
		MMechostr(MSKDEBUG,"libHTML : GetParam, could not allocate memory for paramvalue...\n");
		return 1;
	}
	memcpy((*paramvalue),currentparamvalue,valuelen*sizeof(char));
	(*paramvalue)[valuelen]='\0';
	(*nextparamstring) = currentparamvalue + valuelen + 1;
	return 0;
}

/*
 * FindParam :
 *	In						:	paramstring	(char *)		pointer to the beginning of the string in the inbuf.
 *	Out						:	FindParam		(Param **)	pointer to a variable, which will contain the pointer
 *																					to the allocated memory for the paramlist.
 *	Side Effects	:	none.
 */
Param **FindParam(char *paramstring)
{
	char	*paramname;
	char	*nextparamstring;
	char	*paramvalue;
	Param	*currentparam;
	int		nbparam=1;
	Param	**paramlist;

	paramlist = NULL;
	paramlist = (Param**) malloc(nbparam*sizeof(Param*));
	if (paramlist == NULL)
	{
		MMechostr(MSKDEBUG,"libHTML : FindParam, could not allocate memory for paramlist...\n");
		return NULL;
	}
	nextparamstring = paramstring;

	while (!GetParam(nextparamstring,&paramname,&paramvalue,&nextparamstring))
	{
		nbparam++;
		paramlist = (Param**) realloc(paramlist,nbparam*sizeof(Param*));
		if (paramlist == NULL)
		{
			MMechostr(MSKDEBUG,"libHTML : FindParam, could not reallocate memory for paramlist...\n");
			return NULL;
		}
		currentparam = (Param*) malloc (sizeof(Param));
		if (currentparam == NULL)
		{
			MMechostr(MSKDEBUG,"libHTML : FindParam, could not allocate memory for currentparam...\n");
			return NULL;
		}
		paramlist[nbparam-2]=currentparam;
		currentparam->name = paramname;
		currentparam->value = paramvalue;
	}
		paramlist[nbparam-1]=NULL;																	//terminates the list with a NULL pointer
		return paramlist;

}

/*
 * GetTag :
 *	In						:	currentpos	(char *)			pointer to the beginning of the string in the inbuf.
 *	Out						:	GetTag			(TagStruct *)	pointer to a variable, which will contain the pointer
 *																						to the allocated memory for the current processed tag.
 *	Side Effects	:	none.
 */
TagStruct *GetTag(char *currentpos)
{
	char		*openbracket;
	char		*openbracket2;
	char		*closebracket;
	char		*tagstring;
	char		*tagname;
	int			tagnamelen;
	TagStruct	*followingtag;

	TagStruct *currenttag;

	currenttag = (TagStruct*) malloc(sizeof(TagStruct));

	if (currenttag == NULL)
	{
		MMechostr(MSKDEBUG,"libHTML : GetTag, could not allocate memory for currenttag...\n");
		return NULL;
	}

	openbracket = strchr(currentpos,'<');
    if (openbracket==NULL)
		{
			free(currenttag);
			return NULL;
		}
	closebracket = strchr(currentpos,'>');
    if (closebracket==NULL)
		{
			free(currenttag);
			return NULL;
		}

	openbracket2 = strchr(openbracket+1,'<');
    if (openbracket2==NULL) openbracket2=closebracket;					// if no more '<', the following test will be false.
    if (openbracket2<closebracket) return GetTag(openbracket2);	// skip '<' in text		
	if (openbracket>closebracket) return GetTag(openbracket);			// skip '>' in text

	tagstring = (char*) malloc((closebracket-openbracket)*sizeof(char));
	if (tagstring == NULL)
	{
		MMechostr(MSKDEBUG,"libHTML : GetTag, could not allocate memory for tagstring...\n");
		free(currenttag);
		return NULL;
	}
	memcpy(tagstring,openbracket+1,(closebracket-openbracket-1)*sizeof(char));
	tagstring[closebracket-openbracket-1]='\0';
	tagname = FindTagName(tagstring,&tagnamelen);
	currenttag->name = (char*) malloc((tagnamelen+1)*sizeof(char));
	if (currenttag->name == NULL)
	{
		MMechostr(MSKDEBUG,"libHTML : GetTag, could not allocate memory for currenttag->name...\n");
		free(tagstring);
		free(currenttag);
		return NULL;
	}
	memcpy(currenttag->name,tagname,tagnamelen*sizeof(char));
	currenttag->name[tagnamelen]='\0';

	currenttag->paramlist = FindParam(tagname+tagnamelen+1);	

	currenttag->begin = openbracket;
	currenttag->end = closebracket+1;

//	MMechostr(MSKFOO,"DEBUG : %x %x\n",currenttag->begin,currenttag->end);

	followingtag = GetTag(currenttag->end);

	currenttag->nexttag = followingtag;

	free(tagstring);
	return currenttag;
}

/*
 * InitFatherList :
 *	In						:	none.
 *	Out						:	InitFatherList	(int)	status (0 == successful).
 *	Side Effects	:	allocates memory for the stack of fathers (global var fatherlist).
 */
/*
int InitFatherList()
{
	fatherlist = (TagStruct**) malloc(sizeof(TagStruct*));
	fatherlist[0] = NULL;
	return 0;
}
*/

/*
 * FreeFatherList :
 *	In						:	none.
 *	Out						:	FreeFatherList	(int)	status (0 == successful).
 *	Side Effects	:	free the memory allocated for the stack of fathers (global var fatherlist).
 */
/*
int FreeFatherList()
{
	free(fatherlist);
	return 0;
}
*/

/*
 * PopFather :
 *	In						:	father		(TagStruct *)	pointer to add on the top of the fathers' stack.
 *	Out						:	PopFather	(int)	status (0 == successful).
 *	Side Effects	:	reallocates the memory for the fathers' stack.
 */
/*
int PopFather(TagStruct *father)
{
	int			nbfather = 0;
	TagStruct	**newfatherlist;
	
	while (fatherlist[nbfather++] != NULL);
	newfatherlist = (TagStruct**) malloc((nbfather+1)*sizeof(TagStruct*));
	memcpy(newfatherlist+1,fatherlist,nbfather*sizeof(TagStruct*));
	newfatherlist[0] = father;

	free(fatherlist);
	fatherlist = newfatherlist;

	return 0;
}
*/

/*
 * PullFather :
 *	In						:	none.
 *	Out						:	PullFather	(TagStruct *)	the top most father pointer of the stack.
 *	Side Effects	:	reallocates the memory for the fathers' stack.
 */
/*
TagStruct *PullFather()
{
	int			nbfather = 0;
	TagStruct	**newfatherlist;
	TagStruct	*father;

	if (fatherlist[0] == NULL) return NULL;

	while (fatherlist[nbfather++] != NULL);
	newfatherlist = (TagStruct**) malloc((nbfather-1)*sizeof(TagStruct*));
	memcpy(newfatherlist,fatherlist+1,(nbfather-1)*sizeof(TagStruct*));
	father = fatherlist[0];

	free(fatherlist);
	fatherlist = newfatherlist;

	return father;

}
*/

TagStruct	*FindEndTag(TagStruct	*currenttag)
{
	char			*slashpos;
	TagStruct	*testedtag;

	testedtag = currenttag->nexttag;

	while (testedtag != NULL)
	{
		if (	((slashpos = strchr(testedtag->name,'/')) != NULL) &&
					(!stricmp(SkipBlank(slashpos+1),currenttag->name))	)
			return testedtag;

		testedtag = testedtag->nexttag;
	}
	return NULL;
}
/*
int IsCascadingTag(char *name)
{
	return ((!stricmp("li",name))	||
					(!stricmp("p",name))	||
					(!stricmp("dd",name))	||
					(!stricmp("dt",name))	||
					(!stricmp("td",name))	||
					(!stricmp("th",name))	||
					(!stricmp("tr",name)) );
}
*/

int IsSelfTerminatingTag(char *name)
{
	return ((!stricmp("img",name))	||
					(!stricmp("br",name))		||
					(!stricmp("hr",name))		||
					(!stricmp("meta",name))	||
					(!stricmp("frame",name))||
					(!stricmp("!--",name))	||
					(!stricmp("!doctype",name)) );
}

int IsEndingTag(char *name)
{
	return ((strchr(name,'/')) != NULL);
}


/*
 * NewSortTag :
 *	In						:	currenttag	(TagStruct *)	the current tag to sort.
 *	Out						:	NewSortTag			(TagStruct *)	the tag pointer to be passed to the caller.
 *	Side Effects	:	uses the fathers' stack.
 */
/*
TagStruct *NewSortTag(TagStruct *currenttag)
{

	TagStruct *currentendtag;
	TagStruct *myreturn;

	if (currenttag == NULL)
		return NULL;

	currenttag->sontag = NULL;
	currenttag->brothertag = NULL;
	currenttag->endtag = NULL;

	myreturn = NewSortTag(currenttag->nexttag);

	if ((strchr(currenttag->name,'/')) != NULL) // an ending tag
	{
		if (currenttag->nexttag == NULL)
			return NULL;
		else
		{
			if ((strchr(currenttag->nexttag->name,'/')) != NULL) // an ending tag			
				return myreturn;
			else
				return currenttag->nexttag;
		}
	}
	if (IsSelfTerminatingTag(currenttag->name))
	{
		currenttag->brothertag = currenttag->nexttag;
		return myreturn;
	}
	else
	{
		currentendtag = FindEndTag(currenttag);
		if (currentendtag != NULL)
		{
			currenttag->endtag = currentendtag;
			currenttag->sontag = currenttag->nexttag;
			currenttag->brothertag = myreturn;
			MMechostr(MSKFOO,"DEBUG '%08x' '%s' s'%08x' b'%08x' e'%08x'\n",currenttag,currenttag->name,currenttag->sontag,currenttag->brothertag,currenttag->endtag);
			if ((currentendtag->nexttag != NULL) && ((strchr(currentendtag->nexttag->name,'/')) == NULL))
				return currentendtag->nexttag;
			return NULL;
		}
		else
		{
			currenttag->brothertag = currenttag->nexttag;
			MMechostr(MSKFOO,"DEBUG '%08x' '%s' s'%08x' b'%08x' e'%08x'\n",currenttag,currenttag->name,currenttag->sontag,currenttag->brothertag,currenttag->endtag);
			if ((currentendtag->nexttag != NULL) && ((strchr(currentendtag->nexttag->name,'/')) == NULL))
				return currentendtag->nexttag;
			return NULL;
		}
	}
}
*/

/*
 * SortTag :
 *	In						:	currenttag	(TagStruct *)	the current tag to sort.
 *	Out						:	SortTag			(TagStruct *)	the tag pointer to be passed to the caller.
 *	Side Effects	:	uses the fathers' stack.
 */
TagStruct *SortTag(TagStruct *currentfathertag, TagStruct *currenttag)
{
	TagStruct	*myreturn;
//	TagStruct	*father;
	char		*slashpos;

	if (currenttag == NULL) return NULL;
	{
		currenttag->sontag = NULL;
		currenttag->brothertag = NULL;
		currenttag->fathertag = NULL;
		currenttag->endtag = NULL;

	// ********* case of non container tags
		if ( (!stricmp("pre",currenttag->name))	)
		{
			while ( (currenttag->nexttag != NULL))
			{
				if ((slashpos = strchr(currenttag->nexttag->name,'/')) != NULL)
					if (!stricmp(SkipBlank(slashpos+1),"pre"))
					{
						currenttag->brothertag = currenttag->nexttag;
						currenttag->fathertag = currentfathertag;
						myreturn = SortTag(currentfathertag,currenttag->nexttag);
						return myreturn;
					}
				myreturn = currenttag->nexttag->nexttag;									// skip next tag, go to the tag after.
				if (currenttag->nexttag->name != NULL)
					free(currenttag->nexttag->name);
				if (currenttag->nexttag->paramlist != NULL)
					freeParamList(currenttag->nexttag->paramlist);
				free(currenttag->nexttag);																// free next tag and affiliated.
				currenttag->nexttag = myreturn;														// set the tag after as being the next tag.
			}
			currenttag->fathertag = currentfathertag;
			myreturn = SortTag(currentfathertag,currenttag->nexttag);
			currenttag->brothertag = currenttag->nexttag->brothertag; //A
		}


// ********* case of self terminating tags
		else if (IsSelfTerminatingTag(currenttag->name))
		{
			if(currenttag->nexttag == NULL)															// if no more tags, interrupts recursive call.
				return NULL;

			if ((slashpos = strchr(currenttag->nexttag->name,'/')) == NULL) // not followed by an ending tag
				currenttag->brothertag = currenttag->nexttag;

			currenttag->fathertag = currentfathertag;
			SortTag(currentfathertag,currenttag->nexttag);
			myreturn = currenttag;
		}

// ********* case of ending tags.
		else if ((slashpos = strchr(currenttag->name,'/')) != NULL)
		{
			if(currenttag->nexttag != NULL)
			{
				currenttag->fathertag = currentfathertag;
				if (currentfathertag != NULL)
					myreturn = SortTag(currentfathertag->fathertag,currenttag->nexttag);	
				else
					myreturn = SortTag(NULL,currenttag->nexttag);	

				if ((strchr(currenttag->nexttag->name,'/')) == NULL) // father can have brother
				{
					if(currentfathertag != NULL)
					{
//	MMechostr(MSKFOO,"DEBUG : currenttag '%s' father '%s' brothers\n",currenttag->name,currentfathertag->name);
						currentfathertag->brothertag = myreturn;// brothertag is first non ending following tag
						currentfathertag->endtag = currenttag;								// closing father with current endtag
					}
				}
				else // ending tag followed by another ending tag, the father can't have brother
				{
					if(currentfathertag != NULL)
					{
//		MMechostr(MSKFOO,"DEBUG : currenttag '%s' father '%s' NO brothers\n",currenttag->name,currentfathertag->name);
						currentfathertag->brothertag = NULL; 									// brothertag is NULL
						currentfathertag->endtag = currenttag;								// closing father with current endtag
					}
				}
			}
			else
			{
				currenttag->fathertag = currentfathertag;
				if(currentfathertag != NULL)
				{
//	MMechostr(MSKFOO,"DEBUG : currenttag '%s' father '%s' NO brothers NO NEXTTAG\n",currenttag->name,currentfathertag->name);
					currentfathertag->brothertag = NULL; 									// brothertag is first non ending following tag
					currentfathertag->endtag = currenttag;								// closing father with current endtag
				}
				myreturn = NULL;
			}
			return myreturn;	// interrupts recursive call because it's the last tag.
		}


// ********* case of classic tags
		else
		{
			if(currenttag->nexttag == NULL)															// if no more tags, interrupts recursive call.
				return NULL;
		
			if ((slashpos = strchr(currenttag->nexttag->name,'/')) != NULL) // followed by an ending tag
			{
				currenttag->endtag = currenttag->nexttag;
			}
			else																												//classic tag followed by classic tag or self terminating tag
			{
				currenttag->sontag = currenttag->nexttag;									// brother and endtag will be updated when father is pulled.
			}
			currenttag->fathertag = currentfathertag;
			SortTag(currenttag,currenttag->nexttag);
			myreturn = currenttag;
		}
	}
	return myreturn;
}

/*
int RemoveTagFromList(TagStruct *previoustag,TagStruct *currenttag)
{
	if (currenttag == NULL)
		return 0;

	previoustag->nexttag = currenttag->nexttag;
	FreeTag(currenttag);
	return 0;

}

int InsertTagInList(TagStruct *previoustag,TagStruct *currenttag)
{
	TagStruct *tagnext;

	MMechostr(MSKFOO,"InsertingTag '%s' after '%s'\n",currenttag->name,previoustag->name);

	if (currenttag == NULL)
		return 0;

	tagnext = previoustag->nexttag;
	currenttag->nexttag = tagnext;
	previoustag->nexttag = currenttag;
	return 0;

}

TagStruct *DuplicateTag(TagStruct *currenttag, char *givenname)
{
	TagStruct *newtag;
	int				namelength;
	char			*name;

	if (currenttag == NULL)
		return NULL;
	
	MMechostr(MSKFOO,"DuplicatingTag '%s' to create '%s'\n",currenttag->name,givenname);

	newtag = (TagStruct*) malloc(sizeof(TagStruct));

	if (newtag == NULL)
	{
		MMechostr(MSKFOO,"libHTML : DuplicateTag, could not allocate memory for newtag...\n");
		return NULL;
	}

	namelength = strlen(givenname);
	name = (char*) malloc ((namelength + 1)*sizeof(char));
	if (name == NULL)
	{
		MMechostr(MSKFOO,"libHTML : DuplicateTag, could not allocate memory for name...\n");
		free(newtag);
		return NULL;
	}
	memcpy(name,givenname,namelength);
	name[namelength] = '\0';

	newtag->name = name;

	newtag->paramlist = NULL;
	newtag->paramlist = (Param**) malloc(1*sizeof(Param*));
	newtag->paramlist[0]=NULL;			

	newtag->begin = currenttag->begin;
	newtag->end = currenttag->end;

	return newtag;
}

TagStruct *ListTagGrammarCorrection(TagStruct *previoustag,TagStruct *currenttag,TagStruct **returnedtag)
{
	TagStruct *presumedendingtag;
	TagStruct *insertedendingtag;
	TagStruct	*presumedendingprevioustag;
	char			*endtagname;
	int				namelength;
	char			*slashpos;

	if (currenttag == NULL)
		return NULL;

	if (IsSelfTerminatingTag(currenttag->name))
	{
		MMechostr(MSKFOO,"GrammarCorrection : SelfTerminatingTag '%s'\n",currenttag->name);
		return ListTagGrammarCorrection(currenttag,currenttag->nexttag,returnedtag);	
	}
	else if (IsEndingTag(currenttag->name))
	{
		MMechostr(MSKFOO,"GrammarCorrection : EndingTag '%s'\n",currenttag->name);
		*returnedtag = previoustag;
		return currenttag;
	}
	else if (IsCascadingTag(currenttag->name))
	{
		MMechostr(MSKFOO,"GrammarCorrection : CascadingTag '%s'\n",currenttag->name);
		if (currenttag->nexttag == NULL)
		{
			namelength = strlen(currenttag->name);
			endtagname = (char*) malloc((namelength+2)*sizeof(char));
			endtagname[0] = '/';
			memcpy(endtagname+1,currenttag->name,namelength);
			endtagname[namelength+1] = '\0';
			currenttag->nexttag = DuplicateTag(currenttag,endtagname);
			free(endtagname);
			*returnedtag = NULL;
			return NULL;
		}
		if ((slashpos = strchr(currenttag->nexttag->name,'/')) != NULL)
		{
			if (!stricmp(SkipBlank(slashpos+1),currenttag->name))
			{
				*returnedtag = currenttag->nexttag;
				return currenttag->nexttag->nexttag;
			}
			else
			{
				namelength = strlen(currenttag->name);
				endtagname = (char*) malloc((namelength+2)*sizeof(char));
				endtagname[0] = '/';
				memcpy(endtagname+1,currenttag->name,namelength);
				endtagname[namelength+1] = '\0';
				insertedendingtag = DuplicateTag(currenttag,endtagname);
				InsertTagInList(currenttag,insertedendingtag);
				free(endtagname);
				*returnedtag = insertedendingtag;
				return insertedendingtag->nexttag;
			}
		}
		else if (IsCascadingTag(currenttag->nexttag->name))
		{
			if (!stricmp(currenttag->nexttag->name,currenttag->name))
			{
				namelength = strlen(currenttag->name);
				endtagname = (char*) malloc((namelength+2)*sizeof(char));
				endtagname[0] = '/';
				memcpy(endtagname+1,currenttag->name,namelength);
				endtagname[namelength+1] = '\0';
				insertedendingtag = DuplicateTag(currenttag,endtagname);
				InsertTagInList(currenttag,insertedendingtag);
				free(endtagname);
				*returnedtag = insertedendingtag;
				return insertedendingtag->nexttag;
			}
			else // plus de test necessaire (par exemple <LI> suivi de </UL>)
			{
				namelength = strlen(currenttag->name);
				endtagname = (char*) malloc((namelength+2)*sizeof(char));
				endtagname[0] = '/';
				memcpy(endtagname+1,currenttag->name,namelength);
				endtagname[namelength+1] = '\0';
				insertedendingtag = DuplicateTag(currenttag,endtagname);
				InsertTagInList(currenttag,insertedendingtag);
				free(endtagname);
				*returnedtag = insertedendingtag;
				return insertedendingtag->nexttag;
			}
		}
		else
		{ // ICI CA VA MERDER .....
			presumedendingtag = ListTagGrammarCorrection(currenttag,currenttag->nexttag,&presumedendingprevioustag);
			if (presumedendingtag == NULL)
			{
	MMechostr(MSKFOO,"GROS PROBLEME DANS LE CORRECTEUR : (presumedendingtag == NULL)\n");
				return NULL;
			}
			else
			{
				if ((slashpos = strchr(presumedendingtag->name,'/')) != NULL)
				{
					if (!stricmp(SkipBlank(slashpos+1),currenttag->name))
					{
						*returnedtag = presumedendingtag;
						return presumedendingtag->nexttag;
					}
					else
					{
						namelength = strlen(currenttag->name);
						endtagname = (char*) malloc((namelength+2)*sizeof(char));
						endtagname[0] = '/';
						memcpy(endtagname+1,currenttag->name,namelength);
						endtagname[namelength+1] = '\0';
						insertedendingtag = DuplicateTag(presumedendingtag,endtagname);
						InsertTagInList(presumedendingprevioustag,insertedendingtag);
						free(endtagname);
						*returnedtag = insertedendingtag;
						return insertedendingtag->nexttag;
					}
				}
				else
				{
					namelength = strlen(currenttag->name);
					endtagname = (char*) malloc((namelength+2)*sizeof(char));
					endtagname[0] = '/';
					memcpy(endtagname+1,currenttag->name,namelength);
					endtagname[namelength+1] = '\0';
					insertedendingtag = DuplicateTag(presumedendingtag,endtagname);
					InsertTagInList(presumedendingprevioustag,insertedendingtag);
					free(endtagname);
					*returnedtag = insertedendingtag;
					return insertedendingtag->nexttag;
				}
			}
		}
	}
	else // classic tag
	{
		MMechostr(MSKFOO,"GrammarCorrection : ClassicTag '%s'\n",currenttag->name);
		if (currenttag->nexttag == NULL)
		{
			namelength = strlen(currenttag->name);
			endtagname = (char*) malloc((namelength+2)*sizeof(char));
			endtagname[0] = '/';
			memcpy(endtagname+1,currenttag->name,namelength);
			endtagname[namelength+1] = '\0';
			currenttag->nexttag = DuplicateTag(currenttag,endtagname);
			free(endtagname);
			*returnedtag = NULL;
			return NULL;
		}
		if ((slashpos = strchr(currenttag->nexttag->name,'/')) != NULL)
		{
			if (!stricmp(SkipBlank(slashpos+1),currenttag->name))
			{
				*returnedtag = currenttag->nexttag;
				return currenttag->nexttag->nexttag;
			}
			else
			{
				namelength = strlen(currenttag->name);
				endtagname = (char*) malloc((namelength+2)*sizeof(char));
				endtagname[0] = '/';
				memcpy(endtagname+1,currenttag->name,namelength);
				endtagname[namelength+1] = '\0';
				insertedendingtag = DuplicateTag(currenttag,endtagname);
				InsertTagInList(currenttag,insertedendingtag);
				free(endtagname);
				*returnedtag = insertedendingtag;
				return insertedendingtag->nexttag;
			}
		}
		else
		{ // ICI CA VA MERDER CAR IL FAUT VERIFIER PAR RAPPORT A LA GRAMMAIRE SI LE TAG SUIVANT PEUT ETRE FILS OU NON
			presumedendingtag = ListTagGrammarCorrection(currenttag,currenttag->nexttag,&presumedendingprevioustag);
		MMechostr(MSKFOO,"GrammarCorrection : '%08x' '%08x'\n",presumedendingprevioustag,presumedendingtag);

			if (presumedendingtag == NULL)
			{
	MMechostr(MSKFOO,"GROS PROBLEME DANS LE CORRECTEUR : (presumedendingtag == NULL)\n");
				*returnedtag = NULL;
				return NULL;
			}
			else
			{
				if ((slashpos = strchr(presumedendingtag->name,'/')) != NULL)
				{
					if (!stricmp(SkipBlank(slashpos+1),currenttag->name))
					{
						*returnedtag = presumedendingtag;
						return presumedendingtag->nexttag;
					}
					else 
					{
						namelength = strlen(currenttag->name);
						endtagname = (char*) malloc((namelength+2)*sizeof(char));
						endtagname[0] = '/';
						memcpy(endtagname+1,currenttag->name,namelength);
						endtagname[namelength+1] = '\0';
						insertedendingtag = DuplicateTag(presumedendingtag,endtagname);
						InsertTagInList(presumedendingprevioustag,insertedendingtag);
						free(endtagname);
						*returnedtag = insertedendingtag;
						return insertedendingtag->nexttag;
					}
				}
				else
				{
					namelength = strlen(currenttag->name);
					endtagname = (char*) malloc((namelength+2)*sizeof(char));
					endtagname[0] = '/';
					memcpy(endtagname+1,currenttag->name,namelength);
					endtagname[namelength+1] = '\0';
					insertedendingtag = DuplicateTag(presumedendingtag,endtagname);
					InsertTagInList(presumedendingprevioustag,insertedendingtag);
					free(endtagname);
					*returnedtag = insertedendingtag;
					return insertedendingtag->nexttag;
				}
			}
		}
	}
}

*/

TagStruct	*parse(char* inbuf)
{
	TagStruct	*roottag;

//	InitFatherList();

	if (inbuf == NULL) return NULL;
	roottag = GetTag(inbuf);
//	ListTagGrammarCorrection(NULL,roottag,NULL);
	SortTag(NULL,roottag);
//	NewSortTag(roottag);

	
//	FreeFatherList();
	return roottag;
}

int FreeTag(TagStruct *currenttag)
{

//	MMechostr(MSKFOO,"FreeTag : freeing '%08x' '%s'...\n",currenttag,currenttag->name);

	if (currenttag == NULL)
		return 0;

	free(currenttag->name);
	currenttag->name = NULL;
	freeParamList(currenttag->paramlist);
	currenttag->paramlist = NULL;
	free(currenttag);
	currenttag = NULL;

	return 0;
}

int	FreeList(TagStruct *currenttag)
{
	TagStruct *tagnext;

	MMechostr(MSKTRACE,"FreeList start\n");

	while (currenttag != NULL)
	{
		tagnext = currenttag->nexttag;
		FreeTag(currenttag);
		currenttag = tagnext;
	}
	MMechostr(MSKTRACE,"FreeList end\n");
	return 0;
}

/*
int	FreeTree(TagStruct *currenttag)
{
	TagStruct *tagtofree;

	MMechostr(MSKFOO,"FreeTree : freeing '%08x'...\n",currenttag);

	while (currenttag != NULL)
	{
		if (currenttag->sontag != NULL)
		{
			FreeTree(currenttag->sontag);
			currenttag->sontag = NULL;
		}

		free(currenttag->name);
		currenttag->name = NULL;
		freeParamList(currenttag->paramlist);
		currenttag->paramlist = NULL;

		tagtofree = currenttag;
		currenttag = currenttag->brothertag;
		free(tagtofree);
		tagtofree = NULL;
	}

	return 0;
}
*/

#endif
