-------------------------------------------------------------------------------
--
--  <STRONG>Copyright &copy; 2001, 2002 by Thomas Wolf.</STRONG>
--  <BLOCKQUOTE>
--    This piece of software 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, or (at your option)
--    any later version. This software is distributed in the hope that it will
--    be useful, but <EM>without any warranty</EM>; without even the implied
--    warranty of <EM>merchantability or fitness for a particular purpose.</EM>
--    See the GNU General Public License for  more details. You should have
--    received a copy of the GNU General Public License with this distribution,
--    see file "<A HREF="GPL.txt">GPL.txt</A>". If not, write to the Free
--    Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
--    USA.
--  </BLOCKQUOTE>
--  <BLOCKQUOTE>
--    As a special exception from the GPL, 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 GPL. This exception does not however invalidate any
--    other reasons why the executable file might be covered by the GPL.
--  </BLOCKQUOTE>
--
--  <AUTHOR>
--    Thomas Wolf  (TW) <E_MAIL>
--  </AUTHOR>
--
--  <PURPOSE>
--    Bash-style variable substitution.
--  </PURPOSE>
--
--  <NOT_TASK_SAFE>
--
--  <STORAGE>
--    No dynamic storage allocation. @Expand@ is recursive; the recursion
--    depth (and hence the stack consumption) is limited by the number of
--    variable references and escaped '@$@'-signs in the @Source@ string.
--  </STORAGE>
--
--  <HISTORY>
--    03-MAY-2002   TW  Initial version.
--   14-MAY-2002   TW  Added 'Set_Reference_Character'.
--  </HISTORY>
-------------------------------------------------------------------------------

pragma License (Modified_GPL);

