File:  [Public] / Amaya / amaya / XHTMLbuilder.c
Revision 1.97: download - view: text, annotated - select for diffs
Wed Oct 22 13:04:12 2003 UTC (20 years, 7 months ago) by quint
Branches: MAIN
CVS tags: HEAD
HTML: fixing a crash that happened when parsing a <textarea> that
      contained some text.
VQ

/*
 *
 *  (c) COPYRIGHT INRIA and W3C, 1996-2003
 *  Please first read the full copyright statement in file COPYRIGHT.
 *
 */

/*
 * XHTMLbuilder.c
 * Builds the corresponding abstract tree for a Thot document of type HTML.
 *
 * Authors: L. Carcone
 *          V. Quint 
 */

#define THOT_EXPORT extern
#include "amaya.h"
#include "css.h"
#include "parser.h"
#include "HTML.h"
#include "fetchHTMLname.h"

#include "css_f.h"
#include "EDITstyle_f.h"
#include "fetchXMLname_f.h"
#include "fetchHTMLname_f.h"
#include "html2thot_f.h"
#include "HTMLactions_f.h"
#include "HTMLedit_f.h"
#include "HTMLform_f.h"
#include "HTMLimage_f.h"
#include "HTMLtable_f.h"
#include "HTMLimage_f.h"
#include "UIcss_f.h"
#include "styleparser_f.h"
#include "XHTMLbuilder_f.h"
#include "Xml2thot_f.h"

#define MaxMsgLength 200

/* Elements that cannot contain text as immediate children.
   When some text is present in the HTML file it must be 
   surrounded by a Pseudo_paragraph element */
static int          NoTextChild[] =
{
   HTML_EL_Document, HTML_EL_HTML, HTML_EL_HEAD, HTML_EL_BODY,
   HTML_EL_Definition_List, HTML_EL_Block_Quote, HTML_EL_Directory,
   HTML_EL_Form, HTML_EL_Menu, HTML_EL_FIELDSET,
   HTML_EL_Numbered_List, HTML_EL_Option_Menu,
   HTML_EL_Unnumbered_List, HTML_EL_Definition, HTML_EL_List_Item,
   HTML_EL_MAP, HTML_EL_map, HTML_EL_Applet,
   HTML_EL_Object, HTML_EL_IFRAME, HTML_EL_NOFRAMES,
   HTML_EL_Division, HTML_EL_Center, HTML_EL_NOSCRIPT,
   HTML_EL_Data_cell, HTML_EL_Heading_cell,
   0};

/* Define a pointer to let parser functions access the HTML entity table */
extern XmlEntity *pXhtmlEntityTable;

/* maximum size of error messages */
#define MaxMsgLength 200

/*----------------------------------------------------------------------
  ParseCharset:
  Parses the element HTTP-EQUIV and looks for the charset value.
  ----------------------------------------------------------------------*/
void             ParseCharset (Element el, Document doc) 

{
   AttributeType attrType;
   Attribute     attr;
   SSchema       docSSchema;
   CHARSET       charset;
   char         *text, *text2, *ptrText, *str;
   char          charsetname[MAX_LENGTH];
   int           length;
   int           pos, index = 0;

   charset = TtaGetDocumentCharset (doc);
   if (charset != UNDEFINED_CHARSET)
     /* the charset was already defined by the http header */
     return;

   docSSchema = TtaGetDocumentSSchema (doc);
   attrType.AttrSSchema = docSSchema;
   attrType.AttrTypeNum = HTML_ATTR_http_equiv;
   attr = TtaGetAttribute (el, attrType);
   if (attr != NULL)
     {
       /* There is a HTTP-EQUIV attribute */
       length = TtaGetTextAttributeLength (attr);
       if (length > 0)
	 {
	   text = TtaGetMemory (length + 1);
	   TtaGiveTextAttributeValue (attr, text, &length);
	   if (!strcasecmp (text, "content-type"))
	     {
	       attrType.AttrTypeNum = HTML_ATTR_meta_content;
	       attr = TtaGetAttribute (el, attrType);
	       if (attr != NULL)
		 {
		   length = TtaGetTextAttributeLength (attr);
		   if (length > 0)
		     {
		       text2 = TtaGetMemory (length + 1);
		       TtaGiveTextAttributeValue (attr, text2, &length);
		       ptrText = text2;
		       while (*ptrText)
			 {
			   *ptrText = tolower (*ptrText);
			   ptrText++;
			 }
		       
		       str = strstr (text2, "charset=");
		       if (str)
			 {
			   pos = str - text2 + 8;
			   while (text2[pos] != SPACE &&
				  text2[pos] != TAB && text2[pos] != EOS)
			     charsetname[index++] = text2[pos++];
			   charsetname[index] = EOS;
			   charset = TtaGetCharset (charsetname);
			   if (charset != UNDEFINED_CHARSET)
			     TtaSetDocumentCharset (doc, charset, FALSE);
			 }
		       TtaFreeMemory (text2);
		     }       
		 } 
	     }
	   TtaFreeMemory (text);
	 }
     }
}

/*----------------------------------------------------------------------
   XhtmlCannotContainText 
   Return TRUE if element el is a block element.
  ----------------------------------------------------------------------*/
ThotBool      XhtmlCannotContainText (ElementType elType)

{
   int        i;
   ThotBool   ret;

   if (strcmp (TtaGetSSchemaName (elType.ElSSchema), "HTML"))
      /* not an HTML element */
      ret = TRUE;
   else
     {
       ret = FALSE;
       i = 0;
       while (NoTextChild[i] > 0 && NoTextChild[i] != elType.ElTypeNum)
           i++;
       if (NoTextChild[i] == elType.ElTypeNum)
           ret = TRUE;
     }
   return ret;
}

/*----------------------------------------------------------------------
  XhtmlElementComplete
  Complete Xhtml elements.
  Check its attributes and its contents.
  ----------------------------------------------------------------------*/
void       XhtmlElementComplete (ParserData *context, Element el, int *error)

