File : src/aws-config-ini.adb


------------------------------------------------------------------------------
--                              Ada Web Server                              --
--                                                                          --
--                         Copyright (C) 2000-2003                          --
--                               ACT-Europe                                 --
--                                                                          --
--  Authors: Dmitriy Anisimkov - Pascal Obry                                --
--                                                                          --
--  This library is free software; you can redistribute it and/or modify    --
--  it under the terms of the GNU General Public License as published by    --
--  the Free Software Foundation; either version 2 of the License, or (at   --
--  your option) any later version.                                         --
--                                                                          --
--  This library is distributed in the hope that it will be useful, but     --
--  WITHOUT ANY WARRANTY; without even the implied warranty of              --
--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU       --
--  General Public License for more details.                                --
--                                                                          --
--  You should have received a copy of the GNU General Public License       --
--  along with this library; if not, write to the Free Software Foundation, --
--  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.          --
--                                                                          --
--  As a special exception, if other files instantiate generics from this   --
--  unit, or you link this unit with other files to produce an executable,  --
--  this  unit  does not  by itself cause  the resulting executable to be   --
--  covered by the GNU General Public License. This exception does not      --
--  however invalidate any other reasons why the executable file  might be  --
--  covered by the  GNU Public License.                                     --
------------------------------------------------------------------------------

--  $Id: aws-config-ini.adb,v 1.11 2003/05/06 18:06:46 obry Exp $

with Ada.Command_Line;
with Ada.Strings.Fixed;
with Ada.Strings.Maps;
with Ada.Strings.Unbounded;
with Ada.Text_IO;

with AWS.Utils;

