-----------------------------------------------------------------------
--  wiki-filters -- Wiki filters
--  Copyright (C) 2015, 2016 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------
with Ada.Strings.Wide_Wide_Unbounded;
with Ada.Finalization;

with Wiki.Attributes;
with Wiki.Documents;
with Wiki.Nodes;
with Wiki.Strings;

--  == Filters ==
--  The <b>Wiki.Filters</b> package provides a simple filter framework that allows to plug
--  specific filters when a wiki document is parsed and processed.  The <tt>Filter_Type</tt>
--  implements the <tt>Document_Reader</tt> interface to catch all the wiki document operations
--  and it forwards the different calls to a next wiki document instance.  A filter can do some
--  operations while calls are made so that it can:
--
--  * Get the text content and filter it by looking at forbidden words in some dictionary,
--  * Ignore some formatting construct (for example to forbid the use of links),
--  * Verify and do some corrections on HTML content embedded in wiki text,
--  * Expand some plugins, specific links to complex content.
--
--  To implement a new filter, the <tt>Filter_Type</tt> type must be used as a base type
--  and some of the operations have to be overriden.  The default <tt>Filter_Type</tt> operations
--  just propagate the call to the attached wiki document instance (ie, a kind of pass
--  through filter).
--
package Wiki.Filters is

   pragma Preelaborate;

   use Ada.Strings.Wide_Wide_Unbounded;

   --  ------------------------------
   --  Filter type
   --  ------------------------------
   type Filter_Type is new Ada.Finalization.Limited_Controlled with private;
   type Filter_Type_Access is access all Filter_Type'Class;

   --  Add a simple node such as N_LINE_BREAK, N_HORIZONTAL_RULE or N_PARAGRAPH to the document.
   procedure Add_Node (Filter    : in out Filter_Type;
                       Document  : in out Wiki.Nodes.Document;
                       Kind      : in Wiki.Nodes.Simple_Node_Kind);

   --  Add a text content with the given format to the document.
   procedure Add_Text (Filter    : in out Filter_Type;
                       Document  : in out Wiki.Nodes.Document;
                       Text      : in Wiki.Strings.WString;
                       Format    : in Wiki.Nodes.Format_Map);

   --  Add a section header with the given level in the document.
   procedure Add_Header (Filter    : in out Filter_Type;
                         Document  : in out Wiki.Nodes.Document;
                         Header    : in Wiki.Strings.WString;
                         Level     : in Natural);

   --  Push a HTML node with the given tag to the document.
   procedure Push_Node (Filter     : in out Filter_Type;
                        Document   : in out Wiki.Nodes.Document;
                        Tag        : in Wiki.Nodes.Html_Tag_Type;
                        Attributes : in out Wiki.Attributes.Attribute_List_Type);

   --  Pop a HTML node with the given tag.
   procedure Pop_Node (Filter   : in out Filter_Type;
                       Document : in out Wiki.Nodes.Document;
                       Tag      : in Wiki.Nodes.Html_Tag_Type);

   --  Add a blockquote (<blockquote>).  The level indicates the blockquote nested level.
   --  The blockquote must be closed at the next header.
   procedure Add_Blockquote (Document : in out Filter_Type;
                             Level    : in Natural);

   --  Add a list item (<li>).  Close the previous paragraph and list item if any.
   --  The list item will be closed at the next list item, next paragraph or next header.
   procedure Add_List_Item (Document : in out Filter_Type;
                            Level    : in Positive;
                            Ordered  : in Boolean);

   --  Add a link.
   procedure Add_Link (Filter     : in out Filter_Type;
                       Document   : in out Wiki.Nodes.Document;
                       Name       : in Wiki.Strings.WString;
                       Attributes : in out Wiki.Attributes.Attribute_List_Type);

   --  Add an image.
   procedure Add_Image (Filter     : in out Filter_Type;
                        Document   : in out Wiki.Nodes.Document;
                        Name       : in Wiki.Strings.WString;
                        Attributes : in out Wiki.Attributes.Attribute_List_Type);

   --  Add a quote.
   procedure Add_Quote (Document : in out Filter_Type;
                        Quote    : in Unbounded_Wide_Wide_String;
                        Link     : in Unbounded_Wide_Wide_String;
                        Language : in Unbounded_Wide_Wide_String);

   --  Add a text block that is pre-formatted.
   procedure Add_Preformatted (Document : in out Filter_Type;
                               Text     : in Unbounded_Wide_Wide_String;
                               Format   : in Unbounded_Wide_Wide_String);

   --  Finish the document after complete wiki text has been parsed.
   procedure Finish (Document : in out Filter_Type);

private

   type Filter_Type is new Ada.Finalization.Limited_Controlled with record
      Next     : Filter_Type_Access;
   end record;

end Wiki.Filters;

-----------------------------------------------------------------------
--  wiki-filters -- Wiki filters
--  Copyright (C) 2015, 2016 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------
with Ada.Strings.Wide_Wide_Unbounded;
with Ada.Finalization;

with Wiki.Attributes;
with Wiki.Documents;
with Wiki.Nodes;
with Wiki.Strings;

--  == Filters ==
--  The <b>Wiki.Filters</b> package provides a simple filter framework that allows to plug
--  specific filters when a wiki document is parsed and processed.  The <tt>Filter_Type</tt>
--  implements the <tt>Document_Reader</tt> interface to catch all the wiki document operations
--  and it forwards the different calls to a next wiki document instance.  A filter can do some
--  operations while calls are made so that it can:
--
--  * Get the text content and filter it by looking at forbidden words in some dictionary,
--  * Ignore some formatting construct (for example to forbid the use of links),
--  * Verify and do some corrections on HTML content embedded in wiki text,
--  * Expand some plugins, specific links to complex content.
--
--  To implement a new filter, the <tt>Filter_Type</tt> type must be used as a base type
--  and some of the operations have to be overriden.  The default <tt>Filter_Type</tt> operations
--  just propagate the call to the attached wiki document instance (ie, a kind of pass
--  through filter).
--
package Wiki.Filters is

   pragma Preelaborate;

   use Ada.Strings.Wide_Wide_Unbounded;

   --  ------------------------------
   --  Filter type
   --  ------------------------------
   type Filter_Type is new Ada.Finalization.Limited_Controlled with private;
   type Filter_Type_Access is access all Filter_Type'Class;

   --  Add a simple node such as N_LINE_BREAK, N_HORIZONTAL_RULE or N_PARAGRAPH to the document.
   procedure Add_Node (Filter    : in out Filter_Type;
                       Document  : in out Wiki.Nodes.Document;
                       Kind      : in Wiki.Nodes.Simple_Node_Kind);

   --  Add a text content with the given format to the document.
   procedure Add_Text (Filter    : in out Filter_Type;
                       Document  : in out Wiki.Nodes.Document;
                       Text      : in Wiki.Strings.WString;
                       Format    : in Wiki.Nodes.Format_Map);

   --  Add a section header with the given level in the document.
   procedure Add_Header (Filter    : in out Filter_Type;
                         Document  : in out Wiki.Nodes.Document;
                         Header    : in Wiki.Strings.WString;
                         Level     : in Natural);

   --  Push a HTML node with the given tag to the document.
   procedure Push_Node (Filter     : in out Filter_Type;
                        Document   : in out Wiki.Nodes.Document;
                        Tag        : in Wiki.Nodes.Html_Tag_Type;
                        Attributes : in out Wiki.Attributes.Attribute_List_Type);

   --  Pop a HTML node with the given tag.
   procedure Pop_Node (Filter   : in out Filter_Type;
                       Document : in out Wiki.Nodes.Document;
                       Tag      : in Wiki.Nodes.Html_Tag_Type);

   --  Add a blockquote (<blockquote>).  The level indicates the blockquote nested level.
   --  The blockquote must be closed at the next header.
   procedure Add_Blockquote (Document : in out Filter_Type;
                             Level    : in Natural);

   --  Add a list item (<li>).  Close the previous paragraph and list item if any.
   --  The list item will be closed at the next list item, next paragraph or next header.
   procedure Add_List_Item (Document : in out Filter_Type;
                            Level    : in Positive;
                            Ordered  : in Boolean);

   --  Add a link.
   procedure Add_Link (Filter     : in out Filter_Type;
                       Document   : in out Wiki.Nodes.Document;
                       Name       : in Wiki.Strings.WString;
                       Attributes : in out Wiki.Attributes.Attribute_List_Type);

   --  Add an image.
   procedure Add_Image (Filter     : in out Filter_Type;
                        Document   : in out Wiki.Nodes.Document;
                        Name       : in Wiki.Strings.WString;
                        Attributes : in out Wiki.Attributes.Attribute_List_Type);

   --  Add a quote.
   procedure Add_Quote (Filter     : in out Filter_Type;
                        Document   : in out Wiki.Nodes.Document;
                        Name       : in Wiki.Strings.WString;
                        Attributes : in out Wiki.Attributes.Attribute_List_Type);

   --  Add a text block that is pre-formatted.
   procedure Add_Preformatted (Document : in out Filter_Type;
                               Text     : in Unbounded_Wide_Wide_String;
                               Format   : in Unbounded_Wide_Wide_String);

   --  Finish the document after complete wiki text has been parsed.
   procedure Finish (Document : in out Filter_Type);