{
   Document       doc;   
   ElementType    elType, newElType, childType;
   Element        constElem, child, desc, leaf, prev, next, last,
	          elFrames, lastFrame, lastChild, parent, picture, content;
   Attribute      attr;
   AttributeType  attrType;
   Language       lang;
   char           *text;
   char           lastChar[2];
   char           *name1, *data;
   int            length;
   SSchema        docSSchema;
   ThotBool       isImage;
   PresentationValue    pval;
   PresentationContext  ctxt;

   *error = 0;
   doc = context->doc;
   docSSchema = TtaGetDocumentSSchema (doc);

   elType = TtaGetElementType (el);
   newElType.ElSSchema = elType.ElSSchema;

   if (elType.ElTypeNum != HTML_EL_Text_Area &&
       IsXMLElementInline (elType, doc))
     /* It's an inline element. If it is empty, insert a Basic_Elem to allow
	the user to put the selection within this element */
     /* Don't do it for a Text_Area, as a Inserted_Text element has to be
	created (see below) */
     {
       child = TtaGetFirstChild (el);
       if (child == NULL)
	 /* it's an empty inline element */
	 /* insert a Basic_Elem element in the element */
	 {
	   newElType.ElTypeNum = HTML_EL_Basic_Elem;
	   child = TtaNewTree (doc, newElType, "");
	   TtaInsertFirstChild (&child, el, doc);
	 }
     }
   else
     /* It's a block-level element. Is it within a character-level element? */
     if (elType.ElTypeNum != HTML_EL_Comment_ &&
	 elType.ElTypeNum != HTML_EL_XMLPI)
       BlockInCharLevelElem (el);

   switch (elType.ElTypeNum)
     {
     case HTML_EL_Object:	/* it's an object */
       data = NULL;
       isImage = FALSE;
       /* is there a type attribute on the object element? */
       attrType.AttrSSchema = elType.ElSSchema;
       attrType.AttrTypeNum = HTML_ATTR_Object_type;
       attr = TtaGetAttribute (el, attrType);
       if (attr)
	 /* there is a type attribute. Get its value to see if the object
	    represents an image */
	 {
	   length = TtaGetTextAttributeLength (attr);
	   if (length > 0)
	     {
	       name1 = TtaGetMemory (length + 1);
	       TtaGiveTextAttributeValue (attr, name1, &length);
	       if (!strcmp (name1, AM_MATHML_MIME_TYPE) ||
		   !strcmp (name1, "application/postscript") ||
		   !strcmp (name1, "image/x-bitmap") ||
		   !strcmp (name1, "image/x-xpixmap") ||
		   !strcmp (name1, "image/gif") ||
		   !strcmp (name1, "image/jpeg") ||
		   !strcmp (name1, "image/png") ||
		   !strcmp (name1, "image/svg") ||
		   !strcmp (name1, AM_SVG_MIME_TYPE) ||
		   !strcmp (name1, AM_XHTML_MIME_TYPE) ||
		   !strcmp (name1, "text/html") ||
		   !strcmp (name1, "text/htm") ||
		   !strcmp (name1, AM_GENERIC_XML_MIME_TYPE))
		 isImage = TRUE;
	       TtaFreeMemory (name1);
	     }
	 }

       attrType.AttrTypeNum = HTML_ATTR_data;
       attr = TtaGetAttribute (el, attrType);
       if (attr)
	 /* the object has a data attribute */
	 {
	   length = TtaGetTextAttributeLength (attr);
	   if (length > 0)
	     {
	       data = TtaGetMemory (length + 1);
	       TtaGiveTextAttributeValue (attr, data, &length);
	       if (!isImage)
		 if (!strcmp (&data[length-3], "mml") ||
		     !strcmp (&data[length-3], "gif") ||
		     !strcmp (&data[length-3], "jpg") ||
		     !strcmp (&data[length-4], "jpeg") ||
		     !strcmp (&data[length-3], "png") ||
		     !strcmp (&data[length-3], "svg") ||
		     !strcmp (&data[length-4], "svgz") ||
		     !strcmp (&data[length-3], "htm") ||
		     !strcmp (&data[length-4], "html") ||
		     !strcmp (&data[length-3], "xml"))
		   isImage = TRUE;
	     }
	 }
       picture = NULL;     /* no PICTURE element yet */
       child = TtaGetFirstChild (el);
       if (isImage)
	 /* the object represents an image. We need a PICTURE element as
	    child of the object to hold the image */
	 {
	   if (child)
	     {
	       elType = TtaGetElementType (child);
	       if (elType.ElTypeNum == HTML_EL_PICTURE_UNIT)
		 /* there is already a PICTURE element */
		 picture = child;
	     }
	   /* if the object element has no PICTURE element as its first child
	      create one */
	   if (!picture)
	     {
	       elType.ElTypeNum = HTML_EL_PICTURE_UNIT;
	       picture = TtaNewTree (doc, elType, "");
	       if (child)
		 TtaInsertSibling (picture, child, TRUE, doc);
	       else
		 TtaInsertFirstChild (&picture, el, doc);
	       child = picture;
	     }
	   /* copy attribute data of the object into the SRC attribute of
	      the PICTURE element */
	   if (data)
	     /* the object has a data attribute */
	     {
	       attrType.AttrTypeNum = HTML_ATTR_SRC;
	       attr = TtaGetAttribute (picture, attrType);
	       if (attr == NULL)
		 {
		   attr = TtaNewAttribute (attrType);
		   TtaAttachAttribute (picture, attr, doc);
		 }
	       TtaSetAttributeText (attr, data, picture, doc);
	     }
	   attrType.AttrTypeNum = HTML_ATTR_Height_;
	   attr = TtaGetAttribute (el, attrType);
	   if (attr)
	     /* the Object has a height attribute. Applies it to the
		picture element */
	     {
	       length = TtaGetTextAttributeLength (attr);
	       if (length > 0)
		 {
		   text = TtaGetMemory (length + 1);
		   TtaGiveTextAttributeValue (attr, text, &length);
		   /* create the corresponding attribute IntHeightPercent or */
		   /* IntHeightPxl */
		   CreateAttrHeightPercentPxl (text, el, doc, -1);
		   TtaFreeMemory (text);
		 }
	     }
	   attrType.AttrTypeNum = HTML_ATTR_Width__;
	   attr = TtaGetAttribute (el, attrType);
	   if (attr)
	     /* the Object has a width attribute. Applies it to the
		picture element */
	     {
	       length = TtaGetTextAttributeLength (attr);
	       if (length > 0)
		 {
		   text = TtaGetMemory (length + 1);
		   TtaGiveTextAttributeValue (attr, text, &length);
		   /* create the corresponding attribute IntWidthPercent or */
		   /* IntWidthPxl */
		   CreateAttrWidthPercentPxl (text, el, doc, -1);
		   TtaFreeMemory (text);
		 }
	     }
	 }
       /* is the Object_Content element already created ? */
       if (child)
	 /* the object element has at least 1 child element */
	 {
	   content = NULL;
	   desc = child;
	   elType = TtaGetElementType (desc);
	   if (elType.ElTypeNum != HTML_EL_Object_Content)
	     {
	       TtaNextSibling(&desc);
	       if (desc)
		 elType = TtaGetElementType (desc);
	     }
	   /* is it the Object_Content element ? */
	   if (elType.ElTypeNum == HTML_EL_Object_Content)
	     content = desc;
	   else
	     {
	       /* create an Object_Content element */
	       elType.ElTypeNum = HTML_EL_Object_Content;
	       content = TtaNewElement (doc, elType);
	       if (picture)
		 TtaInsertSibling (content, picture, FALSE, doc);
	       else
		 TtaInsertSibling (content, child, TRUE, doc);
	       /* move previous existing children into Object_Content */
	       child = TtaGetLastChild(el);
	       while (child != content)
		 {
		   TtaRemoveTree (child, doc);
		   TtaInsertFirstChild (&child, content, doc);
		   child = TtaGetLastChild(el);
		 }
	     }
	   if (picture && content)
	     /* there is a picture element. The Object_Content must not be
		displayed in the main view */
	     {
	       ctxt = TtaGetSpecificStyleContext (doc);
	       /* the presentation rule to be set is not a CSS rule */
	       ctxt->cssSpecificity = 0;
	       ctxt->destroy = FALSE;
	       pval.typed_data.unit = UNIT_PX;
	       pval.typed_data.value = 0;
	       pval.typed_data.real = FALSE;
	       TtaSetStylePresentation (PRVisibility, content, NULL, ctxt, pval);
	     }
	 }
       if (data)
	 TtaFreeMemory (data);
       break;

     case HTML_EL_Unnumbered_List:
     case HTML_EL_Numbered_List:
     case HTML_EL_Menu:
     case HTML_EL_Directory:
       /* It's a List element. It should only have List_Item children.
	  If it has List element chidren, move these List elements
	  within their previous List_Item sibling.  This is to fix
	  a bug in document generated by Mozilla. */
       prev = NULL;
       next = NULL;
       child = TtaGetFirstChild (el);
       while (child != NULL)
	 {
	   next = child;
	   TtaNextSibling (&next);
	   elType = TtaGetElementType (child);
	   if (elType.ElTypeNum == HTML_EL_Unnumbered_List ||
	       elType.ElTypeNum == HTML_EL_Numbered_List ||
	       elType.ElTypeNum == HTML_EL_Menu ||
	       elType.ElTypeNum == HTML_EL_Directory)
	     /* this list element is a child of another list element */
	     if (prev)
	       {
		 elType = TtaGetElementType (prev);
		 if (elType.ElTypeNum == HTML_EL_List_Item)
		   {
		     /* get the last child of the previous List_Item */
		     desc = TtaGetFirstChild (prev);
		     last = NULL;
		     while (desc)
		       {
			 last = desc;
			 TtaNextSibling (&desc);
		       }
		     /* move the list element after the last child of the
			previous List_Item */
		     TtaRemoveTree (child, doc);
		     if (last)
		       TtaInsertSibling (child, last, FALSE, doc);
		     else
		       TtaInsertFirstChild (&child, prev, doc);
		     child = prev;
		   }
	       }
	   prev = child;
	   child = next;
	 }
       break;
       
     case HTML_EL_FRAMESET:
       /* The FRAMESET element is now complete.  Gather all its FRAMESET
	  and FRAME children and wrap them up in a Frames element */
       elFrames = NULL; lastFrame = NULL;
       lastChild = NULL;
       child = TtaGetFirstChild (el);
       while (child != NULL)
	 {
	   next = child;
	   TtaNextSibling (&next);
	   elType = TtaGetElementType (child);
	   if (elType.ElTypeNum == HTML_EL_FRAMESET ||
	       elType.ElTypeNum == HTML_EL_FRAME ||
	       elType.ElTypeNum == HTML_EL_Comment_)
	     {
	       /* create the Frames element if it does not exist */
	       if (elFrames == NULL)
		 {
		   newElType.ElSSchema = docSSchema;
		   newElType.ElTypeNum = HTML_EL_Frames;
		   elFrames = TtaNewElement (doc, newElType);
		   if (DocumentMeta[doc]->xmlformat)
		     XmlSetElemLineNumber (elFrames);
		   else
		     SetHtmlElemLineNumber (elFrames);
		   TtaInsertSibling (elFrames, child, TRUE, doc);
		 }
	       /* move the element as the last child of the Frames element */
	       TtaRemoveTree (child, doc);
	       if (lastFrame == NULL)
		 TtaInsertFirstChild (&child, elFrames, doc);
	       else
		 TtaInsertSibling (child, lastFrame, FALSE, doc);
	       lastFrame = child;
	     }
	   child = next;
	 }
       break;
       
     case HTML_EL_Input:	/* it's an INPUT without any TYPE attribute */
       /* Create a child of type Text_Input */
       elType.ElTypeNum = HTML_EL_Text_Input;
       child = TtaNewTree (doc, elType, "");
       if (DocumentMeta[doc]->xmlformat)
	 XmlSetElemLineNumber (child);
       else
	 SetHtmlElemLineNumber (child);
       TtaInsertFirstChild (&child, el, doc);
       /* now, process it like a Text_Input element */

     case HTML_EL_Text_Input:
     case HTML_EL_Password_Input:
     case HTML_EL_File_Input:
       /* set default size */
       attrType.AttrSSchema = elType.ElSSchema;
       attrType.AttrTypeNum = HTML_ATTR_IntAreaSize;
       attr = TtaGetAttribute (el, attrType);
       if (!attr)
	 CreateAttrIntAreaSize (20, el, doc);
       /* get element Inserted_Text */
       child = TtaGetFirstChild (el);
       if (child != NULL)
	 {
	   attrType.AttrTypeNum = HTML_ATTR_Value_;
	   attr = TtaGetAttribute (el, attrType);
	   if (attr != NULL)
	     {
	       /* copy the value of attribute "value" into the first text
		  leaf of element */
	       length = TtaGetTextAttributeLength (attr);
	       if (length > 0)
		 {
		   /* get the text leaf */
		   leaf = TtaGetFirstChild (child);
		   if (leaf != NULL)
		     {
		       childType = TtaGetElementType (leaf);
		       if (childType.ElTypeNum == HTML_EL_TEXT_UNIT)
			 {
			   /* copy attribute value into the text leaf */
			   text = TtaGetMemory (length + 1);
			   TtaGiveTextAttributeValue (attr, text, &length);
			   TtaSetTextContent (leaf, text, 
					      TtaGetDefaultLanguage (), doc);
			   TtaFreeMemory (text);
			 }
		     }
		 }
	     }
	 }
       break;
       
     case HTML_EL_META:
       ParseCharset (el, doc);
       break;

     case HTML_EL_STYLE_:	/* it's a STYLE element */
     case HTML_EL_SCRIPT_:	/* it's a SCRIPT element */
     case HTML_EL_Preformatted:	/* it's a PRE */
       /* if the last line of the Preformatted is empty, remove it */
       leaf = XmlLastLeafInElement (el);
       if (leaf != NULL)
	 {
	   elType = TtaGetElementType (leaf);
	   if (elType.ElTypeNum == HTML_EL_TEXT_UNIT)
	     /* the last leaf is a TEXT element */
	     {
	       length = TtaGetTextLength (leaf);
	       if (length > 0)
		 {
		   TtaGiveSubString (leaf, lastChar, length, 1);
		   if (lastChar[0] == EOL)
		     /* last character is new line, delete it */
		     {
		       if (length == 1)
			 /* empty TEXT element */
			 TtaDeleteTree (leaf, doc);
		       else
			 /* remove the last character */
			 TtaDeleteTextContent (leaf, length, 1, doc);
		     }
		 }
	     }
	 }
       if (DocumentMeta[doc] && DocumentMeta[doc]->xmlformat)
	 {
	   if (IsXmlParsingCSS ())
	     {
	       text = GetStyleContents (el);
	       if (text)
		 {
		   ReadCSSRules (doc, NULL, text, NULL,
				 TtaGetElementLineNumber (el), FALSE, el);
		   TtaFreeMemory (text);
		 }
	       SetXmlParsingCSS (FALSE);
	     }
	 }
       else
	 {
	   if (IsHtmlParsingCSS ())
	     {
	       text = GetStyleContents (el);
	       if (text)
		 {
		   ReadCSSRules (doc, NULL, text, NULL,
				 TtaGetElementLineNumber (el), FALSE, el);
		   TtaFreeMemory (text);
		 }
	       SetHtmlParsingCSS (FALSE);
	     }
	 }
       /* and continue as if it were a Preformatted or a Script */
       break;
       
     case HTML_EL_Text_Area:	/* it's a Text_Area */
       if (DocumentMeta[doc]->xmlformat)
	 SetParsingTextArea (FALSE);
       else
	 SetHtmlParsingTextArea (FALSE);
       child = TtaGetFirstChild (el);
       if (child == NULL)
	 /* it's an empty Text_Area */
	 /* insert a Inserted_Text element and a child Basic_Elem in the
            Text_Area element */
	 {
	   newElType.ElTypeNum = HTML_EL_Inserted_Text;
	   child = TtaNewTree (doc, newElType, "");
	   TtaInsertFirstChild (&child, el, doc);
	 }
       else
	 {
	   /* save the text into Default_Value attribute */
	   attrType.AttrSSchema = docSSchema;
	   attrType.AttrTypeNum = HTML_ATTR_Default_Value;
	   if (TtaGetAttribute (el, attrType) == NULL)
	     /* attribute Default_Value is missing */
	     {
	       desc = TtaGetFirstChild (child);
	       if (desc)
		 {
		   length = TtaGetTextLength (desc);
		   if (length > 0)
		     {
		       length++;
		       attr = TtaNewAttribute (attrType);
		       TtaAttachAttribute (el, attr, doc);
		       text = TtaGetMemory (length);
		       TtaGiveTextContent (desc, text, &length, &lang);
		       TtaSetAttributeText (attr, text, el, doc);
		       TtaFreeMemory (text);
		     }
		 }
	     }
	 }
       /* insert a Frame element */
       newElType.ElTypeNum = HTML_EL_Frame;
       constElem = TtaNewTree (doc, newElType, "");
       TtaInsertSibling (constElem, child, FALSE, doc);
       break;
       
     case HTML_EL_Radio_Input:
     case HTML_EL_Checkbox_Input:
       /* put an attribute Checked if it is missing */
       attrType.AttrSSchema = docSSchema;
       attrType.AttrTypeNum = HTML_ATTR_Checked;
       if (TtaGetAttribute (el, attrType) == NULL)
	 /* attribute Checked is missing */
	 {
	   attr = TtaNewAttribute (attrType);
	   TtaAttachAttribute (el, attr, doc);
	   TtaSetAttributeValue (attr, HTML_ATTR_Checked_VAL_No_, el, doc);
	 }
       break;
       
     case HTML_EL_Option_Menu:
       /* Check that at least one option has a SELECTED attribute */
       OnlyOneOptionSelected (el, doc, TRUE);
       break;

     case HTML_EL_PICTURE_UNIT:
       break;
       
     case HTML_EL_LINK:
       CheckCSSLink (el, doc, docSSchema);
       break;
       
     case HTML_EL_Data_cell:
     case HTML_EL_Heading_cell:
       /* insert a pseudo paragraph into empty cells */
       child = TtaGetFirstChild (el);
       if (child == NULL)
	 {
	   elType.ElTypeNum = HTML_EL_Pseudo_paragraph;
	   child = TtaNewTree (doc, elType, "");
	   if (child != NULL)
	       TtaInsertFirstChild (&child, el, doc);
	 }
       
       /* detect whether we are parsing a whole table or just a cell */
       if (DocumentMeta[doc]->xmlformat)
	 {
	   if (IsWithinXmlTable ())
	     NewCell (el, doc, FALSE, FALSE);
	 }
       else
	 {
	   if (IsWithinHtmlTable ())
	     NewCell (el, doc, FALSE, FALSE);
	 }
       break;
       
     case HTML_EL_Table:
       CheckTable (el, doc);
       SubWithinTable ();
       break;
       
     case HTML_EL_TITLE:
       /* show the TITLE in the main window */
       UpdateTitle (el, doc);
       break;

     case HTML_EL_rbc:
       /* an rbc element has been read. Its parent should be a complex_ruby.
	  Change the type of the parent, as simple_ruby are created by
	  default */
       parent = TtaGetParent (el);
       if (parent)
	 {
	   newElType = TtaGetElementType (parent);
	   if (newElType.ElSSchema == elType.ElSSchema &&
	       newElType.ElTypeNum == HTML_EL_simple_ruby)
	      TtaChangeElementType (parent, HTML_EL_complex_ruby);
	 }
       break;

     case HTML_EL_rtc1:
       /* an rtc element has been parsed. If it has already a rtc1 sibling,
	  change its type to rtc2 */
       prev = el;
       do
	 {
	   TtaPreviousSibling(&prev);
	   if (prev)
	     {
	       newElType = TtaGetElementType (prev);
	       if (newElType.ElSSchema == elType.ElSSchema &&
		   newElType.ElTypeNum == HTML_EL_rtc1)
		 {
		   TtaChangeElementType (el, HTML_EL_rtc2);
		   prev = NULL;
		 }
	     }
	 }
       while (prev);
       break;

     default:
       break;
     }
}

