-----------------------------------------------------------------------
--  Frames - Representation of stack frames
--  Copyright (C) 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 Ada.Unchecked_Deallocation;
with Interfaces; use Interfaces;
with MAT.Types; use MAT.Types;
package body MAT.Frames is

   procedure Free is
      new Ada.Unchecked_Deallocation (Frame, Frame_Ptr);

   --  Return the parent frame.
   function Parent (F : in Frame_Ptr) return Frame_Ptr is
   begin
      return F.Parent;
   end Parent;

   --  Returns the backtrace of the current frame (up to the root).
   function Backtrace (F :  in Frame_Ptr) return PC_Table is
      Pc      : Pc_Table (1 .. F.Depth);
      Current : Frame_Ptr := F;
      Pos     : Natural   := Current.Depth;
      New_Pos : Natural;
   begin
      while Pos /= 0 loop
         New_Pos := Pos - Current.Local_Depth + 1;
         Pc (New_Pos .. Pos) := Current.Calls (1 .. Current.Local_Depth);
         Pos     := New_Pos - 1;
         Current := Current.Parent;
      end loop;
      return Pc;
   end Backtrace;

   --  Returns the number of children in the frame.
   --  When recursive is true, compute in the sub-tree.
   function Count_Children (F : in Frame_Ptr;
                            Recursive : in Boolean := False) return Natural is
      Count : Natural   := 0;
      N : Natural;
      Child : Frame_Ptr := F.Children;
   begin
      while Child /= null loop
         Count := Count + 1;
         if Recursive then
            declare
               N : Natural := Count_Children (Child, True);
            begin
               if N > 0 then
                  N := N - 1;
               end if;
               Count := Count + N;
            end;
         end if;
         Child := Child.Next;
      end loop;
      return Count;
   end Count_Children;

   --  Returns all the direct calls made by the current frame.
   function Calls (F : in Frame_Ptr) return PC_Table is
      Nb_Calls : Natural   := Count_Children (F);
      Pc       : Pc_Table (1 .. Nb_Calls);
      Child    : Frame_Ptr := F.Children;
      Pos      : Natural   := 1;
   begin
      while Child /= null loop
         Pc (Pos) := Child.Calls (1);
         Pos   := Pos + 1;
         Child := Child.Next;
      end loop;
      return Pc;
   end Calls;

   --  Returns the current stack depth (# of calls from the root
   --  to reach the frame).
   function Current_Depth (F : in Frame_Ptr) return Natural is
   begin
      return F.Depth;
   end Current_Depth;

   --  Create a root for stack frame representation.
   function Create_Root return Frame_Ptr is
   begin
      return new Frame;
   end Create_Root;

   --  Destroy the frame tree recursively.
   procedure Destroy (Tree : in out Frame_Ptr) is
      F : Frame_Ptr;
   begin
      --  Destroy its children recursively.
      while Tree.Children /= null loop
         F := Tree.Children;
         Destroy (F);
      end loop;

      --  Unlink from parent list.
      if Tree.Parent /= null then
         F := Tree.Parent.Children;
         if F = Tree then
            Tree.Parent.Children := Tree.Next;
         else
            while F /= null and F.Next /= Tree loop
               F := F.Next;
            end loop;
            if F = null then
               raise Program_Error;
            end if;
            F.Next := Tree.Next;
         end if;
      end if;
      Free (Tree);
   end Destroy;

   --  Release the frame when its reference is no longer necessary.
   procedure Release (F : in Frame_Ptr) is
      Current : Frame_Ptr := F;
   begin
      --  Scan the fram until the root is reached
      --  and decrement the used counter.  Free the frames
      --  when the used counter reaches 0.
      while Current /= null loop
         if Current.Used <= 1 then
            declare
               Tree : Frame_Ptr := Current;
            begin
               Current := Current.Parent;
               Destroy (Tree);
            end;
         else
            Current.Used := Current.Used - 1;
            Current := Current.Parent;
         end if;
      end loop;
   end Release;

   --  Split the node pointed to by `F' at the position `Pos'
   --  in the caller chain.  A new parent is created for the node
   --  and the brothers of the node become the brothers of the
   --  new parent.
   --
   --  Returns in `F' the new parent node.
   procedure Split (F : in out Frame_Ptr; Pos : in Positive) is

      --  Before:                       After:
      --
      --    +-------+             +-------+
      --  /-|  P    |           /-|  P    |
      --  | +-------+           | +-------+
      --  |       ^             |       ^
      --  |   +-------+         |    +-------+
      --  ...>| node  |...      ....>|  new  |...        (0..N brothers)
      --      +-------+              +-------+
      --       |     ^              |      ^
      --       | +-------+          | +-------+
      --       ->|  c    |          ->| node  |-->0      (0 brother)
      --         +-------+            +-------+
      --                                    |
      --                                +-------+
      --                                |   c   |
      --                                +-------+
      --
      New_Parent : Frame_Ptr := new Frame '(Parent      => F.Parent,
                                            Next        => F.Next,
                                            Children    => F,
                                            Used        => F.Used,
                                            Depth       => F.Depth,
                                            Local_Depth => Pos,
                                            Calls       => (others => 0));
      Child : Frame_Ptr := F.Parent.Children;
   begin
      --  Move the PC values in the new parent.
      New_Parent.Calls (1 .. Pos) := F.Calls (1 .. Pos);
      F.Calls (1 .. F.Local_Depth - Pos) := F.Calls (Pos + 1 .. F.Local_Depth);
      F.Parent         := New_Parent;
      F.Next           := null;
      New_Parent.Depth := F.Depth - F.Local_Depth + Pos;
      F.Local_Depth    := F.Local_Depth - Pos;

      --  Remove F from its parent children list and replace if with New_Parent.
      if Child = F then
         New_Parent.Parent.Children := New_Parent;
      else
         while Child.Next /= F loop
            Child := Child.Next;
         end loop;
         Child.Next := New_Parent;
      end if;
      F := New_Parent;
   end Split;

   procedure Add_Frame (F  : in Frame_Ptr;
                        Pc : in Pc_Table;
                        Result : out Frame_Ptr) is
      Child         : Frame_Ptr := F;
      Pos           : Positive  := Pc'First;
      Current_Depth : Natural   := F.Depth;
      Cnt           : Local_Depth_Type;
   begin
      while Pos <= Pc'Last loop
         Cnt := Frame_Group_Size;
         if Pos + Cnt > Pc'Last then
            Cnt := Pc'Last - Pos + 1;
         end if;
         Current_Depth := Current_Depth + Cnt;
         Child := new Frame '(Parent      => Child,
                              Next        => Child.Children,
                              Children    => null,
                              Used        => 1,
                              Depth       => Current_Depth,
                              Local_Depth => Cnt,
                              Calls       => (others => 0));
         Child.Calls (1 .. Cnt) := Pc (Pos .. Pos + Cnt - 1);
         Pos := Pos + Cnt;
         Child.Parent.Children := Child;
      end loop;
      Result := Child;
   end Add_Frame;

   procedure Insert (F : in Frame_Ptr;
                     Pc : in Pc_Table;
                     Result : out Frame_Ptr) is
      Current : Frame_Ptr := F;
      Child   : Frame_Ptr;
      Pos     : Positive  := Pc'First;
      Lpos    : Positive  := 1;
      Addr    : Target_Addr;
   begin
      while Pos <= Pc'Last loop
         Addr := Pc (Pos);
         if Lpos <= Current.Local_Depth then
            if Addr = Current.Calls (Lpos) then
               Lpos := Lpos + 1;
               Pos  := Pos + 1;

               --  Split this node
            else
               if Lpos > 1 then
                  Split (Current, Lpos - 1);
               end if;
               Add_Frame (Current, Pc (Pos .. Pc'Last), Result);
               return;
            end if;
         else
            --  Find the first child which has the address.
            Child := Current.Children;
            while Child /= null loop
               exit when Child.Calls (1) = Addr;
               Child := Child.Next;
            end loop;
            if Child = null then
               Add_Frame (Current, Pc (Pos .. Pc'Last), Result);
               return;
            end if;
            Current := Child;
            Lpos    := 2;
            Pos     := Pos + 1;
            Current.Used := Current.Used + 1;
         end if;
      end loop;
      if Lpos <= Current.Local_Depth then
         Split (Current, Lpos - 1);
      end if;
      Result := Current;
   end Insert;

   --  Find the child frame which has the given PC address.
   --  Returns that frame pointer or raises the Not_Found exception.
   function Find (F : in Frame_Ptr; Pc : in Target_Addr) return Frame_Ptr is
      Child : Frame_Ptr := F.Children;
   begin
      while Child /= null loop
         if Child.Local_Depth >= 1 and then Child.Calls (1) = Pc then
            return Child;
         end if;
         Child := Child.Next;
      end loop;
      raise Not_Found;
   end Find;

   --  Find the child frame which has the given PC address.
   --  Returns that frame pointer or raises the Not_Found exception.
   function Find (F : in Frame_Ptr; Pc : in PC_Table) return Frame_Ptr is
      Child : Frame_Ptr := F;
      Pos   : Positive  := Pc'First;
      Lpos  : Positive;
   begin
      while Pos <= Pc'Last loop
         Child := Find (Child, Pc (Pos));
         Pos  := Pos + 1;
         Lpos := 2;
         --  All the PC of the child frame must match.
         while Pos <= Pc'Last and Lpos <= Child.Local_Depth loop
            if Child.Calls (Lpos) /= Pc (Pos) then
               raise Not_Found;
            end if;
            Lpos := Lpos + 1;
            Pos  := Pos + 1;
         end loop;
      end loop;
      return Child;
   end Find;

   --  Find the child frame which has the given PC address.
   --  Returns that frame pointer or raises the Not_Found exception.
   procedure Find (F       : in Frame_Ptr;
                   Pc      : in PC_Table;
                   Result  : out Frame_Ptr;
                   Last_Pc : out Natural) is
      Current : Frame_Ptr := F;
      Pos     : Positive  := Pc'First;
      Lpos    : Positive;
   begin
      Main_Search:
      while Pos <= Pc'Last loop
         declare
            Addr  : Target_Addr := Pc (Pos);
            Child : Frame_Ptr   := Current.Children;
         begin
            --  Find the child which has the corresponding PC.
            loop
               exit Main_Search when Child = null;
               exit when Child.Local_Depth >= 1 and Child.Calls (1) = Addr;
               Child := Child.Next;
            end loop;

            Current := Child;
            Pos  := Pos + 1;
            Lpos := 2;
            --  All the PC of the child frame must match.
            while Pos <= Pc'Last and Lpos <= Current.Local_Depth loop
               exit Main_Search when Current.Calls (Lpos) /= Pc (Pos);
               Lpos := Lpos + 1;
               Pos  := Pos + 1;
            end loop;
         end;
      end loop Main_Search;
      Result := Current;
      if Pos > Pc'Last then
         Last_Pc := 0;
      else
         Last_Pc := Pos;
      end if;
   end Find;

end MAT.Frames;

-----------------------------------------------------------------------
--  mat-frames - Representation of stack frames
--  Copyright (C) 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 Ada.Unchecked_Deallocation;
with Interfaces; use Interfaces;
with MAT.Types; use MAT.Types;
package body MAT.Frames is

   procedure Free is
      new Ada.Unchecked_Deallocation (Frame, Frame_Type);

   --  ------------------------------
   --  Return the parent frame.
   --  ------------------------------
   function Parent (Frame : in Frame_Type) return Frame_Type is
   begin
      if Frame = null then
         return null;
      else
         return Frame.Parent;
      end if;
   end Parent;

   --  Returns the backtrace of the current frame (up to the root).
   function Backtrace (Frame :  in Frame_Type) return Frame_Table is
      Pc      : Prame_Table (1 .. F.Depth);
      Current : Frame_Type := Frame;
      Pos     : Natural   := Current.Depth;
      New_Pos : Natural;
   begin
      while Pos /= 0 loop
         New_Pos := Pos - Current.Local_Depth + 1;
         Pc (New_Pos .. Pos) := Current.Calls (1 .. Current.Local_Depth);
         Pos     := New_Pos - 1;
         Current := Current.Parent;
      end loop;
      return Pc;
   end Backtrace;

   --  Returns the number of children in the frame.
   --  When recursive is true, compute in the sub-tree.
   function Count_Children (F : in Frame_Ptr;
                            Recursive : in Boolean := False) return Natural is
      Count : Natural   := 0;
      N : Natural;
      Child : Frame_Ptr := F.Children;
   begin
      while Child /= null loop
         Count := Count + 1;
         if Recursive then
            declare
               N : Natural := Count_Children (Child, True);
            begin
               if N > 0 then
                  N := N - 1;
               end if;
               Count := Count + N;
            end;
         end if;
         Child := Child.Next;
      end loop;
      return Count;
   end Count_Children;

   --  Returns all the direct calls made by the current frame.
   function Calls (F : in Frame_Ptr) return PC_Table is
      Nb_Calls : Natural   := Count_Children (F);
      Pc       : Pc_Table (1 .. Nb_Calls);
      Child    : Frame_Ptr := F.Children;
      Pos      : Natural   := 1;
   begin
      while Child /= null loop
         Pc (Pos) := Child.Calls (1);
         Pos   := Pos + 1;
         Child := Child.Next;
      end loop;
      return Pc;
   end Calls;

   --  Returns the current stack depth (# of calls from the root
   --  to reach the frame).
   function Current_Depth (F : in Frame_Ptr) return Natural is
   begin
      return F.Depth;
   end Current_Depth;

   --  Create a root for stack frame representation.
   function Create_Root return Frame_Ptr is
   begin
      return new Frame;
   end Create_Root;

   --  Destroy the frame tree recursively.
   procedure Destroy (Tree : in out Frame_Ptr) is
      F : Frame_Ptr;
   begin
      --  Destroy its children recursively.
      while Tree.Children /= null loop
         F := Tree.Children;
         Destroy (F);
      end loop;

      --  Unlink from parent list.
      if Tree.Parent /= null then
         F := Tree.Parent.Children;
         if F = Tree then
            Tree.Parent.Children := Tree.Next;
         else
            while F /= null and F.Next /= Tree loop
               F := F.Next;
            end loop;
            if F = null then
               raise Program_Error;
            end if;
            F.Next := Tree.Next;
         end if;
      end if;
      Free (Tree);
   end Destroy;

   --  Release the frame when its reference is no longer necessary.
   procedure Release (F : in Frame_Ptr) is
      Current : Frame_Ptr := F;
   begin
      --  Scan the fram until the root is reached
      --  and decrement the used counter.  Free the frames
      --  when the used counter reaches 0.
      while Current /= null loop
         if Current.Used <= 1 then
            declare
               Tree : Frame_Ptr := Current;
            begin
               Current := Current.Parent;
               Destroy (Tree);
            end;
         else
            Current.Used := Current.Used - 1;
            Current := Current.Parent;
         end if;
      end loop;
   end Release;

   --  Split the node pointed to by `F' at the position `Pos'
   --  in the caller chain.  A new parent is created for the node
   --  and the brothers of the node become the brothers of the
   --  new parent.
   --
   --  Returns in `F' the new parent node.
   procedure Split (F : in out Frame_Ptr; Pos : in Positive) is

      --  Before:                       After:
      --
      --    +-------+             +-------+
      --  /-|  P    |           /-|  P    |
      --  | +-------+           | +-------+
      --  |       ^             |       ^
      --  |   +-------+         |    +-------+
      --  ...>| node  |...      ....>|  new  |...        (0..N brothers)
      --      +-------+              +-------+
      --       |     ^              |      ^
      --       | +-------+          | +-------+
      --       ->|  c    |          ->| node  |-->0      (0 brother)
      --         +-------+            +-------+
      --                                    |
      --                                +-------+
      --                                |   c   |
      --                                +-------+
      --
      New_Parent : Frame_Ptr := new Frame '(Parent      => F.Parent,
                                            Next        => F.Next,
                                            Children    => F,
                                            Used        => F.Used,
                                            Depth       => F.Depth,
                                            Local_Depth => Pos,
                                            Calls       => (others => 0));
      Child : Frame_Ptr := F.Parent.Children;
   begin
      --  Move the PC values in the new parent.
      New_Parent.Calls (1 .. Pos) := F.Calls (1 .. Pos);
      F.Calls (1 .. F.Local_Depth - Pos) := F.Calls (Pos + 1 .. F.Local_Depth);
      F.Parent         := New_Parent;
      F.Next           := null;
      New_Parent.Depth := F.Depth - F.Local_Depth + Pos;
      F.Local_Depth    := F.Local_Depth - Pos;

      --  Remove F from its parent children list and replace if with New_Parent.
      if Child = F then
         New_Parent.Parent.Children := New_Parent;
      else
         while Child.Next /= F loop
            Child := Child.Next;
         end loop;
         Child.Next := New_Parent;
      end if;
      F := New_Parent;
   end Split;

   procedure Add_Frame (F  : in Frame_Ptr;
                        Pc : in Pc_Table;
                        Result : out Frame_Ptr) is
      Child         : Frame_Ptr := F;
      Pos           : Positive  := Pc'First;
      Current_Depth : Natural   := F.Depth;
      Cnt           : Local_Depth_Type;
   begin
      while Pos <= Pc'Last loop
         Cnt := Frame_Group_Size;
         if Pos + Cnt > Pc'Last then
            Cnt := Pc'Last - Pos + 1;
         end if;
         Current_Depth := Current_Depth + Cnt;
         Child := new Frame '(Parent      => Child,
                              Next        => Child.Children,
                              Children    => null,
                              Used        => 1,
                              Depth       => Current_Depth,
                              Local_Depth => Cnt,
                              Calls       => (others => 0));
         Child.Calls (1 .. Cnt) := Pc (Pos .. Pos + Cnt - 1);
         Pos := Pos + Cnt;
         Child.Parent.Children := Child;
      end loop;
      Result := Child;
   end Add_Frame;

   procedure Insert (F : in Frame_Ptr;
                     Pc : in Pc_Table;
                     Result : out Frame_Ptr) is
      Current : Frame_Ptr := F;
      Child   : Frame_Ptr;
      Pos     : Positive  := Pc'First;
      Lpos    : Positive  := 1;
      Addr    : Target_Addr;
   begin
      while Pos <= Pc'Last loop
         Addr := Pc (Pos);
         if Lpos <= Current.Local_Depth then
            if Addr = Current.Calls (Lpos) then
               Lpos := Lpos + 1;
               Pos  := Pos + 1;

               --  Split this node
            else
               if Lpos > 1 then
                  Split (Current, Lpos - 1);
               end if;
               Add_Frame (Current, Pc (Pos .. Pc'Last), Result);
               return;
            end if;
         else
            --  Find the first child which has the address.
            Child := Current.Children;
            while Child /= null loop
               exit when Child.Calls (1) = Addr;
               Child := Child.Next;
            end loop;
            if Child = null then
               Add_Frame (Current, Pc (Pos .. Pc'Last), Result);
               return;
            end if;
            Current := Child;
            Lpos    := 2;
            Pos     := Pos + 1;
            Current.Used := Current.Used + 1;
         end if;
      end loop;
      if Lpos <= Current.Local_Depth then
         Split (Current, Lpos - 1);
      end if;
      Result := Current;
   end Insert;

   --  Find the child frame which has the given PC address.
   --  Returns that frame pointer or raises the Not_Found exception.
   function Find (F : in Frame_Ptr; Pc : in Target_Addr) return Frame_Ptr is
      Child : Frame_Ptr := F.Children;
   begin
      while Child /= null loop
         if Child.Local_Depth >= 1 and then Child.Calls (1) = Pc then
            return Child;
         end if;
         Child := Child.Next;
      end loop;
      raise Not_Found;
   end Find;

   --  Find the child frame which has the given PC address.
   --  Returns that frame pointer or raises the Not_Found exception.
   function Find (F : in Frame_Ptr; Pc : in PC_Table) return Frame_Ptr is
      Child : Frame_Ptr := F;
      Pos   : Positive  := Pc'First;
      Lpos  : Positive;
   begin
      while Pos <= Pc'Last loop
         Child := Find (Child, Pc (Pos));
         Pos  := Pos + 1;
         Lpos := 2;
         --  All the PC of the child frame must match.
         while Pos <= Pc'Last and Lpos <= Child.Local_Depth loop
            if Child.Calls (Lpos) /= Pc (Pos) then
               raise Not_Found;
            end if;
            Lpos := Lpos + 1;
            Pos  := Pos + 1;
         end loop;
      end loop;
      return Child;
   end Find;

   --  Find the child frame which has the given PC address.
   --  Returns that frame pointer or raises the Not_Found exception.
   procedure Find (F       : in Frame_Ptr;
                   Pc      : in PC_Table;
                   Result  : out Frame_Ptr;
                   Last_Pc : out Natural) is
      Current : Frame_Ptr := F;
      Pos     : Positive  := Pc'First;
      Lpos    : Positive;
   begin
      Main_Search:
      while Pos <= Pc'Last loop
         declare
            Addr  : Target_Addr := Pc (Pos);
            Child : Frame_Ptr   := Current.Children;
         begin
            --  Find the child which has the corresponding PC.
            loop
               exit Main_Search when Child = null;
               exit when Child.Local_Depth >= 1 and Child.Calls (1) = Addr;
               Child := Child.Next;
            end loop;

            Current := Child;
            Pos  := Pos + 1;
            Lpos := 2;
            --  All the PC of the child frame must match.
            while Pos <= Pc'Last and Lpos <= Current.Local_Depth loop
               exit Main_Search when Current.Calls (Lpos) /= Pc (Pos);
               Lpos := Lpos + 1;
               Pos  := Pos + 1;
            end loop;
         end;
      end loop Main_Search;
      Result := Current;
      if Pos > Pc'Last then
         Last_Pc := 0;
      else
         Last_Pc := Pos;
      end if;
   end Find;

end MAT.Frames;

Refactor the Parent operation

Refactor the Parent operation


-----------------------------------------------------------------------
--  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 Ada.Strings.Wide_Wide_Unbounded;

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

--  == Wiki Parsers ==
--  The Wikis.Parsers package implements a parser for several well known wiki formats.
--  The parser works with the Document_Reader interface type which defines several
--  procedures that are called by the parser when the wiki text is scanned.
package Wiki.Parsers is

   pragma Preelaborate;

   --  Defines the possible wiki syntax supported by the parser.
   type Wiki_Syntax_Type
     is (
         --  Google wiki syntax http://code.google.com/p/support/wiki/WikiSyntax
         SYNTAX_GOOGLE,

         --  Creole wiki syntax http://www.wikicreole.org/wiki/Creole1.0
         SYNTAX_CREOLE,

         --  Dotclear syntax http://dotclear.org/documentation/2.0/usage/syntaxes
         SYNTAX_DOTCLEAR,

         --  PhpBB syntax http://wiki.phpbb.com/Help:Formatting
         SYNTAX_PHPBB,

         --  MediaWiki syntax http://www.mediawiki.org/wiki/Help:Formatting
         SYNTAX_MEDIA_WIKI,

         --  Markdown
         SYNTAX_MARKDOWN,

         --  A mix of the above
         SYNTAX_MIX,

         --  The input is plain possibly incorrect HTML.
         SYNTAX_HTML);

   type Parser is tagged limited private;

   --  Add the plugin to the wiki engine.
   procedure Add_Plugin (Engine : in out Parser;
                         Name   : in String;
                         Plugin : in Wiki.Plugins.Wiki_Plugin_Access);

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

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

   --  Parse the wiki text contained in Text according to the wiki syntax configured
   --  on the wiki engine.  The document reader operations are invoked while parsing the wiki
   --  text.
   procedure Parse (Engine : in out Parser;
                    Text   : in Wide_Wide_String;
                    Into   : in Wiki.Documents.Document_Reader_Access);

   --  Parse the wiki text contained in Text according to the wiki syntax
   --  specified in Syntax and invoke the document reader procedures defined
   --  by into.
   procedure Parse (Into   : in Wiki.Documents.Document_Reader_Access;
                    Text   : in Wide_Wide_String;
                    Syntax : in Wiki_Syntax_Type := SYNTAX_MIX);

private

   use Ada.Strings.Wide_Wide_Unbounded;

   HT : constant Wide_Wide_Character := Wide_Wide_Character'Val (16#09#);
   LF : constant Wide_Wide_Character := Wide_Wide_Character'Val (16#0A#);
   CR : constant Wide_Wide_Character := Wide_Wide_Character'Val (16#0D#);

   type Input is interface;
   type Input_Access is access all Input'Class;
   procedure Read_Char (From : in out Input;
                        Token : out Wide_Wide_Character;
                        Eof   : out Boolean) is abstract;

   type Parser is tagged limited record
      Pending             : Wide_Wide_Character;
      Has_Pending         : Boolean;
      Syntax              : Wiki_Syntax_Type;
      Document            : Wiki.Nodes.Document;
      Filters             : Wiki.Filters.Filter_Type_Access;
--      Document            : Wiki.Documents.Document_Reader_Access;
      Format              : Wiki.Documents.Format_Map;
      Text                : Wiki.Strings.BString (512);
      Token               : 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;
      Is_Dotclear         : Boolean := False;
      Link_Title_First    : Boolean := False;
      Check_Image_Link    : Boolean := False;
      Header_Offset       : Integer := 0;
      Quote_Level         : Natural := 0;
      Escape_Char         : Wide_Wide_Character;
      List_Level          : Natural := 0;
      Reader              : Input_Access := null;
      Attributes          : Wiki.Attributes.Attribute_List_Type;
   end record;

   type Parser_Handler is access procedure (P     : in out Parser;
                                            Token : in Wide_Wide_Character);

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

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

   --  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 Wide_Wide_Character);

   --  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 Wide_Wide_Character);

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

   procedure Start_Element (P          : in out Parser;
                            Name       : in Unbounded_Wide_Wide_String;
                            Attributes : in Wiki.Attributes.Attribute_List_Type);

   procedure End_Element (P    : in out Parser;
                          Name : in Ada.Strings.Wide_Wide_Unbounded.Unbounded_Wide_Wide_String);

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 Ada.Strings.Wide_Wide_Unbounded;

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

--  == Wiki Parsers ==
--  The Wikis.Parsers package implements a parser for several well known wiki formats.
--  The parser works with the Document_Reader interface type which defines several
--  procedures that are called by the parser when the wiki text is scanned.
package Wiki.Parsers is

   pragma Preelaborate;

   --  Defines the possible wiki syntax supported by the parser.
   type Wiki_Syntax_Type
     is (
         --  Google wiki syntax http://code.google.com/p/support/wiki/WikiSyntax
         SYNTAX_GOOGLE,

         --  Creole wiki syntax http://www.wikicreole.org/wiki/Creole1.0
         SYNTAX_CREOLE,

         --  Dotclear syntax http://dotclear.org/documentation/2.0/usage/syntaxes
         SYNTAX_DOTCLEAR,

         --  PhpBB syntax http://wiki.phpbb.com/Help:Formatting
         SYNTAX_PHPBB,

         --  MediaWiki syntax http://www.mediawiki.org/wiki/Help:Formatting
         SYNTAX_MEDIA_WIKI,

         --  Markdown
         SYNTAX_MARKDOWN,

         --  A mix of the above
         SYNTAX_MIX,

         --  The input is plain possibly incorrect HTML.
         SYNTAX_HTML);

   type Parser is tagged limited private;

   --  Add the plugin to the wiki engine.
   procedure Add_Plugin (Engine : in out Parser;
                         Name   : in String;
                         Plugin : in Wiki.Plugins.Wiki_Plugin_Access);

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

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

   --  Parse the wiki text contained in Text according to the wiki syntax configured
   --  on the wiki engine.  The document reader operations are invoked while parsing the wiki
   --  text.
   procedure Parse (Engine : in out Parser;
                    Text   : in Wide_Wide_String;
                    Into   : in Wiki.Documents.Document_Reader_Access);

   --  Parse the wiki text contained in Text according to the wiki syntax
   --  specified in Syntax and invoke the document reader procedures defined
   --  by into.
   procedure Parse (Into   : in Wiki.Documents.Document_Reader_Access;
                    Text   : in Wide_Wide_String;
                    Syntax : in Wiki_Syntax_Type := SYNTAX_MIX);

private

   use Ada.Strings.Wide_Wide_Unbounded;

   HT : constant Wide_Wide_Character := Wide_Wide_Character'Val (16#09#);
   LF : constant Wide_Wide_Character := Wide_Wide_Character'Val (16#0A#);
   CR : constant Wide_Wide_Character := Wide_Wide_Character'Val (16#0D#);

   type Input is interface;
   type Input_Access is access all Input'Class;
   procedure Read_Char (From : in out Input;
                        Token : out Wide_Wide_Character;
                        Eof   : out Boolean) is abstract;

   type Parser is tagged limited record
      Pending             : Wide_Wide_Character;
      Has_Pending         : Boolean;
      Syntax              : Wiki_Syntax_Type;
      Document            : Wiki.Nodes.Document;
      Filters             : Wiki.Filters.Filter_Type_Access;
--      Document            : Wiki.Documents.Document_Reader_Access;
      Format              : Wiki.Documents.Format_Map;
      Text                : Wiki.Strings.BString (512);
      Token               : 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;
      Is_Dotclear         : Boolean := False;
      Link_Title_First    : Boolean := False;
      Check_Image_Link    : Boolean := False;
      Header_Offset       : Integer := 0;
      Quote_Level         : Natural := 0;
      Escape_Char         : Wide_Wide_Character;
      List_Level          : Natural := 0;
      Reader              : Input_Access := null;
      Attributes          : Wiki.Attributes.Attribute_List_Type;
   end record;

   type Parser_Handler is access procedure (P     : in out Parser;
                                            Token : in Wide_Wide_Character);

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

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

   --  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 Wide_Wide_Character);

   --  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 Wide_Wide_Character);

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

   procedure Start_Element (P          : in out Parser;
                            Tag        : in Wiki.Nodes.Html_Tag_Type;
                            Attributes : in Wiki.Attributes.Attribute_List_Type);

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

end Wiki.Parsers;

Use Wiki.Nodes.Html_Tag_Type for the tag type for Start_Element and End_Element procedures


-----------------------------------------------------------------------
--  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.  The string is assumed to be in UTF-8 format.
   procedure Parse (Engine : in out Parser;
                    Text   : in String;
                    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.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;
      Preformat_Column    : Natural := 1;
      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'Class;
                   Token : out Wiki.Strings.WChar);
   pragma Inline (Peek);

   --  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;

-----------------------------------------------------------------------
--  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.  The string is assumed to be in UTF-8 format.
   procedure Parse (Engine : in out Parser;
                    Text   : in String;
                    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.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             : aliased 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;
      Header_Offset       : Integer := 0;
      Preformat_Column    : Natural := 1;
      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'Class;
                   Token : out Wiki.Strings.WChar);
   pragma Inline (Peek);

   --  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;

Remove the Is_Hidden boolean to use the wiki context


-----------------------------------------------------------------------
--  ADO SQL -- Basic SQL Generation
--  Copyright (C) 2010, 2011, 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.
-----------------------------------------------------------------------

--  Utilities for creating SQL queries and statements.
package body ADO.SQL is

   function Escape (Str : in Unbounded_String) return String is
   begin
      return Escape (To_String (Str));
   end Escape;

   function Escape (Str : in String) return String is
      S : String (1 .. 2 + Str'Length * 2);
      J : Positive := S'First;
   begin
      if Str = "" then
         return "NULL";
      end if;

      S (J) := ''';

      for K in Str'Range loop
         if Str (K) = ''' then
            J := J + 1;
            S (J) := ''';
         end if;
         J := J + 1;
         S (J) := Str (K);
      end loop;

      J := J + 1;
      S (J) := ''';

      return S (1 .. J);
   end Escape;

   --  --------------------
   --  Buffer
   --  --------------------

   --  --------------------
   --  Clear the SQL buffer.
   --  --------------------
   procedure Clear (Target : in out Buffer) is
   begin
      Target.Buf := To_Unbounded_String ("");
   end Clear;

   --  --------------------
   --  Append an SQL extract into the buffer.
   --  --------------------
   procedure Append (Target : in out Buffer;
                     SQL    : in String) is
   begin
      Append (Target.Buf, SQL);
   end Append;

   --  --------------------
   --  Append a name in the buffer and escape that
   --  name if this is a reserved keyword.
   --  --------------------
   procedure Append_Name (Target : in out Buffer;
                          Name   : in String) is
      use type ADO.Drivers.Dialects.Dialect_Access;
      Dialect : constant ADO.Drivers.Dialects.Dialect_Access := Target.Get_Dialect;
   begin
      if Dialect /= null and then Dialect.Is_Reserved (Name) then
         declare
            Quote : constant Character := Dialect.Get_Identifier_Quote;
         begin
            Append (Target.Buf, Quote);
            Append (Target.Buf, Name);
            Append (Target.Buf, Quote);
         end;
      else
         Append (Target.Buf, Name);
      end if;
   end Append_Name;

   --  --------------------
   --  Append a string value in the buffer and
   --  escape any special character if necessary.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in String) is
   begin
      Append (Target.Buf, Value);
   end Append_Value;

   --  --------------------
   --  Append a string value in the buffer and
   --  escape any special character if necessary.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in Unbounded_String) is
   begin
      Append (Target.Buf, Value);
   end Append_Value;

   --  --------------------
   --  Append the integer value in the buffer.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in Long_Integer) is
      S : constant String := Long_Integer'Image (Value);
   begin
      Append (Target.Buf, S (S'First + 1 .. S'Last));
   end Append_Value;

   --  --------------------
   --  Append the integer value in the buffer.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in Integer) is
      S : constant String := Integer'Image (Value);
   begin
      Append (Target.Buf, S (S'First + 1 .. S'Last));
   end Append_Value;

   --  --------------------
   --  Append the identifier value in the buffer.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in Identifier) is
      S : constant String := Identifier'Image (Value);
   begin
      Append (Target.Buf, S (S'First + 1 .. S'Last));
   end Append_Value;

   --  --------------------
   --  Get the SQL string that was accumulated in the buffer.
   --  --------------------
   function To_String (From : in Buffer) return String is
   begin
      return To_String (From.Buf);
   end To_String;

   --  --------------------
   --  Clear the query object.
   --  --------------------
   overriding
   procedure Clear (Target : in out Query) is
   begin
      ADO.Parameters.List (Target).Clear;
      Target.Join.Clear;
      Target.Filter.Clear;
      Target.SQL.Clear;
   end Clear;

   --  --------------------
   --  Set the SQL dialect description object.
   --  --------------------
   procedure Set_Dialect (Target : in out Query;
                          D      : in ADO.Drivers.Dialects.Dialect_Access) is
   begin
      ADO.Parameters.Abstract_List (Target).Set_Dialect (D);
      Set_Dialect (Target.SQL, D);
      Set_Dialect (Target.Filter, D);
      Set_Dialect (Target.Join, D);
   end Set_Dialect;

   procedure Set_Filter (Target : in out Query;
                         Filter : in String) is
   begin
      Target.Filter.Buf := To_Unbounded_String (Filter);
   end Set_Filter;

   function Get_Filter (Source : in Query) return String is
   begin
      if Source.Filter.Buf = Null_Unbounded_String then
         return "";
      else
         return To_String (Source.Filter.Buf);
      end if;
   end Get_Filter;

   function Has_Filter (Source : in Query) return Boolean is
   begin
      return Source.Filter.Buf /= Null_Unbounded_String
        and Length (Source.Filter.Buf) > 0;
   end Has_Filter;

   --  --------------------
   --  Set the join condition.
   --  --------------------
   procedure Set_Join (Target : in out Query;
                       Join   : in String) is
   begin
      Target.Join.Buf := To_Unbounded_String (Join);
   end Set_Join;

   --  --------------------
   --  Returns true if there is a join condition
   --  --------------------
   function Has_Join (Source : in Query) return Boolean is
   begin
      return Source.Join.Buf /= Null_Unbounded_String
        and Length (Source.Join.Buf) > 0;
   end Has_Join;

   --  --------------------
   --  Get the join condition
   --  --------------------
   function Get_Join (Source : in Query) return String is
   begin
      if Source.Join.Buf = Null_Unbounded_String then
         return "";
      else
         return To_String (Source.Join.Buf);
      end if;
   end Get_Join;

   --  --------------------
   --  Set the parameters from another parameter list.
   --  If the parameter list is a query object, also copy the filter part.
   --  --------------------
   procedure Set_Parameters (Params : in out Query;
                             From   : in ADO.Parameters.Abstract_List'Class) is
   begin
      ADO.Parameters.List (Params).Set_Parameters (From);
      if From in Query'Class then
         declare
            L : constant Query'Class := Query'Class (From);
         begin
            Params.Filter := L.Filter;
            Params.Join   := L.Join;
         end;
      end if;
   end Set_Parameters;

   --  --------------------
   --  Expand the parameters into the query and return the expanded SQL query.
   --  --------------------
   function Expand (Source : in Query) return String is
   begin
      return ADO.Parameters.Abstract_List (Source).Expand (To_String (Source.SQL.Buf));
   end Expand;

   procedure Add_Field (Update : in out Update_Query'Class;
                        Name   : in String) is
   begin
      Update.Pos := Update.Pos + 1;
      if Update.Pos > 1 then
         Append (Target => Update.Set_Fields, SQL => ",");
         Append (Target => Update.Fields, SQL => ",");
      end if;
      Append_Name (Target => Update.Set_Fields, Name => Name);
      if Update.Is_Update_Stmt then
         Append (Target => Update.Set_Fields, SQL => " = ?");
      end if;
      Append (Target => Update.Fields, SQL => "?");
   end Add_Field;

   --  ------------------------------
   --  Set the SQL dialect description object.
   --  ------------------------------
   procedure Set_Dialect (Target : in out Update_Query;
                          D      : in ADO.Drivers.Dialects.Dialect_Access) is
   begin
      Target.Set_Fields.Set_Dialect (D);
      Target.Fields.Set_Dialect (D);
      Query (Target).Set_Dialect (D);
   end Set_Dialect;

   --  ------------------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  ------------------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Boolean) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Integer) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Long_Long_Integer) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Identifier) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Add_Param (Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Entity_Type) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Add_Param (Value => Integer (Value));
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Ada.Calendar.Time) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Add_Param (Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in String) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Unbounded_String) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  ------------------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  ------------------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in ADO.Blob_Ref) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  ------------------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to NULL.
   --  ------------------------------
   procedure Save_Null_Field (Update : in out Update_Query;
                              Name   : in String) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Null_Param (Position => Update.Pos);
   end Save_Null_Field;

   --  --------------------
   --  Check if the update/insert query has some fields to update.
   --  --------------------
   function Has_Save_Fields (Update : in Update_Query) return Boolean is
   begin
      return Update.Pos > 0;
   end Has_Save_Fields;

   procedure Set_Insert_Mode (Update : in out Update_Query) is
   begin
      Update.Is_Update_Stmt := False;
   end Set_Insert_Mode;

   procedure Append_Fields (Update : in out Update_Query;
                            Mode   : in Boolean := False) is
   begin
      if Mode then
         Append (Target => Update.SQL, SQL => To_String (Update.Fields.Buf));
      else
         Append (Target => Update.SQL, SQL => To_String (Update.Set_Fields.Buf));
      end if;
   end Append_Fields;

end ADO.SQL;

-----------------------------------------------------------------------
--  ADO SQL -- Basic SQL Generation
--  Copyright (C) 2010, 2011, 2012, 2015 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.
-----------------------------------------------------------------------

--  Utilities for creating SQL queries and statements.
package body ADO.SQL is

   --  --------------------
   --  Buffer
   --  --------------------

   --  --------------------
   --  Clear the SQL buffer.
   --  --------------------
   procedure Clear (Target : in out Buffer) is
   begin
      Target.Buf := To_Unbounded_String ("");
   end Clear;

   --  --------------------
   --  Append an SQL extract into the buffer.
   --  --------------------
   procedure Append (Target : in out Buffer;
                     SQL    : in String) is
   begin
      Append (Target.Buf, SQL);
   end Append;

   --  --------------------
   --  Append a name in the buffer and escape that
   --  name if this is a reserved keyword.
   --  --------------------
   procedure Append_Name (Target : in out Buffer;
                          Name   : in String) is
      use type ADO.Drivers.Dialects.Dialect_Access;
      Dialect : constant ADO.Drivers.Dialects.Dialect_Access := Target.Get_Dialect;
   begin
      if Dialect /= null and then Dialect.Is_Reserved (Name) then
         declare
            Quote : constant Character := Dialect.Get_Identifier_Quote;
         begin
            Append (Target.Buf, Quote);
            Append (Target.Buf, Name);
            Append (Target.Buf, Quote);
         end;
      else
         Append (Target.Buf, Name);
      end if;
   end Append_Name;

   --  --------------------
   --  Append a string value in the buffer and
   --  escape any special character if necessary.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in String) is
   begin
      Append (Target.Buf, Value);
   end Append_Value;

   --  --------------------
   --  Append a string value in the buffer and
   --  escape any special character if necessary.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in Unbounded_String) is
   begin
      Append (Target.Buf, Value);
   end Append_Value;

   --  --------------------
   --  Append the integer value in the buffer.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in Long_Integer) is
      S : constant String := Long_Integer'Image (Value);
   begin
      Append (Target.Buf, S (S'First + 1 .. S'Last));
   end Append_Value;

   --  --------------------
   --  Append the integer value in the buffer.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in Integer) is
      S : constant String := Integer'Image (Value);
   begin
      Append (Target.Buf, S (S'First + 1 .. S'Last));
   end Append_Value;

   --  --------------------
   --  Append the identifier value in the buffer.
   --  --------------------
   procedure Append_Value (Target : in out Buffer;
                           Value  : in Identifier) is
      S : constant String := Identifier'Image (Value);
   begin
      Append (Target.Buf, S (S'First + 1 .. S'Last));
   end Append_Value;

   --  --------------------
   --  Get the SQL string that was accumulated in the buffer.
   --  --------------------
   function To_String (From : in Buffer) return String is
   begin
      return To_String (From.Buf);
   end To_String;

   --  --------------------
   --  Clear the query object.
   --  --------------------
   overriding
   procedure Clear (Target : in out Query) is
   begin
      ADO.Parameters.List (Target).Clear;
      Target.Join.Clear;
      Target.Filter.Clear;
      Target.SQL.Clear;
   end Clear;

   --  --------------------
   --  Set the SQL dialect description object.
   --  --------------------
   procedure Set_Dialect (Target : in out Query;
                          D      : in ADO.Drivers.Dialects.Dialect_Access) is
   begin
      ADO.Parameters.Abstract_List (Target).Set_Dialect (D);
      Set_Dialect (Target.SQL, D);
      Set_Dialect (Target.Filter, D);
      Set_Dialect (Target.Join, D);
   end Set_Dialect;

   procedure Set_Filter (Target : in out Query;
                         Filter : in String) is
   begin
      Target.Filter.Buf := To_Unbounded_String (Filter);
   end Set_Filter;

   function Get_Filter (Source : in Query) return String is
   begin
      if Source.Filter.Buf = Null_Unbounded_String then
         return "";
      else
         return To_String (Source.Filter.Buf);
      end if;
   end Get_Filter;

   function Has_Filter (Source : in Query) return Boolean is
   begin
      return Source.Filter.Buf /= Null_Unbounded_String
        and Length (Source.Filter.Buf) > 0;
   end Has_Filter;

   --  --------------------
   --  Set the join condition.
   --  --------------------
   procedure Set_Join (Target : in out Query;
                       Join   : in String) is
   begin
      Target.Join.Buf := To_Unbounded_String (Join);
   end Set_Join;

   --  --------------------
   --  Returns true if there is a join condition
   --  --------------------
   function Has_Join (Source : in Query) return Boolean is
   begin
      return Source.Join.Buf /= Null_Unbounded_String
        and Length (Source.Join.Buf) > 0;
   end Has_Join;

   --  --------------------
   --  Get the join condition
   --  --------------------
   function Get_Join (Source : in Query) return String is
   begin
      if Source.Join.Buf = Null_Unbounded_String then
         return "";
      else
         return To_String (Source.Join.Buf);
      end if;
   end Get_Join;

   --  --------------------
   --  Set the parameters from another parameter list.
   --  If the parameter list is a query object, also copy the filter part.
   --  --------------------
   procedure Set_Parameters (Params : in out Query;
                             From   : in ADO.Parameters.Abstract_List'Class) is
   begin
      ADO.Parameters.List (Params).Set_Parameters (From);
      if From in Query'Class then
         declare
            L : constant Query'Class := Query'Class (From);
         begin
            Params.Filter := L.Filter;
            Params.Join   := L.Join;
         end;
      end if;
   end Set_Parameters;

   --  --------------------
   --  Expand the parameters into the query and return the expanded SQL query.
   --  --------------------
   function Expand (Source : in Query) return String is
   begin
      return ADO.Parameters.Abstract_List (Source).Expand (To_String (Source.SQL.Buf));
   end Expand;

   procedure Add_Field (Update : in out Update_Query'Class;
                        Name   : in String) is
   begin
      Update.Pos := Update.Pos + 1;
      if Update.Pos > 1 then
         Append (Target => Update.Set_Fields, SQL => ",");
         Append (Target => Update.Fields, SQL => ",");
      end if;
      Append_Name (Target => Update.Set_Fields, Name => Name);
      if Update.Is_Update_Stmt then
         Append (Target => Update.Set_Fields, SQL => " = ?");
      end if;
      Append (Target => Update.Fields, SQL => "?");
   end Add_Field;

   --  ------------------------------
   --  Set the SQL dialect description object.
   --  ------------------------------
   procedure Set_Dialect (Target : in out Update_Query;
                          D      : in ADO.Drivers.Dialects.Dialect_Access) is
   begin
      Target.Set_Fields.Set_Dialect (D);
      Target.Fields.Set_Dialect (D);
      Query (Target).Set_Dialect (D);
   end Set_Dialect;

   --  ------------------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  ------------------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Boolean) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Integer) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Long_Long_Integer) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Identifier) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Add_Param (Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Entity_Type) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Add_Param (Value => Integer (Value));
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Ada.Calendar.Time) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Add_Param (Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in String) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  --------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  --------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in Unbounded_String) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  ------------------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to the Value.
   --  ------------------------------
   procedure Save_Field (Update : in out Update_Query;
                         Name   : in String;
                         Value  : in ADO.Blob_Ref) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Param (Position => Update.Pos, Value => Value);
   end Save_Field;

   --  ------------------------------
   --  Prepare the update/insert query to save the table field
   --  identified by Name and set it to NULL.
   --  ------------------------------
   procedure Save_Null_Field (Update : in out Update_Query;
                              Name   : in String) is
   begin
      Update.Add_Field (Name => Name);
      Update_Query'Class (Update).Bind_Null_Param (Position => Update.Pos);
   end Save_Null_Field;

   --  --------------------
   --  Check if the update/insert query has some fields to update.
   --  --------------------
   function Has_Save_Fields (Update : in Update_Query) return Boolean is
   begin
      return Update.Pos > 0;
   end Has_Save_Fields;

   procedure Set_Insert_Mode (Update : in out Update_Query) is
   begin
      Update.Is_Update_Stmt := False;
   end Set_Insert_Mode;

   procedure Append_Fields (Update : in out Update_Query;
                            Mode   : in Boolean := False) is
   begin
      if Mode then
         Append (Target => Update.SQL, SQL => To_String (Update.Fields.Buf));
      else
         Append (Target => Update.SQL, SQL => To_String (Update.Set_Fields.Buf));
      end if;
   end Append_Fields;

end ADO.SQL;

Remove the Escape functions

Remove the Escape functions


--  Copyright (c) 2016 onox <denkpadje@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.

private with Ada.Containers.Vectors;
private with Ada.Strings.Unbounded;

with Orka.Transforms.SIMD_Matrices;

generic
   with package Transforms is new Orka.Transforms.SIMD_Matrices (<>);
package Orka.Scenes.Generic_Scene_Trees is
   pragma Preelaborate;

   subtype Matrix4 is Transforms.Matrix4;

   type Tree is tagged private;

   type Cursor is private;

   function To_Cursor (Object : Tree; Name : String) return Cursor;

   function Depth (Object : Tree) return Positive;

   function Width (Object : Tree; Level : Positive) return Natural
     with Pre => Level <= Object.Depth;

   procedure Update_Tree (Object : in out Tree);

   procedure Update_Tree (Object : in out Tree; Root_Transform : Transforms.Matrix4);

   procedure Set_Visibility (Object : in out Tree; Node : Cursor; Visible : Boolean);

   function Visibility (Object : Tree; Node : Cursor) return Boolean;

   procedure Set_Local_Transform (Object : in out Tree; Node : Cursor; Transform : Transforms.Matrix4);

   function World_Transform (Object : Tree; Node : Cursor) return Transforms.Matrix4;

   function Root_Name (Object : Tree) return String;

   function Create_Tree (Name : String) return Tree;

   procedure Add_Node (Object : in out Tree; Name, Parent : String);

   procedure Remove_Node (Object : in out Tree; Name : String);

   Unknown_Node_Error : exception;
   --  Exception raised if a given node does not exist

   Root_Removal_Error : exception;
   --  Exception raised if user tries to remove the root node

private

   package SU renames Ada.Strings.Unbounded;

   type Node is record
      Offset : Positive;
      Count  : Natural;
      Name   : SU.Unbounded_String;
   end record;

   package Node_Vectors is new Ada.Containers.Vectors (Positive, Node);

   package Boolean_Vectors is new Ada.Containers.Vectors (Positive, Boolean);

   use type Transforms.Matrix4;
   package Matrix_Vectors is new Ada.Containers.Vectors (Positive, Transforms.Matrix4);

   type Level is record
      Nodes : Node_Vectors.Vector;
      Local_Transforms : Matrix_Vectors.Vector;
      World_Transforms : Matrix_Vectors.Vector;
      Local_Visibilities : Boolean_Vectors.Vector;
      World_Visibilities : Boolean_Vectors.Vector;
   end record;

   package Level_Vectors is new Ada.Containers.Vectors (Positive, Level);

   type Tree is tagged record
      Levels : Level_Vectors.Vector;
   end record;

   type Cursor is record
      Level, Offset : Positive;
   end record;

   function Depth (Object : Tree) return Positive is
     (Positive (Object.Levels.Length));

   function Width (Object : Tree; Level : Positive) return Natural is
     (Natural (Object.Levels (Level).Nodes.Length));

end Orka.Scenes.Generic_Scene_Trees;

--  Copyright (c) 2016 onox <denkpadje@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.

private with Ada.Containers.Vectors;
private with Ada.Strings.Unbounded;

with Orka.Transforms.SIMD_Matrices;

generic
   with package Transforms is new Orka.Transforms.SIMD_Matrices (<>);
package Orka.Scenes.Generic_Scene_Trees is
   pragma Preelaborate;

   subtype Matrix4 is Transforms.Matrix4;

   type Tree is tagged private;

   type Cursor is private;

   function To_Cursor (Object : Tree; Name : String) return Cursor;

   function Depth (Object : Tree) return Positive;

   function Width (Object : Tree; Level : Positive) return Natural
     with Pre => Level <= Object.Depth;

   procedure Update_Tree (Object : in out Tree);

   procedure Update_Tree (Object : in out Tree; Root_Transform : Transforms.Matrix4);

   procedure Set_Visibility (Object : in out Tree; Node : Cursor; Visible : Boolean);

   function Visibility (Object : Tree; Node : Cursor) return Boolean;

   procedure Set_Local_Transform (Object : in out Tree; Node : Cursor; Transform : Transforms.Matrix4);

   function World_Transform (Object : Tree; Node : Cursor) return Transforms.Matrix4;

   function Root_Name (Object : Tree) return String;

   function Create_Tree (Name : String) return Tree;

   procedure Add_Node (Object : in out Tree; Name, Parent : String);

   procedure Remove_Node (Object : in out Tree; Name : String);

   Unknown_Node_Error : exception;
   --  Exception raised if a given node does not exist

   Root_Removal_Error : exception;
   --  Exception raised if user tries to remove the root node

private

   package SU renames Ada.Strings.Unbounded;

   type Node is record
      Offset : Positive;
      Count  : Natural;
      Name   : SU.Unbounded_String;
   end record;

   pragma Suppress (Tampering_Check);
   --  Disabling the tampering check speeds up execution of Add_Node,
   --  reducing the time to create a full scene tree to around 20 %.

   package Node_Vectors is new Ada.Containers.Vectors (Positive, Node);

   package Boolean_Vectors is new Ada.Containers.Vectors (Positive, Boolean);

   use type Transforms.Matrix4;
   package Matrix_Vectors is new Ada.Containers.Vectors (Positive, Transforms.Matrix4);

   type Level is record
      Nodes : Node_Vectors.Vector;
      Local_Transforms : Matrix_Vectors.Vector;
      World_Transforms : Matrix_Vectors.Vector;
      Local_Visibilities : Boolean_Vectors.Vector;
      World_Visibilities : Boolean_Vectors.Vector;
   end record;

   package Level_Vectors is new Ada.Containers.Vectors (Positive, Level);

   type Tree is tagged record
      Levels : Level_Vectors.Vector;
   end record;

   type Cursor is record
      Level, Offset : Positive;
   end record;

   function Depth (Object : Tree) return Positive is
     (Positive (Object.Levels.Length));

   function Width (Object : Tree; Level : Positive) return Natural is
     (Natural (Object.Levels (Level).Nodes.Length));

end Orka.Scenes.Generic_Scene_Trees;

orka: Disable Tampering_Check to speed up adding nodes to a scene tree

Signed-off-by: onox <34c1d3d2d1347bea60a26f46574de21a7a79b6d5@gmail.com>


-----------------------------------------------------------------------
--  wiki-render -- Wiki renderer
--  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 Wiki.Nodes;
with Wiki.Strings;
with Wiki.Documents;

--  == Wiki Renderer ==
--  The <tt>Wiki.Render</tt> package represents the renderer that takes a wiki document
--  and render the result either in text, HTML or another format.
--
--  @include wiki-render-html.ads
--  @include wiki-render-text.ads
--  @include wiki-render-wiki.ads
package Wiki.Render is

   pragma Preelaborate;

   type Link_Renderer is limited interface;
   type Link_Renderer_Access is access all Link_Renderer'Class;

   --  Get the image link that must be rendered from the wiki image link.
   procedure Make_Image_Link (Renderer : in Link_Renderer;
                              Link     : in Wiki.Strings.WString;
                              URI      : out Wiki.Strings.UString;
                              Width    : out Natural;
                              Height   : out Natural) is abstract;

   --  Get the page link that must be rendered from the wiki page link.
   procedure Make_Page_Link (Renderer : in Link_Renderer;
                             Link     : in Wiki.Strings.WString;
                             URI      : out Wiki.Strings.UString;
                             Exists   : out Boolean) is abstract;

   type Default_Link_Renderer is new Link_Renderer with null record;

   --  Get the image link that must be rendered from the wiki image link.
   overriding
   procedure Make_Image_Link (Renderer : in Default_Link_Renderer;
                              Link     : in Wiki.Strings.WString;
                              URI      : out Wiki.Strings.UString;
                              Width    : out Natural;
                              Height   : out Natural);

   --  Get the page link that must be rendered from the wiki page link.
   overriding
   procedure Make_Page_Link (Renderer : in Default_Link_Renderer;
                             Link     : in Wiki.Strings.WString;
                             URI      : out Wiki.Strings.UString;
                             Exists   : out Boolean);

   --  ------------------------------
   --  Document renderer
   --  ------------------------------
   type Renderer is limited interface;
   type Renderer_Access is access all Renderer'Class;

   --  Render the node instance from the document.
   procedure Render (Engine : in out Renderer;
                     Doc    : in Wiki.Documents.Document;
                     Node   : in Wiki.Nodes.Node_Type) is abstract;

   --  Finish the rendering pass after all the wiki document nodes are rendered.
   procedure Finish (Engine : in out Renderer;
                     Doc    : in Wiki.Documents.Document) is null;

   --  Render the list of nodes from the document.
   procedure Render (Engine : in out Renderer'Class;
                     Doc    : in Wiki.Documents.Document;
                     List   : in Wiki.Nodes.Node_List_Access);

   --  Render the document.
   procedure Render (Engine : in out Renderer'Class;
                     Doc    : in Wiki.Documents.Document);

end Wiki.Render;

-----------------------------------------------------------------------
--  wiki-render -- Wiki renderer
--  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 Wiki.Nodes;
with Wiki.Strings;
with Wiki.Documents;

--  == Wiki Renderer ==
--  The <tt>Wiki.Render</tt> package represents the renderer that takes a wiki document
--  and render the result either in text, HTML or another format.
--
--  @include wiki-render-html.ads
--  @include wiki-render-links.ads
--  @include wiki-render-text.ads
--  @include wiki-render-wiki.ads
package Wiki.Render is

   pragma Preelaborate;

   --  ------------------------------
   --  Document renderer
   --  ------------------------------
   type Renderer is limited interface;
   type Renderer_Access is access all Renderer'Class;

   --  Render the node instance from the document.
   procedure Render (Engine : in out Renderer;
                     Doc    : in Wiki.Documents.Document;
                     Node   : in Wiki.Nodes.Node_Type) is abstract;

   --  Finish the rendering pass after all the wiki document nodes are rendered.
   procedure Finish (Engine : in out Renderer;
                     Doc    : in Wiki.Documents.Document) is null;

   --  Render the list of nodes from the document.
   procedure Render (Engine : in out Renderer'Class;
                     Doc    : in Wiki.Documents.Document;
                     List   : in Wiki.Nodes.Node_List_Access);

   --  Render the document.
   procedure Render (Engine : in out Renderer'Class;
                     Doc    : in Wiki.Documents.Document);

end Wiki.Render;

Move the Link_Renderer and Default_Link_Renderer in the Wiki.Render.Links pacakge