private

   type Filter_Type is new Ada.Finalization.Limited_Controlled with record
      Next     : Filter_Type_Access;
   end record;

end Wiki.Filters;

Update the Add_Quote procedure definition


-----------------------------------------------------------------------
--  wiki-parsers -- Wiki parser
--  Copyright (C) 2011, 2015, 2016 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

with Wiki.Attributes;
with Wiki.Plugins;
with Wiki.Filters;
with Wiki.Strings;
with Wiki.Documents;
with Wiki.Streams;

--  === Wiki Parsers ===
--  The Wikis.Parsers package implements a parser for several well known wiki formats
--  but also for HTML.  While reading the input, the parser populates a wiki <tt>Document</tt>
--  instance with headers, paragraphs, links, and other elements.
--
--     Engine : Wiki.Parsers.Parser;
--
--  Before using the parser, it must be configured to choose the syntax by using the
--  <tt>Set_Syntax</tt> procedure:
--
--    Engine.Set_Syntax (Wiki.SYNTAX_HTML);
--
--  The parser can be configured to use filters.  A filter is added by using the
--  <tt>Add_Filter</tt> procedure.  A filter is added at begining of the chain so that
--  the filter added last is called first.  The wiki <tt>Document</tt> is always built through
--  the filter chain so this allows filters to change or alter the content that was parsed.
--
--    Engine.Add_Filter (TOC'Unchecked_Access);
--    Engine.Add_Filter (Filter'Unchecked_Access);
--
--  The <tt>Parse</tt> procedure is then used to parse either a string content or some stream
--  represented by the <tt>Input_Stream</tt> interface.  After the <tt>Parse</tt> procedure
--  completes, the <tt>Document</tt> instance holds the wiki document.
--
--    Engine.Parse (Some_Text, Doc);
--
package Wiki.Parsers is

   pragma Preelaborate;

   type Parser is tagged limited private;

   --  Set the plugin factory to find and use plugins.
   procedure Set_Plugin_Factory (Engine  : in out Parser;
                                 Factory : in Wiki.Plugins.Plugin_Factory_Access);

   --  Set the wiki syntax that the wiki engine must use.
   procedure Set_Syntax (Engine : in out Parser;
                         Syntax : in Wiki_Syntax := SYNTAX_MIX);

   --  Add a filter in the wiki engine.
   procedure Add_Filter (Engine : in out Parser;
                         Filter : in Wiki.Filters.Filter_Type_Access);

   --  Set the plugin context.
   procedure Set_Context (Engine  : in out Parser;
                          Context : in Wiki.Plugins.Plugin_Context);

   --  Parse the wiki text contained in Text according to the wiki syntax
   --  defined on the parser.
   procedure Parse (Engine : in out Parser;
                    Text   : in Wiki.Strings.WString;
                    Doc    : in out Wiki.Documents.Document);

   --  Parse the wiki text contained in Text according to the wiki syntax
   --  defined on the parser.
   procedure Parse (Engine : in out Parser;
                    Text   : in Wiki.Strings.UString;
                    Doc    : in out Wiki.Documents.Document);

   --  Parse the wiki stream managed by <tt>Stream</tt> according to the wiki syntax configured
   --  on the wiki engine.
   procedure Parse (Engine : in out Parser;
                    Stream : in Wiki.Streams.Input_Stream_Access;
                    Doc    : in out Wiki.Documents.Document);

private

   type Parser_Handler is access procedure (P     : in out Parser;
                                            Token : in Wiki.Strings.WChar);

   type Parser_Table is array (0 .. 127) of Parser_Handler;
   type Parser_Table_Access is access constant Parser_Table;

   type Parser is tagged limited record
      Context             : Wiki.Plugins.Plugin_Context;
      Pending             : Wiki.Strings.WChar;
      Has_Pending         : Boolean;
      Previous_Syntax     : Wiki_Syntax;
      Table               : Parser_Table_Access;
      Document            : Wiki.Documents.Document;
      Format              : Wiki.Format_Map;
      Text                : Wiki.Strings.BString (512);
      Empty_Line          : Boolean := True;
      Is_Eof              : Boolean := False;
      In_Paragraph        : Boolean := False;
      In_List             : Boolean := False;
      Need_Paragraph      : Boolean := True;
      Link_Double_Bracket : Boolean := False;
      Link_No_Space       : Boolean := False;
      Is_Dotclear         : Boolean := False;
      Link_Title_First    : Boolean := False;
      Check_Image_Link    : Boolean := False;
      Is_Hidden           : Boolean := False;
      Header_Offset       : Integer := 0;
      Quote_Level         : Natural := 0;
      Escape_Char         : Wiki.Strings.WChar;
      Param_Char          : Wiki.Strings.WChar;
      List_Level          : Natural := 0;
      Reader              : Wiki.Streams.Input_Stream_Access := null;
      Attributes          : Wiki.Attributes.Attribute_List;
   end record;

   --  Peek the next character from the wiki text buffer.
   procedure Peek (P     : in out Parser;
                   Token : out Wiki.Strings.WChar);

   --  Put back the character so that it will be returned by the next call to Peek.
   procedure Put_Back (P     : in out Parser;
                       Token : in Wiki.Strings.WChar);

   --  Skip all the spaces and tabs as well as end of the current line (CR+LF).
   procedure Skip_End_Of_Line (P : in out Parser);

   --  Skip white spaces and tabs.
   procedure Skip_Spaces (P : in out Parser);

   --  Flush the wiki text that was collected in the text buffer.
   procedure Flush_Text (P : in out Parser);

   --  Flush the wiki dl/dt/dd definition list.
   procedure Flush_List (P : in out Parser);

   --  Append a character to the wiki text buffer.
   procedure Parse_Text (P     : in out Parser;
                         Token : in Wiki.Strings.WChar);

   --  Check if the link refers to an image and must be rendered as an image.
   function Is_Image (P    : in Parser;
                      Link : in Wiki.Strings.WString) return Boolean;

   --  Find the plugin with the given name.
   --  Returns null if there is no such plugin.
   function Find (P    : in Parser;
                  Name : in Wiki.Strings.WString) return Wiki.Plugins.Wiki_Plugin_Access;

   type String_Array is array (Positive range <>) of Wiki.String_Access;

   --  Extract a list of parameters separated by the given separator (ex: '|').
   procedure Parse_Parameters (P          : in out Parser;
                               Separator  : in Wiki.Strings.WChar;
                               Terminator : in Wiki.Strings.WChar;
                               Names      : in String_Array;
                               Max        : in Positive := 200);

   procedure Start_Element (P          : in out Parser;
                            Tag        : in Wiki.Html_Tag;
                            Attributes : in out Wiki.Attributes.Attribute_List);

   procedure End_Element (P    : in out Parser;
                          Tag  : in Wiki.Html_Tag);

   procedure Parse_Token (P     : in out Parser);

end Wiki.Parsers;

-----------------------------------------------------------------------
--  wiki-parsers -- Wiki parser
--  Copyright (C) 2011, 2015, 2016 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

with Wiki.Attributes;
with Wiki.Plugins;
with Wiki.Filters;
with Wiki.Strings;
with Wiki.Documents;
with Wiki.Streams;

--  === Wiki Parsers ===
--  The Wikis.Parsers package implements a parser for several well known wiki formats
--  but also for HTML.  While reading the input, the parser populates a wiki <tt>Document</tt>
--  instance with headers, paragraphs, links, and other elements.
--
--     Engine : Wiki.Parsers.Parser;
--
--  Before using the parser, it must be configured to choose the syntax by using the
--  <tt>Set_Syntax</tt> procedure:
--
--    Engine.Set_Syntax (Wiki.SYNTAX_HTML);
--
--  The parser can be configured to use filters.  A filter is added by using the
--  <tt>Add_Filter</tt> procedure.  A filter is added at begining of the chain so that
--  the filter added last is called first.  The wiki <tt>Document</tt> is always built through
--  the filter chain so this allows filters to change or alter the content that was parsed.
--
--    Engine.Add_Filter (TOC'Unchecked_Access);
--    Engine.Add_Filter (Filter'Unchecked_Access);
--
--  The <tt>Parse</tt> procedure is then used to parse either a string content or some stream
--  represented by the <tt>Input_Stream</tt> interface.  After the <tt>Parse</tt> procedure
--  completes, the <tt>Document</tt> instance holds the wiki document.
--
--    Engine.Parse (Some_Text, Doc);
--
package Wiki.Parsers is

   pragma Preelaborate;

   type Parser is tagged limited private;

   --  Set the plugin factory to find and use plugins.
   procedure Set_Plugin_Factory (Engine  : in out Parser;
                                 Factory : in Wiki.Plugins.Plugin_Factory_Access);

   --  Set the wiki syntax that the wiki engine must use.
   procedure Set_Syntax (Engine : in out Parser;
                         Syntax : in Wiki_Syntax := SYNTAX_MIX);

   --  Add a filter in the wiki engine.
   procedure Add_Filter (Engine : in out Parser;
                         Filter : in Wiki.Filters.Filter_Type_Access);

   --  Set the plugin context.
   procedure Set_Context (Engine  : in out Parser;
                          Context : in Wiki.Plugins.Plugin_Context);

   --  Parse the wiki text contained in Text according to the wiki syntax
   --  defined on the parser.
   procedure Parse (Engine : in out Parser;
                    Text   : in Wiki.Strings.WString;
                    Doc    : in out Wiki.Documents.Document);

   --  Parse the wiki text contained in Text according to the wiki syntax
   --  defined on the parser.
   procedure Parse (Engine : in out Parser;
                    Text   : in Wiki.Strings.UString;
                    Doc    : in out Wiki.Documents.Document);

   --  Parse the wiki stream managed by <tt>Stream</tt> according to the wiki syntax configured
   --  on the wiki engine.
   procedure Parse (Engine : in out Parser;
                    Stream : in Wiki.Streams.Input_Stream_Access;
                    Doc    : in out Wiki.Documents.Document);

private

   type Parser_Handler is access procedure (P     : in out Parser;
                                            Token : in Wiki.Strings.WChar);

   type Parser_Table is array (0 .. 127) of Parser_Handler;
   type Parser_Table_Access is access constant Parser_Table;

   type Parser is tagged limited record
      Context             : Wiki.Plugins.Plugin_Context;
      Pending             : Wiki.Strings.WChar;
      Has_Pending         : Boolean;
      Previous_Syntax     : Wiki_Syntax;
      Table               : Parser_Table_Access;
      Document            : Wiki.Documents.Document;
      Format              : Wiki.Format_Map;
      Text                : Wiki.Strings.BString (512);
      Empty_Line          : Boolean := True;
      Is_Eof              : Boolean := False;
      In_Paragraph        : Boolean := False;
      In_List             : Boolean := False;
      Need_Paragraph      : Boolean := True;
      Link_Double_Bracket : Boolean := False;
      Link_No_Space       : Boolean := False;
      Is_Dotclear         : Boolean := False;
      Link_Title_First    : Boolean := False;
      Check_Image_Link    : Boolean := False;
      Is_Hidden           : Boolean := False;
      Header_Offset       : Integer := 0;
      Quote_Level         : Natural := 0;
      Escape_Char         : Wiki.Strings.WChar;
      Param_Char          : Wiki.Strings.WChar;
      List_Level          : Natural := 0;
      Reader              : Wiki.Streams.Input_Stream_Access := null;
      Attributes          : Wiki.Attributes.Attribute_List;
   end record;

   --  Peek the next character from the wiki text buffer.
   procedure Peek (P     : in out Parser;
                   Token : out Wiki.Strings.WChar);

   --  Put back the character so that it will be returned by the next call to Peek.
   procedure Put_Back (P     : in out Parser;
                       Token : in Wiki.Strings.WChar);

   --  Skip all the spaces and tabs as well as end of the current line (CR+LF).
   procedure Skip_End_Of_Line (P : in out Parser);

   --  Skip white spaces and tabs.
   procedure Skip_Spaces (P : in out Parser);

   --  Flush the wiki text that was collected in the text buffer.
   procedure Flush_Text (P : in out Parser);

   --  Flush the wiki dl/dt/dd definition list.
   procedure Flush_List (P : in out Parser);

   --  Append a character to the wiki text buffer.
   procedure Parse_Text (P     : in out Parser;
                         Token : in Wiki.Strings.WChar);

   --  Check if the link refers to an image and must be rendered as an image.
   --  Returns a positive index of the start the the image link.
   function Is_Image (P    : in Parser;
                      Link : in Wiki.Strings.WString) return Natural;

   --  Find the plugin with the given name.
   --  Returns null if there is no such plugin.
   function Find (P    : in Parser;
                  Name : in Wiki.Strings.WString) return Wiki.Plugins.Wiki_Plugin_Access;

   type String_Array is array (Positive range <>) of Wiki.String_Access;

   --  Extract a list of parameters separated by the given separator (ex: '|').
   procedure Parse_Parameters (P          : in out Parser;
                               Separator  : in Wiki.Strings.WChar;
                               Terminator : in Wiki.Strings.WChar;
                               Names      : in String_Array;
                               Max        : in Positive := 200);

   procedure Start_Element (P          : in out Parser;
                            Tag        : in Wiki.Html_Tag;
                            Attributes : in out Wiki.Attributes.Attribute_List);

   procedure End_Element (P    : in out Parser;
                          Tag  : in Wiki.Html_Tag);

   procedure Parse_Token (P     : in out Parser);

end Wiki.Parsers;

Change Is_Image to return the image start position offset


-----------------------------------------------------------------------
--  ado-datasets -- Datasets
--  Copyright (C) 2013, 2014 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------
with Util.Beans.Objects.Time;

with ADO.Schemas;
with ADO.Statements;

package body ADO.Datasets is

   --  ------------------------------
   --  Execute the SQL query on the database session and populate the dataset.
   --  The column names are used to setup the dataset row bean definition.
   --  ------------------------------
   procedure List (Into    : in out Dataset;
                   Session : in out ADO.Sessions.Session'Class;
                   Query   : in ADO.Queries.Context'Class) is
      procedure Fill (Data : in out Util.Beans.Objects.Datasets.Object_Array);

      Stmt : ADO.Statements.Query_Statement := Session.Create_Statement (Query);

      procedure Fill (Data : in out Util.Beans.Objects.Datasets.Object_Array) is
         use ADO.Schemas;
      begin
         for I in Data'Range loop
            case Stmt.Get_Column_Type (I - 1) is
               --  Boolean column
               when T_BOOLEAN =>
                  Data (I) := Util.Beans.Objects.To_Object (Stmt.Get_Boolean (I - 1));

               when T_TINYINT | T_SMALLINT | T_INTEGER | T_LONG_INTEGER | T_YEAR =>
                  Data (I) := Util.Beans.Objects.To_Object (Stmt.Get_Integer (I - 1));

               when T_FLOAT | T_DOUBLE | T_DECIMAL =>
                  Data (I) := Util.Beans.Objects.Null_Object;

               when T_ENUM =>
                  Data (I) := Util.Beans.Objects.To_Object (Stmt.Get_String (I - 1));

               when T_TIME | T_DATE | T_DATE_TIME | T_TIMESTAMP =>
                  Data (I) := Util.Beans.Objects.Time.To_Object (Stmt.Get_Time (I - 1));

               when T_CHAR | T_VARCHAR =>
                  Data (I) := Util.Beans.Objects.To_Object (Stmt.Get_String (I - 1));

               when T_BLOB =>
                  Data (I) := Util.Beans.Objects.Null_Object;

               when T_SET | T_UNKNOWN | T_NULL =>
                  Data (I) := Util.Beans.Objects.Null_Object;

            end case;
         end loop;
      end Fill;

   begin
      Stmt.Execute;
      Into.Clear;
      if Stmt.Has_Elements then
         for I in 1 .. Stmt.Get_Column_Count loop
            Into.Add_Column (Stmt.Get_Column_Name (I - 1));
         end loop;
         while Stmt.Has_Elements loop
            Into.Append (Fill'Access);
            Stmt.Next;
         end loop;
      end if;
   end List;

   --  ------------------------------
   --  Get the number of items in a list by executing an SQL query.
   --  ------------------------------
   function Get_Count (Session : in ADO.Sessions.Session'Class;
                       Query   : in ADO.Queries.Context'Class) return Natural is
      Stmt : ADO.Statements.Query_Statement := Session.Create_Statement (Query);
   begin
      Stmt.Execute;
      return Stmt.Get_Result_Integer;
   end Get_Count;

end ADO.Datasets;

-----------------------------------------------------------------------
--  ado-datasets -- Datasets
--  Copyright (C) 2013, 2014, 2018 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------
with Util.Beans.Objects.Time;

with ADO.Schemas;
with ADO.Statements;

package body ADO.Datasets is

   --  ------------------------------
   --  Execute the SQL query on the database session and populate the dataset.
   --  The column names are used to setup the dataset row bean definition.
   --  ------------------------------
   procedure List (Into    : in out Dataset;
                   Session : in out ADO.Sessions.Session'Class;
                   Query   : in ADO.Queries.Context'Class) is
      procedure Fill (Data : in out Util.Beans.Objects.Datasets.Object_Array);

      Stmt : ADO.Statements.Query_Statement := Session.Create_Statement (Query);

      procedure Fill (Data : in out Util.Beans.Objects.Datasets.Object_Array) is
         use ADO.Schemas;
      begin
         for I in Data'Range loop
            if Stmt.Is_Null (I - 1) then
               Data (I) := Util.Beans.Objects.Null_Object;
            else
               case Stmt.Get_Column_Type (I - 1) is
                  --  Boolean column
               when T_BOOLEAN =>
                  Data (I) := Util.Beans.Objects.To_Object (Stmt.Get_Boolean (I - 1));

               when T_TINYINT | T_SMALLINT | T_INTEGER | T_LONG_INTEGER | T_YEAR =>
                  Data (I) := Util.Beans.Objects.To_Object (Stmt.Get_Integer (I - 1));

               when T_FLOAT | T_DOUBLE | T_DECIMAL =>
                  Data (I) := Util.Beans.Objects.Null_Object;

               when T_ENUM =>
                  Data (I) := Util.Beans.Objects.To_Object (Stmt.Get_String (I - 1));

               when T_TIME | T_DATE | T_DATE_TIME | T_TIMESTAMP =>
                  Data (I) := Util.Beans.Objects.Time.To_Object (Stmt.Get_Time (I - 1));

               when T_CHAR | T_VARCHAR =>
                  Data (I) := Util.Beans.Objects.To_Object (Stmt.Get_String (I - 1));

               when T_BLOB =>
                  Data (I) := Util.Beans.Objects.Null_Object;

               when T_SET | T_UNKNOWN | T_NULL =>
                  Data (I) := Util.Beans.Objects.Null_Object;

               end case;
            end if;
         end loop;
      end Fill;

   begin
      Stmt.Execute;
      Into.Clear;
      if Stmt.Has_Elements then
         for I in 1 .. Stmt.Get_Column_Count loop
            Into.Add_Column (Stmt.Get_Column_Name (I - 1));
         end loop;
         while Stmt.Has_Elements loop
            Into.Append (Fill'Access);
            Stmt.Next;
         end loop;
      end if;
   end List;

   --  ------------------------------
   --  Get the number of items in a list by executing an SQL query.
   --  ------------------------------
   function Get_Count (Session : in ADO.Sessions.Session'Class;
                       Query   : in ADO.Queries.Context'Class) return Natural is
      Stmt : ADO.Statements.Query_Statement := Session.Create_Statement (Query);
   begin
      Stmt.Execute;
      return Stmt.Get_Result_Integer;
   end Get_Count;

end ADO.Datasets;

Check for a NULL column and set the value to a Null_Object


-----------------------------------------------------------------------
--  gen-commands-docs -- Extract and generate documentation for the project
--  Copyright (C) 2012 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

with GNAT.Command_Line;

with Ada.Text_IO;

with Gen.Artifacts.Docs;
with Gen.Model.Packages;
package body Gen.Commands.Docs is

   use GNAT.Command_Line;

   --  ------------------------------
   --  Execute the command with the arguments.
   --  ------------------------------
   procedure Execute (Cmd       : in Command;
                      Generator : in out Gen.Generator.Handler) is
      pragma Unreferenced (Cmd);

      Doc : Gen.Artifacts.Docs.Artifact;
      M   : Gen.Model.Packages.Model_Definition;
   begin
      Generator.Read_Project ("dynamo.xml", False);

      --  Setup the target directory where the distribution is created.
      declare
         Target_Dir : constant String := Get_Argument;
      begin
         if Target_Dir'Length = 0 then
            Generator.Error ("Missing target directory");
            return;
         end if;
         Generator.Set_Result_Directory (Target_Dir);
      end;
--
--        --  Read the package description.
--        declare
--           Package_File : constant String := Get_Argument;
--        begin
--           if Package_File'Length > 0 then
--              Gen.Generator.Read_Package (Generator, Package_File);
--           else
--              Gen.Generator.Read_Package (Generator, "package.xml");
--           end if;
--        end;

      Doc.Prepare (M, Generator);
--        --  Run the generation.
--        Gen.Generator.Prepare (Generator);
--        Gen.Generator.Generate_All (Generator);
--        Gen.Generator.Finish (Generator);
   end Execute;

   --  ------------------------------
   --  Write the help associated with the command.
   --  ------------------------------
   procedure Help (Cmd       : in Command;
                   Generator : in out Gen.Generator.Handler) is
      pragma Unreferenced (Cmd, Generator);
      use Ada.Text_IO;
   begin
      Put_Line ("build-doc: Extract and generate the project documentation");
      Put_Line ("Usage: build-doc");
      New_Line;
      Put_Line ("  Extract the documentation from the project source files and generate the");
      Put_Line ("  project documentation.  The following files are scanned:");
      Put_Line ("    - Ada specifications (src/*.ads)");
      Put_Line ("    - XML configuration files (config/*.xml)");
      Put_Line ("    - XML database model files (db/*.xml)");
   end Help;

end Gen.Commands.Docs;

-----------------------------------------------------------------------
--  gen-commands-docs -- Extract and generate documentation for the project
--  Copyright (C) 2012 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

with GNAT.Command_Line;

with Ada.Text_IO;

with Gen.Artifacts.Docs;
with Gen.Model.Packages;
package body Gen.Commands.Docs is

   use GNAT.Command_Line;

   --  ------------------------------
   --  Execute the command with the arguments.
   --  ------------------------------
   procedure Execute (Cmd       : in Command;
                      Generator : in out Gen.Generator.Handler) is
      pragma Unreferenced (Cmd);

      Doc : Gen.Artifacts.Docs.Artifact;
      M   : Gen.Model.Packages.Model_Definition;
   begin
      Generator.Read_Project ("dynamo.xml", False);

      --  Setup the target directory where the distribution is created.
      declare
         Target_Dir : constant String := Get_Argument;
      begin
         if Target_Dir'Length = 0 then
            Generator.Error ("Missing target directory");
            return;
         end if;
         Generator.Set_Result_Directory (Target_Dir);
      end;

      Doc.Prepare (M, Generator);
   end Execute;

   --  ------------------------------
   --  Write the help associated with the command.
   --  ------------------------------
   procedure Help (Cmd       : in Command;
                   Generator : in out Gen.Generator.Handler) is
      pragma Unreferenced (Cmd, Generator);
      use Ada.Text_IO;
   begin
      Put_Line ("build-doc: Extract and generate the project documentation");
      Put_Line ("Usage: build-doc");
      New_Line;
      Put_Line ("  Extract the documentation from the project source files and generate the");
      Put_Line ("  project documentation.  The following files are scanned:");
      Put_Line ("    - Ada specifications (src/*.ads)");
      Put_Line ("    - XML configuration files (config/*.xml)");
      Put_Line ("    - XML database model files (db/*.xml)");
   end Help;

end Gen.Commands.Docs;

Remove unused commented code

Remove unused commented code


-----------------------------------------------------------------------
--  EL.Expressions -- Expression Nodes
--  Copyright (C) 2009, 2010, 2011, 2012, 2013, 2020 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

--  The 'ELNode' describes an expression that can later be evaluated
--  on an expression context.  Expressions are parsed and translated
--  to a read-only tree.

with EL.Functions;
with Ada.Strings.Wide_Wide_Unbounded;
with Ada.Strings.Unbounded;
with Util.Concurrent.Counters;
private package EL.Expressions.Nodes is

   pragma Preelaborate;

   use EL.Functions;
   use Ada.Strings.Wide_Wide_Unbounded;
   use Ada.Strings.Unbounded;

   type Reduction;

   type ELNode is abstract tagged limited record
      Ref_Counter : Util.Concurrent.Counters.Counter;
   end record;

   type ELNode_Access is access all ELNode'Class;

   type Reduction is record
      Node  : ELNode_Access;
      Value : EL.Objects.Object;
   end record;

   --  Evaluate a node on a given context.  If
   function Get_Safe_Value (Expr    : in ELNode;
                            Context : in ELContext'Class) return Object;

   --  Evaluate a node on a given context.
   function Get_Value (Expr    : in ELNode;
                       Context : in ELContext'Class) return Object is abstract;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   function Reduce (Expr    : access ELNode;
                    Context : in ELContext'Class) return Reduction is abstract;

   --  Delete the expression tree (calls Delete (ELNode_Access) recursively).
   procedure Delete (Node : in out ELNode) is abstract;

   --  Delete the expression tree.  Free the memory allocated by nodes
   --  of the expression tree.  Clears the node pointer.
   procedure Delete (Node : in out ELNode_Access);

   --  ------------------------------
   --  Unary expression node
   --  ------------------------------
   type ELUnary is new ELNode with private;

   type Unary_Node is (EL_VOID, EL_NOT, EL_MINUS, EL_EMPTY);

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELUnary;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELUnary;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELUnary);

   --  ------------------------------
   --  Binary expression node
   --  ------------------------------
   type ELBinary is new ELNode with private;
   type Binary_Node is (EL_EQ, EL_NE, EL_LE, EL_LT, EL_GE, EL_GT,
                        EL_ADD, EL_SUB, EL_MUL, EL_DIV, EL_MOD,
                        EL_AND, EL_OR, EL_LAND, EL_LOR, EL_CONCAT);

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELBinary;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELBinary;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELBinary);

   --  ------------------------------
   --  Ternary expression node
   --  ------------------------------
   type ELTernary is new ELNode with private;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELTernary;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELTernary;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELTernary);

   --  ------------------------------
   --  Variable to be looked at in the expression context
   --  ------------------------------
   type ELVariable is new ELNode with private;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELVariable;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELVariable;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELVariable);

   --  ------------------------------
   --  Value property referring to a variable
   --  ------------------------------
   type ELValue (Len : Natural) is new ELNode with private;
   type ELValue_Access is access all ELValue'Class;

   --  Check if the target bean is a readonly bean.
   function Is_Readonly (Node    : in ELValue;
                         Context : in ELContext'Class) return Boolean;

   --  Get the variable name.
   function Get_Variable_Name (Node : in ELValue) return String;

   --  Evaluate the node and return a method info with
   --  the bean object and the method binding.
   function Get_Method_Info (Node    : in ELValue;
                             Context : in ELContext'Class) return Method_Info;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELValue;
                       Context : ELContext'Class) return Object;

   --  Evaluate the node and set the value on the associated bean.
   --  Raises Invalid_Variable if the target object is not a bean.
   --  Raises Invalid_Expression if the target bean is not writeable.
   procedure Set_Value (Node    : in ELValue;
                        Context : in ELContext'Class;
                        Value   : in Objects.Object);

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELValue;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELValue);

   --  ------------------------------
   --  Literal object (integer, boolean, float, string)
   --  ------------------------------
   type ELObject is new ELNode with private;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELObject;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELObject;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELObject);

   --  ------------------------------
   --  Function call with up to 4 arguments
   --  ------------------------------
   type ELFunction is new ELNode with private;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELFunction;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELFunction;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELFunction);

   --  Create constant nodes
   function Create_Node (Value : Boolean) return ELNode_Access;
   function Create_Node (Value : Long_Long_Integer) return ELNode_Access;
   function Create_Node (Value : String) return ELNode_Access;
   function Create_Node (Value : Wide_Wide_String) return ELNode_Access;
   function Create_Node (Value : Long_Float) return ELNode_Access;
   function Create_Node (Value : Unbounded_Wide_Wide_String) return ELNode_Access;
   function Create_Variable (Name : in Wide_Wide_String) return ELNode_Access;
   function Create_Value (Variable : in ELNode_Access;
                          Name     : in Wide_Wide_String) return ELNode_Access;

   --  Create unary expressions
   function Create_Node (Of_Type : Unary_Node;
                         Expr    : ELNode_Access) return ELNode_Access;

   --  Create binary expressions
   function Create_Node (Of_Type : Binary_Node;
                         Left    : ELNode_Access;
                         Right   : ELNode_Access) return ELNode_Access;

   --  Create a ternary expression.
   function Create_Node (Cond  : ELNode_Access;
                         Left  : ELNode_Access;
                         Right : ELNode_Access) return ELNode_Access;

   --  Create a function call
   function Create_Node (Func  : EL.Functions.Function_Access;
                         Arg1  : ELNode_Access) return ELNode_Access;

   --  Create a function call
   function Create_Node (Func  : EL.Functions.Function_Access;
                         Arg1  : ELNode_Access;
                         Arg2  : ELNode_Access) return ELNode_Access;

   --  Create a function call
   function Create_Node (Func  : EL.Functions.Function_Access;
                         Arg1  : ELNode_Access;
                         Arg2  : ELNode_Access;
                         Arg3  : ELNode_Access) return ELNode_Access;

   --  Create a function call
   function Create_Node (Func  : EL.Functions.Function_Access;
                         Arg1  : ELNode_Access;
                         Arg2  : ELNode_Access;
                         Arg3  : ELNode_Access;
                         Arg4  : ELNode_Access) return ELNode_Access;

private

   type ELUnary is new ELNode with record
      Kind : Unary_Node;
      Node : ELNode_Access;
   end record;

   --  ------------------------------
   --  Binary nodes
   --  ------------------------------

   type ELBinary is new ELNode with record
      Kind  : Binary_Node;
      Left  : ELNode_Access;
      Right : ELNode_Access;
   end record;

   --  ------------------------------
   --  Ternary expression
   --  ------------------------------
   type ELTernary is new ELNode with record
      Cond  : ELNode_Access;
      Left  : ELNode_Access;
      Right : ELNode_Access;
   end record;

   --  #{bean.name}   - Bean name, Bean property
   --  #{bean[12]}    - Bean name,

   --  Variable to be looked at in the expression context
   type ELVariable is new ELNode with record
      Name     : Unbounded_String;
   end record;
   type ELVariable_Access is access all ELVariable;

   type ELValue (Len : Natural) is new ELNode with record
      Variable : ELNode_Access;
      Name     : String (1 .. Len);
   end record;

   --  A literal object (integer, boolean, float, String)
   type ELObject is new ELNode with record
      Value : Object;
   end record;

   --  A function call with up to 4 arguments.
   type ELFunction is new ELNode with record
      Func : EL.Functions.Function_Access;
      Arg1 : ELNode_Access;
      Arg2 : ELNode_Access;
      Arg3 : ELNode_Access;
      Arg4 : ELNode_Access;
   end record;

end EL.Expressions.Nodes;

-----------------------------------------------------------------------
--  el-expressions-nodes -- Expression Nodes
--  Copyright (C) 2009, 2010, 2011, 2012, 2013, 2020, 2021 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

--  The 'ELNode' describes an expression that can later be evaluated
--  on an expression context.  Expressions are parsed and translated
--  to a read-only tree.

with EL.Functions;
with Ada.Strings.Wide_Wide_Unbounded;
private with Ada.Strings.Unbounded;
with Util.Concurrent.Counters;
private package EL.Expressions.Nodes is

   pragma Preelaborate;

   use EL.Functions;
   use Ada.Strings.Wide_Wide_Unbounded;
   use Ada.Strings.Unbounded;

   type Reduction;

   type ELNode is abstract tagged limited record
      Ref_Counter : Util.Concurrent.Counters.Counter;
   end record;

   type ELNode_Access is access all ELNode'Class;

   type Reduction is record
      Node  : ELNode_Access;
      Value : EL.Objects.Object;
   end record;

   --  Evaluate a node on a given context.  If
   function Get_Safe_Value (Expr    : in ELNode;
                            Context : in ELContext'Class) return Object;

   --  Evaluate a node on a given context.
   function Get_Value (Expr    : in ELNode;
                       Context : in ELContext'Class) return Object is abstract;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   function Reduce (Expr    : access ELNode;
                    Context : in ELContext'Class) return Reduction is abstract;

   --  Delete the expression tree (calls Delete (ELNode_Access) recursively).
   procedure Delete (Node : in out ELNode) is abstract;

   --  Delete the expression tree.  Free the memory allocated by nodes
   --  of the expression tree.  Clears the node pointer.
   procedure Delete (Node : in out ELNode_Access);

   --  ------------------------------
   --  Unary expression node
   --  ------------------------------
   type ELUnary is new ELNode with private;

   type Unary_Node is (EL_VOID, EL_NOT, EL_MINUS, EL_EMPTY);

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELUnary;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELUnary;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELUnary);

   --  ------------------------------
   --  Binary expression node
   --  ------------------------------
   type ELBinary is new ELNode with private;
   type Binary_Node is (EL_EQ, EL_NE, EL_LE, EL_LT, EL_GE, EL_GT,
                        EL_ADD, EL_SUB, EL_MUL, EL_DIV, EL_MOD,
                        EL_AND, EL_OR, EL_LAND, EL_LOR, EL_CONCAT);

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELBinary;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELBinary;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELBinary);

   --  ------------------------------
   --  Ternary expression node
   --  ------------------------------
   type ELTernary is new ELNode with private;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELTernary;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELTernary;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELTernary);

   --  ------------------------------
   --  Variable to be looked at in the expression context
   --  ------------------------------
   type ELVariable is new ELNode with private;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELVariable;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELVariable;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELVariable);

   --  ------------------------------
   --  Value property referring to a variable
   --  ------------------------------
   type ELValue (Len : Natural) is new ELNode with private;
   type ELValue_Access is access all ELValue'Class;

   --  Check if the target bean is a readonly bean.
   function Is_Readonly (Node    : in ELValue;
                         Context : in ELContext'Class) return Boolean;

   --  Get the variable name.
   function Get_Variable_Name (Node : in ELValue) return String;

   --  Evaluate the node and return a method info with
   --  the bean object and the method binding.
   function Get_Method_Info (Node    : in ELValue;
                             Context : in ELContext'Class) return Method_Info;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELValue;
                       Context : ELContext'Class) return Object;

   --  Evaluate the node and set the value on the associated bean.
   --  Raises Invalid_Variable if the target object is not a bean.
   --  Raises Invalid_Expression if the target bean is not writeable.
   procedure Set_Value (Node    : in ELValue;
                        Context : in ELContext'Class;
                        Value   : in Objects.Object);

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELValue;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELValue);

   --  ------------------------------
   --  Literal object (integer, boolean, float, string)
   --  ------------------------------
   type ELObject is new ELNode with private;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELObject;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELObject;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELObject);

   --  ------------------------------
   --  Function call with up to 4 arguments
   --  ------------------------------
   type ELFunction is new ELNode with private;

   --  Evaluate a node on a given context.
   overriding
   function Get_Value (Expr    : ELFunction;
                       Context : ELContext'Class) return Object;

   --  Reduce the expression by eliminating variables which are known
   --  and computing constant expressions.  Returns either a new expression
   --  tree or a constant value.
   overriding
   function Reduce (Expr    : access ELFunction;
                    Context : in ELContext'Class) return Reduction;

   overriding
   procedure Delete (Node : in out ELFunction);

   --  Create constant nodes
   function Create_Node (Value : Boolean) return ELNode_Access;
   function Create_Node (Value : Long_Long_Integer) return ELNode_Access;
   function Create_Node (Value : String) return ELNode_Access;
   function Create_Node (Value : Wide_Wide_String) return ELNode_Access;
   function Create_Node (Value : Long_Float) return ELNode_Access;
   function Create_Node (Value : Unbounded_Wide_Wide_String) return ELNode_Access;
   function Create_Variable (Name : in Wide_Wide_String) return ELNode_Access;
   function Create_Value (Variable : in ELNode_Access;
                          Name     : in Wide_Wide_String) return ELNode_Access;

   --  Create unary expressions
   function Create_Node (Of_Type : Unary_Node;
                         Expr    : ELNode_Access) return ELNode_Access;

   --  Create binary expressions
   function Create_Node (Of_Type : Binary_Node;
                         Left    : ELNode_Access;
                         Right   : ELNode_Access) return ELNode_Access;

   --  Create a ternary expression.
   function Create_Node (Cond  : ELNode_Access;
                         Left  : ELNode_Access;
                         Right : ELNode_Access) return ELNode_Access;

   --  Create a function call
   function Create_Node (Func  : EL.Functions.Function_Access;
                         Arg1  : ELNode_Access) return ELNode_Access;

   --  Create a function call
   function Create_Node (Func  : EL.Functions.Function_Access;
                         Arg1  : ELNode_Access;
                         Arg2  : ELNode_Access) return ELNode_Access;

   --  Create a function call
   function Create_Node (Func  : EL.Functions.Function_Access;
                         Arg1  : ELNode_Access;
                         Arg2  : ELNode_Access;
                         Arg3  : ELNode_Access) return ELNode_Access;

   --  Create a function call
   function Create_Node (Func  : EL.Functions.Function_Access;
                         Arg1  : ELNode_Access;
                         Arg2  : ELNode_Access;
                         Arg3  : ELNode_Access;
                         Arg4  : ELNode_Access) return ELNode_Access;

private

   type ELUnary is new ELNode with record
      Kind : Unary_Node;
      Node : ELNode_Access;
   end record;

   --  ------------------------------
   --  Binary nodes
   --  ------------------------------

   type ELBinary is new ELNode with record
      Kind  : Binary_Node;
      Left  : ELNode_Access;
      Right : ELNode_Access;
   end record;

   --  ------------------------------
   --  Ternary expression
   --  ------------------------------
   type ELTernary is new ELNode with record
      Cond  : ELNode_Access;
      Left  : ELNode_Access;
      Right : ELNode_Access;
   end record;

   --  #{bean.name}   - Bean name, Bean property
   --  #{bean[12]}    - Bean name,

   --  Variable to be looked at in the expression context
   type ELVariable is new ELNode with record
      Name     : Unbounded_String;
   end record;
   type ELVariable_Access is access all ELVariable;

   type ELValue (Len : Natural) is new ELNode with record
      Variable : ELNode_Access;
      Name     : String (1 .. Len);
   end record;

   --  A literal object (integer, boolean, float, String)
   type ELObject is new ELNode with record
      Value : Object;
   end record;

   --  A function call with up to 4 arguments.
   type ELFunction is new ELNode with record
      Func : EL.Functions.Function_Access;
      Arg1 : ELNode_Access;
      Arg2 : ELNode_Access;
      Arg3 : ELNode_Access;
      Arg4 : ELNode_Access;
   end record;

end EL.Expressions.Nodes;

Change with clause to private with for the Unbounded package


-----------------------------------------------------------------------
--  awa-tags -- Tags management
--  Copyright (C) 2013 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------
package AWA.Tags is

   pragma Pure;

end AWA.Tags;

-----------------------------------------------------------------------
--  awa-tags -- Tags management
--  Copyright (C) 2013 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

--  == Introduction ==
--  The <b>Tags</b> module allows to associate general purpose tags to any database entity.
--
--  == Model ==
--  [http://ada-awa.googlecode.com/svn/wiki/awa_tags_model.png]
--
--  @include awa-tags-modules.ads
package AWA.Tags is

   pragma Pure;

end AWA.Tags;

Add some documentation

Add some documentation


-----------------------------------------------------------------------
--  wiki-nodes -- Wiki Document Internal representation
--  Copyright (C) 2016 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

package body Wiki.Nodes is

   type Tag_Array is array (Html_Tag_Type) of String_Access;

   HTML_TAG_NAME  : aliased constant String := "html";
   HEAD_TAG_NAME  : aliased constant String := "head";
   TITLE_TAG_NAME : aliased constant String := "title";
   BASE_TAG_NAME  : aliased constant String := "base";
   LINK_TAG_NAME  : aliased constant String := "link";
   META_TAG_NAME  : aliased constant String := "meta";
   STYLE_TAG_NAME : aliased constant String := "style";
   BODY_TAG_NAME  : aliased constant String := "body";
   ARTICLE_TAG_NAME : aliased constant String := "article";
   SECTION_TAG_NAME : aliased constant String := "section";
   NAV_TAG_NAME     : aliased constant String := "nav";
   ASIDE_TAG_NAME   : aliased constant String := "aside";

   Tag_Names : constant Tag_Array :=
     (
      HTML_TAG    => HTML_TAG_NAME'Access,
      HEAD_TAG    => HEAD_TAG_NAME'Access,
      TITLE_TAG   => TITLE_TAG_NAME'Access,
      BASE_TAG    => BASE_TAG_NAME'Access,
      LINK_TAG    => LINK_TAG_NAME'Access,
      META_TAG    => META_TAG_NAME'Access,
      STYLE_TAG   => STYLE_TAG_NAME'Access,
      BODY_TAG    => BODY_TAG_NAME'Access,
      ARTICLE_TAG => ARTICLE_TAG_NAME'Access,
      SECTION_TAG => SECTION_TAG_NAME'Access,
      NAV_TAG     => NAV_TAG_NAME'Access,
      ASIDE_TAG   => ASIDE_TAG_NAME'Access,
      others => null
     );

   --  ------------------------------
   --  Get the HTML tag name.
   --  ------------------------------
   function Get_Tag_Name (Tag : in Html_Tag_Type) return String_Access is
   begin
      return Tag_Names (Tag);
   end Get_Tag_Name;

   --  ------------------------------
   --  Create a text node.
   --  ------------------------------
   function Create_Text (Text : in WString) return Node_Type_Access is
   begin
      return new Node_Type '(Kind => N_TEXT,
                             Len  => Text'Length,
                             Text => Text,
                             others => <>);
   end Create_Text;

   --  ------------------------------
   --  Append a HTML tag start node to the document.
   --  ------------------------------
   procedure Add_Tag (Document   : in out Wiki.Nodes.Document;
                      Tag        : in Html_Tag_Type;
                      Attributes : in Wiki.Attributes.Attribute_List_Type) is
      Node : constant Node_Type_Access := new Node_Type '(Kind       => N_TAG_START,
                                                          Len        => 0,
                                                          Tag_Start  => Tag,
                                                          Attributes => Attributes,
                                                          Children   => null,
                                                          Parent     => Document.Current);
   begin
      Append (Document.Nodes, Node);
      Document.Current := Node;
   end Add_Tag;

   procedure End_Tag (Document : in out Wiki.Nodes.Document;
                      Tag      : in Html_Tag_Type) is
   begin
      if Document.Current /= null then
         Document.Current := Document.Current.Parent;
      end if;
   end End_Tag;

   --  ------------------------------
   --  Append a node to the document.
   --  ------------------------------
   procedure Append (Into : in out Document;
                     Node : in Node_Type_Access) is
   begin
      if Into.Current = null then
         Append (Into.Nodes, Node);
      else
         if Into.Current.Children = null then
            Into.Current.Children := new Node_List;
         end if;
         Append (Into.Current.Children.all, Node);
      end if;
   end Append;

   --  ------------------------------
   --  Append a simple node such as N_LINE_BREAK, N_HORIZONTAL_RULE or N_PARAGRAPH.
   --  ------------------------------
   procedure Append (Into : in out Document;
                     Kind : in Simple_Node_Kind) is
   begin
      case Kind is
         when N_LINE_BREAK =>
            Append (Into, new Node_Type '(Kind => N_LINE_BREAK, Len => 0));

         when N_HORIZONTAL_RULE =>
            Append (Into, new Node_Type '(Kind => N_HORIZONTAL_RULE, Len => 0));

         when N_PARAGRAPH =>
            Append (Into, new Node_Type '(Kind => N_PARAGRAPH, Len => 0));

      end  case;
   end Append;

   --  ------------------------------
   --  Append a node to the node list.
   --  ------------------------------
   procedure Append (Into : in out Node_List;
                     Node : in Node_Type_Access) is
      Block : Node_List_Block_Access := Into.Current;
   begin
      if Block.Last = Block.Max then
         Block.Next := new Node_List_Block (Into.Length);
         Block := Block.Next;
         Into.Current := Block;
      end if;
      Block.Last := Block.Last + 1;
      Block.List (Block.Last) := Node;
      Into.Length := Into.Length + 1;
   end Append;

end Wiki.Nodes;

-----------------------------------------------------------------------
--  wiki-nodes -- Wiki Document Internal representation
--  Copyright (C) 2016 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------

package body Wiki.Nodes is

   type Tag_Array is array (Html_Tag_Type) of String_Access;

   HTML_TAG_NAME  : aliased constant String := "html";
   HEAD_TAG_NAME  : aliased constant String := "head";
   TITLE_TAG_NAME : aliased constant String := "title";
   BASE_TAG_NAME  : aliased constant String := "base";
   LINK_TAG_NAME  : aliased constant String := "link";
   META_TAG_NAME  : aliased constant String := "meta";
   STYLE_TAG_NAME : aliased constant String := "style";
   BODY_TAG_NAME  : aliased constant String := "body";
   ARTICLE_TAG_NAME : aliased constant String := "article";
   SECTION_TAG_NAME : aliased constant String := "section";
   NAV_TAG_NAME     : aliased constant String := "nav";
   ASIDE_TAG_NAME   : aliased constant String := "aside";

   Tag_Names : constant Tag_Array :=
     (
      HTML_TAG    => HTML_TAG_NAME'Access,
      HEAD_TAG    => HEAD_TAG_NAME'Access,
      TITLE_TAG   => TITLE_TAG_NAME'Access,
      BASE_TAG    => BASE_TAG_NAME'Access,
      LINK_TAG    => LINK_TAG_NAME'Access,
      META_TAG    => META_TAG_NAME'Access,
      STYLE_TAG   => STYLE_TAG_NAME'Access,
      BODY_TAG    => BODY_TAG_NAME'Access,
      ARTICLE_TAG => ARTICLE_TAG_NAME'Access,
      SECTION_TAG => SECTION_TAG_NAME'Access,
      NAV_TAG     => NAV_TAG_NAME'Access,
      ASIDE_TAG   => ASIDE_TAG_NAME'Access,
      others => null
     );

   --  ------------------------------
   --  Get the HTML tag name.
   --  ------------------------------
   function Get_Tag_Name (Tag : in Html_Tag_Type) return String_Access is
   begin
      return Tag_Names (Tag);
   end Get_Tag_Name;

   --  ------------------------------
   --  Find the tag from the tag name.
   --  ------------------------------
   function Find_Tag (Name : in Wide_Wide_String) return Html_Tag_Type is
   begin
      --  The list of possible tags is well known and will not change very often.
      --  The tag lookup is implemented to be efficient with 2 or 3 embedded cases that
      --  reduce the comparison to the minimum.  The result is a large case statement that
      --  becomes unreadable.
      case Name'Length is
         when 0 =>
            return UNKNOWN_TAG;

         when 1 =>
            case Name (Name'First) is
            when 'a' | 'A' =>
               return A_TAG;
            when 'b' | 'B' =>
               return B_TAG;
            when 'i' | 'I' =>
               return I_TAG;
            when 'p' | 'P' =>
               return P_TAG;
            when 'q' | 'Q' =>
               return Q_TAG;
            when 's' | 'S' =>
               return S_TAG;
            when 'u' | 'U' =>
               return U_TAG;
            when others =>
               return UNKNOWN_TAG;
            end case;

         when 2 =>
            case Name (Name'First) is
            when 'b' | 'B' =>
               case Name (Name'Last) is
                  when 'r' | 'R' =>
                     return BR_TAG;
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'd' | 'D' =>
               case Name (Name'Last) is
                  when 'l' | 'L' =>
                     return DL_TAG;
                  when 't' | 'T' =>
                     return DT_TAG;
                  when 'd' | 'D' =>
                     return DD_TAG;
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'e' | 'E' =>
               case Name (Name'Last) is
                  when 'm' | 'M' =>
                     return EM_TAG;
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'h' | 'H' =>
               case Name (Name'Last) is
                  when '1' =>
                     return H1_TAG;
                  when '2' =>
                     return H2_TAG;
                  when '3' =>
                     return H3_TAG;
                  when '4' =>
                     return H4_TAG;
                  when '5' =>
                     return H5_TAG;
                  when '6' =>
                     return H6_TAG;
                  when 'r' | 'R' =>
                     return HR_TAG;
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'l' | 'L' =>
               case Name (Name'Last) is
                  when 'i' | 'I' =>
                     return LI_TAG;
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'o' | 'O' =>
               case Name (Name'Last) is
                  when 'l' | 'L' =>
                     return OL_TAG;
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'r' | 'R' =>
               case Name (Name'Last) is
                  when 'b' | 'B' =>
                     return RB_TAG;
                  when 'p' | 'P' =>
                     return RP_TAG;
                  when 't' | 'T' =>
                     return RT_TAG;
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 't' | 'T' =>
               case Name (Name'Last) is
                  when 'r' | 'R' =>
                     return TR_TAG;
                  when 'd' | 'D' =>
                     return TD_TAG;
                  when 'h' | 'H' =>
                     return TH_TAG;
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'u' | 'U' =>
               case Name (Name'Last) is
                  when 'l' | 'L' =>
                     return UL_TAG;
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when others =>
               return UNKNOWN_TAG;

            end case;

         when 3 =>
            case Name (Name'First) is
            when 'b' | 'B' =>
               case Name (Name'Last) is
                  when 'i' | 'I' =>
                     return Tag (Name, "bdi", BDI_TAG);
                  when 'o' | 'O' =>
                     return Tag (Name, "bdo", BDO_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'c' | 'C' =>
               return Tag (Name, "col", COL_TAG);

            when 'd' | 'D' =>
               case Name (Name'First + 1) is
                  when 'i' | 'I' =>
                     return Tag (Name, "div", DIV_TAG);
                  when 'f' | 'F' =>
                     return Tag (Name, "dfn", DFN_TAG);
                  when 'e' | 'E' =>
                     return Tag (Name, "del", DEL_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'i' | 'I' =>
               case Name (Name'Last) is
                  when 'g' | 'G' =>
                     return Tag (Name, "img", IMG_TAG);
                  when 's' | 'S' =>
                     return Tag (Name, "ins", INS_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'k' | 'K' =>
               return Tag (Name, "kbd", KBD_TAG);

            when 'm' | 'M' =>
               return Tag (Name, "map", MAP_TAG);

            when 'n' | 'N' =>
               return Tag (Name, "nav", NAV_TAG);

            when 'p' | 'P' =>
               return Tag (Name, "pre", PRE_TAG);

            when 'r' | 'R' =>
               return Tag (Name, "rtc", RTC_TAG);

            when 's' | 'S' =>
               case Name (Name'Last) is
                  when 'b' | 'B' =>
                     return Tag (Name, "sub", SUB_TAG);
                  when 'n' | 'N' =>
                     return SPAN_TAG;
                  when 'p' | 'P' =>
                     return Tag (Name, "sup", SUP_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'v' | 'V' =>
               return Tag (Name, "var", VAR_TAG);

            when 'w' | 'W' =>
               return Tag (Name, "wbr", WBR_TAG);

            when others =>
               return UNKNOWN_TAG;
            end case;

         when 4 =>
            case Name (Name'First) is
            when 'a' | 'A' =>
               case Name (Name'First + 1) is
                  when 'b' | 'B' =>
                     return Tag (Name, "abbr", ABBR_TAG);
                  when 'r' | 'R' =>
                     return Tag (Name, "area", AREA_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'b' | 'B' =>
               case Name (Name'First + 1) is
                  when 'a' | 'A' =>
                     return Tag (Name, "base", BASE_TAG);
                  when 'o' | 'O' =>
                     return Tag (Name, "body", BODY_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'c' | 'C' =>
               case Name (Name'First + 1) is
                  when 'i' | 'I' =>
                     return Tag (Name, "cite", CITE_TAG);
                  when 'o' | 'O' =>
                     return Tag (Name, "code", CODE_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'd' | 'D' =>
               return Tag (Name, "data", DATA_TAG);

            when 'f' | 'F' =>
               return Tag (Name, "form", FORM_TAG);

            when 'h' | 'H' =>
               case Name (Name'First + 1) is
                  when 't' | 'T' =>
                     return Tag (Name, "html", HTML_TAG);
                  when 'e' | 'E' =>
                     return Tag (Name, "head", HEAD_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'l' | 'L' =>
               return Tag (Name, "link", LINK_TAG);

            when 'm' | 'M' =>
               case Name (Name'Last) is
                  when 'a' | 'A' =>
                     return Tag (Name, "meta", META_TAG);
                  when 'n' | 'N' =>
                     return Tag (Name, "main", MAIN_TAG);
                  when 'k' | 'K' =>
                     return Tag (Name, "mark", MARK_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'r' | 'R' =>
               return Tag (Name, "ruby", RUBY_TAG);

            when 's' | 'S' =>
               case Name (Name'First + 1) is
                  when 'p' | 'P' =>
                     return Tag (Name, "span", SPAN_TAG);
                  when 'a' | 'A' =>
                     return Tag (Name, "samp", SAMP_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 't' | 'T' =>
               return Tag (Name, "time", TIME_TAG);

            when others =>
               return UNKNOWN_TAG;
            end case;

         when 5 =>
            case Name (Name'First) is
            when 'a' | 'A' =>
               case Name (Name'First + 1) is
                  when 's' | 'S' =>
                     return Tag (Name, "aside", ASIDE_TAG);
                  when 'u' | 'U' =>
                     return Tag (Name, "audio", AUDIO_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'e' | 'E' =>
               return Tag (Name, "embed", EMBED_TAG);

            when 'i' | 'I' =>
               return Tag (Name, "input", INPUT_TAG);

            when 'l' | 'L' =>
               return Tag (Name, "label", LABEL_TAG);

            when 'm' | 'M' =>
               return Tag (Name, "meter", METER_TAG);

            when 'p' | 'P' =>
               return Tag (Name, "param", PARAM_TAG);

            when 's' | 'S' =>
               case Name (Name'First + 1) is
                  when 't' | 'T' =>
                     return Tag (Name, "style", STYLE_TAG);
                  when 'm' | 'M' =>
                     return Tag (Name, "small", SMALL_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 't' | 'T' =>
               case Name (Name'First + 1) is
                  when 'i' | 'I' =>
                     return Tag (Name, "title", TITLE_TAG);
                  when 'r' | 'R' =>
                     return Tag (Name, "track", TRACK_TAG);
                  when 'a' | 'A' =>
                     return Tag (Name, "table", TABLE_TAG);
                  when 'b' | 'B' =>
                     return Tag (Name, "tbody", TBODY_TAG);
                  when 'h' | 'H' =>
                     return Tag (Name, "thead", THEAD_TAG);
                  when 'f' | 'F' =>
                     return Tag (Name, "tfoot", TFOOT_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'v' | 'V' =>
               return Tag (Name, "video", VIDEO_TAG);

            when others =>
               return UNKNOWN_TAG;
            end case;

         when others =>
            case Name (Name'First) is
            when 'a' | 'A' =>
               case Name (Name'First + 1) is
                  when 'r' | 'R' =>
                     return Tag (Name, "article", ARTICLE_TAG);
                  when 'd' | 'D' =>
                     return Tag (Name, "address", ADDRESS_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'b' | 'B' =>
               case Name (Name'First + 1) is
                  when 'l' | 'L' =>
                     return Tag (Name, "blockquote", BLOCKQUOTE_TAG);
                  when 'u' | 'U' =>
                     return Tag (Name, "button", BUTTON_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'c' | 'C' =>
               case Name (Name'First + 2) is
                  when 'p' | 'P' =>
                     return Tag (Name, "caption", CAPTION_TAG);
                  when 'l' | 'L' =>
                     return Tag (Name, "colgroup", COLGROUP_TAG);
                  when 'n' | 'N' =>
                     return Tag (Name, "canvas", CANVAS_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'd' | 'D' =>
               return Tag (Name, "datalist", DATALIST_TAG);

            when 'f' | 'F' =>
               case Name (Name'Last) is
                  when 'r' | 'R' =>
                     return Tag (Name, "footer", FOOTER_TAG);
                  when 'e' | 'E' =>
                     return Tag (Name, "figure", FIGURE_TAG);
                  when 'n' | 'N' =>
                     return Tag (Name, "figcaption", FIGCAPTION_TAG);
                  when 't' | 'T' =>
                     return Tag (Name, "fieldset", FIELDSET_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'h' | 'H' =>
               return Tag (Name, "header", HEADER_TAG);

            when 'i' | 'I' =>
               return Tag (Name, "iframe", IFRAME_TAG);

            when 'k' | 'K' =>
               return Tag (Name, "keygen", KEYGEN_TAG);

            when 'l' | 'L' =>
               return Tag (Name, "legend", LEGEND_TAG);

            when 'n' | 'N' =>
               return Tag (Name, "noscript", NOSCRIPT_TAG);

            when 'o' | 'O' =>
               case Name (Name'First + 3) is
                  when 'e' | 'E' =>
                     return Tag (Name, "object", OBJECT_TAG);
                  when 'g' | 'G' =>
                     return Tag (Name, "optgroup", OPTGROUP_TAG);
                  when 'i' | 'I' =>
                     return Tag (Name, "option", OPTION_TAG);
                  when 'p' | 'P' =>
                     return Tag (Name, "output", OUTPUT_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 'p' | 'P' =>
               return Tag (Name, "progress", PROGRESS_TAG);

            when 's' | 'S' =>
               case Name (Name'First + 3) is
                  when 't' | 'T' =>
                     return Tag (Name, "section", SECTION_TAG);
                  when 'o' | 'O' =>
                     return Tag (Name, "strong", STRONG_TAG);
                  when 'r' | 'R' =>
                     return Tag (Name, "source", SOURCE_TAG);
                  when 'e' | 'E' =>
                     return Tag (Name, "select", SELECT_TAG);
                  when 'i' | 'I' =>
                     return Tag (Name, "script", SCRIPT_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when 't' | 'T' =>
               case Name (Name'Last) is
                  when 'a' | 'A' =>
                     return Tag (Name, "textarea", TEXTAREA_TAG);
                  when 'e' | 'E' =>
                     return Tag (Name, "template", TEMPLATE_TAG);
                  when others =>
                     return UNKNOWN_TAG;
               end case;

            when others =>
               return UNKNOWN_TAG;
            end case;
      end case;
   end Find_Tag;

   --  ------------------------------
   --  Create a text node.
   --  ------------------------------
   function Create_Text (Text : in WString) return Node_Type_Access is
   begin
      return new Node_Type '(Kind => N_TEXT,
                             Len  => Text'Length,
                             Text => Text,
                             others => <>);
   end Create_Text;

   --  ------------------------------
   --  Append a HTML tag start node to the document.
   --  ------------------------------
   procedure Add_Tag (Document   : in out Wiki.Nodes.Document;
                      Tag        : in Html_Tag_Type;
                      Attributes : in Wiki.Attributes.Attribute_List_Type) is
      Node : constant Node_Type_Access := new Node_Type '(Kind       => N_TAG_START,
                                                          Len        => 0,
                                                          Tag_Start  => Tag,
                                                          Attributes => Attributes,
                                                          Children   => null,
                                                          Parent     => Document.Current);
   begin
      Append (Document.Nodes, Node);
      Document.Current := Node;
   end Add_Tag;

   procedure End_Tag (Document : in out Wiki.Nodes.Document;
                      Tag      : in Html_Tag_Type) is
   begin
      if Document.Current /= null then
         Document.Current := Document.Current.Parent;
      end if;
   end End_Tag;

   --  ------------------------------
   --  Append a node to the document.
   --  ------------------------------
   procedure Append (Into : in out Document;
                     Node : in Node_Type_Access) is
   begin
      if Into.Current = null then
         Append (Into.Nodes, Node);
      else
         if Into.Current.Children = null then
            Into.Current.Children := new Node_List;
         end if;
         Append (Into.Current.Children.all, Node);
      end if;
   end Append;

   --  ------------------------------
   --  Append a simple node such as N_LINE_BREAK, N_HORIZONTAL_RULE or N_PARAGRAPH.
   --  ------------------------------
   procedure Append (Into : in out Document;
                     Kind : in Simple_Node_Kind) is
   begin
      case Kind is
         when N_LINE_BREAK =>
            Append (Into, new Node_Type '(Kind => N_LINE_BREAK, Len => 0));

         when N_HORIZONTAL_RULE =>
            Append (Into, new Node_Type '(Kind => N_HORIZONTAL_RULE, Len => 0));

         when N_PARAGRAPH =>
            Append (Into, new Node_Type '(Kind => N_PARAGRAPH, Len => 0));

      end  case;
   end Append;

   --  ------------------------------
   --  Append a node to the node list.
   --  ------------------------------
   procedure Append (Into : in out Node_List;
                     Node : in Node_Type_Access) is
      Block : Node_List_Block_Access := Into.Current;
   begin
      if Block.Last = Block.Max then
         Block.Next := new Node_List_Block (Into.Length);
         Block := Block.Next;
         Into.Current := Block;
      end if;
      Block.Last := Block.Last + 1;
      Block.List (Block.Last) := Node;
      Into.Length := Into.Length + 1;
   end Append;

end Wiki.Nodes;

Implement Find_Tag procedure (from Wiki.Filters.Html package)