/*----------------------------------------------------------------------
   PutInContent    
   Put the string ChrString in the leaf of current element.
  ----------------------------------------------------------------------*/
Element         PutInContent (char *ChrString, ParserData *context)

{
   Element      el, child;
   ElementType  elType;
   int          length;

   el = NULL;
   if (context->lastElement != NULL)
     {
	/* search first leaf of current element */
	el = context->lastElement;
	do
	  {
	     child = TtaGetFirstChild (el);
	     if (child != NULL)
		el = child;
	  }
	while (child != NULL);
	elType = TtaGetElementType (el);
	length = 0;
	if (elType.ElTypeNum == 1)
	   length = TtaGetTextLength (el);
	if (length == 0)
	   TtaSetTextContent (el, ChrString, context->language, context->doc);
	else
	   TtaAppendTextContent (el, ChrString, context->doc);
     }
   return el;
}

/*----------------------------------------------------------------------
  UnknownXhtmlNameSpace
  The element doesn't belong to a supported namespace
  ----------------------------------------------------------------------*/
void UnknownXhtmlNameSpace (ParserData *context, Element *unknownEl,
			    char* content)
{
   ElementType     elType;
   Element         elText;

   /* Create a new Invalid_element */
   elType.ElSSchema = GetXMLSSchema (XHTML_TYPE, context->doc);
   elType.ElTypeNum = HTML_EL_XHTML_Unknown_namespace;
   *unknownEl = TtaNewElement (context->doc, elType);
   if (*unknownEl != NULL)
     {
       XmlSetElemLineNumber (*unknownEl);
       InsertXmlElement (unknownEl);
       context->lastElementClosed = TRUE;
       elType.ElTypeNum = HTML_EL_TEXT_UNIT;
       elText = TtaNewElement (context->doc, elType);
       XmlSetElemLineNumber (elText);
       TtaInsertFirstChild (&elText, *unknownEl, context->doc);
       TtaSetTextContent (elText, content, context->language, context->doc);
       TtaSetAccessRight (elText, ReadOnly, context->doc);
     }
}

