/*
**      SWISH++
**      mod/html/elements.c
**
**      Copyright (C) 1998  Paul J. Lucas
**
**      This program is free software; you can redistribute it and/or modify
**      it under the terms of the GNU General Public License as published by
**      the Free Software Foundation; either version 2 of the License, or
**      (at your option) any later version.
**
**      This program is distributed in the hope that it will be useful,
**      but WITHOUT ANY WARRANTY; without even the implied warranty of
**      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**      GNU General Public License for more details.
**
**      You should have received a copy of the GNU General Public License
**      along with this program; if not, write to the Free Software
**      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#ifdef  MOD_html

// local
#include "elements.h"

//*****************************************************************************
//
// SYNOPSIS
//
        element_map::element_map()
//
// DESCRIPTION
//
//      Construct (initialize) an element_map.
//
// SEE ALSO
//
//      Shane McCarron, et al.  "XHTML 2.0," World Wide Web Consortium,
//      August 2002.
//          http://www.w3.org/TR/xhtml2/
//
//      Dave Raggett, Arnaud Le Hors, and Ian Jacobs.  "Index of Elements,"
//      HTML 4.0 Specification, World Wide Web Consortium, April 1998.
//          http://www.w3.org/TR/REC-html40/index/elements.html
//
//      Marcin Sawicki, et al.  "Ruby Annotation," World Wide Web Consortium,
//      April 6, 2001.
//          http://www.w3.org/TR/2001/PR-ruby-20010406/
//
//      Netscape Communications Corporation.  "HTML Tag Reference," January
//      1998.
//          http://developer.netscape.com/docs/manuals/htmlguid/index.htm
//
//*****************************************************************************
{
    typedef char const *const cpcc;
    //
    // Declare character pointers having values equal to element's end_tag_type
    // enum so that we can have a simple array of strings below where each
    // "row" has varying length.  It's kind of a hack, but it works.
    //
    cpcc F = reinterpret_cast< char const* >( element::et_forbidden );
    cpcc O = reinterpret_cast< char const* >( element::et_optional  );
    cpcc R = reinterpret_cast< char const* >( element::et_required  );

    //
    // Elements that have forbidden end tags (obviously) have no tags listed
    // for them in the rows below.
    //
    // Elements that have optional end tags have a null-terminated list of tags
    // that close them, either explicitly (their own end tag) or implicitly (a
    // tag from some other element).
    //
    // Elements that have required end tags simply list their single end tag.
    // Yes, it's easy, given a start tag, to know what it's end tag is (the
    // same tag, but with a leading '/'); however, the code in parse_html_tag()
    // in mod_html.c is made simpler by explicitly giving the end tag here
    // rather than having to construct a temporary string prepending a '/' to
    // the tag.
    //
    static char const *const end_tag_table[] = {

    //  element         end tag tags that close it  status
    //  ------------    ------- ------------------  ---------------
        "a",            R,      "/a",
        "abbr",         R,      "/abbr",
        "acronym",      R,      "/acronym",
        "address",      R,      "/address",
        "applet",       R,      "/applet",          // deprecated
        "area",         F,
        "b",            R,      "/b",
        "base",         F,
        "basefont",     F,                          // deprecated
        "bdo",          R,      "/bdo",
        "big",          R,      "/big",
        "blink",        R,      "/blink",           // nonstandard
        "blockquote",   R,      "/blockquote",
        "body",         O,      "/body", "/html", 0,
        "br",           F,
        "button",       R,      "/button",
        "caption",      R,      "/caption",
        "center",       R,      "/center",          // deprecated
        "cite",         R,      "/cite",
        "code",         R,      "/code",
        "col",          F,

        "colgroup",     O,      "colgroup", "/colgroup",
                                "tbody", "tfoot", "thead",
                                "tr",
                                "/table",
                                0,

        "dd",           O,      "dd", "/dd", "/dl", "dt", "/dt", 0,
        "del",          R,      "/del",
        "dfn",          R,      "/dfn",
        "dir",          R,      "/dir",             // deprecated
        "div",          R,      "/div",
        "dl",           R,      "/dl",
        "dt",           O,      "dt", "/dt", "/dl", 0,
        "em",           R,      "/em",
        "embed",        R,      "/embed",           // nonstandard
        "fieldset",     R,      "/fieldset",
        "font",         R,      "/font",            // deprecated
        "form",         R,      "/form",
        "frame",        F,
        "frameset",     R,      "/frameset",
        "h",            R,      "/h",               // XHTML 2.0
        "h1",           R,      "/h1",
        "h2",           R,      "/h2",
        "h3",           R,      "/h3",
        "h4",           R,      "/h4",
        "h5",           R,      "/h5",
        "h6",           R,      "/h6",
        "head",         O,      "body", "/body", "/head", "/html", 0,
        "hr",           F,
        "html",         O,      "/html", 0,
        "i",            R,      "/i",
        "iframe",       R,      "/iframe",
        "ilayer",       R,      "/ilayer",          // nonstandard
        "img",          F,
        "input",        F,
        "ins",          R,      "/ins",
        "isindex",      F,                          // deprecated
        "kbd",          R,      "/kbd",
        "keygen",       F,                          // nonstandard
        "label",        R,      "/label",
        "layer",        R,      "/layer",           // nonstandard
        "legend",       R,      "/legend",
        "li",           O,      "li", "/li", "/ol", "/ul", 0,
        "line",         R,      "/line",            // XHTML 2.0
        "link",         F,
        "map",          R,      "/map",
        "menu",         R,      "/menu",            // deprecated
        "meta",         F,
        "multicol",     R,      "/multicol",        // nonstandard
        "name",         R,      "/name",            // XHTML 2.0
        "nl",           R,      "/nl",              // XHTML 2.0
        "nobr",         F,                          // nonstandard
        "noembed",      R,      "/noembed",         // nonstandard
        "noframes",     R,      "/noframes",
        "nolayer",      R,      "/nolayer",         // nonstandard
        "noscript",     R,      "/noscript",
        "object",       R,      "/object",
        "ol",           R,      "/ol",
        "optgroup",     R,      "/optgroup",

        "option",       O,      "/optgroup",
                                "option", "/option",
                                "/select",
                                0,

        "p",            O,      "address", "/address",
                                "applet", "/applet",
                                "blockquote", "/blockquote",
                                "/body",
                                "br",
                                "caption", "/caption",
                                "center", "/center",
                                "dd", "/dd",
                                "div", "/div",
                                "dl", "/dl",
                                "dt", "/dt",
                                "embed", "/embed",
                                "form", "/form",
                                "frame", "/frame",
                                "frameset", "/frameset",
                                "h1", "/h1",
                                "h2", "/h2",
                                "h3", "/h3",
                                "h4", "/h4",
                                "h5", "/h5",
                                "h6", "/h6",
                                "hr",
                                "/html",
                                "layer", "/layer",
                                "li", "/li",
                                "map", "/map",
                                "multicol", "/multicol",
                                "noembed", "/noembed",
                                "noframes", "/noframes",
                                "nolayer", "/nolayer",
                                "noscript", "/noscript",
                                "object", "/object",
                                "ol", "/ol",
                                "p", "/p",
                                "plaintext",
                                "pre", "/pre",
                                "script", "/script",
                                "select", "/select",
                                "style", "/style",
                                "table", "/table",
                                "tbody", "/tbody"
                                "td", "/td",
                                "tfoot", "/tfoot"
                                "th", "/th",
                                "thead", "/thead"
                                "tr", "/tr",
                                "ul", "/ul",
                                "xmp", "/xmp",
                                0,

        "param",        F,
        "plaintext",    F,                          // deprecated
        "pre",          R,      "/pre",
        "q",            R,      "/q",               // deprecated
        "quote",        R,      "/quote",           // XHTML 2.0

        "ruby",         R,      "/ruby",            // ruby elements
        "rb",           R,      "/rb",
        "rbc",          R,      "/rbc",
        "rp",           R,      "/rp",
        "rt",           R,      "/rt",
        "rtc",          R,      "/rtc",

        "s",            R,      "/s",               // deprecated
        "samp",         R,      "/samp",
        "script",       R,      "/script",
        "section",      R,      "/section",         // XHTML 2.0
        "select",       R,      "/select",
        "server",       R,      "/server",          // nonstandard
        "small",        R,      "/small",
        "spacer",       F,                          // nonstandard
        "span",         R,      "/span",
        "strike",       R,      "/strike",          // deprecated
        "strong",       R,      "/strong",
        "style",        R,      "/style",
        "sub",          R,      "/sub",
        "sup",          R,      "/sup",
        "table",        R,      "/table",
        "tbody",        O,      "tbody", "/tbody", 0,

        "td",           O,      "tbody", "/tbody",
                                "td", "/td",
                                "tfoot", "/tfoot",
                                "th",
                                "/table",
                                "tr", "/tr",
                                0,

        "textarea",     R,      "/textarea",
        "tfoot",        O,      "tbody", "/tfoot", "thead", 0,

        "th",           O,      "tbody", "/tbody",
                                "td",
                                "tfoot", "/tfoot",
                                "th", "/th",
                                "/table",
                                "tr", "/tr",
                                0,

        "thead",        O,      "tbody", "tfoot", "/thead", 0,
        "title",        R,      "/title",

        "tr",           O,      "tbody", "/tbody",
                                "tfoot", "/tfoot",
                                "/thead",
                                "tr", "/tr",
                                "/table",
                                0,

        "tt",           R,      "/tt",
        "u",            R,      "/u",               // deprecated
        "ul",           R,      "/ul",
        "var",          R,      "/var",
        "wbr",          F,                          // nonstandard
        "xmp",          R,      "/xmp",             // deprecated

        0
    };

    for ( register char const *const *p = end_tag_table; *p; ++p ) {
        //
        // The ugly double, old-style casts below are necessary because C++ has
        // become overly pedantic about casting to enums.
        //
        element::end_tag_type const
            v = (element::end_tag_type const)(long const)(p[1]);
        element &e = insert( value_type( *p++, element( v ) ) ).first->second;

        switch ( v ) {

            case element::et_forbidden:
                // do nothing
                break;

            case element::et_optional:
                //
                // Elements that have optional end tags have a null-terminated
                // list of closing tags.
                //
                while ( *++p )
                    e.close_tags.insert( *p );
                break;

            case element::et_required:
                //
                // Elements that have required and tags have a single closing
                // tag.
                //
                e.close_tags.insert( *++p );
                break;
        }
    }
}

//*****************************************************************************
//
// SYNOPSIS
//
        element_map const& element_map::instance()
//
// DESCRIPTION
//
//      Define and initialize (exactly once) a static instance of element_map
//      and return a reference to it.  The reason for this function is to
//      guarantee that there is exactly one instance of it and that it is
//      initialized before its first use across all translation units,
//      something that would not guaranteed if it were defined and initialized
//      at file scope.
//
// RETURN VALUE
//
//      Returns a reference to a static instance of an initialized element_map.
//
// SEE ALSO
//
//      Margaret A. Ellis and Bjarne Stroustrup.  "The Annotated C++ Reference
//      Manual."  Addison-Wesley, Reading, MA, 1990.  p. 19.
//
//*****************************************************************************
{
    static element_map const m;
    return m;
}

#endif  /* MOD_html */
/* vim:set et sw=4 ts=4: */
