--- /dev/null
+Changed: ParameterHandler::print_parameters() in LaTeX format now correctly
+escapes special characters. As a consequence, the names of labels changed because they are now mangled. See the documentation for more details.
+<br>
+(Timo Heister, 2017/11/03)
* parameters. The various sections of parameters are then represented by
* latex section and subsection commands as well as by nested enumerations.
*
+ * You can reference specific parameter sections and individual parameters
+ * by the labels that are generated automatically for each entry. The
+ * labels have the format <code>parameters:section1/subsection1</code>
+ * and <code>parameters:section1/subsection1/someentry</code>. Because
+ * special characters can appear in the section and entry names, these
+ * will be "mangled". Here, all characters except <code>[a-zA-Z0-9]</code>
+ * are replaced by <code>_XX</code>, where <code>XX</code> is the digit
+ * ascii code of the character in hexadecimal encoding (so a space becomes
+ * <code>_20</code> for example).
+ *
+ * While this function escapes special LaTeX-specific characters (backslash,
+ * underscore, etc.) in most of the output (names, default values, etc.),
+ * the documentation string is passed as-is. This means you can use math
+ * environments and other formatting in the description, but you need
+ * to escape quotes, backslashes, underscores, etc. yourself.
+ *
* In addition, all parameter names are listed with <code>@\index</code>
* statements in two indices called <code>prmindex</code> (where the name of
* each parameter is listed in the index) and <code>prmindexfull</code>
*/
std::unique_ptr<PatternBase> pattern_factory (const std::string &description);
+ /**
+ * Escape the string @p input for the specified @p style so that characters
+ * will appear as intended. For example, characters like _ can not be
+ * written as is in LateX and have to be escaped as \_.
+ */
+ std::string escape(const std::string &input, const PatternBase::OutputStyle style);
+
+
/**
* Test for the string being an integer. If bounds are given to the
* constructor, then the integer given also needs to be within the interval
case LaTeX:
{
+ auto escape = [] (const std::string &input)
+ {
+ return Patterns::escape(input, Patterns::PatternBase::LaTeX);
+ };
+
// if there are any parameters in this section then print them
// as an itemized list
bool parameters_exist_here = false;
const std::string value = p->second.get<std::string>("value");
// print name
- out << "\\item {\\it Parameter name:} {\\tt " << demangle(p->first) << "}\n"
+ out << "\\item {\\it Parameter name:} {\\tt "
+ << escape(demangle(p->first)) << "}\n"
<< "\\phantomsection\\label{parameters:";
+ // labels are not to be escaped but mangled:
for (unsigned int i=0; i<target_subsection_path.size(); ++i)
- out << target_subsection_path[i] << "/";
- out << demangle(p->first);
+ out << mangle(target_subsection_path[i]) << "/";
+ out << p->first;
out << "}\n\n"
<< '\n';
out << "\\index[prmindex]{"
- << demangle(p->first)
+ << escape(demangle(p->first))
<< "}\n";
out << "\\index[prmindexfull]{";
for (unsigned int i=0; i<target_subsection_path.size(); ++i)
- out << target_subsection_path[i] << "!";
- out << demangle(p->first)
+ out << escape(target_subsection_path[i]) << "!";
+ out << escape(demangle(p->first))
<< "}\n";
// finally print value and default
- out << "{\\it Value:} " << value << "\n\n"
+ out << "{\\it Value:} " << escape(value) << "\n\n"
<< '\n'
<< "{\\it Default:} "
- << p->second.get<std::string>("default_value") << "\n\n"
+ << escape(p->second.get<std::string>("default_value"))
+ << "\n\n"
<< '\n';
- // if there is a documenting string, print it as well
+ // if there is a documenting string, print it as well but
+ // don't escape to allow formatting/formulas
if (!p->second.get<std::string>("documentation").empty())
out << "{\\it Description:} "
<< p->second.get<std::string>("documentation") << "\n\n"
<< '\n';
- // also output possible values
+ // also output possible values, do not escape because the
+ // description internally will use LaTeX formatting
const unsigned int pattern_index = p->second.get<unsigned int> ("pattern");
const std::string desc_str = patterns[pattern_index]->description (Patterns::PatternBase::LaTeX);
out << "{\\it Possible values:} "
const std::string alias = p->second.get<std::string>("alias");
// print name
- out << "\\item {\\it Parameter name:} {\\tt " << demangle(p->first) << "}\n"
+ out << "\\item {\\it Parameter name:} {\\tt "
+ << escape(demangle(p->first)) << "}\n"
<< "\\phantomsection\\label{parameters:";
+ // do not escape but mangle labels:
for (unsigned int i=0; i<target_subsection_path.size(); ++i)
- out << target_subsection_path[i] << "/";
- out << demangle(p->first);
+ out << mangle(target_subsection_path[i]) << "/";
+ out << p->first;
out << "}\n\n"
<< '\n';
out << "\\index[prmindex]{"
- << demangle(p->first)
+ << escape(demangle(p->first))
<< "}\n";
out << "\\index[prmindexfull]{";
for (unsigned int i=0; i<target_subsection_path.size(); ++i)
- out << target_subsection_path[i] << "!";
- out << demangle(p->first)
+ out << escape(target_subsection_path[i]) << "!";
+ out << escape(demangle(p->first))
<< "}\n";
// finally print alias and indicate if it is deprecated
out << "This parameter is an alias for the parameter ``\\texttt{"
- << alias << "}''."
+ << escape(alias) << "}''."
<< (p->second.get<std::string>("deprecation_status") == "true"
?
" Its use is deprecated."
case LaTeX:
{
+ auto escape = [] (const std::string &input)
+ {
+ return Patterns::escape(input, Patterns::PatternBase::LaTeX);
+ };
+
out << '\n'
<< "\\subsection{Parameters in section \\tt ";
// find the path to the current section so that we can
// print it in the \subsection{...} heading
for (unsigned int i=0; i<target_subsection_path.size(); ++i)
- out << target_subsection_path[i] << "/";
- out << demangle(p->first);
+ out << escape(target_subsection_path[i]) << "/";
+ out << escape(demangle(p->first));
out << "}" << '\n';
out << "\\label{parameters:";
case LaTeX:
{
+ auto escape = [] (const std::string &input)
+ {
+ return Patterns::escape(input, Patterns::PatternBase::LaTeX);
+ };
+
// if there are any parameters in this section then print them
// as an itemized list
bool parameters_exist_here = false;
const std::string value = p->second.get<std::string>("value");
// print name
- out << "\\item {\\it Parameter name:} {\\tt " << demangle(p->first) << "}\n"
+ out << "\\item {\\it Parameter name:} {\\tt " << escape(demangle(p->first)) << "}\n"
<< "\\phantomsection\\label{parameters:";
for (unsigned int i=0; i<subsection_path.size(); ++i)
- out << subsection_path[i] << "/";
- out << demangle(p->first);
+ out << mangle(subsection_path[i]) << "/";
+ out << p->first;
out << "}\n\n"
<< std::endl;
out << "\\index[prmindex]{"
- << demangle(p->first)
+ << escape(demangle(p->first))
<< "}\n";
out << "\\index[prmindexfull]{";
for (unsigned int i=0; i<subsection_path.size(); ++i)
- out << subsection_path[i] << "!";
- out << demangle(p->first)
+ out << escape(subsection_path[i]) << "!";
+ out << escape(demangle(p->first))
<< "}\n";
// finally print value and default
- out << "{\\it Value:} " << value << "\n\n"
+ out << "{\\it Value:} " << escape(value) << "\n\n"
<< std::endl
<< "{\\it Default:} "
- << p->second.get<std::string>("default_value") << "\n\n"
+ << escape(p->second.get<std::string>("default_value")) << "\n\n"
<< std::endl;
// if there is a documenting string, print it as well
const std::string alias = p->second.get<std::string>("alias");
// print name
- out << "\\item {\\it Parameter name:} {\\tt " << demangle(p->first) << "}\n"
+ out << "\\item {\\it Parameter name:} {\\tt " << escape(demangle(p->first)) << "}\n"
<< "\\phantomsection\\label{parameters:";
for (unsigned int i=0; i<subsection_path.size(); ++i)
- out << subsection_path[i] << "/";
- out << demangle(p->first);
+ out << mangle(subsection_path[i]) << "/";
+ out << p->first;
out << "}\n\n"
<< std::endl;
out << "\\index[prmindex]{"
- << demangle(p->first)
+ << escape(demangle(p->first))
<< "}\n";
out << "\\index[prmindexfull]{";
for (unsigned int i=0; i<subsection_path.size(); ++i)
- out << subsection_path[i] << "!";
- out << demangle(p->first)
+ out << escape(subsection_path[i]) << "!";
+ out << escape(demangle(p->first))
<< "}\n";
// finally print alias and indicate if it is deprecated
out << "This parameter is an alias for the parameter ``\\texttt{"
- << alias << "}''."
+ << escape(alias) << "}''."
<< (p->second.get<std::string>("deprecation_status") == "true"
?
" Its use is deprecated."
break;
case LaTeX:
{
+ auto escape = [] (const std::string &input)
+ {
+ return Patterns::escape(input, Patterns::PatternBase::LaTeX);
+ };
+
out << std::endl
<< "\\subsection{Parameters in section \\tt ";
// find the path to the current section so that we can
// print it in the \subsection{...} heading
for (unsigned int i=0; i<subsection_path.size(); ++i)
- out << subsection_path[i] << "/";
- out << demangle(p->first);
+ out << escape(subsection_path[i]) << "/";
+ out << escape(demangle(p->first));
out << "}" << std::endl;
out << "\\label{parameters:";
+ std::string escape(const std::string &input, const PatternBase::OutputStyle style)
+ {
+ switch (style)
+ {
+ case PatternBase::Machine:
+ case PatternBase::Text:
+ return input;
+ case PatternBase::LaTeX:
+ {
+ std::string u;
+ u.reserve (input.size());
+ for (auto c : input)
+ {
+ switch (c)
+ {
+ case '#':
+ case '$':
+ case '%':
+ case '&':
+ case '_':
+ case '{':
+ case '}':
+ // simple escaping:
+ u.push_back('\\');
+ u.push_back(c);
+ break;
+
+ case '\\':
+ u.append("\\textbackslash{}");
+ break;
+
+ case '^':
+ u.append("\\^{}");
+ break;
+
+ case '~':
+ u.append("\\~{}");
+ break;
+
+ default:
+ // all other chars are just copied:
+ u.push_back(c);
+ }
+ }
+ return u;
+ }
+ default:
+ Assert(false, ExcNotImplemented());
+ }
+ return "";
+ }
+
+
+
std::unique_ptr<PatternBase> pattern_factory(const std::string &description)
{
std::unique_ptr<PatternBase> p;
std::ostringstream description;
description << "Any one of "
- << Utilities::replace_in_string(sequence,"|",", ");
+ << escape(Utilities::replace_in_string(sequence,"|",", "), style);
return description.str();
}
<< min_elements << " to " << max_elements
<< " elements ";
if (separator != ",")
- description << "separated by <" << separator << "> ";
+ description << "separated by <"
+ << escape(separator, style)
+ << "> ";
description << "where each element is ["
<< pattern->description(style)
<< "]";
std::ostringstream description;
description << "A key"
- << key_value_separator
+ << escape(key_value_separator, style)
<< "value map of "
<< min_elements << " to " << max_elements
<< " elements ";
if (separator != ",")
- description << " separated by <" << separator << "> ";
+ description << " separated by <" << escape(separator, style) << "> ";
description << " where each key is ["
<< key_pattern->description(style)
<< "]"
<< patterns.size()
<< " elements ";
if (separator != ":")
- description << " separated by <" << separator << "> ";
+ description << " separated by <" << escape(separator, style) << "> ";
description << " where each element is ["
<< patterns[0]->description(style)
<< "]";
for (unsigned int i=1; i<patterns.size(); ++i)
{
- description << separator
+ description << escape(separator, style)
<< "[" << patterns[i]->description(style) << "]";
}
std::ostringstream description;
description << "A comma-separated list of any of "
- << Utilities::replace_in_string(sequence,"|",", ");
+ << escape(Utilities::replace_in_string(sequence,"|",", "), style);
return description.str();
}
--- /dev/null
+// ---------------------------------------------------------------------
+//
+// Copyright (C) 2003 - 2016 by the deal.II authors
+//
+// This file is part of the deal.II library.
+//
+// The deal.II library is free software; you can use it, redistribute
+// it, and/or modify it under the terms of the GNU Lesser General
+// Public License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+// The full text of the license can be found in the file LICENSE at
+// the top level of the deal.II distribution.
+//
+// ---------------------------------------------------------------------
+
+
+
+// test escaping of underscores in ParameterHandler::print_parameters(LaTeX)
+
+#include "../tests.h"
+#include <deal.II/base/parameter_handler.h>
+
+
+int main ()
+{
+ initlog();
+
+ // latex header to make it easy to check the .tex output:
+ deallog.get_file_stream() << "\\documentclass{article}\n"
+ "\\usepackage{amsmath}\n"
+ "\\usepackage{imakeidx}\n"
+ "\\makeindex[name=prmindex, title=Index of run-time parameter entries]\n"
+ "\\makeindex[name=prmindexfull, title=Index of run-time parameters with section names]\n"
+ "\\usepackage[colorlinks,linkcolor=blue,urlcolor=blue,citecolor=blue,baseurl=../]{hyperref}\n"
+ "\\begin{document}\n" << std::endl;
+
+ ParameterHandler prm;
+ prm.enter_subsection ("section_1");
+ {
+ prm.enter_subsection ("section_2&3");
+ {
+ prm.declare_entry ("list",
+ "default_1",
+ Patterns::List(Patterns::Selection("default_1|b|c|d|e|f|g|h")),
+ "docs 1");
+ prm.declare_entry ("int_hello",
+ "1",
+ Patterns::Integer());
+ prm.declare_entry ("text",
+ "default text with _ ~ \\ # & { }",
+ Patterns::Anything(),
+ "documentation with formulas: $x_3$");
+ }
+ prm.leave_subsection ();
+ prm.declare_entry ("some other entry with {%}",
+ "3.1415926",
+ Patterns::Double(),
+ "documentation");
+ }
+ prm.leave_subsection ();
+
+ prm.print_parameters (deallog.get_file_stream(), ParameterHandler::LaTeX);
+
+ deallog.get_file_stream() << "\n\n"
+ "\\printindex[prmindex]\n"
+ "\\printindex[prmindexfull]\n"
+ "\\end{document}" << std::endl;
+}
--- /dev/null
+
+\documentclass{article}
+\usepackage{amsmath}
+\usepackage{imakeidx}
+\makeindex[name=prmindex, title=Index of run-time parameter entries]
+\makeindex[name=prmindexfull, title=Index of run-time parameters with section names]
+\usepackage[colorlinks,linkcolor=blue,urlcolor=blue,citecolor=blue,baseurl=../]{hyperref}
+\begin{document}
+
+\subsection{Global parameters}
+\label{parameters:global}
+
+
+
+\subsection{Parameters in section \tt section\_1}
+\label{parameters:section_5f1}
+
+\begin{itemize}
+\item {\it Parameter name:} {\tt some other entry with \{\%\}}
+\phantomsection\label{parameters:section_5f1/some_20other_20entry_20with_20_7b_25_7d}
+
+
+\index[prmindex]{some other entry with \{\%\}}
+\index[prmindexfull]{section\_1!some other entry with \{\%\}}
+{\it Value:} 3.1415926
+
+
+{\it Default:} 3.1415926
+
+
+{\it Description:} documentation
+
+
+{\it Possible values:} A floating point number $v$ such that $-\text{MAX\_DOUBLE} \leq v \leq \text{MAX\_DOUBLE}$
+\end{itemize}
+
+
+
+\subsection{Parameters in section \tt section\_1/section\_2\&3}
+\label{parameters:section_5f1/section_5f2_263}
+
+\begin{itemize}
+\item {\it Parameter name:} {\tt int\_hello}
+\phantomsection\label{parameters:section_5f1/section_5f2_263/int_5fhello}
+
+
+\index[prmindex]{int\_hello}
+\index[prmindexfull]{section\_1!section\_2\&3!int\_hello}
+{\it Value:} 1
+
+
+{\it Default:} 1
+
+
+{\it Possible values:} An integer $n$ such that $-2147483648\leq n \leq 2147483647$
+\item {\it Parameter name:} {\tt list}
+\phantomsection\label{parameters:section_5f1/section_5f2_263/list}
+
+
+\index[prmindex]{list}
+\index[prmindexfull]{section\_1!section\_2\&3!list}
+{\it Value:} default\_1
+
+
+{\it Default:} default\_1
+
+
+{\it Description:} docs 1
+
+
+{\it Possible values:} A list of 0 to 4294967295 elements where each element is [Any one of default\_1, b, c, d, e, f, g, h]
+\item {\it Parameter name:} {\tt text}
+\phantomsection\label{parameters:section_5f1/section_5f2_263/text}
+
+
+\index[prmindex]{text}
+\index[prmindexfull]{section\_1!section\_2\&3!text}
+{\it Value:} default text with \_ \~{} \textbackslash{} \# \& \{ \}
+
+
+{\it Default:} default text with \_ \~{} \textbackslash{} \# \& \{ \}
+
+
+{\it Description:} documentation with formulas: $x_3$
+
+
+{\it Possible values:} Any string
+\end{itemize}
+
+
+\printindex[prmindex]
+\printindex[prmindexfull]
+\end{document}