-----------------------------------------------------------------------
--  ADO Sessions -- Sessions Management
--  Copyright (C) 2009, 2010, 2011, 2012, 2013, 2015, 2017 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.Finalization;

with ADO.Schemas;
with ADO.Statements;
with ADO.Objects;
with ADO.Objects.Cache;
with ADO.Drivers.Connections;
with ADO.Queries;
with ADO.SQL;
with ADO.Caches;

with Util.Concurrent.Counters;
limited with ADO.Sequences;
limited with ADO.Schemas.Entities;

--  == Session ==
--  The `ADO.Sessions` package defines the control and management of database sessions.
--  The database session is represented by the `Session` or `Master_Session` types.
--  It provides operation to create a database statement that can be executed.
--  The `Session` type is used to represent read-only database sessions.  It provides
--  operations to query the database but it does not allow to update or delete content.
--  The `Master_Session` type extends the `Session` type to provide write
--  access and it provides operations to get update or delete statements.  The differentiation
--  between the two sessions is provided for the support of database replications with
--  databases such as MySQL.
--
--  @include ado-sessions-factory.ads
--  @include ado-sequences.ads
--
package ADO.Sessions is

   use ADO.Statements;

   --  Raised for all errors reported by the database
   DB_Error : exception;

   --  Raised if the database connection is not open.
   NOT_OPEN : exception;

   NOT_FOUND : exception;

   NO_DATABASE : exception;

   --  Raised when the connection URI is invalid.
   Connection_Error : exception;

   --  The database connection status
   type Connection_Status is (OPEN, CLOSED);

   type Object_Factory is tagged private;

   --  ---------
   --  Session
   --  ---------
   --  Read-only database connection (or slave connection).
   --
   type Session is tagged private;

   --  Get the session status.
   function Get_Status (Database : in Session) return Connection_Status;

   --  Get the database driver which manages this connection.
   function Get_Driver (Database : in Session) return ADO.Drivers.Connections.Driver_Access;

   --  Close the session.
   procedure Close (Database : in out Session);

   --  Insert a new cache in the manager.  The cache is identified by the given name.
   procedure Add_Cache (Database : in out Session;
                        Name     : in String;
                        Cache    : in ADO.Caches.Cache_Type_Access);

   --  Attach the object to the session.
   procedure Attach (Database : in out Session;
                     Object   : in ADO.Objects.Object_Ref'Class);

   --  Check if the session contains the object identified by the given key.
   function Contains (Database : in Session;
                      Item     : in ADO.Objects.Object_Key) return Boolean;

   --  Remove the object from the session cache.
   procedure Evict (Database : in out Session;
                    Item     : in ADO.Objects.Object_Key);

   --  Create a query statement.  The statement is not prepared
   function Create_Statement (Database : in Session;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Query_Statement;

   --  Create a query statement.  The statement is not prepared
   function Create_Statement (Database : in Session;
                              Query    : in String)
                              return Query_Statement;

   --  Create a query statement.  The statement is not prepared
   function Create_Statement (Database : in Session;
                              Query    : in ADO.Queries.Context'Class)
                              return Query_Statement;

   --  Create a query statement and initialize the SQL statement with the query definition.
   function Create_Statement (Database : in Session;
                              Query    : in ADO.Queries.Query_Definition_Access)
                              return Query_Statement;

   --  Create a query statement.  The statement is not prepared
   function Create_Statement (Database : in Session;
                              Query    : in ADO.SQL.Query'Class;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Query_Statement;

   --  Load the database schema definition for the current database.
   procedure Load_Schema (Database : in Session;
                          Schema   : out ADO.Schemas.Schema_Definition);

   --  Internal method to get the session proxy associated with the given database session.
   --  The session proxy is associated with some ADO objects to be able to retrieve the database
   --  session for the implementation of lazy loading.  The session proxy is kept until the
   --  session exist and at least one ADO object is refering to it.
   function Get_Session_Proxy (Database : in Session) return ADO.Objects.Session_Proxy_Access;

   --  ---------
   --  Master Session
   --  ---------
   --  Read-write session.
   --
   type Master_Session is new Session with private;

   --  Start a transaction.
   procedure Begin_Transaction (Database : in out Master_Session);

   --  Commit the current transaction.
   procedure Commit (Database : in out Master_Session);

   --  Rollback the current transaction.
   procedure Rollback (Database : in out Master_Session);

   --  Allocate an identifier for the table.
   procedure Allocate (Database : in out Master_Session;
                       Id       : in out ADO.Objects.Object_Record'Class);

   --  Flush the objects that were modified.
   procedure Flush (Database : in out Master_Session);

   --  Create a delete statement
   function Create_Statement (Database : in Master_Session;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Delete_Statement;

   --  Create an update statement
   function Create_Statement (Database : in Master_Session;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Update_Statement;

   --  Create an insert statement
   function Create_Statement (Database : in Master_Session;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Insert_Statement;

   type Session_Record is limited private;
   type Session_Record_Access is access all Session_Record;

private

   type Entity_Cache_Access is access ADO.Schemas.Entities.Entity_Cache;

   type Object_Factory is tagged record
      A : Integer;
   end record;
   type Object_Factory_Access is access all Object_Factory'Class;

   --  The Session_Record maintains the connection information to the database for
   --  the duration of the session.  It also maintains a cache of application objects
   --  which is used when session objects are fetched (either through Load or a Find).
   --  The connection is released and the session record is deleted when the session
   --  is closed with Close.
   --
   --  For the lazy loading support, each object is associated with a shared Session_Proxy
   --  object that allows to give access to the session record associated with the object.
   --  When a session is closed, the Session_Proxy is not deleted but it is simply
   --  unlinked from the session record.
   type Session_Record is limited record
      Counter  : Util.Concurrent.Counters.Counter := Util.Concurrent.Counters.ONE;
      Database : ADO.Drivers.Connections.Ref.Ref;
      Proxy    : ADO.Objects.Session_Proxy_Access;
      Cache    : ADO.Objects.Cache.Object_Cache;
      Entities : Entity_Cache_Access;
      Values   : ADO.Caches.Cache_Manager_Access;
      Queries  : ADO.Queries.Query_Manager_Access;
   end record;

   type Session is new Ada.Finalization.Controlled with record
      Impl : Session_Record_Access := null;
   end record;

   overriding
   procedure Adjust (Object : in out Session);

   overriding
   procedure Finalize (Object : in out Session);

   type Factory_Access is access all ADO.Sequences.Factory;

   type Master_Session is new Session with record
      Sequences : Factory_Access;
   end record;

   procedure Check_Session (Database : in Session'Class;
                            Message  : in String := "");
   pragma Inline (Check_Session);

end ADO.Sessions;

-----------------------------------------------------------------------
--  ADO Sessions -- Sessions Management
--  Copyright (C) 2009, 2010, 2011, 2012, 2013, 2015, 2017 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.Finalization;

with ADO.Schemas;
with ADO.Statements;
with ADO.Objects;
with ADO.Objects.Cache;
with ADO.Drivers.Connections;
with ADO.Queries;
with ADO.SQL;
with ADO.Caches;

with Util.Concurrent.Counters;
limited with ADO.Sequences;
limited with ADO.Schemas.Entities;

--  = Session =
--  The `ADO.Sessions` package defines the control and management of database sessions.
--  The database session is represented by the `Session` or `Master_Session` types.
--  It provides operation to create a database statement that can be executed.
--  The `Session` type is used to represent read-only database sessions.  It provides
--  operations to query the database but it does not allow to update or delete content.
--  The `Master_Session` type extends the `Session` type to provide write
--  access and it provides operations to get update or delete statements.  The differentiation
--  between the two sessions is provided for the support of database replications with
--  databases such as MySQL.
--
--  @include ado-sessions-sources.ads
--  @include ado-sessions-factory.ads
--  @include ado-caches.ads
package ADO.Sessions is

   use ADO.Statements;

   --  Raised for all errors reported by the database
   DB_Error : exception;

   --  Raised if the database connection is not open.
   NOT_OPEN : exception;

   NOT_FOUND : exception;

   NO_DATABASE : exception;

   --  Raised when the connection URI is invalid.
   Connection_Error : exception;

   --  The database connection status
   type Connection_Status is (OPEN, CLOSED);

   type Object_Factory is tagged private;

   --  ---------
   --  Session
   --  ---------
   --  Read-only database connection (or slave connection).
   --
   type Session is tagged private;

   --  Get the session status.
   function Get_Status (Database : in Session) return Connection_Status;

   --  Get the database driver which manages this connection.
   function Get_Driver (Database : in Session) return ADO.Drivers.Connections.Driver_Access;

   --  Close the session.
   procedure Close (Database : in out Session);

   --  Insert a new cache in the manager.  The cache is identified by the given name.
   procedure Add_Cache (Database : in out Session;
                        Name     : in String;
                        Cache    : in ADO.Caches.Cache_Type_Access);

   --  Attach the object to the session.
   procedure Attach (Database : in out Session;
                     Object   : in ADO.Objects.Object_Ref'Class);

   --  Check if the session contains the object identified by the given key.
   function Contains (Database : in Session;
                      Item     : in ADO.Objects.Object_Key) return Boolean;

   --  Remove the object from the session cache.
   procedure Evict (Database : in out Session;
                    Item     : in ADO.Objects.Object_Key);

   --  Create a query statement.  The statement is not prepared
   function Create_Statement (Database : in Session;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Query_Statement;

   --  Create a query statement.  The statement is not prepared
   function Create_Statement (Database : in Session;
                              Query    : in String)
                              return Query_Statement;

   --  Create a query statement.  The statement is not prepared
   function Create_Statement (Database : in Session;
                              Query    : in ADO.Queries.Context'Class)
                              return Query_Statement;

   --  Create a query statement and initialize the SQL statement with the query definition.
   function Create_Statement (Database : in Session;
                              Query    : in ADO.Queries.Query_Definition_Access)
                              return Query_Statement;

   --  Create a query statement.  The statement is not prepared
   function Create_Statement (Database : in Session;
                              Query    : in ADO.SQL.Query'Class;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Query_Statement;

   --  Load the database schema definition for the current database.
   procedure Load_Schema (Database : in Session;
                          Schema   : out ADO.Schemas.Schema_Definition);

   --  Internal method to get the session proxy associated with the given database session.
   --  The session proxy is associated with some ADO objects to be able to retrieve the database
   --  session for the implementation of lazy loading.  The session proxy is kept until the
   --  session exist and at least one ADO object is refering to it.
   function Get_Session_Proxy (Database : in Session) return ADO.Objects.Session_Proxy_Access;

   --  ---------
   --  Master Session
   --  ---------
   --  Read-write session.
   --
   type Master_Session is new Session with private;

   --  Start a transaction.
   procedure Begin_Transaction (Database : in out Master_Session);

   --  Commit the current transaction.
   procedure Commit (Database : in out Master_Session);

   --  Rollback the current transaction.
   procedure Rollback (Database : in out Master_Session);

   --  Allocate an identifier for the table.
   procedure Allocate (Database : in out Master_Session;
                       Id       : in out ADO.Objects.Object_Record'Class);

   --  Flush the objects that were modified.
   procedure Flush (Database : in out Master_Session);

   --  Create a delete statement
   function Create_Statement (Database : in Master_Session;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Delete_Statement;

   --  Create an update statement
   function Create_Statement (Database : in Master_Session;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Update_Statement;

   --  Create an insert statement
   function Create_Statement (Database : in Master_Session;
                              Table    : in ADO.Schemas.Class_Mapping_Access)
                              return Insert_Statement;

   type Session_Record is limited private;
   type Session_Record_Access is access all Session_Record;

private

   type Entity_Cache_Access is access ADO.Schemas.Entities.Entity_Cache;

   type Object_Factory is tagged record
      A : Integer;
   end record;
   type Object_Factory_Access is access all Object_Factory'Class;

   --  The Session_Record maintains the connection information to the database for
   --  the duration of the session.  It also maintains a cache of application objects
   --  which is used when session objects are fetched (either through Load or a Find).
   --  The connection is released and the session record is deleted when the session
   --  is closed with Close.
   --
   --  For the lazy loading support, each object is associated with a shared Session_Proxy
   --  object that allows to give access to the session record associated with the object.
   --  When a session is closed, the Session_Proxy is not deleted but it is simply
   --  unlinked from the session record.
   type Session_Record is limited record
      Counter  : Util.Concurrent.Counters.Counter := Util.Concurrent.Counters.ONE;
      Database : ADO.Drivers.Connections.Ref.Ref;
      Proxy    : ADO.Objects.Session_Proxy_Access;
      Cache    : ADO.Objects.Cache.Object_Cache;
      Entities : Entity_Cache_Access;
      Values   : ADO.Caches.Cache_Manager_Access;
      Queries  : ADO.Queries.Query_Manager_Access;
   end record;

   type Session is new Ada.Finalization.Controlled with record
      Impl : Session_Record_Access := null;
   end record;

   overriding
   procedure Adjust (Object : in out Session);

   overriding
   procedure Finalize (Object : in out Session);

   type Factory_Access is access all ADO.Sequences.Factory;

   type Master_Session is new Session with record
      Sequences : Factory_Access;
   end record;

   procedure Check_Session (Database : in Session'Class;
                            Message  : in String := "");
   pragma Inline (Check_Session);

end ADO.Sessions;

Add some documentation

Add some documentation


-----------------------------------------------------------------------
--  asf.sessions -- ASF Sessions
--  Copyright (C) 2010, 2011 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 EL.Objects;
with Ada.Calendar;
with Ada.Finalization;
with Ada.Strings.Unbounded;
with ASF.Principals;
private with Util.Beans.Objects.Maps;
private with Util.Concurrent.Locks;
private with Util.Concurrent.Counters;

--  The <b>ASF.Sessions</b> package is an Ada implementation of the
--  Java servlet Specification (See JSR 315 at jcp.org).
package ASF.Sessions is

   --  Raised if there is no session.
   No_Session : exception;

   --  The default session inactive timeout.
   DEFAULT_INACTIVE_TIMEOUT : constant Duration := 300.0;

   --  Provides a way to identify a user across more than one page request
   --  or visit to a Web site and to store information about that user.
   --
   --  The servlet container uses this interface to create a session between
   --  an HTTP client and an HTTP server.  The session persists for a specified
   --  time period, across more than one connection or page request from the user.
   --  A session usually corresponds to one user, who may visit a site many times.
   --  The server can maintain a session in many ways such as using cookies
   --  or rewriting URLs.
   --
   --  This interface allows servlets to
   --   * View and manipulate information about a session, such as the session
   --     identifier, creation time, and last accessed time
   --   * Bind objects to sessions, allowing user information to persist across
   --     multiple user connections
   --
   --  A servlet should be able to handle cases in which the client does not
   --  choose to join a session, such as when cookies are intentionally turned off.
   --  Until the client joins the session, isNew returns true. If the client chooses
   --  not to join the session, getSession will return a different session on each
   --  request, and isNew will always return true.
   --
   --  Session information is scoped only to the current web application (ServletContext),
   --  so information stored in one context will not be directly visible in another.
   type Session is tagged private;

   --  Returns true if the session is valid.
   function Is_Valid (Sess : in Session'Class) return Boolean;

   --  Returns a string containing the unique identifier assigned to this session.
   --  The identifier is assigned by the servlet container and is implementation dependent.
   function Get_Id (Sess : in Session) return String;

   --  Returns the last time the client sent a request associated with this session,
   --  as the number of milliseconds since midnight January 1, 1970 GMT, and marked
   --  by the time the container recieved the request.
   --
   --  Actions that your application takes, such as getting or setting a value associated
   --  with the session, do not affect the access time.
   function Get_Last_Accessed_Time (Sess : in Session) return Ada.Calendar.Time;

   --  Returns the maximum time interval, in seconds, that the servlet container will
   --  keep this session open between client accesses. After this interval, the servlet
   --  container will invalidate the session. The maximum time interval can be set with
   --  the Set_Max_Inactive_Interval method.
   --  A negative time indicates the session should never timeout.
   function Get_Max_Inactive_Interval (Sess : in Session) return Duration;

   --  Specifies the time, in seconds, between client requests before the servlet
   --  container will invalidate this session. A negative time indicates the session
   --  should never timeout.
   procedure Set_Max_Inactive_Interval (Sess     : in Session;
                                        Interval : in Duration);

   --  Returns the object bound with the specified name in this session,
   --  or null if no object is bound under the name.
   function Get_Attribute (Sess : in Session;
                           Name : in String) return EL.Objects.Object;

   --  Binds an object to this session, using the name specified.
   --  If an object of the same name is already bound to the session,
   --  the object is replaced.
   --
   --  If the value passed in is null, this has the same effect as calling
   --  removeAttribute().
   procedure Set_Attribute (Sess  : in out Session;
                            Name  : in String;
                            Value : in EL.Objects.Object);

   --  Removes the object bound with the specified name from this session.
   --  If the session does not have an object bound with the specified name,
   --  this method does nothing.
   procedure Remove_Attribute (Sess : in out Session;
                               Name : in String);

   --  Gets the principal that authenticated to the session.
   --  Returns null if there is no principal authenticated.
   function Get_Principal (Sess : in Session) return ASF.Principals.Principal_Access;

   --  Sets the principal associated with the session.
   procedure Set_Principal (Sess      : in out Session;
                            Principal : in ASF.Principals.Principal_Access);

   --  Invalidates this session then unbinds any objects bound to it.
   procedure Invalidate (Sess : in out Session);

   Null_Session : constant Session;
private

   type Session_Record;
   type Session_Record_Access is access all Session_Record'Class;

   type Session_Record is new Ada.Finalization.Limited_Controlled with record
      --  Reference counter.
      Ref_Counter  : Util.Concurrent.Counters.Counter;

      --  RW lock to protect access to members.
      Lock         : Util.Concurrent.Locks.RW_Lock;

      --  Attributes bound to this session.
      Attributes   : aliased Util.Beans.Objects.Maps.Map;

      --  Time when the session was created.
      Create_Time  : Ada.Calendar.Time;

      --  Time when the session was last accessed.
      Access_Time  : Ada.Calendar.Time;

      --  Max inactive time in seconds.
      Max_Inactive : Duration := DEFAULT_INACTIVE_TIMEOUT;

      --  Session identifier.
      Id           : Ada.Strings.Unbounded.String_Access;

      --  True if the session is active.
      Is_Active    : Boolean := True;

      --  When not null, the principal that authenticated to this session.
      Principal  : ASF.Principals.Principal_Access := null;
   end record;

   overriding
   procedure Finalize (Object : in out Session_Record);

   type Session is new Ada.Finalization.Controlled with record
      Impl : Session_Record_Access;
   end record;

   --  Adjust (increment) the session record reference counter.
   overriding
   procedure Adjust (Object : in out Session);

   --  Decrement the session record reference counter and free the session record
   --  if this was the last session reference.
   overriding
   procedure Finalize (Object : in out Session);

   Null_Session : constant Session := Session'(Ada.Finalization.Controlled with Impl => null);

end ASF.Sessions;

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

package ASF.Sessions renames Servlet.Sessions;

Package ASF.Sessions moved to Servlet.Sessions


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

with Util.Log.Loggers;

with ASF.Server.Web;

with Atlas.Applications;
procedure Atlas.Server is

   Log     : constant Util.Log.Loggers.Logger := Util.Log.Loggers.Create ("Atlas.Server");
   App     : constant Atlas.Applications.Application_Access := new Atlas.Applications.Application;
   WS      : ASF.Server.Web.AWS_Container;
begin
   Atlas.Applications.Initialize (App);
   WS.Register_Application (Atlas.Applications.CONTEXT_PATH, App.all'Access);
   Log.Info ("Connect you browser to: http://localhost:8080/atlas/index.html");
   WS.Start;
   delay 365.0 * 24.0 * 3600.0;
   App.Close;
exception
   when E : others =>
      Log.Error ("Exception in server: " &
                 Ada.Exceptions.Exception_Name (E) & ": " &
                 Ada.Exceptions.Exception_Message (E));
end Atlas.Server;

-----------------------------------------------------------------------
--  Atlas-server -- Application server
--  Copyright (C) 2011, 2012, 2013, 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.Exceptions;

with Util.Log.Loggers;

with AWS.Config.Set;
with ASF.Server.Web;
with AWA.Setup.Applications;

with Atlas.Applications;
procedure Atlas.Server is

   procedure Configure (Config : in out AWS.Config.Object);

   Log     : constant Util.Log.Loggers.Logger := Util.Log.Loggers.Create ("Atlas.Server");
   App     : constant Atlas.Applications.Application_Access := new Atlas.Applications.Application;
   WS      : ASF.Server.Web.AWS_Container;
   Setup   : AWA.Setup.Applications.Application;

   procedure Configure (Config : in out AWS.Config.Object) is
   begin
      AWS.Config.Set.Input_Line_Size_Limit (1_000_000);
      AWS.Config.Set.Max_Connection (Config, 2);
      AWS.Config.Set.Accept_Queue_Size (Config, 100);
      AWS.Config.Set.Send_Buffer_Size (Config, 128 * 1024);
      AWS.Config.Set.Upload_Size_Limit (Config, 100_000_000);
   end Configure;

begin
   WS.Configure (Configure'Access);
WS.Start;
   Setup.Setup ("atlas.properties", WS);
   Atlas.Applications.Initialize (App);
   WS.Register_Application (Atlas.Applications.CONTEXT_PATH, App.all'Access);
   Log.Info ("Connect you browser to: http://localhost:8080/atlas/index.html");
   --  WS.Start;
   delay 365.0 * 24.0 * 3600.0;
   App.Close;
exception
   when E : others =>
      Log.Error ("Exception in server: " &
                 Ada.Exceptions.Exception_Name (E) & ": " &
                 Ada.Exceptions.Exception_Message (E));
end Atlas.Server;

Add the setup application to configure the Atlas application


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

   --  A UIComponent can have several validators.  To keep the implementation light and
   --  simple, a fixed array is used.  Most components will have one or two validators.
   --  Define the number of validators per component (UIInput).
   MAX_VALIDATORS_PER_COMPONENT : constant Positive := 5;

   --  Message displayed when the submitted value is required but is empty.
   REQUIRED_MESSAGE_ID          : constant String := "asf.faces.component.UIInput.REQUIRED";

   --  ------------------------------
   --  Form Component
   --  ------------------------------
   type UIForm is new UIHtmlComponent with private;
   type UIForm_Access is access all UIForm'Class;

   --  Check whether the form is submitted.
   function Is_Submitted (UI : in UIForm) return Boolean;

   --  Called during the Apply Request phase to indicate that this
   --  form is submitted.
   procedure Set_Submitted (UI : in out UIForm);

   --  Get the action URL to set on the HTML form
   function Get_Action (UI      : in UIForm;
                        Context : in Faces_Context'Class) return String;

   overriding
   procedure Encode_Begin (UI      : in UIForm;
                           Context : in out Faces_Context'Class);

   overriding
   procedure Encode_End (UI      : in UIForm;
                         Context : in out Faces_Context'Class);

   overriding
   procedure Decode (UI      : in out UIForm;
                     Context : in out Faces_Context'Class);

   overriding
   procedure Process_Decodes (UI      : in out UIForm;
                              Context : in out Faces_Context'Class);

   --  ------------------------------
   --  Input Component
   --  ------------------------------
   type UIInput is new Text.UIOutput and Holders.Editable_Value_Holder with private;
   type UIInput_Access is access all UIInput'Class;

   --  Check if this component has the required attribute set.
   function Is_Required (UI      : in UIInput;
                         Context : in Faces_Context'Class) return Boolean;

   --  Find the form component which contains the input component.
   --  Returns null if the input is not within a form component.
   function Get_Form (UI : in UIInput) return UIForm_Access;

   --  Get the value of the component.  If the component has a submitted value, returns it.
   --  If the component has a local value which is not null, returns it.
   --  Otherwise, if we have a Value_Expression evaluate and returns the value.
   overriding
   function Get_Value (UI    : in UIInput) return EL.Objects.Object;

   --  Set the input component as a password field.
   procedure Set_Secret (UI    : in out UIInput;
                         Value : in Boolean);

   --  Render the input element.
   procedure Render_Input (UI       : in UIInput;
                           Context  : in out Faces_Context'Class;
                           Write_Id : in Boolean := True);

   overriding
   procedure Encode_Begin (UI      : in UIInput;
                           Context : in out Faces_Context'Class);

   overriding
   procedure Process_Decodes (UI      : in out UIInput;
                              Context : in out Faces_Context'Class);

   --  Perform the component tree processing required by the Process Validations
   --  phase of the request processing lifecycle for all facets of this component,
   --  all children of this component, and this component itself, as follows:
   --

   --
If this component rendered property is false, skip further processing.
   --
Call the Process_Validators of all facets and children.
   --

   procedure Process_Validators (UI      : in out UIInput;
                                 Context : in out Faces_Context'Class);

   overriding
   procedure Process_Updates (UI      : in out UIInput;
                              Context : in out Faces_Context'Class);

   --  Validate the submitted value.
   --

   --
Retreive the submitted value
   --
If the value is null, exit without further processing.
   --
Validate the value by calling Validate_Value
   --

   procedure Validate (UI      : in out UIInput;
                       Context : in out Faces_Context'Class);

   --  Set the valid property:
   --

   --
If the required property is true, ensure the
   --         value is not empty
   --
Call the Validate procedure on each validator
   --         registered on this component.
   --
Set the valid property if all validator passed.
   --

   procedure Validate_Value (UI      : in out UIInput;
                             Value   : in EL.Objects.Object;
                             Context : in out Faces_Context'Class);

   --  Add the validator to be used on the component.  The ASF implementation limits
   --  to 5 the number of validators that can be set on a component (See UIInput).
   --  The validator instance will be freed when the editable value holder is deleted
   --  unless Shared is true.
   overriding
   procedure Add_Validator (UI        : in out UIInput;
                            Validator : in ASF.Validators.Validator_Access;
                            Shared    : in Boolean := False);

   --  Delete the UI input instance.
   overriding
   procedure Finalize (UI : in out UIInput);

   --  ------------------------------
   --  InputTextarea Component
   --  ------------------------------
   type UIInputTextarea is new UIInput with private;
   type UIInputTextarea_Access is access all UIInputTextarea'Class;

   --  Render the textarea element.
   overriding
   procedure Render_Input (UI       : in UIInputTextarea;
                           Context  : in out Faces_Context'Class;
                           Write_Id : in Boolean := True);

   --  ------------------------------
   --  Input_Hidden Component
   --  ------------------------------
   type UIInput_Hidden is new UIInput with private;
   type UIInput_Hidden_Access is access all UIInput_Hidden'Class;

   --  Render the inputHidden element.
   overriding
   procedure Render_Input (UI       : in UIInput_Hidden;
                           Context  : in out Faces_Context'Class;
                           Write_Id : in Boolean := True);

   --  ------------------------------
   --  InputFile Component
   --  ------------------------------
   type UIInput_File is new UIInput with private;
   type UIInput_File_Access is access all UIInput_File'Class;

   --  Render the input file element.
   overriding
   procedure Render_Input (UI       : in UIInput_File;
                           Context  : in out Faces_Context'Class;
                           Write_Id : in Boolean := True);

   --  Validate the submitted file.
   --

   --
Retreive the submitted value
   --
If the value is null, exit without further processing.
   --
Validate the value by calling Validate_Value
   --

   overriding
   procedure Validate (UI      : in out UIInput_File;
                       Context : in out Faces_Context'Class);

   overriding
   procedure Process_Updates (UI      : in out UIInput_File;
                              Context : in out Faces_Context'Class);

   --  ------------------------------
   --  Button Component
   --  ------------------------------
   type UICommand is new UIHtmlComponent with private;

   overriding
   procedure Encode_Begin (UI      : in UICommand;
                           Context : in out Faces_Context'Class);

   --  Get the value to write on the output.
   function Get_Value (UI    : in UICommand) return EL.Objects.Object;

   --  Set the value to write on the output.
   procedure Set_Value (UI    : in out UICommand;
                        Value : in EL.Objects.Object);

   --  Get the action method expression to invoke if the command is pressed.
   function Get_Action_Expression (UI      : in UICommand;
                                   Context : in Faces_Context'Class)
                                  return EL.Expressions.Method_Expression;

   overriding
   procedure Process_Decodes (UI      : in out UICommand;
                              Context : in out Faces_Context'Class);

   --  Broadcast the event to the event listeners installed on this component.
   --  Listeners are called in the order in which they were added.
   overriding
   procedure Broadcast (UI      : in out UICommand;
                        Event   : not null access ASF.Events.Faces.Faces_Event'Class;
                        Context : in out Faces_Context'Class);

private

   type Validator is record
      Validator : ASF.Validators.Validator_Access := null;
      Shared    : Boolean := False;
   end record;

   type Validator_Array is array (1 .. MAX_VALIDATORS_PER_COMPONENT) of Validator;

   type UIInput is new Text.UIOutput and Holders.Editable_Value_Holder with record
      Submitted_Value : EL.Objects.Object;
      Is_Valid        : Boolean := False;
      Is_Secret       : Boolean := False;
      Validators      : Validator_Array;
   end record;

   type UIInputTextarea is new UIInput with record
      Rows  : Natural;
      Cols  : Natural;
   end record;

   type UIInput_Hidden is new UIInput with null record;

   type UIInput_File is new UIInput with null record;

   type UICommand is new UIHtmlComponent with record
      Value : EL.Objects.Object;
   end record;

   type UIForm is new UIHtmlComponent with record
      Is_Submitted : Boolean := False;
   end record;

end ASF.Components.Html.Forms;

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

   --  A UIComponent can have several validators.  To keep the implementation light and
   --  simple, a fixed array is used.  Most components will have one or two validators.
   --  Define the number of validators per component (UIInput).
   MAX_VALIDATORS_PER_COMPONENT : constant Positive := 5;

   --  Message displayed when the submitted value is required but is empty.
   REQUIRED_MESSAGE_ID          : constant String := "asf.faces.component.UIInput.REQUIRED";

   --  ------------------------------
   --  Form Component
   --  ------------------------------
   type UIForm is new UIHtmlComponent with private;
   type UIForm_Access is access all UIForm'Class;

   --  Check whether the form is submitted.
   function Is_Submitted (UI : in UIForm) return Boolean;

   --  Called during the Apply Request phase to indicate that this
   --  form is submitted.
   procedure Set_Submitted (UI : in out UIForm);

   --  Get the action URL to set on the HTML form
   function Get_Action (UI      : in UIForm;
                        Context : in Faces_Context'Class) return String;

   overriding
   procedure Encode_Begin (UI      : in UIForm;
                           Context : in out Faces_Context'Class);

   overriding
   procedure Encode_End (UI      : in UIForm;
                         Context : in out Faces_Context'Class);

   overriding
   procedure Decode (UI      : in out UIForm;
                     Context : in out Faces_Context'Class);

   overriding
   procedure Process_Decodes (UI      : in out UIForm;
                              Context : in out Faces_Context'Class);

   --  ------------------------------
   --  Input Component
   --  ------------------------------
   type UIInput is new Text.UIOutput and Holders.Editable_Value_Holder with private;
   type UIInput_Access is access all UIInput'Class;

   --  Check if this component has the required attribute set.
   function Is_Required (UI      : in UIInput;
                         Context : in Faces_Context'Class) return Boolean;

   --  Find the form component which contains the input component.
   --  Returns null if the input is not within a form component.
   function Get_Form (UI : in UIInput) return UIForm_Access;

   --  Get the value of the component.  If the component has a submitted value, returns it.
   --  If the component has a local value which is not null, returns it.
   --  Otherwise, if we have a Value_Expression evaluate and returns the value.
   overriding
   function Get_Value (UI    : in UIInput) return EL.Objects.Object;

   --  Get the input parameter from the submitted context.  This operation is called by
   --  <tt>Process_Decodes</tt> to retrieve the request parameter associated with the component.
   function Get_Parameter (UI      : in UIInput;
                           Context : in Faces_Context'Class) return String;

   --  Set the input component as a password field.
   procedure Set_Secret (UI    : in out UIInput;
                         Value : in Boolean);

   --  Render the input element.
   procedure Render_Input (UI       : in UIInput;
                           Context  : in out Faces_Context'Class;
                           Write_Id : in Boolean := True);

   overriding
   procedure Encode_Begin (UI      : in UIInput;
                           Context : in out Faces_Context'Class);

   overriding
   procedure Process_Decodes (UI      : in out UIInput;
                              Context : in out Faces_Context'Class);

   --  Perform the component tree processing required by the Process Validations
   --  phase of the request processing lifecycle for all facets of this component,
   --  all children of this component, and this component itself, as follows:
   --

   --
If this component rendered property is false, skip further processing.
   --
Call the Process_Validators of all facets and children.
   --

   procedure Process_Validators (UI      : in out UIInput;
                                 Context : in out Faces_Context'Class);

   overriding
   procedure Process_Updates (UI      : in out UIInput;
                              Context : in out Faces_Context'Class);

   --  Validate the submitted value.
   --

   --
Retreive the submitted value
   --
If the value is null, exit without further processing.
   --
Validate the value by calling Validate_Value
   --

   procedure Validate (UI      : in out UIInput;
                       Context : in out Faces_Context'Class);

   --  Set the valid property:
   --

   --
If the required property is true, ensure the
   --         value is not empty
   --
Call the Validate procedure on each validator
   --         registered on this component.
   --
Set the valid property if all validator passed.
   --

   procedure Validate_Value (UI      : in out UIInput;
                             Value   : in EL.Objects.Object;
                             Context : in out Faces_Context'Class);

   --  Add the validator to be used on the component.  The ASF implementation limits
   --  to 5 the number of validators that can be set on a component (See UIInput).
   --  The validator instance will be freed when the editable value holder is deleted
   --  unless Shared is true.
   overriding
   procedure Add_Validator (UI        : in out UIInput;
                            Validator : in ASF.Validators.Validator_Access;
                            Shared    : in Boolean := False);

   --  Delete the UI input instance.
   overriding
   procedure Finalize (UI : in out UIInput);

   --  ------------------------------
   --  InputTextarea Component
   --  ------------------------------
   type UIInputTextarea is new UIInput with private;
   type UIInputTextarea_Access is access all UIInputTextarea'Class;

   --  Render the textarea element.
   overriding
   procedure Render_Input (UI       : in UIInputTextarea;
                           Context  : in out Faces_Context'Class;
                           Write_Id : in Boolean := True);

   --  ------------------------------
   --  Input_Hidden Component
   --  ------------------------------
   type UIInput_Hidden is new UIInput with private;
   type UIInput_Hidden_Access is access all UIInput_Hidden'Class;

   --  Render the inputHidden element.
   overriding
   procedure Render_Input (UI       : in UIInput_Hidden;
                           Context  : in out Faces_Context'Class;
                           Write_Id : in Boolean := True);

   --  ------------------------------
   --  InputFile Component
   --  ------------------------------
   type UIInput_File is new UIInput with private;
   type UIInput_File_Access is access all UIInput_File'Class;

   --  Render the input file element.
   overriding
   procedure Render_Input (UI       : in UIInput_File;
                           Context  : in out Faces_Context'Class;
                           Write_Id : in Boolean := True);

   --  Validate the submitted file.
   --

   --
Retreive the submitted value
   --
If the value is null, exit without further processing.
   --
Validate the value by calling Validate_Value
   --

   overriding
   procedure Validate (UI      : in out UIInput_File;
                       Context : in out Faces_Context'Class);

   overriding
   procedure Process_Updates (UI      : in out UIInput_File;
                              Context : in out Faces_Context'Class);

   --  ------------------------------
   --  Button Component
   --  ------------------------------
   type UICommand is new UIHtmlComponent with private;

   overriding
   procedure Encode_Begin (UI      : in UICommand;
                           Context : in out Faces_Context'Class);

   --  Get the value to write on the output.
   function Get_Value (UI    : in UICommand) return EL.Objects.Object;

   --  Set the value to write on the output.
   procedure Set_Value (UI    : in out UICommand;
                        Value : in EL.Objects.Object);

   --  Get the action method expression to invoke if the command is pressed.
   function Get_Action_Expression (UI      : in UICommand;
                                   Context : in Faces_Context'Class)
                                  return EL.Expressions.Method_Expression;

   overriding
   procedure Process_Decodes (UI      : in out UICommand;
                              Context : in out Faces_Context'Class);

   --  Broadcast the event to the event listeners installed on this component.
   --  Listeners are called in the order in which they were added.
   overriding
   procedure Broadcast (UI      : in out UICommand;
                        Event   : not null access ASF.Events.Faces.Faces_Event'Class;
                        Context : in out Faces_Context'Class);

private

   type Validator is record
      Validator : ASF.Validators.Validator_Access := null;
      Shared    : Boolean := False;
   end record;

   type Validator_Array is array (1 .. MAX_VALIDATORS_PER_COMPONENT) of Validator;

   type UIInput is new Text.UIOutput and Holders.Editable_Value_Holder with record
      Submitted_Value : EL.Objects.Object;
      Is_Valid        : Boolean := False;
      Is_Secret       : Boolean := False;
      Validators      : Validator_Array;
   end record;

   type UIInputTextarea is new UIInput with record
      Rows  : Natural;
      Cols  : Natural;
   end record;

   type UIInput_Hidden is new UIInput with null record;

   type UIInput_File is new UIInput with null record;

   type UICommand is new UIHtmlComponent with record
      Value : EL.Objects.Object;
   end record;

   type UIForm is new UIHtmlComponent with record
      Is_Submitted : Boolean := False;
   end record;

end ASF.Components.Html.Forms;

Declare the Get_Parameter function for UIInput tagged record


-----------------------------------------------------------------------
--  writer -- Response stream writer
--  Copyright (C) 2009, 2010, 2011 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 Unicode;
package body ASF.Contexts.Writer is

   use Unicode;

   procedure Write_Escape (Stream : in out ResponseWriter'Class;
                           Char   : in Character);

   --  Close the current XML entity if an entity was started
   procedure Close_Current (Stream : in out ResponseWriter'Class);

   --  ------------------------------
   --  Response Writer
   --  ------------------------------

   --  ------------------------------
   --  Initialize the response stream for the given content type and
   --  encoding.  An internal buffer is allocated for writing the stream.
   --  ------------------------------
   procedure Initialize (Stream       : in out ResponseWriter;
                         Content_Type : in String;
                         Encoding     : in String;
                         Output       : in ASF.Streams.Print_Stream) is
   begin
      Stream.Initialize (Output);
      Stream.Content_Type := To_Unbounded_String (Content_Type);
      Stream.Encoding     := Unicode.Encodings.Get_By_Name (Encoding);
   end Initialize;

   --  ------------------------------
   --  Flush the response stream and release the buffer.
   --  ------------------------------
   procedure Finalize (Object : in out ResponseWriter) is
   begin
      Object.Flush;
   end Finalize;

   --  ------------------------------
   --  Get the content type.
   --  ------------------------------
   function Get_Content_Type (Stream : in ResponseWriter) return String is
   begin
      return To_String (Stream.Content_Type);
   end Get_Content_Type;

   --  ------------------------------
   --  Get the character encoding.
   --  ------------------------------
   function Get_Encoding (Stream : in ResponseWriter) return String is
   begin
      return Stream.Encoding.Name.all;
   end Get_Encoding;

   --  ------------------------------
   --  Close the current XML entity if an entity was started
   --  ------------------------------
   procedure Close_Current (Stream : in out ResponseWriter'Class) is
   begin
      if Stream.Close_Start then
         Stream.Write ('>');
         Stream.Close_Start := False;
      end if;
   end Close_Current;

   --  ------------------------------
   --  Start an XML element with the given name.
   --  ------------------------------
   procedure Start_Element (Stream : in out ResponseWriter;
                            Name   : in String) is
   begin
      Close_Current (Stream);
      Stream.Write ('<');
      Stream.Write (Name);
      Stream.Close_Start := True;
   end Start_Element;

   --  ------------------------------
   --  Start an XML element with the given name.
   --  ------------------------------
   procedure Start_Optional_Element (Stream : in out ResponseWriter;
                                     Name   : in String) is
   begin
      Close_Current (Stream);
      Stream.Optional_Element (1 .. Name'Length) := Name;
      Stream.Optional_Element_Size := Name'Length;
   end Start_Optional_Element;

   --  ------------------------------
   --  Closes an XML element of the given name.
   --  ------------------------------
   procedure End_Element (Stream : in out ResponseWriter;
                          Name   : in String) is
   begin
      Close_Current (Stream);
      Stream.Write ("</");
      Stream.Write (Name);
      Stream.Write ('>');
   end End_Element;

   --  ------------------------------
   --  Closes an XML element of the given name.
   --  ------------------------------
   procedure End_Optional_Element (Stream : in out ResponseWriter;
                                   Name   : in String) is
   begin
      Close_Current (Stream);
      if Stream.Optional_Element_Written then
         Stream.Write ("</");
         Stream.Write (Name);
         Stream.Write ('>');
      end if;
      Stream.Optional_Element_Written := False;
      Stream.Optional_Element_Size    := 0;
   end End_Optional_Element;

   --  ------------------------------
   --  Write an XML element using the given name and with the content.
   --  This is similar to calling Start_Element, Write_Text
   --  and End_Element.
   --  ------------------------------
   procedure Write_Element (Stream   : in out ResponseWriter;
                            Name     : in String;
                            Content  : in String) is
   begin
      Stream.Start_Element (Name);
      Stream.Write_Text (Content);
      Stream.End_Element (Name);
   end Write_Element;

   procedure Write_Wide_Element (Stream   : in out ResponseWriter;
                                 Name     : in String;
                                 Content  : in Wide_Wide_String) is
   begin
      Stream.Start_Element (Name);
      Stream.Write_Wide_Text (Content);
      Stream.End_Element (Name);
   end Write_Wide_Element;

   procedure Write_Attribute (Stream : in out ResponseWriter;
                              Name   : in String;
                              Value  : in String) is
   begin
      --  If we have an optional element, start it.
      if Stream.Optional_Element_Size > 0 and not Stream.Optional_Element_Written then
         Stream.Write ('<');
         Stream.Write (Stream.Optional_Element (1 .. Stream.Optional_Element_Size));
         Stream.Close_Start := True;
         Stream.Optional_Element_Written := True;
      end if;
      if Stream.Close_Start then
         Stream.Write (' ');
         Stream.Write (Name);
         Stream.Write ('=');
         Stream.Write ('"');
         for I in Value'Range loop
            declare
               C : constant Character := Value (I);
            begin
               if C = '"' then
                  Stream.Write (""");
               else
                  Stream.Write_Escape (C);
               end if;
            end;
         end loop;
         Stream.Write ('"');
      end if;
   end Write_Attribute;

   procedure Write_Attribute (Stream : in out ResponseWriter;
                              Name   : in String;
                              Value  : in Unbounded_String) is
   begin
      Stream.Write_Attribute (Name, To_String (Value));
   end Write_Attribute;

   procedure Write_Attribute (Stream : in out ResponseWriter;
                              Name   : in String;
                              Value  : in EL.Objects.Object) is
      S : constant String := EL.Objects.To_String (Value);
   begin
      Stream.Write_Attribute (Name, S);
   end Write_Attribute;

   --  ------------------------------
   --  Write a text escaping any character as necessary.
   --  ------------------------------
   procedure Write_Text (Stream : in out ResponseWriter;
                         Text   : in String) is
   begin
      for I in Text'Range loop
         ResponseWriter'Class (Stream).Write_Char (Text (I));
      end loop;
   end Write_Text;

   procedure Write_Text (Stream : in out ResponseWriter;
                         Text   : in Unbounded_String) is
      Count : constant Natural := Length (Text);
   begin
      if Count > 0 then
         for I in 1 .. Count loop
            ResponseWriter'Class (Stream).Write_Char (Element (Text, I));
         end loop;
      end if;
   end Write_Text;

   procedure Write_Wide_Text (Stream : in out ResponseWriter;
                              Text   : in Wide_Wide_String) is
   begin
      for I in Text'Range loop
         ResponseWriter'Class (Stream).Write_Wide_Char (Text (I));
      end loop;
   end Write_Wide_Text;

   procedure Write_Text (Stream : in out ResponseWriter;
                         Value  : in EL.Objects.Object) is
      use EL.Objects;

      Of_Type : constant EL.Objects.Data_Type := EL.Objects.Get_Type (Value);
   begin
      case Of_Type is
         when TYPE_BOOLEAN =>
            Close_Current (Stream);
            if To_Boolean (Value) then
               ResponseWriter'Class (Stream).Write ("true");
            else
               ResponseWriter'Class (Stream).Write ("false");
            end if;

         when TYPE_INTEGER | TYPE_FLOAT =>
            Close_Current (Stream);
            ResponseWriter'Class (Stream).Write (To_String (Value));

         when TYPE_STRING =>
            ResponseWriter'Class (Stream).Write_Text (To_String (Value));

         when others =>
            ResponseWriter'Class (Stream).Write_Wide_Text (To_Wide_Wide_String (Value));

      end case;
   end Write_Text;

   --  ------------------------------
   --  Write a character on the response stream and escape that character
   --  as necessary.
   --  ------------------------------
   procedure Write_Char (Stream : in out ResponseWriter;
                         Char   : in Character) is
   begin
      Close_Current (Stream);
      Write_Escape (Stream, Char);
   end Write_Char;

   --  ------------------------------
   --  Internal method to write a character on the response stream
   --  and escape that character as necessary.  Unlike 'Write_Char',
   --  this operation does not closes the current XML entity.
   --  ------------------------------
   procedure Write_Escape (Stream : in out ResponseWriter'Class;
                           Char   : in Character) is
      Code : constant Unicode_Char := Character'Pos (Char);
   begin
      --  Tilde or less...
      if Code < 16#A0# then
         --  If "?" or over, no escaping is needed (this covers
         --  most of the Latin alphabet)
         if Code > 16#3F# or Code <= 16#20# then
            Stream.Write (Char);
         elsif Char = '<' then
            Stream.Write ("<");
         elsif Char = '>' then
            Stream.Write (">");
         elsif Char = '&' then
            Stream.Write ("&");
         else
            Stream.Write (Char);
         end if;
      else
         declare
            S : String (1 .. 5) := "�";
            C : Unicode_Char;
         begin
            C := Code and 16#0F#;
            if C > 10 then
               S (4) := Character'Val (C - 10 + Character'Pos ('A'));
            else
               S (4) := Character'Val (C + Character'Pos ('0'));
            end if;
            C := (Code / 16) and 16#0F#;
            if C > 10 then
               S (3) := Character'Val (C - 10 + Character'Pos ('A'));
            else
               S (3) := Character'Val (C + Character'Pos ('0'));
            end if;
            Stream.Write (S);
         end;
      end if;
   end Write_Escape;

   --  ------------------------------
   --  Write a character on the response stream and escape that character
   --  as necessary.
   --  ------------------------------
   procedure Write_Wide_Char (Stream : in out ResponseWriter;
                              Char   : in Wide_Wide_Character) is
      Code : constant Unicode_Char := Wide_Wide_Character'Pos (Char);
   begin
      Close_Current (Stream);
      --  Tilde or less...
      if Code < 16#100# then
         Stream.Write_Char (Character'Val (Code));
      else
         declare
            S : String (1 .. 5) := "�";
            C : Unicode_Char;
         begin
            C := Code and 16#0F#;
            if C > 10 then
               S (4) := Character'Val (C - 10 + Character'Pos ('A'));
            else
               S (4) := Character'Val (C + Character'Pos ('0'));
            end if;
            C := (Code / 16) and 16#0F#;
            if C > 10 then
               S (3) := Character'Val (C - 10 + Character'Pos ('A'));
            else
               S (3) := Character'Val (C + Character'Pos ('0'));
            end if;
            Stream.Write (S);
         end;
      end if;
   end Write_Wide_Char;

   --  ------------------------------
   --  Write a string on the stream.
   --  ------------------------------
   procedure Write (Stream : in out ResponseWriter;
                    Item   : in Ada.Strings.Unbounded.Unbounded_String) is
   begin
      Close_Current (Stream);
      ASF.Streams.Print_Stream (Stream).Write (Item);
   end Write;

end ASF.Contexts.Writer;

-----------------------------------------------------------------------
--  writer -- Response stream writer
--  Copyright (C) 2009, 2010, 2011 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 Unicode;
package body ASF.Contexts.Writer is

   use Unicode;

   procedure Write_Escape (Stream : in out ResponseWriter'Class;
                           Char   : in Character);

   --  Close the current XML entity if an entity was started
   procedure Close_Current (Stream : in out ResponseWriter'Class);

   --  ------------------------------
   --  Response Writer
   --  ------------------------------

   --  ------------------------------
   --  Initialize the response stream for the given content type and
   --  encoding.  An internal buffer is allocated for writing the stream.
   --  ------------------------------
   procedure Initialize (Stream       : in out ResponseWriter;
                         Content_Type : in String;
                         Encoding     : in String;
                         Output       : in ASF.Streams.Print_Stream) is
   begin
      Stream.Initialize (Output);
      Stream.Content_Type := To_Unbounded_String (Content_Type);
      Stream.Encoding     := Unicode.Encodings.Get_By_Name (Encoding);
   end Initialize;

   --  ------------------------------
   --  Flush the response stream and release the buffer.
   --  ------------------------------
   procedure Finalize (Object : in out ResponseWriter) is
   begin
      Object.Flush;
   end Finalize;

   --  ------------------------------
   --  Get the content type.
   --  ------------------------------
   function Get_Content_Type (Stream : in ResponseWriter) return String is
   begin
      return To_String (Stream.Content_Type);
   end Get_Content_Type;

   --  ------------------------------
   --  Get the character encoding.
   --  ------------------------------
   function Get_Encoding (Stream : in ResponseWriter) return String is
   begin
      return Stream.Encoding.Name.all;
   end Get_Encoding;

   --  ------------------------------
   --  Close the current XML entity if an entity was started
   --  ------------------------------
   procedure Close_Current (Stream : in out ResponseWriter'Class) is
   begin
      if Stream.Close_Start then
         Stream.Write ('>');
         Stream.Close_Start := False;
      end if;
   end Close_Current;

   --  ------------------------------
   --  Start an XML element with the given name.
   --  ------------------------------
   procedure Start_Element (Stream : in out ResponseWriter;
                            Name   : in String) is
   begin
      Close_Current (Stream);
      Stream.Write ('<');
      Stream.Write (Name);
      Stream.Close_Start := True;
   end Start_Element;

   --  ------------------------------
   --  Start an XML element with the given name.
   --  ------------------------------
   procedure Start_Optional_Element (Stream : in out ResponseWriter;
                                     Name   : in String) is
   begin
      Close_Current (Stream);
      Stream.Optional_Element (1 .. Name'Length) := Name;
      Stream.Optional_Element_Size := Name'Length;
   end Start_Optional_Element;

   --  ------------------------------
   --  Closes an XML element of the given name.
   --  ------------------------------
   procedure End_Element (Stream : in out ResponseWriter;
                          Name   : in String) is
   begin
      Close_Current (Stream);
      Stream.Write ("</");
      Stream.Write (Name);
      Stream.Write ('>');
   end End_Element;

   --  ------------------------------
   --  Closes an XML element of the given name.
   --  ------------------------------
   procedure End_Optional_Element (Stream : in out ResponseWriter;
                                   Name   : in String) is
   begin
      Close_Current (Stream);
      if Stream.Optional_Element_Written then
         Stream.Write ("</");
         Stream.Write (Name);
         Stream.Write ('>');
      end if;
      Stream.Optional_Element_Written := False;
      Stream.Optional_Element_Size    := 0;
   end End_Optional_Element;

   --  ------------------------------
   --  Write an XML element using the given name and with the content.
   --  This is similar to calling Start_Element, Write_Text
   --  and End_Element.
   --  ------------------------------
   procedure Write_Element (Stream   : in out ResponseWriter;
                            Name     : in String;
                            Content  : in String) is
   begin
      Stream.Start_Element (Name);
      Stream.Write_Text (Content);
      Stream.End_Element (Name);
   end Write_Element;

   procedure Write_Wide_Element (Stream   : in out ResponseWriter;
                                 Name     : in String;
                                 Content  : in Wide_Wide_String) is
   begin
      Stream.Start_Element (Name);
      Stream.Write_Wide_Text (Content);
      Stream.End_Element (Name);
   end Write_Wide_Element;

   procedure Write_Attribute (Stream : in out ResponseWriter;
                              Name   : in String;
                              Value  : in String) is
   begin
      --  If we have an optional element, start it.
      if Stream.Optional_Element_Size > 0 and not Stream.Optional_Element_Written then
         Stream.Write ('<');
         Stream.Write (Stream.Optional_Element (1 .. Stream.Optional_Element_Size));
         Stream.Close_Start := True;
         Stream.Optional_Element_Written := True;
      end if;
      if Stream.Close_Start then
         Stream.Write (' ');
         Stream.Write (Name);
         Stream.Write ('=');
         Stream.Write ('"');
         for I in Value'Range loop
            declare
               C : constant Character := Value (I);
            begin
               if C = '"' then
                  Stream.Write (""");
               else
                  Stream.Write_Escape (C);
               end if;
            end;
         end loop;
         Stream.Write ('"');
      end if;
   end Write_Attribute;

   procedure Write_Attribute (Stream : in out ResponseWriter;
                              Name   : in String;
                              Value  : in Unbounded_String) is
   begin
      Stream.Write_Attribute (Name, To_String (Value));
   end Write_Attribute;

   procedure Write_Attribute (Stream : in out ResponseWriter;
                              Name   : in String;
                              Value  : in EL.Objects.Object) is
      S : constant String := EL.Objects.To_String (Value);
   begin
      Stream.Write_Attribute (Name, S);
   end Write_Attribute;

   --  ------------------------------
   --  Write a text escaping any character as necessary.
   --  ------------------------------
   procedure Write_Text (Stream : in out ResponseWriter;
                         Text   : in String) is
   begin
      for I in Text'Range loop
         ResponseWriter'Class (Stream).Write_Char (Text (I));
      end loop;
   end Write_Text;

   procedure Write_Text (Stream : in out ResponseWriter;
                         Text   : in Unbounded_String) is
      Count : constant Natural := Length (Text);
   begin
      if Count > 0 then
         for I in 1 .. Count loop
            ResponseWriter'Class (Stream).Write_Char (Element (Text, I));
         end loop;
      end if;
   end Write_Text;

   procedure Write_Wide_Text (Stream : in out ResponseWriter;
                              Text   : in Wide_Wide_String) is
   begin
      for I in Text'Range loop
         ResponseWriter'Class (Stream).Write_Wide_Char (Text (I));
      end loop;
   end Write_Wide_Text;

   procedure Write_Text (Stream : in out ResponseWriter;
                         Value  : in EL.Objects.Object) is
      use EL.Objects;

      Of_Type : constant EL.Objects.Data_Type := EL.Objects.Get_Type (Value);
   begin
      case Of_Type is
         when TYPE_BOOLEAN =>
            Close_Current (Stream);
            if To_Boolean (Value) then
               ResponseWriter'Class (Stream).Write ("true");
            else
               ResponseWriter'Class (Stream).Write ("false");
            end if;

         when TYPE_INTEGER | TYPE_FLOAT =>
            Close_Current (Stream);
            ResponseWriter'Class (Stream).Write (To_String (Value));

         when TYPE_STRING =>
            ResponseWriter'Class (Stream).Write_Text (To_String (Value));

         when others =>
            ResponseWriter'Class (Stream).Write_Wide_Text (To_Wide_Wide_String (Value));

      end case;
   end Write_Text;

   --  ------------------------------
   --  Write a character on the response stream and escape that character
   --  as necessary.
   --  ------------------------------
   procedure Write_Char (Stream : in out ResponseWriter;
                         Char   : in Character) is
   begin
      Close_Current (Stream);
      Write_Escape (Stream, Char);
   end Write_Char;

   --  ------------------------------
   --  Internal method to write a character on the response stream
   --  and escape that character as necessary.  Unlike 'Write_Char',
   --  this operation does not closes the current XML entity.
   --  ------------------------------
   procedure Write_Escape (Stream : in out ResponseWriter'Class;
                           Char   : in Character) is
      Code : constant Unicode_Char := Character'Pos (Char);
   begin
      --  Tilde or less...
--        if Code < 16#A0# then
         --  If "?" or over, no escaping is needed (this covers
         --  most of the Latin alphabet)
         if Code > 16#3F# or Code <= 16#20# then
            Stream.Write (Char);
         elsif Char = '<' then
            Stream.Write ("<");
         elsif Char = '>' then
            Stream.Write (">");
         elsif Char = '&' then
            Stream.Write ("&");
         else
            Stream.Write (Char);
         end if;
--        else
--           declare
--              S : String (1 .. 5) := "�";
--              C : Unicode_Char;
--           begin
--              C := Code and 16#0F#;
--              if C > 10 then
--                 S (4) := Character'Val (C - 10 + Character'Pos ('A'));
--              else
--                 S (4) := Character'Val (C + Character'Pos ('0'));
--              end if;
--              C := (Code / 16) and 16#0F#;
--              if C > 10 then
--                 S (3) := Character'Val (C - 10 + Character'Pos ('A'));
--              else
--                 S (3) := Character'Val (C + Character'Pos ('0'));
--              end if;
--              Stream.Write (S);
--           end;
--        end if;
   end Write_Escape;

   --  ------------------------------
   --  Write a character on the response stream and escape that character
   --  as necessary.
   --  ------------------------------
   procedure Write_Wide_Char (Stream : in out ResponseWriter;
                              Char   : in Wide_Wide_Character) is
      Code : constant Unicode_Char := Wide_Wide_Character'Pos (Char);
   begin
      Close_Current (Stream);
      --  Tilde or less...
      if Code < 16#100# then
         Stream.Write_Char (Character'Val (Code));
      else
         declare
            S : String (1 .. 5) := "�";
            C : Unicode_Char;
         begin
            C := Code and 16#0F#;
            if C > 10 then
               S (4) := Character'Val (C - 10 + Character'Pos ('A'));
            else
               S (4) := Character'Val (C + Character'Pos ('0'));
            end if;
            C := (Code / 16) and 16#0F#;
            if C > 10 then
               S (3) := Character'Val (C - 10 + Character'Pos ('A'));
            else
               S (3) := Character'Val (C + Character'Pos ('0'));
            end if;
            Stream.Write (S);
         end;
      end if;
   end Write_Wide_Char;

   --  ------------------------------
   --  Write a string on the stream.
   --  ------------------------------
   procedure Write (Stream : in out ResponseWriter;
                    Item   : in Ada.Strings.Unbounded.Unbounded_String) is
   begin
      Close_Current (Stream);
      ASF.Streams.Print_Stream (Stream).Write (Item);
   end Write;

end ASF.Contexts.Writer;

Write the character above 0xA0 as is. This allows to have UTF-8 sequences in a String and generate UTF-8 pages.


-----------------------------------------------------------------------
--  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.
--
--     Doc    : Wiki.Documents.Document;
--     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 <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;

   --  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 := 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
   --  defined on the parser.
   procedure Parse (Engine : in out Parser;
                    Text   : in Wiki.Strings.WString;
                    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
      Pending             : Wiki.Strings.WChar;
      Has_Pending         : Boolean;
      Syntax              : Wiki_Syntax;
      Previous_Syntax     : Wiki_Syntax;
      Table               : Parser_Table_Access;
      Document            : Wiki.Documents.Document;
      Filters             : Wiki.Filters.Filter_Chain;
      Format              : Wiki.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;
      Link_No_Space       : 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         : Wiki.Strings.WChar;
      List_Level          : Natural := 0;
      Reader              : Wiki.Streams.Input_Stream_Access := null;
      Attributes          : Wiki.Attributes.Attribute_List;
   end record;

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

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

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

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

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

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

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

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

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

   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.
--
--     Doc    : Wiki.Documents.Document;
--     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 <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;

   --  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 := 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
   --  defined on the parser.
   procedure Parse (Engine : in out Parser;
                    Text   : in Wiki.Strings.WString;
                    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
      Pending             : Wiki.Strings.WChar;
      Has_Pending         : Boolean;
      Syntax              : Wiki_Syntax;
      Previous_Syntax     : Wiki_Syntax;
      Table               : Parser_Table_Access;
      Document            : Wiki.Documents.Document;
      Filters             : Wiki.Filters.Filter_Chain;
      Factory             : Wiki.Plugins.Plugin_Factory_Access;
      Format              : Wiki.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;
      Link_No_Space       : 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         : Wiki.Strings.WChar;
      List_Level          : Natural := 0;
      Reader              : Wiki.Streams.Input_Stream_Access := null;
      Attributes          : Wiki.Attributes.Attribute_List;
   end record;

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

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

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

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

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

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

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

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

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

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

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

   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;

Declare the Find function to identify a plugin instance Add a plugin factory to the Parser type


-----------------------------------------------------------------------
--  druss-tools -- Druss main tool
--  Copyright (C) 2017 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------
with GNAT.Command_Line;  use GNAT.Command_Line;
with Ada.Command_Line;
with Bbox.API;
with Util.Properties;
with Ada.Text_IO;
with Ada.Exceptions;
with Ada.Strings.Unbounded;
with Util.Commands;
with Util.Http.Clients.Curl;
with Druss.Gateways;
with Druss.Config;
with Druss.Commands;
procedure Druss.Tools is

   use Ada.Text_IO;
   use Ada.Strings.Unbounded;

   Debug   : Boolean := False;
   Verbose : Boolean := False;
   List    : Druss.Gateways.Gateway_Vector;
   First   : Natural := 0;
begin
   Druss.Commands.Initialize;
   Initialize_Option_Scan (Stop_At_First_Non_Switch => True, Section_Delimiters => "targs");
   --  Parse the command line
   loop
      case Getopt ("* v d e E o: t: c:") is
         when ASCII.NUL => exit;

         when 'c' =>
            null;--  Set_Config_Directory (Parameter);

         when 'd' =>
            Debug := True;

         when 'v' =>
            Verbose := True;

         when '*' =>
            exit;

         when others =>
            null;
      end case;
      First := First + 1;
   end loop;
   Druss.Config.Initialize;
   Util.Http.Clients.Curl.Register;
   declare
      Cmd_Name : constant String := Full_Switch;
      Args     : Util.Commands.Default_Argument_List (First + 1);
      Ctx      : Druss.Commands.Context_Type;
   begin
      if Cmd_Name = "" then
         Druss.Commands.Driver.Usage (Args);
         Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
         return;
      end if;
      Druss.Config.Get_Gateways (Ctx.Gateways);
      Druss.Commands.Driver.Execute (Cmd_Name, Args, Ctx);
   end;

exception
   when E : Invalid_Switch =>
      Ada.Text_IO.Put_Line ("Invalid option: " & Ada.Exceptions.Exception_Message (E));
      Ada.Command_Line.Set_Exit_Status (2);

end Druss.Tools;

-----------------------------------------------------------------------
--  druss-tools -- Druss main tool
--  Copyright (C) 2017 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------
with GNAT.Command_Line;  use GNAT.Command_Line;
with Ada.Command_Line;
with Ada.Text_IO;
with Ada.Exceptions;
with Ada.Strings.Unbounded;
with Util.Commands;
with Util.Http.Clients.Curl;
with Druss.Config;
with Druss.Commands;
procedure Druss.Tools is

   use Ada.Text_IO;
   use Ada.Strings.Unbounded;

   Config   : Ada.Strings.Unbounded.Unbounded_String;
   Output   : Ada.Strings.Unbounded.Unbounded_String;
   Debug    : Boolean := False;
   Verbose  : Boolean := False;
   First    : Natural := 0;
   All_Args : Util.Commands.Default_Argument_List (0);
begin
   Druss.Commands.Initialize;
   Initialize_Option_Scan (Stop_At_First_Non_Switch => True, Section_Delimiters => "targs");
   --  Parse the command line
   loop
      case Getopt ("* v d o: c:") is
         when ASCII.NUL => exit;

         when 'c' =>
            Config := Ada.Strings.Unbounded.To_Unbounded_String (Parameter);

         when 'o' =>
            Output := Ada.Strings.Unbounded.To_Unbounded_String (Parameter);

         when 'd' =>
            Debug := True;

         when 'v' =>
            Verbose := True;

         when '*' =>
            exit;

         when others =>
            null;
      end case;
      First := First + 1;
   end loop;
   Druss.Config.Initialize;
   Util.Http.Clients.Curl.Register;
   if First >= Ada.Command_Line.Argument_Count then
      Ada.Text_IO.Put_Line ("Missing command name to execute.");
      Druss.Commands.Driver.Usage (All_Args);
      Ada.Command_Line.Set_Exit_Status (Ada.Command_Line.Failure);
      return;
   end if;
   declare
      Cmd_Name : constant String := Full_Switch;
      Args     : Util.Commands.Default_Argument_List (First + 1);
      Ctx      : Druss.Commands.Context_Type;
   begin
      Druss.Config.Get_Gateways (Ctx.Gateways);
      Druss.Commands.Driver.Execute (Cmd_Name, Args, Ctx);
   end;

exception
   when E : Invalid_Switch =>
      Ada.Text_IO.Put_Line ("Invalid option: " & Ada.Exceptions.Exception_Message (E));
      Ada.Command_Line.Set_Exit_Status (2);

end Druss.Tools;

Add the -o <file> and -c <file> options Fix the command execution to report usage if no command is given