/*----------------------------------------------------------------------
   CreateHTMLAttribute
   create an attribute of type attrType for the element el.
  ----------------------------------------------------------------------*/
void CreateHTMLAttribute (Element       el,
			  AttributeType attrType,
			  char*         text,
			  ThotBool      isInvalid,
			  Document      doc,
			  Attribute    *lastAttribute,
			  Element      *lastAttrElement)
{
   int         attrKind;
   int         length;
   char       *buffer;
   Attribute   attr, oldAttr;

   if (attrType.AttrTypeNum != 0)
     {
       oldAttr = TtaGetAttribute (el, attrType);
       if (oldAttr != NULL)
	 /* this attribute already exists */
	 attr = oldAttr;
       else
	 /* create a new attribute and attach it to the element */
	 {
	   attr = TtaNewAttribute (attrType);
	   TtaAttachAttribute (el, attr, doc);
	 }
       *lastAttribute = attr;
       *lastAttrElement = el;

       TtaGiveAttributeType (attr, &attrType, &attrKind);
       if (attrKind == 0)	/* enumerate */
	 TtaSetAttributeValue (attr, 1, el, doc);

       /* attribute BORDER without any value (ThotBool attribute) is */
       /* considered as BORDER=1 */
       if (attrType.AttrTypeNum == HTML_ATTR_Border)
	 TtaSetAttributeValue (attr, 1, el, doc);

       if (isInvalid)
	 /* Copy the name of the invalid attribute as the content */
	 /* of the Invalid_attribute attribute. */
	 {
	   length = strlen (text) + 2;
	   length += TtaGetTextAttributeLength (attr);
	   buffer = TtaGetMemory (length + 1);
	   TtaGiveTextAttributeValue (attr, buffer, &length);
	   strcat (buffer, " ");
	   strcat (buffer, text);
	   TtaSetAttributeText (attr, buffer, el, doc);
	   TtaFreeMemory (buffer);
	 }
     }
}