package Util.Environment.Bash is

   pragma Elaborate_Body;

   type Bash_Expander is new String_Expander with private;

   function Expand
     (Self   : access Bash_Expander;
      Source : in     String)
     return String;
   --  Replaces all references to environment variables in @Source@ by that
   --  variable's definition (or the empty string, if an environment variable
   --  is not defined) and returns the resulting string.
   --
   --  A @Bash_Expander@ uses a syntax very similar to that of the GNU
   --  @bash@ shell. An environment variable has a name, which is an
   --  identifier:
   --
   --  <PRE>
   --      Ident = Alpha <B>{</B> Alpha <B>|</B> Digit <B>|</B> '_' <B>}</B>.
   --      Alpha = 'A' .. 'Z' <B>|</B> 'a' ..'z'.
   --      Digit = '0' .. '9'.
   --  </PRE>
   --
   --  A simple reference to a variable has the form
   --
   --  <PRE>
   --      $Identifier
   --  </PRE>
   --
   --  and is replaced as a whole (including the '$' sign) by the variable's
   --  value or by the empty string if no such variable is defined.
   --
   --  More interesting are the complex variable references, which have the
   --  <A NAME="bash_syntax">syntax</A>
   --
   --  <PRE>
   --     Value     = <EM>any string, maybe containing environment
   --                 variable references</EM>.
   --     Operator  = :- <B>|</B> :+.
   --     Reference = ${Var_Name<B>[</B>Operator<B>[</B>Value<B>]]</B>}.
   --     Var_Name  = Value <B>|</B> !Identifier.
   --  </PRE>
   --
   --  In all forms, <CODE>Variable_Name</CODE> can have one of three formats:
   --
   --  <UL>
   --    <LI>An identifier: expands to the empty string if no such variable
   --        is defined, and to the variable's value otherwise.
   --    <LI>A '!' and an identifier: expands the identifier as above, but
   --        then takes the result of this expansion as the name of another
   --        variable, which is then expanded. This is known as <EM>indirect
   --        expansion</EM>, and is limited to one level of indirection only.
   --    <LI>Some arbitrary string that may contain embedded references to
   --        variables: environment variable substitution is performed on the
   --        whole thing, and the resulting value is taken to be the name of
   --        a variable, which is then expanded. This <EM>recursive
   --        expansion</EM> is <EM>unknown</EM> in @bash@>, and it is done
   --        for as many levels as specified.
   --  </UL>
   --
   --  The semantics of these forms is as follows:
   --
   --  <DL><DT>@${Variable_Name}@
   --    <DD>Is identical to the simple form of references @$Identifier@
   --        except that it also allows indirect and recursive expansion.</DL>
   --
   --  <DL><DT>@${Variable_Name:-Value}@
   --    <DD>Is replaced by the result of @${Variable_Name}@ unless that
   --        result is empty, in which case it is replaced by the expansion
   --        of @Value@.</DL>
   --
   --  <DL><DT>@${Variable_Name:+Value}@
   --    <DD>Is replaced by the expansion of @Value@ if the result of
   --        @${Variable_Name}@ is non-empty, or the empty string otherwise.
   --        (@:+@ is the inverse of @:-@.)</DL>
   --
   --  Indirect expansion using the '@!@' character is supported only to keep
   --  the syntax as close to the one used by @bash@ as possible. It is
   --  actually superfluous and can be replaced by the more powerful (and, so
   --  I think, simpler because more regular) recursive expansion:
   --  "@${!Some_Name}@" is identical to "@${${Some_Name}}@" or
   --  "@${$Some_Name}@".
   --
   --  In all operators, the '@:@' is actually optional. It appears that it
   --  is optional in @bash@ (although the manual doesn't say so),
   --  and I have therefore chosen to make it optional here, too.
   --
   --  To include a literal dollar sign '@$@' in the result of the expansion
   --  of @Source@, escape it with a backslash and write "@\$@". If, for some
   --  reason, you want to have a backslash immediately before a variable
   --  reference without escaping the dollar sign, escape the backslash by
   --  writing <EM>two</EM> backslashes before the dollar. The sequence
   --  "@\\@" immediately followed by a variable reference is replaced by
   --  a single backslash and the substitution of the reference.
   --
   --  Variable references that are not terminated properly are not replaced.
   --  E.g. "<CODE>${Var</CODE>" is returned unchanged.
   --
   --  A @Bash_Expander@ implements only the two operators '@-@' and '@+@'.
   --  Other operators may be added in derived types.
   --
   --  Also, a @Bash_Expander@ has <EM>no</EM> special variables. To add those,
   --  override @Get@ and/or @Expand_Variable@ as needed. In general, special
   --  variables with names that are not identifiers will require overriding
   --  of @Expand_Variable@. Other special variables may be implemented by
   --  overriding @Get@ only.

   function Legal_Name
     (Self   : access Bash_Expander;
      Source : in     String)
     return Natural;

   function Indirection
     (Self : access Bash_Expander;
      Name : in     String)
     return String;

   function Prefix
     (Self   : access Bash_Expander;
      Source : in     String;
      Last   : access Natural)
     return String;

   function Recurse
     (Self   : access Bash_Expander;
      Source : in     String)
     return String;

   --  Default does anything required for plain bash-style variable expansion.
   --  In general, you'll only need to override this to add special handling
   --  of isolated cases, and then invoke this default operation. @Last@ shall
   --  be set to 0 in case of error (when no expansion shall occur), otherwise
   --  to the index of the first character in @Name@ not processed anymore
   --  (which may be <= @Name'Last@ only if @Prefix@ is @True@).
   --
   --  @Prefix@ is @True@ if @Expand_Variable@ shall use only the longest
   --  possible legal prefix of @Name@ as the variable name.
   --
   --  @Indirect@ is @True@ if indirect expansion shall be performed.

   function Is_Operator
     (Self     : access Bash_Expander;
      Selector : in     Character)
     return Boolean;
   --  Return @True@ if @Selector@ is a legal operator for your variation of
   --  bash-style variable substitution, and @False@ otherwise. The default
   --  returns @True@ only if @Selector@ is '@+@' or '@-@'.

   function Execute_Operator
     (Self         : access Bash_Expander;
      Operator     : in     Character;
      Var_Name     : in     String;
      Indirect     : in     Boolean;
      Default_Part : in     String)
     return String;
   --  Execute a variable substitition that uses an @Operator@. @Var_Name@ is
   --  the @Var_Name@ part of the above <A HREF="#bash_syntax">syntax</A>, and
   --  @Default_Part@ is the @Value@ from that syntax. if @Indirect@ is @True@,
   --  @Var_Name@ is only the @Identifier@, it doesn't include the '@!@' sign.
   --
   --  Returns the expansion (which may be empty).

   procedure Set_Reference_Character
     (Self : access Bash_Expander;
      Char : in     Character);
   --  By default, a @Bash_Expander@ uses the "@$@" sign to signal the start
   --  of a variable reference. However, sometimes you might want to use some
   --  other character. With this operation, you can redefine the character
   --  used.

private

   type Bash_Expander is new String_Expander with
      record
         Ref_Char : Character := '$';
      end record;

end Util.Environment.Bash;
