summaryrefslogtreecommitdiff
path: root/cli
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2016-01-28 07:24:22 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2016-01-28 07:24:22 +0200
commit648b616c86e05c74b9ad25ad2bb5e5adf4172619 (patch)
tree16daf0db543e17b2e5fd90ac65d33f2de563d896 /cli
parent6d52ac69e940a6be6c15c5c6f84a183bf56899c8 (diff)
Add support for file expansion in prologue/epilogue files
This is similar to variable expansion ($name$) except here we detect if the name starts with ./ or ../ and treat it as a path relative to the prologue/ epilogue file.
Diffstat (limited to 'cli')
-rw-r--r--cli/context.cxx71
-rw-r--r--cli/context.hxx16
-rw-r--r--cli/generator.cxx4
3 files changed, 72 insertions, 19 deletions
diff --git a/cli/context.cxx b/cli/context.cxx
index f1906c2..c87087b 100644
--- a/cli/context.cxx
+++ b/cli/context.cxx
@@ -6,6 +6,7 @@
#include <stack>
#include <vector>
#include <cstring> // strncmp()
+#include <fstream>
#include <sstream>
#include <iostream>
@@ -1595,11 +1596,11 @@ format (output_type ot, string const& s, bool para)
}
string context::
-substitute (const string& s, semantics::cli_unit& u)
+substitute (const string& s, semantics::cli_unit& u, const path* d)
{
string r;
- // Scan the string looking for variables ($var$).
+ // Scan the string looking for variables ($var$) or paths.
//
size_t b (0), e (b);
for (size_t n (s.size ()); e != n; ++e)
@@ -1613,38 +1614,78 @@ substitute (const string& s, semantics::cli_unit& u)
continue;
}
- // Scan for as long as it is a C identifier.
+ bool file (false);
+
+ // Scan for as long as it is a C identifier or a file.
//
size_t p (e + 1); // Position of the second '$'.
for (; p != n; ++p)
{
char c (s[p]);
+ bool f (p == e + 1); // First.
- if (!(c == '_' ||
- ('a' <= c && c <= 'z') ||
- ('A' <= c && c <= 'Z') ||
- (p != e + 1 && '0' <= c && c <= '9')))
- break;
+ if (d != 0 && f && c == '.' && p + 1 != n &&
+ (s[p + 1] == '/' || // "./"
+ (s[p + 1] == '.' && p + 2 != n && s[p + 2] == '/'))) // "../"
+ file = true;
+
+ if (file)
+ {
+ if (c == '$')
+ break;
+ }
+ else
+ {
+ if (!(c == '_' ||
+ ('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z') ||
+ (!f && '0' <= c && c <= '9')))
+ break;
+ }
}
// Note: check that the second '$' is not escaped.
//
if (p != n && s[p] == '$' && (p + 1 == n || s[p + 1] != '$'))
{
- r.append (s, b, e - b);
+ r.append (s, b, e - b); // Save what came before the expansion.
- // Lookup and substiute the variable.
+ // Var/file name.
//
++e;
string v (s, e, p - e);
- if (semantics::doc* d = u.lookup<semantics::doc> ("", "var: " + v))
- r += d->front ();
+ if (file)
+ {
+ path p (*d / path (v));
+ p.normalize (); // Apply '.' and '..'.
+
+ ifstream ifs (p.string ().c_str (), ifstream::in | ifstream::binary);
+ if (!ifs.is_open ())
+ {
+ cerr << p << ": error: unable to open in read mode" << endl;
+ throw generation_failed ();
+ }
+
+ // We don't expect our file to contain '\0' so use that as the
+ // delimiter to read the entire file with getline().
+ //
+ string s;
+ getline (ifs, s, '\0');
+ r += s;
+ }
else
{
- cerr << "error: undefined variable '" << v << "' in '" << s << "'"
- << endl;
- throw generation_failed ();
+ // Lookup and substiute the variable.
+ //
+ if (semantics::doc* d = u.lookup<semantics::doc> ("", "var: " + v))
+ r += d->front ();
+ else
+ {
+ cerr << "error: undefined variable '" << v << "' in '" << s << "'"
+ << endl;
+ throw generation_failed ();
+ }
}
e = p;
diff --git a/cli/context.hxx b/cli/context.hxx
index f16f8c2..cdc0aa5 100644
--- a/cli/context.hxx
+++ b/cli/context.hxx
@@ -13,6 +13,7 @@
#include <cstddef> // std::size_t
#include <cutl/shared-ptr.hxx>
+#include <cutl/fs/path.hxx>
#include "options.hxx"
#include "semantics.hxx"
@@ -44,6 +45,9 @@ public:
typedef std::size_t size_t;
typedef std::string string;
+ typedef cutl::fs::path path;
+ typedef cutl::fs::invalid_path invalid_path;
+
typedef ::options options_type;
typedef ::usage usage_type;
typedef ::class_doc class_doc_type;
@@ -111,13 +115,19 @@ public:
void
format_line (output_type, string&, const char*, size_t);
- // Substitute doc variable expansions ($var$).
+ // Substitute doc variable expansions ($var$). Var must be a C identifier.
+ // If the path is not NULL, then also recognize names that start with either
+ // ./ or ../ and treat them as files relative to path. Such file expansions
+ // are substituted with the files' contents.
//
static string
- substitute (const string&, semantics::cli_unit&);
+ substitute (const string&, semantics::cli_unit&, const path* = 0);
string
- substitute (const string& s) {return substitute (s, unit);}
+ substitute (const string& s, const path* p = 0)
+ {
+ return substitute (s, unit, p);
+ }
public:
static string const&
diff --git a/cli/generator.cxx b/cli/generator.cxx
index 486c793..5964c25 100644
--- a/cli/generator.cxx
+++ b/cli/generator.cxx
@@ -94,12 +94,14 @@ namespace
ifstream ifs;
open (ifs, file);
+ path d (path (file).directory ());
+
// getline() will set the failbit if it failed to extract anything,
// not even the delimiter and eofbit if it reached eof before seeing
// the delimiter.
//
for (string s; getline (ifs, s); )
- os << context::substitute (s, u) << endl;
+ os << context::substitute (s, u, &d) << endl;
}
}
}