/*----------------------------------------------------------------------
   HTMLTypeAttrValue
   Value val has been read for the HTML attribute TYPE.
   Create a child for the current Thot element INPUT accordingly.
  ----------------------------------------------------------------------*/
void               HTMLTypeAttrValue (char       *val,
				      Attribute   lastAttribute,
				      Element     lastAttrElement,
				      ParserData *context)

{
  ElementType      elType;
  Element          newChild;
  AttributeType    attrType;
  Attribute        attr;
  char             msgBuffer[MaxMsgLength];
  int              value;
  int              numberOfLinesRead;

  value = MapAttrValue (DummyAttribute, val);
  if (value <= 0)
    {
      if (strlen (val) > MaxMsgLength - 40)
         val[MaxMsgLength - 40] = EOS;
      sprintf (msgBuffer, "Unknown attribute value \"type = %s\"", val);
      HTMLParseError (context->doc, msgBuffer);
      attrType.AttrSSchema = TtaGetDocumentSSchema (context->doc);
      attrType.AttrTypeNum = pHTMLAttributeMapping[0].ThotAttribute;
      sprintf (msgBuffer, "type=%s", val);
      CreateHTMLAttribute (context->lastElement, attrType, msgBuffer, TRUE,
			   context->doc, &lastAttribute, &lastAttrElement);
    }
  else
    {
      elType = TtaGetElementType (context->lastElement);
      if (elType.ElTypeNum != HTML_EL_Input)
	{
	  if (strlen (val) > MaxMsgLength - 40)
	    val[MaxMsgLength - 40] = EOS;
	  sprintf (msgBuffer, "Duplicate attribute \"type = %s\"", val);
	}
      else
	{
	  elType.ElSSchema = TtaGetDocumentSSchema (context->doc);
	  elType.ElTypeNum = value;
	  newChild = TtaNewTree (context->doc, elType, "");
	  numberOfLinesRead = 0;
	  TtaSetElementLineNumber (newChild, numberOfLinesRead);
	  TtaInsertFirstChild (&newChild, context->lastElement, context->doc);
	  if (value == HTML_EL_PICTURE_UNIT)
	    {
	      /* add the attribute IsInput to input pictures */
	      attrType.AttrSSchema = elType.ElSSchema;
	      attrType.AttrTypeNum = HTML_ATTR_IsInput;
	      attr = TtaNewAttribute (attrType);
	      TtaAttachAttribute (newChild, attr, context->doc);
	    }
	}
    }
}

/*----------------------------------------------------------------------
   XhtmlTypeAttrValue 
   Value val has been read for the HTML attribute TYPE.
   Create a child for the current Thot element INPUT accordingly.
  ----------------------------------------------------------------------*/
void              XhtmlTypeAttrValue (char       *val,
				      Attribute   currentAttribute,
				      Element     lastAttrElement,
				      ParserData *context)

{
  ElementType     elType;
  Element         newChild;
  AttributeType   attrType;
  Attribute       attr;
  char            msgBuffer[MaxMsgLength];
  int             value;
  ThotBool        level;

  /* Look in the dummy section of the attribute value table */
  attrType.AttrTypeNum = DummyAttribute;
  MapHTMLAttributeValue (val, attrType, &value);
  if (value <= 0)
    /* invalid value for the type attribute of an input element */
    {
      sprintf (msgBuffer, "Unknown attribute value \"type=%s\"", val);
      XmlParseError (errorParsing, msgBuffer, 0);
      MapHTMLAttribute ("unknown_attr", &attrType, NULL,
			&level, context->doc);
      sprintf (msgBuffer, "type=%s", val);
      CreateHTMLAttribute (context->lastElement, attrType, msgBuffer, TRUE,
			   context->doc, &currentAttribute, &lastAttrElement);
    }
  else
    /* value is the Thot type of the element to be created for this value of
       the TYPE attribute */
    {
      elType = TtaGetElementType (context->lastElement);
      if (elType.ElTypeNum != HTML_EL_Input)
	{
	  sprintf (msgBuffer, "Duplicate attribute \"type = %s\"", val);
	  XmlParseError (errorParsing, msgBuffer, 0);
	}
      else
	{
	  elType.ElTypeNum = value;
	  newChild = TtaNewTree (context->doc, elType, "");
	  XmlSetElemLineNumber (newChild);
	  TtaInsertFirstChild (&newChild, context->lastElement, context->doc);
	  if (value == HTML_EL_PICTURE_UNIT)
	    {
	      /* add the attribute IsInput to input pictures */
	      attrType.AttrSSchema = elType.ElSSchema;
	      attrType.AttrTypeNum = HTML_ATTR_IsInput;
	      attr = TtaNewAttribute (attrType);
	      TtaAttachAttribute (newChild, attr, context->doc);
	    }
	}
    }
}

/*----------------------------------------------------------------------
   CreateAttrWidthPercentPxl
   an HTML attribute "width" has been created for a Table, an image,
   an Object of a HR.
   Create the corresponding attribute IntWidthPercent or IntWidthPxl.
   oldWidth is -1 or the old image width.
  ----------------------------------------------------------------------*/
