Package: Util.Environment.Bash

Description

Copyright © 2001, 2002 by Thomas Wolf.
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 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 with this distribution, see file "GPL.txt". If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
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.

Version: 1.1

Author:
Thomas Wolf (TW) <twolf AT acm DOT org>
Purpose:
Bash-style variable substitution.
Tasking Semantics
Neither task- nor abortion-safe.
Storage Semantics
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.

Header

package Util.Environment.Bash is
 
pragma Elaborate_Body;

Type Summary

Bash_Expander derived from String_Expander
Overridden Operations:  Expand
New Operations:  Execute_Operator, Indirection, Is_Operator, Legal_Name, Prefix, Recurse, Set_Reference_Character
Inherited Operations:  Get

Other Items:

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:

      Ident = Alpha { Alpha | Digit | '_' }.
      Alpha = 'A' .. 'Z' | 'a' ..'z'.
      Digit = '0' .. '9'.
  

A simple reference to a variable has the form

      $Identifier
  

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 syntax

     Value     = any string, maybe containing environment
                 variable references.
     Operator  = :- | :+.
     Reference = ${Var_Name[Operator[Value]]}.
     Var_Name  = Value | !Identifier.
  

In all forms, Variable_Name can have one of three formats:

  • An identifier: expands to the empty string if no such variable is defined, and to the variable's value otherwise.
  • 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 indirect expansion, and is limited to one level of indirection only.
  • 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 recursive expansion is unknown in bash>, and it is done for as many levels as specified.

The semantics of these forms is as follows:

${Variable_Name}
Is identical to the simple form of references $Identifier except that it also allows indirect and recursive expansion.
${Variable_Name:-Value}
Is replaced by the result of ${Variable_Name} unless that result is empty, in which case it is replaced by the expansion of Value.
${Variable_Name:+Value}
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 :-.)

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 two 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. "${Var" 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 no 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 syntax, 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

   --  Implementation-defined ...
end Util.Environment.Bash;