aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2020-10-15 14:20:44 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2020-10-15 14:20:44 +0200
commit921c2d503a63f4769fdf1c7e6eb31be2706f9bea (patch)
tree487698c7e2877dec1eed4945cd2d1e9e09b7eb66
parent291a737de8f92a7f620853133aa404b98e552a21 (diff)
Add ability to specify fallback value for NULL substitutions with in.null
-rw-r--r--doc/manual.cli13
-rw-r--r--libbuild2/bash/rule.cxx5
-rw-r--r--libbuild2/bash/rule.hxx3
-rw-r--r--libbuild2/in/init.cxx5
-rw-r--r--libbuild2/in/rule.cxx45
-rw-r--r--libbuild2/in/rule.hxx13
-rw-r--r--libbuild2/version/rule.cxx6
-rw-r--r--libbuild2/version/rule.hxx3
8 files changed, 73 insertions, 20 deletions
diff --git a/doc/manual.cli b/doc/manual.cli
index 59084d6..0cd5a5e 100644
--- a/doc/manual.cli
+++ b/doc/manual.cli
@@ -8156,6 +8156,19 @@ target-specific variables. Typed variable values are converted to string
using the corresponding \c{builtin.string()} function overload before
substitution.
+Using an undefined variable in a substitution is an error. Using a \c{null}
+value in a substitution is also an error unless the fallback value is
+specified with the \c{in.null} variable. For example:
+
+\
+# buildfile
+
+h{config}: in{config}
+{
+ in.null = '' # Substitute null values with empty string.
+}
+\
+
A number of other build system modules, for example, \l{#module-version
\c{version}} and \l{#module-bash \c{bash}}, are based on the \c{in} module and
provide extended functionality. The \c{in} preprocessing rule matches any
diff --git a/libbuild2/bash/rule.cxx b/libbuild2/bash/rule.cxx
index 148da95..9fc89d7 100644
--- a/libbuild2/bash/rule.cxx
+++ b/libbuild2/bash/rule.cxx
@@ -195,11 +195,12 @@ namespace build2
action a,
const target& t,
const string& n,
- bool strict) const
+ bool strict,
+ const optional<string>& null) const
{
return n.compare (0, 6, "import") == 0 && (n[6] == ' ' || n[6] == '\t')
? substitute_import (l, a, t, trim (string (n, 7)))
- : rule::substitute (l, a, t, n, strict);
+ : rule::substitute (l, a, t, n, strict, null);
}
string in_rule::
diff --git a/libbuild2/bash/rule.hxx b/libbuild2/bash/rule.hxx
index 0774b5f..81c4604 100644
--- a/libbuild2/bash/rule.hxx
+++ b/libbuild2/bash/rule.hxx
@@ -51,7 +51,8 @@ namespace build2
action a,
const target&,
const string&,
- bool) const override;
+ bool,
+ const optional<string>&) const override;
string
substitute_import (const location&,
diff --git a/libbuild2/in/init.cxx b/libbuild2/in/init.cxx
index 6cd2f96..18071f8 100644
--- a/libbuild2/in/init.cxx
+++ b/libbuild2/in/init.cxx
@@ -59,6 +59,11 @@ namespace build2
// unknown substitutions as is.
//
vp.insert<string> ("in.substitution");
+
+ // Fallback value to use for NULL value substitutions. If unspecified,
+ // NULL substitutions are an error.
+ //
+ vp.insert<string> ("in.null");
}
// Register target types.
diff --git a/libbuild2/in/rule.cxx b/libbuild2/in/rule.cxx
index 16747ab..b64541c 100644
--- a/libbuild2/in/rule.cxx
+++ b/libbuild2/in/rule.cxx
@@ -116,6 +116,14 @@ namespace build2
fail << "invalid substitution mode '" << *s << "'";
}
+ // NULL substitutions.
+ //
+ optional<string> null;
+ if (const string* s = cast_null<string> (t["in.null"]))
+ null = *s;
+ else
+ null = null_;
+
// Determine if anything needs to be updated.
//
timestamp mt (t.load_mtime ());
@@ -220,7 +228,7 @@ namespace build2
// can be overriden with custom substitution semantics.
//
optional<string> v (
- substitute (location (ip, ln), a, t, n, strict));
+ substitute (location (ip, ln), a, t, n, strict, null));
assert (v); // Rule semantics change without version increment?
@@ -360,7 +368,8 @@ namespace build2
// pointing to the opening symbol and e -- to the closing.
//
string name (s, b + 1, e - b -1);
- if (optional<string> val = substitute (l, a, t, name, strict))
+ if (optional<string> val =
+ substitute (l, a, t, name, strict, null))
{
// Save in depdb.
//
@@ -429,11 +438,26 @@ namespace build2
}
string rule::
- lookup (const location& l, action, const target& t, const string& n) const
+ lookup (const location& loc,
+ action,
+ const target& t,
+ const string& n,
+ const optional<string>& null) const
{
- if (auto x = t[n])
+ auto l (t[n]);
+
+ if (l.defined ())
{
- value v (*x);
+ value v (*l);
+
+ if (v.null)
+ {
+ if (null)
+ return *null;
+ else
+ fail (loc) << "null value in variable '" << n << "'" <<
+ info << "use in.null to specify null value substiution string";
+ }
// For typed values call string() for conversion.
//
@@ -445,16 +469,16 @@ namespace build2
: t.ctx.functions.call (&t.base_scope (),
"string",
vector_view<value> (&v, 1),
- l));
+ loc));
}
catch (const invalid_argument& e)
{
- fail (l) << e <<
+ fail (loc) << e <<
info << "while substituting '" << n << "'" << endf;
}
}
else
- fail (l) << "undefined variable '" << n << "'" << endf;
+ fail (loc) << "undefined variable '" << n << "'" << endf;
}
optional<string> rule::
@@ -462,7 +486,8 @@ namespace build2
action a,
const target& t,
const string& n,
- bool strict) const
+ bool strict,
+ const optional<string>& null) const
{
// In the lax mode scan the fragment to make sure it is a variable name
// (that is, it can be expanded in a buildfile as just $<name>; see
@@ -486,7 +511,7 @@ namespace build2
}
}
- return lookup (l, a, t, n);
+ return lookup (l, a, t, n, null);
}
}
}
diff --git a/libbuild2/in/rule.hxx b/libbuild2/in/rule.hxx
index cf67060..2fa1305 100644
--- a/libbuild2/in/rule.hxx
+++ b/libbuild2/in/rule.hxx
@@ -33,11 +33,13 @@ namespace build2
rule (string rule_id,
string program,
char symbol = '$',
- bool strict = true)
+ bool strict = true,
+ optional<string> null = nullopt)
: rule_id_ (move (rule_id)),
program_ (move (program)),
symbol_ (symbol),
- strict_ (strict) {}
+ strict_ (strict),
+ null_ (move (null)) {}
virtual bool
match (action, target&, const string&) const override;
@@ -65,7 +67,8 @@ namespace build2
lookup (const location&,
action,
const target&,
- const string& name) const;
+ const string& name,
+ const optional<string>& null) const;
// Perform variable substitution. Return nullopt if it should be
// ignored.
@@ -75,13 +78,15 @@ namespace build2
action,
const target&,
const string& name,
- bool strict) const;
+ bool strict,
+ const optional<string>& null) const;
protected:
const string rule_id_;
const string program_;
char symbol_;
bool strict_;
+ optional<string> null_;
};
}
}
diff --git a/libbuild2/version/rule.cxx b/libbuild2/version/rule.cxx
index 6fd97ae..919dfcf 100644
--- a/libbuild2/version/rule.cxx
+++ b/libbuild2/version/rule.cxx
@@ -88,7 +88,8 @@ namespace build2
lookup (const location& l,
action a,
const target& t,
- const string& n) const
+ const string& n,
+ const optional<string>& null) const
{
// Note that this code will be executed during up-to-date check for each
// substitution so let's try not to do anything overly sub-optimal here.
@@ -108,7 +109,8 @@ namespace build2
return rule::lookup (l, // Standard lookup.
a,
t,
- p == string::npos ? n : string (n, p + 1));
+ p == string::npos ? n : string (n, p + 1),
+ null);
}
string pn (n, 0, p);
diff --git a/libbuild2/version/rule.hxx b/libbuild2/version/rule.hxx
index f9e7655..ddc5e11 100644
--- a/libbuild2/version/rule.hxx
+++ b/libbuild2/version/rule.hxx
@@ -29,7 +29,8 @@ namespace build2
lookup (const location&,
action,
const target&,
- const string&) const override;
+ const string&,
+ const optional<string>&) const override;
};
// Pre-process manifest before installation to patch in the version.