package GNATCOLL.Templates is
type Substitution_Value is record
Name : GNAT.Strings.String_Access;
Value : GNAT.Strings.String_Access;
end record;
type Substitution_Array is array (Natural range <>) of Substitution_Value;
procedure Free (Substrings : in out Substitution_Array);
-- Free the memory occupied by the array
No_Substitution : constant Substitution_Array;
type Substitute_Callback is access
function (Name : String;
Quoted : Boolean) return String;
-- A callback for Substitute below. It is called once for each '%...'
-- parameter found in the string. Name doesn't include the delimiter.
-- Quoted indicate whether the parameter was quoted, i.e. the '%...' was
-- found as part of a quoted substring (for instance
-- a "quoted %version substring" b
-- The reason is that the substituted version could be different in such
-- a case, and the substituted value might need to protect quote symbols
-- in its replacement string.
-- Should raise Invalid_Substitution if Name cannot be substituted
Default_Delimiter : constant Character := '%';
-- The default delimiter used to mark the special substrings. It can be
-- overridden in the various Substitute subprograms below.
-- The special substrings always start with this delimiter, and including
-- the following number or identifier. That identifier can be quoted
-- between curly braces ({...}) or parentheses to avoid ambiguities.
-- For instance:
-- a%bcd*df => identifier name is "bcd"
-- a%123ab => identifier name is "123"
-- a%{bc}d*df => identifier name is "bc"
-- a%(bc)d*df => identifier name is "bc"
--
-- If the identifier is a number, the special character "-" will
-- be included in the name if it follows the number exactly:
-- a %1- b => identifier name is "1-"
-- a %1+ b => identifier name is "1"
-- The goal is to use this to indicate a range of parameter (in the first
-- example above, the intended substitution is the value of %1 concatenated
-- with that of %2, %3,..., so is an equivalent of "%1%2%3%4" if there are
-- four possible parameters.
--
-- If the first character after the delimiter is not an alphanumeric
-- character, that will be the name of the identifier
-- a %* b => identifier name is "*"
-- a %^ b => identifier name is "^"
--
-- When the delimiter is duplicated, it will always be replaced by a
-- single instance of the delimiter (unless you have specified another
-- explicit replacement for it in the Substrings parameter). For instance,
-- if the string contains "a%%b" it will be replaced with "a%b".
--
-- When an identifier is specified within curly braces or parentheses, a
-- default value can be specified for it, which will be used if no other
-- substitution is available. The syntax is similar to that of the Unix
-- shell:
-- %{var:-default}
-- where "default" is the default value to use.
type Error_Handling is (Keep_As_Is,
Replace_With_Empty,
Report_Error);
-- What to do when no substitution value was found:
-- If Keep_As_Is, the text is unaltered. "%invalid" remains as is
-- If Replace_With_Empty, the text is replaced with the empty string.
-- "%invalid" becomes "".
-- If Report_Error, an exception Invalid_Substitution is raised
function Substitute
(Str : String;
Substrings : Substitution_Array := No_Substitution;
Callback : Substitute_Callback := null;
Delimiter : Character := Default_Delimiter;
Recursive : Boolean := False;
Errors : Error_Handling := Keep_As_Is) return String;
-- Replace all substrings in Str that start with Delimiter (see the
-- declaration of Default_Delimiter for more information on identifier
-- names).
-- If an identifier found in Str matches no entry from Substrings,
-- Callback is called to try and find the appropriate substitution. If
-- that raises Invalid_Substitution, and the identifier contains a default
-- value, it is used.
-- If no substitution value was found, the behavior depends on the
-- Error parameter.
--
-- If Recursive is true, then this function will also substitute substrings
-- in the values specified in Substrings, for instance:
-- Delimiter := %
-- Substrings (1) := (Name => "a", Value => "c%b")
-- Substrings (2) := (Name => "b", Value => "d")
--
-- Str := "%a" results in "cd" if Recursive is True
-- results in "c%b" otherwise
Invalid_Substitution : exception;
end GNATCOLL.Templates;