package body AWS.Config.Ini is

   use Ada;
   use Ada.Strings.Unbounded;

   function Program_Ini_File return String;
   --  Returns initialization filename for current server (using the
   --  executable name and adding .ini)

   procedure Read_If_Present
     (Config   : in out Object;
      Filename : in     String);
   --  Read and parse Filename, does not raise an exception if the file does
   --  not exists.

   ----------------------
   -- Program_Ini_File --
   ----------------------

   function Program_Ini_File return String is
      Exec_Name : constant String := Ada.Command_Line.Command_Name;
      Last      : Natural;
      First     : Natural;
   begin
      First := Strings.Fixed.Index
        (Exec_Name, Strings.Maps.To_Set ("/\"), Going => Strings.Backward);

      if First = 0 then
         First := Exec_Name'First;
      end if;

      Last := Strings.Fixed.Index
        (Exec_Name (First .. Exec_Name'Last), ".", Strings.Backward);

      if Last = 0 then
         return Exec_Name & ".ini";
      else
         return Exec_Name (Exec_Name'First .. Last) & "ini";
      end if;
   end Program_Ini_File;

   ----------
   -- Read --
   ----------

   procedure Read
     (Config   : in out Object;
      Filename : in     String)
   is

      procedure Error_Message (Filename : in String; Message : in String);
      --  Output error message with filename and line number.

      procedure Set_Value
        (Filename : in String;
         Key      : in String;
         Value    : in String);

      Line : Natural;
      --  current line number parsed

      Process_Mode : constant Boolean := True;
      --  Set to True when parsing a file that can support per process
      --  options.

      -------------------
      -- Error_Message --
      -------------------

      procedure Error_Message (Filename : in String; Message : in String) is
      begin
         Text_IO.Put (Text_IO.Current_Error, '(' & Filename & ':');
         Text_IO.Put (Text_IO.Current_Error, AWS.Utils.Image (Line));
         Text_IO.Put_Line (Text_IO.Current_Error, ") " & Message & '.');
      end Error_Message;

      ---------------
      -- Set_Value --
      ---------------

      procedure Set_Value
        (Filename : in String;
         Key      : in String;
         Value    : in String)
      is
         use Ada.Strings.Unbounded;

         function "+" (S : in String)
           return Unbounded_String
           renames To_Unbounded_String;

         Expected_Type : Unbounded_String;

         P : Parameter_Name;

      begin

         begin
            P := Parameter_Name'Value (Key);
         exception
            when others =>
               Error_Message (Filename, "unrecognized option " & Key);
               return;
         end;

         if P in Server_Parameter_Name then

            case Config.P (P).Kind is
               when Str =>
                  Expected_Type := +"string";
                  Config.P (P).Str_Value := +Value;

               when Dir =>
                  Expected_Type := +"string";

                  if Value (Value'Last) = '/'
                    or else Value (Value'Last) = '\'
                  then
                     Config.P (P).Dir_Value := +Value;
                  else
                     Config.P (P).Dir_Value := +(Value & '/');
                  end if;

               when Pos =>
                  Expected_Type := +"positive";
                  Config.P (P).Pos_Value := Positive'Value (Value);

               when Dur =>
                  Expected_Type := +"duration";
                  Config.P (P).Dur_Value := Duration'Value (Value);

               when Bool =>
                  Expected_Type := +"boolean";
                  Config.P (P).Bool_Value := Boolean'Value (Value);

            end case;

         else

            if not Process_Mode then
               Error_Message
                 (Filename,
                  "Per process option (" & Key
                  & ") not supported for this file");
            end if;

            case Process_Options (P).Kind is

               when Str =>
                  Expected_Type := +"string";
                  Process_Options (P).Str_Value := +Value;

               when Dir =>
                  Expected_Type := +"string";

                  if Value (Value'Last) = '/'
                    or else Value (Value'Last) = '\'
                  then
                     Process_Options (P).Dir_Value := +Value;
                  else
                     Process_Options (P).Dir_Value := +(Value & '/');
                  end if;

               when Pos =>
                  Expected_Type := +"positive";
                  Process_Options (P).Pos_Value := Positive'Value (Value);

               when Dur =>
                  Expected_Type := +"duration";
                  Process_Options (P).Dur_Value := Duration'Value (Value);

               when Bool =>
                  Expected_Type := +"boolean";
                  Process_Options (P).Bool_Value := Boolean'Value (Value);
            end case;

         end if;

      exception
         when others =>
            Error_Message
              (Filename,
               "wrong value for " & Key
               & " " & To_String (Expected_Type) & " expected");

      end Set_Value;

      Separators : constant Strings.Maps.Character_Set
        := Strings.Maps.To_Set (' ' & ASCII.HT);

      File    : Text_IO.File_Type;
      Buffer  : String (1 .. 1024);
      Last    : Natural;

      K_First : Natural;
      K_Last  : Natural;

   begin
      Text_IO.Open (Name => Filename,
                    File => File,
                    Mode => Text_IO.In_File);
      Line := 0;

      while not Text_IO.End_Of_File (File) loop

         Text_IO.Get_Line (File, Buffer, Last);
         Line := Line + 1;

         --  Remove comments

         for I in 1 .. Last loop
            if Buffer (I) = '#' then
               Last := I - 1;
               exit;
            end if;
         end loop;

         if Last /= 0 then

            --  Looks for Key token

            Strings.Fixed.Find_Token
              (Buffer (1 .. Last), Separators, Strings.Outside,
               K_First, K_Last);

            if K_Last /= 0 then

               declare
                  Key   : constant String := Buffer (K_First .. K_Last);
                  Value : constant String := Strings.Fixed.Trim
                    (Buffer (K_Last + 1 .. Last), Separators, Separators);
               begin
                  if Value = "" then
                     Error_Message (Filename, "No value for " & Key);
                  else
                     Set_Value (Filename, Key, Value);
                  end if;
               end;

            else
               Error_Message (Filename, "wrong format");
            end if;

         end if;
      end loop;

      Text_IO.Close (File);
   end Read;

   ---------------------
   -- Read_If_Present --
   ---------------------

   procedure Read_If_Present
     (Config   : in out Object;
      Filename : in     String) is
   begin
      Read (Config, Filename);
   exception
      when Text_IO.Name_Error =>
         null;
   end Read_If_Present;

begin
   Read_If_Present (Server_Config, "aws.ini");
   Read_If_Present (Server_Config, Program_Ini_File);
end AWS.Config.Ini;