void CreateAttrWidthPercentPxl (char *buffer, Element el,
				Document doc, int oldWidth)
{
  AttributeType   attrTypePxl, attrTypePercent;
  Attribute       attrOld, attrNew;
  int             length, val;
  char            msgBuffer[MaxMsgLength];
  ElementType	  elType, childType;
  Element         origEl, child;
  int             w, h;
  ThotBool        isImage;

  origEl = el;
  elType = TtaGetElementType (el);
  isImage = (elType.ElTypeNum == HTML_EL_PICTURE_UNIT ||
	     elType.ElTypeNum == HTML_EL_Data_cell ||
	     elType.ElTypeNum == HTML_EL_Heading_cell ||
	     elType.ElTypeNum == HTML_EL_Object);
  if (elType.ElTypeNum == HTML_EL_Object)
    /* the width attribute is attached to an Object element */
    {
      child = TtaGetFirstChild (el);
      if (child)
	{
	  childType = TtaGetElementType (child);
	  if (childType.ElTypeNum == HTML_EL_PICTURE_UNIT)
	    /* the Object element is of type image. apply the width
	       attribute to the actual image element */
	    el = child;
	}
    }
  /* remove trailing spaces */
  length = strlen (buffer) - 1;
  while (length > 0 && buffer[length] <= SPACE)
    length--;
  attrTypePxl.AttrSSchema = TtaGetDocumentSSchema (doc);
  attrTypePercent.AttrSSchema = TtaGetDocumentSSchema (doc);
  attrTypePxl.AttrTypeNum = HTML_ATTR_IntWidthPxl;
  attrTypePercent.AttrTypeNum = HTML_ATTR_IntWidthPercent;
  /* is the last character a '%' ? */
  if (buffer[length] == '%')
    {
      /* remove IntWidthPxl */
      attrOld = TtaGetAttribute (el, attrTypePxl);
      /* update IntWidthPercent */
      attrNew = TtaGetAttribute (el, attrTypePercent);
      if (attrNew == NULL)
	{
	  attrNew = TtaNewAttribute (attrTypePercent);
	  TtaAttachAttribute (el, attrNew, doc);
	}
      else if (isImage && oldWidth == -1)
	{
	  if (attrOld == NULL)
	    oldWidth = TtaGetAttributeValue (attrNew);
	  else
	    oldWidth = TtaGetAttributeValue (attrOld);
	}
    }
  else
    {
      /* remove IntWidthPercent */
      attrOld = TtaGetAttribute (el, attrTypePercent);
      /* update IntWidthPxl */
      attrNew = TtaGetAttribute (el, attrTypePxl);
      if (attrNew == NULL)
	{
	  attrNew = TtaNewAttribute (attrTypePxl);
	  TtaAttachAttribute (el, attrNew, doc);
	}
      else if (isImage && oldWidth == -1)
	{
	  TtaGiveBoxSize (el, doc, 1, UnPixel, &w, &h);
	  if (attrOld == NULL)
	    oldWidth = w * TtaGetAttributeValue (attrNew) / 100;
	  else
	    oldWidth = w * TtaGetAttributeValue (attrOld) / 100;	  
	}
    }

  if (attrOld != NULL)
    TtaRemoveAttribute (el, attrOld, doc);
  if (sscanf (buffer, "%d", &val))
    TtaSetAttributeValue (attrNew, val, el, doc);
  else
    /* its not a number. Delete attribute and send an error message */
    {
    TtaRemoveAttribute (el, attrNew, doc);
    if (strlen (buffer) > MaxMsgLength - 30)
        buffer[MaxMsgLength - 30] = EOS;
    sprintf (msgBuffer, "Invalid attribute value \"%s\"", buffer);
    HTMLParseError (doc, msgBuffer);
    }
  if (isImage)
    UpdateImageMap (origEl, doc, oldWidth, -1);
}

/*----------------------------------------------------------------------
   CreateAttrHeightPercentPxl
   an HTML attribute "width" has been created for a Table, an image,
   an Object or a HR.
   Create the corresponding attribute IntHeightPercent or IntHeightPxl.
   oldHeight is -1 or the old image width.
  ----------------------------------------------------------------------*/
void CreateAttrHeightPercentPxl (char *buffer, Element el,
				Document doc, int oldHeight)
{
  AttributeType   attrTypePxl, attrTypePercent;
  Attribute       attrOld, attrNew;
  int             length, val;
  char            msgBuffer[MaxMsgLength];
  ElementType	  elType, childType;
  Element         origEl, child;
  int             w, h;
  ThotBool        isImage;

  origEl = el;
  elType = TtaGetElementType (el);
  isImage = (elType.ElTypeNum == HTML_EL_PICTURE_UNIT ||
	     elType.ElTypeNum == HTML_EL_Data_cell ||
	     elType.ElTypeNum == HTML_EL_Heading_cell ||
	     elType.ElTypeNum == HTML_EL_Object);
  if (elType.ElTypeNum == HTML_EL_Object)
    /* the height attribute is attached to an Object element */
    {
      child = TtaGetFirstChild (el);
      if (!child)
	return;
      else
	{
	  childType = TtaGetElementType (child);
	  if (childType.ElTypeNum == HTML_EL_PICTURE_UNIT)
	    /* the Object element is of type image. apply the width
	       attribute to the actual image element */
	    el = child;
	  else
	    return;
	}
    }
  /* remove trailing spaces */
  length = strlen (buffer) - 1;
  while (length > 0 && buffer[length] <= SPACE)
    length--;
  attrTypePxl.AttrSSchema = TtaGetDocumentSSchema (doc);
  attrTypePercent.AttrSSchema = TtaGetDocumentSSchema (doc);
  attrTypePxl.AttrTypeNum = HTML_ATTR_IntHeightPxl;
  attrTypePercent.AttrTypeNum = HTML_ATTR_IntHeightPercent;
  /* is the last character a '%' ? */
  if (buffer[length] == '%')
    {
      /* remove IntHeightPxl */
      attrOld = TtaGetAttribute (el, attrTypePxl);
      /* update IntHeightPercent */
      attrNew = TtaGetAttribute (el, attrTypePercent);
      if (attrNew == NULL)
	{
	  attrNew = TtaNewAttribute (attrTypePercent);
	  TtaAttachAttribute (el, attrNew, doc);
	}
      else if (isImage && oldHeight == -1)
	{
	  if (attrOld == NULL)
	    oldHeight = TtaGetAttributeValue (attrNew);
	  else
	    oldHeight = TtaGetAttributeValue (attrOld);
	}
    }
  else
    {
      /* remove IntHeightPercent */
      attrOld = TtaGetAttribute (el, attrTypePercent);
      /* update IntHeightPxl */
      attrNew = TtaGetAttribute (el, attrTypePxl);
      if (attrNew == NULL)
	{
	  attrNew = TtaNewAttribute (attrTypePxl);
	  TtaAttachAttribute (el, attrNew, doc);
	}
      else if (isImage && oldHeight == -1)
	{
	  TtaGiveBoxSize (el, doc, 1, UnPixel, &w, &h);
	  if (attrOld == NULL)
	    oldHeight = w * TtaGetAttributeValue (attrNew) / 100;
	  else
	    oldHeight = w * TtaGetAttributeValue (attrOld) / 100;	  
	}
    }

  if (attrOld != NULL)
    TtaRemoveAttribute (el, attrOld, doc);
  if (sscanf (buffer, "%d", &val))
    TtaSetAttributeValue (attrNew, val, el, doc);
  else
    /* its not a number. Delete attribute and send an error message */
    {
    TtaRemoveAttribute (el, attrNew, doc);
    if (strlen (buffer) > MaxMsgLength - 30)
        buffer[MaxMsgLength - 30] = EOS;
    sprintf (msgBuffer, "Invalid attribute value \"%s\"", buffer);
    HTMLParseError (doc, msgBuffer);
    }
  if (isImage)
    UpdateImageMap (origEl, doc, oldHeight, -1);
}

/*----------------------------------------------------------------------
   CreateAttrIntAreaSize
   an HTML attribute "size" has been created or modified for a input element.
   Create or update the corresponding attribute IntAreaSize.
  ----------------------------------------------------------------------*/
void CreateAttrIntAreaSize (int value, Element el, Document doc)
{
  AttributeType   attrType;
  Attribute       attr;
  ElementType	  elType;

  elType = TtaGetElementType (el);
  attrType.AttrSSchema = elType.ElSSchema;
  attrType.AttrTypeNum = HTML_ATTR_IntAreaSize;
  attr = TtaGetAttribute (el, attrType);
  if (!attr)
    {
      attr = TtaNewAttribute (attrType);
      TtaAttachAttribute (el, attr, doc);
    }
  /* the presentation rule associated with attribute IntAreaSize expresses
     the element width in "em". Convert the value into em */
  TtaSetAttributeValue (attr, (int) (value * 0.55), el, doc);
}

