From 4bd33d0eb078b23d1c9ec181f07159e9141bea69 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 31 Oct 2015 16:45:18 +0200 Subject: Add support for expanding documentation variables --- cli/generator.cxx | 98 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 83 insertions(+), 15 deletions(-) diff --git a/cli/generator.cxx b/cli/generator.cxx index 4623db9..f67b8aa 100644 --- a/cli/generator.cxx +++ b/cli/generator.cxx @@ -92,19 +92,87 @@ namespace } void - append (ostream& os, vector const& text, string const& file) + append (ostream& os, const string& s, semantics::cli_unit& u) { - for (vector::const_iterator i (text.begin ()); - i != text.end (); ++i) + // Scan the string looking for variable substitutions ($var$). + // + size_t b (0), e (b); + for (size_t n (s.size ()); e != n; ++e) { - os << *i << endl; + if (s[e] == '$' && e + 1 != n) + { + if (s[e + 1] == '$') // Escape. + { + os.write (s.c_str () + b, ++e - b); // Write one, skip the other. + b = e + 1; + continue; + } + + // Scan for as long as it is a C identifier. + // + size_t p (e + 1); // Position of the second '$'. + for (; p != n; ++p) + { + char c (s[p]); + + if (!(c == '_' || + ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || + (p != e + 1 && '0' <= c && c <= '9'))) + break; + } + + // Note: check that the second '$' is not escaped. + // + if (p != n && s[p] == '$' && (p + 1 == n || s[p + 1] != '$')) + { + os.write (s.c_str () + b, e - b); + + // Lookup and substiute the variable. + // + ++e; + string v (s, e, p - e); + + if (semantics::doc* d = u.lookup ("", "var: " + v)) + os << d->front (); + else + { + cerr << "error: undefined variable '" << v << "' in '" << s << "'" + << endl; + throw generation_failed (); + } + + e = p; + b = e + 1; + } + } } + os.write (s.c_str () + b, e - b); // Last chunk. + os << endl; + } + + void + append (ostream& os, + vector const& text, + string const& file, + semantics::cli_unit& u) + { + for (vector::const_iterator i (text.begin ()); + i != text.end (); ++i) + append (os, *i, u); + if (!file.empty ()) { ifstream ifs; open (ifs, file); - os << ifs.rdbuf (); + + // 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); ) + append (os, s, u); } } } @@ -274,7 +342,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) // hxx << "// Begin prologue." << endl << "//" << endl; - append (hxx, ops.hxx_prologue (), ops.hxx_prologue_file ()); + append (hxx, ops.hxx_prologue (), ops.hxx_prologue_file (), unit); hxx << "//" << endl << "// End prologue." << endl << endl; @@ -301,7 +369,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) // hxx << "// Begin epilogue." << endl << "//" << endl; - append (hxx, ops.hxx_epilogue (), ops.hxx_epilogue_file ()); + append (hxx, ops.hxx_epilogue (), ops.hxx_epilogue_file (), unit); hxx << "//" << endl << "// End epilogue." << endl << endl; @@ -319,7 +387,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) // ixx << "// Begin prologue." << endl << "//" << endl; - append (ixx, ops.ixx_prologue (), ops.ixx_prologue_file ()); + append (ixx, ops.ixx_prologue (), ops.ixx_prologue_file (), unit); ixx << "//" << endl << "// End prologue." << endl << endl; @@ -339,7 +407,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) // ixx << "// Begin epilogue." << endl << "//" << endl; - append (ixx, ops.ixx_epilogue (), ops.ixx_epilogue_file ()); + append (ixx, ops.ixx_epilogue (), ops.ixx_epilogue_file (), unit); ixx << "//" << endl << "// End epilogue." << endl; } @@ -353,7 +421,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) // cxx << "// Begin prologue." << endl << "//" << endl; - append (cxx, ops.cxx_prologue (), ops.cxx_prologue_file ()); + append (cxx, ops.cxx_prologue (), ops.cxx_prologue_file (), unit); cxx << "//" << endl << "// End prologue." << endl << endl; @@ -382,7 +450,7 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) // cxx << "// Begin epilogue." << endl << "//" << endl; - append (cxx, ops.cxx_epilogue (), ops.cxx_epilogue_file ()); + append (cxx, ops.cxx_epilogue (), ops.cxx_epilogue_file (), unit); cxx << "//" << endl << "// End epilogue." << endl << endl; @@ -418,14 +486,14 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) // ostream& os (ops.stdout_ () ? cout : static_cast (man)); - append (os, ops.man_prologue (), ops.man_prologue_file ()); + append (os, ops.man_prologue (), ops.man_prologue_file (), unit); os << man_header; context ctx (os, unit, ops); generate_man (ctx); - append (os, ops.man_epilogue (), ops.man_epilogue_file ()); + append (os, ops.man_epilogue (), ops.man_epilogue_file (), unit); } // HTML output @@ -457,14 +525,14 @@ generate (options const& ops, semantics::cli_unit& unit, path const& p) // ostream& os (ops.stdout_ () ? cout : static_cast (html)); - append (os, ops.html_prologue (), ops.html_prologue_file ()); + append (os, ops.html_prologue (), ops.html_prologue_file (), unit); os << html_header; context ctx (os, unit, ops); generate_html (ctx); - append (os, ops.html_epilogue (), ops.html_epilogue_file ()); + append (os, ops.html_epilogue (), ops.html_epilogue_file (), unit); } auto_rm.cancel (); -- cgit v1.1