/*----------------------------------------------------------------------
   CreateAttrIntSize
   an HTML attribute "size" has been created for a Font element.
   Create the corresponding internal attribute.
  ----------------------------------------------------------------------*/
void              CreateAttrIntSize (char *buffer, Element el, Document doc)

{
   AttributeType  attrType;
   int            val, ind, factor, delta;
   Attribute      attr;
   char         msgBuffer[MaxMsgLength];

   /* is the first character a '+' or a '-' ? */
   ind = 0;
   factor = 1;
   delta = 0;
   if (buffer[0] == '+')
     {
       attrType.AttrTypeNum = HTML_ATTR_IntSizeIncr;
       ind++;
       factor = 1;
     }
   else if (buffer[0] == '-')
     {
       attrType.AttrTypeNum = HTML_ATTR_IntSizeDecr;
       ind++;
       factor = 1;
     }
   else
     {
       attrType.AttrTypeNum = HTML_ATTR_IntSizeRel;
       delta = 1;
     }
   attrType.AttrSSchema = TtaGetDocumentSSchema (doc);
   attr = TtaGetAttribute (el, attrType);
   if (sscanf (&buffer[ind], "%d", &val))
     {
       val = val * factor + delta;
       if (attr == NULL)
	 {
	   /* this attribute doesn't exist, create it */
	   attr = TtaNewAttribute (attrType);
	   TtaAttachAttribute (el, attr, doc);
	 }
       TtaSetAttributeValue (attr, val, el, doc);
     }
   else
     /* its not a number. Delete attribute and send an error message */
     {
       if (attr)
         TtaRemoveAttribute (el, attr, doc);
       if (strlen (buffer) > MaxMsgLength - 30)
         buffer[MaxMsgLength - 30] = EOS;
       sprintf (msgBuffer, "Invalid attribute value \"%s\"", buffer);
       HTMLParseError (doc, msgBuffer);
     }
}
/*----------------------------------------------------------------------
   EndOfHTMLAttributeValue
   Filling of an HTML attribute value
  ----------------------------------------------------------------------*/
void EndOfHTMLAttributeValue (char *attrValue,
			      AttributeMapping *lastMappedAttr,
			      Attribute currentAttribute,
			      Element lastAttrElement,
			      ThotBool UnknownAttr,
			      ParserData *context,
			      ThotBool isXML)
{
  AttributeType   attrType, attrType1;
  Attribute       attr;
  ElementType	  elType;
  Element         child, root;
  Language        lang;
  char            translation;
  char            shape;
  char           *buffer;
  char           *attrName;
  char            msgBuffer[MaxMsgLength];
  int             val;
  int             length;
  int             attrKind;
  ThotBool        done = FALSE;
  ThotBool            loadcss;

  /* treatments of some particular HTML attributes */
  if (!strcmp (lastMappedAttr->XMLattribute, "style"))
    {
      TtaSetAttributeText (currentAttribute, attrValue,
			   lastAttrElement, context->doc);
      /* check if we have to load CSS */
      TtaGetEnvBoolean ("LOAD_CSS", &loadcss);
      if (loadcss)
	ParseHTMLSpecificStyle (context->lastElement, attrValue,
				context->doc, 100, FALSE);
      done = TRUE;
    }
  else
    {
      if (!strcmp (lastMappedAttr->XMLattribute, "link"))
	HTMLSetAlinkColor (context->doc, context->lastElement, attrValue);
      else if (!strcmp (lastMappedAttr->XMLattribute, "alink"))
	HTMLSetAactiveColor (context->doc, context->lastElement, attrValue);
      else if (!strcmp (lastMappedAttr->XMLattribute, "vlink"))
	HTMLSetAvisitedColor (context->doc, context->lastElement, attrValue);
    }

  if (!done)
    {
      val = 0;
      translation = lastMappedAttr->AttrOrContent;
      switch (translation)
	{
	case 'C':	/* Content */
	  child = PutInContent (attrValue, context);
	  if (child != NULL)
	    TtaAppendTextContent (child, "\" ", context->doc);
	  break;
	  
	case 'A':
	  if (currentAttribute != NULL)
	    {
	      TtaGiveAttributeType (currentAttribute, &attrType, &attrKind);
	      switch (attrKind)
		{
		case 0:	/* enumerate */
		  if (isXML)
		    MapHTMLAttributeValue (attrValue, attrType, &val);
		  else
		    val = MapAttrValue (lastMappedAttr->ThotAttribute,
					attrValue);
		  if (val < 0)
		    {
		      TtaGiveAttributeType (currentAttribute,
					    &attrType, &attrKind);
		      attrName = TtaGetAttributeName (attrType);
		      sprintf (msgBuffer,
			       "Invalid attribute value \"%s = %s\"",
			       attrName, attrValue);
		      if (isXML)
			XmlParseError (errorParsing, msgBuffer, 0);
		      else
			/* we are parsing an HTML file, not an XHTML file */
			{
			  /* generate an error message in the log */
			  HTMLParseError (context->doc, msgBuffer);
			  /* special case for value POLYGON of attribute 
			     shape (AREA element) */
			  if (attrType.AttrTypeNum == HTML_ATTR_shape &&
			      strcasecmp (attrValue, "POLYGON") == 0)
			    {
			      val = HTML_ATTR_shape_VAL_polygon;
			      /* interpret it as if it were "poly" */
			      TtaSetAttributeValue (currentAttribute, val,
					  lastAttrElement, context->doc);
			    }
			  else
			    /* remove the attribute and replace it by an */
			    /* Invalid_attribute (not for XHTML) */
			    {
			      TtaRemoveAttribute (lastAttrElement,
					      currentAttribute, context->doc);
			      attrType.AttrSSchema = 
				         TtaGetDocumentSSchema (context->doc);
			      attrType.AttrTypeNum =
			               pHTMLAttributeMapping[0].ThotAttribute;
			      sprintf (msgBuffer, "%s=%s", attrName,attrValue);
			      CreateHTMLAttribute (lastAttrElement, attrType,
					 msgBuffer, TRUE, context->doc,
					 &currentAttribute, &lastAttrElement);
			    }
			}
		    }
		  else
		    TtaSetAttributeValue (currentAttribute, val,
					  lastAttrElement, context->doc);
		  break;
		case 1:	/* integer */
		  if (attrType.AttrTypeNum == HTML_ATTR_Border &&
		      !strcasecmp (attrValue, "border"))
		    {
		      /* border="border" for a table */
		      val = 1;
		      TtaSetAttributeValue (currentAttribute, val,
					    lastAttrElement, context->doc);
		    }
		  else if (sscanf (attrValue, "%d", &val))
		    TtaSetAttributeValue (currentAttribute, val,
					  lastAttrElement, context->doc);
		  else
		    {
		      TtaRemoveAttribute (lastAttrElement, currentAttribute,
					  context->doc);
		      sprintf (msgBuffer,
			       "Unknown attribute value \"%s\"",
			       attrValue);
		      if (isXML)
			XmlParseError (errorParsing, msgBuffer, 0);
		      else
			HTMLParseError (context->doc, msgBuffer);
		    }
		  break;
		case 2:	/* text */
		  if (!UnknownAttr)
		    {
		      TtaSetAttributeText (currentAttribute, attrValue,
					   lastAttrElement, context->doc);
		      if (attrType.AttrTypeNum == HTML_ATTR_Language)
			{
			  /* it's a LANG attribute value */
			  lang = TtaGetLanguageIdFromName (attrValue);
			  if (lang < 0)
			    {
			      sprintf (msgBuffer,
				       "warning - unsupported language: %s",
				       attrValue);
			      if (isXML)
				XmlParseError (warningMessage, msgBuffer, 0);
			      else
				HTMLParseError (context->doc, msgBuffer);
			    }
			  else
			    {
			      /* change current language */
			      context->language = lang;
			      if (isXML)
				SetLanguagInXmlStack (lang);
			      else
				SetLanguagInHTMLStack (lang);
			    }
			  root = TtaGetRootElement (context->doc);
			  if (lastAttrElement == root)
			    /* it's a LANG attribute on the root element */
			    /* set the RealLang attribute */
			    {
			      attrType1.AttrSSchema = TtaGetDocumentSSchema (context->doc);
			      attrType1.AttrTypeNum = HTML_ATTR_RealLang;
			      /* this attribute could be already present,
				 (lang and xml:lang attributes) */
			      if (!TtaGetAttribute (lastAttrElement,
						    attrType1))
				/* it's not present. Add it */
				{
				  attr = TtaNewAttribute (attrType1);
				  TtaAttachAttribute (lastAttrElement,
						      attr, context->doc);
				  TtaSetAttributeValue (attr,
							HTML_ATTR_RealLang_VAL_Yes_,
							lastAttrElement,
							context->doc);
				}
			    }
			}
		      else if (attrType.AttrTypeNum == HTML_ATTR_accesskey)
			TtaAddAccessKey (context->doc, (unsigned int)attrValue[0],
					 lastAttrElement);
		    }
		  else
		    {
		      /* this is the content of an invalid attribute */
		      /* append it to the current Invalid_attribute */
		      if (!isXML)
			{
			  length = strlen (attrValue) + 2;
			  length += TtaGetTextAttributeLength (currentAttribute);
			  buffer = TtaGetMemory (length + 1);
			  TtaGiveTextAttributeValue (currentAttribute,
						     buffer, &length);
			  strcat (buffer, "=");
			  strcat (buffer, attrValue);
			  TtaSetAttributeText (currentAttribute, buffer,
					       lastAttrElement, context->doc);
			  TtaFreeMemory (buffer);
			}
		    }
		  break;
		case 3:	/* reference */
		  break;
		}
	    }
	  break;
	  
	case SPACE:
	  if (isXML)
	    XhtmlTypeAttrValue (attrValue, currentAttribute,
				lastAttrElement, context);
	  else
	    HTMLTypeAttrValue (attrValue, currentAttribute,
			       lastAttrElement, context);
	  break;
	  
	 default:
	   break;
	}

      if (lastMappedAttr->ThotAttribute == HTML_ATTR_Width__)
	/* HTML attribute "width" */
	{
	  /* if it's an Object element, wait until all attributes are handled,
	     especially the data attribute that may generate the image to
	     which the width has to be applied */
	  elType = TtaGetElementType (lastAttrElement);
	  if (elType.ElTypeNum != HTML_EL_Object)
	    /* create the corresponding attribute IntWidthPercent or */
	    /* IntWidthPxl */
	    CreateAttrWidthPercentPxl (attrValue, lastAttrElement,
				       context->doc, -1);
	}
      else if (lastMappedAttr->ThotAttribute == HTML_ATTR_Height_)
	/* HTML attribute "height" */
	{
	  /* if it's an Object element, wait until all attributes are handled,
	     especially the data attribute that may generate the image to
	     which the height has to be applied */
	  elType = TtaGetElementType (lastAttrElement);
	  if (elType.ElTypeNum != HTML_EL_Object)
	    /* create the corresponding attribute IntHeightPercent or */
	    /* IntHeightPxl */
	    CreateAttrHeightPercentPxl (attrValue, lastAttrElement,
					context->doc, -1);
	}
      else if (lastMappedAttr->ThotAttribute == HTML_ATTR_Area_Size)
	/* HTML attribute "size" for an element "input" */
	CreateAttrIntAreaSize (val, lastAttrElement, context->doc);
      else if (!strcmp (lastMappedAttr->XMLattribute, "size"))
	{
	  TtaGiveAttributeType (currentAttribute, &attrType, &attrKind);
	  if (attrType.AttrTypeNum == HTML_ATTR_Font_size)
	    CreateAttrIntSize (attrValue, lastAttrElement, context->doc);
	}
      else if (!strcmp (lastMappedAttr->XMLattribute, "shape"))
	{
	  child = TtaGetFirstChild (lastAttrElement);
	  if (child != NULL)
	    {
	      switch (val)
		{
		case HTML_ATTR_shape_VAL_rectangle:
		  shape = 'R';
		  break;
		case HTML_ATTR_shape_VAL_circle:
		  shape = 'a';
		  break;
		case HTML_ATTR_shape_VAL_polygon:
		  shape = 'p';
		  break;
		default:
		  shape = SPACE;
		  break;
		}
	      TtaSetGraphicsShape (child, shape, context->doc);
	    }
	}
      else if (!strcmp (lastMappedAttr->XMLattribute, "value"))
	{
	  elType = TtaGetElementType (lastAttrElement);
	  if (elType.ElTypeNum == HTML_EL_Text_Input ||
	      elType.ElTypeNum == HTML_EL_Password_Input ||
	      elType.ElTypeNum == HTML_EL_File_Input ||
	      elType.ElTypeNum == HTML_EL_Input)
	    /* create a Default_Value attribute with the same content */
	    {
	      attrType1.AttrSSchema = attrType.AttrSSchema;
	      attrType1.AttrTypeNum = HTML_ATTR_Default_Value;
	      attr = TtaNewAttribute (attrType1);
	      TtaAttachAttribute (lastAttrElement, attr, context->doc);
	      TtaSetAttributeText (attr, attrValue,
				   lastAttrElement, context->doc);
	    }
	}
      else
	{
	  /* Some HTML attributes are equivalent to a CSS property:      */
	  /*      background     ->                   background         */
	  /*      bgcolor        ->                   background         */
	  /*      text           ->                   color              */
	  /*      color          ->                   color              */
	  if (!strcmp (lastMappedAttr->XMLattribute, "background"))
	    {
	      if (strlen (attrValue) > MaxMsgLength - 30)
		attrValue[MaxMsgLength - 30] = EOS;
	      HTMLSetBackgroundImage (context->doc, context->lastElement,
				      REPEAT, attrValue, FALSE);
	    }
	  else if (!strcmp (lastMappedAttr->XMLattribute, "bgcolor"))
	    HTMLSetBackgroundColor (context->doc, context->lastElement,
				    attrValue);
	  else if (!strcmp (lastMappedAttr->XMLattribute, "text") ||
		   !strcmp (lastMappedAttr->XMLattribute, "color"))
	    HTMLSetForegroundColor (context->doc,
				    context->lastElement, attrValue);
	}
    }
}

/*----------------------------------------------------------------------
   MapHTMLAttributeValue
   Search in the Attribute Value Mapping Table the entry for the attribute
   ThotAtt and its value attVal. Returns the corresponding Thot value.
  ----------------------------------------------------------------------*/
void MapHTMLAttributeValue (char *attVal, AttributeType attrType, int *value)
{
  MapXMLAttributeValue (XHTML_TYPE, attVal, attrType, value);
}

Webmaster