//-----------------------------------------------------------
// Copyright Christian Arnault LAL-Orsay CNRS
// arnault@lal.in2p3.fr
// See the complete license in cmt_license.txt "http://www.cecill.info".
//-----------------------------------------------------------
#include "cmt_model.h"
#include "cmt_fragment.h"
#include "cmt_symbol.h"
/**
* Filters out all predefined XML constructs.
*/
void CmtModel::filter (cmt_string& text)
{
text.replace_all ("", "\t");
text.replace_all ("", "\r");
text.replace_all ("", "\n");
}
void CmtModel::display (cmt_string& text)
{
text.replace_all ("<", "<");
text.replace_all (">", ">");
text.replace_all ("\\\"", "\"");
text.replace_all ("\\\'", "\'");
text.replace_all ("", "");
Symbol::expand (text);
cout << text;
}
void CmtModel::expand (const cmt_string& input_text)
{
int openmarker;
int closemarker;
CmtSystem::cmt_string_vector subargs;
cmt_string text = input_text;
cmt_string remaining;
filter (text);
for (;;)
{
/**
* Look for the next < ... /> pattern
* If not found, then simply dump the text as it is.
*/
openmarker = text.find ("<");
if (openmarker == cmt_string::npos) break;
closemarker = text.find (openmarker, "/>");
if (closemarker == cmt_string::npos) break;
if (CmtSystem::testenv ("CMTTESTMODEL"))
{
cerr << "text=[" << text << "]" << endl;
}
/**
* Extract the command from the pattern
*/
cmt_string command;
text.substr (openmarker + 1, closemarker - openmarker - 1, command);
if (CmtSystem::testenv ("CMTTESTMODEL"))
{
cerr << "command=[" << command << "]" << endl;
}
/**
* Get what is left from the original text beyond the pattern
*/
text.substr (closemarker + 2, remaining);
/**
* Cut the original text up to the pattern start
*/
text.erase (openmarker);
/**
* Now display it
*/
display (text);
/**
* Convert the extracted command into words
*/
CmtSystem::split (command, " ", subargs);
/**
* Recursively expand it
*/
expand (subargs);
/**
* The next iteration will operate on the remaining text
*/
text = remaining;
}
if (CmtSystem::testenv ("CMTTESTMODEL"))
{
cerr << "text=[" << text << "]" << endl;
}
/**
* Display what is left after extracting the last pattern
*/
display (text);
cout << endl;
}
void CmtModel::strict_expand (const cmt_string& input_text)
{
CmtSystem::cmt_string_vector subargs;
cmt_string text = input_text;
cmt_string remaining;
// The patterns for syntax parsing
cmt_string open_element = " we have a multiple one
it = its;
multiple = true;
}
else if (its == exp_open_elements.end ())
{
// no multiple element -> we have a single one
}
else if (it < its)
{
// the single is before the multiple
}
else
{
// the multiple is before the single
it = its;
multiple = true;
}
remaining = text.substr (pos, it._pos - pos);
display (remaining);
//cout << "pos=" << pos << " open_element -> p=" << it._pos << " l=" << it._length << endl;
pos = it._pos + it._length;
it = exp_word.begin (text, pos);
if (it._pos != pos)
{
cerr << "Syntax error: no element name" << endl;
break;
}
//cout << "pos=" << pos << " word -> p=" << it._pos << " l=" << it._length << endl;
pos += it._length;
cmt_string element = it (text);
//cout << "pos=" << pos << " element=" << element << endl;
subargs.clear ();
{
cmt_string& s = subargs.add ();
s = element;
}
for (;;)
{
it = exp_skip_spaces.begin (text, pos);
if (it._pos == pos)
{
//cout << "pos=" << pos << " skip_spaces -> p=" << it._pos << " l=" << it._length << endl;
pos += it._length;
}
//cout << "pos=" << pos << endl;
it = exp_close_element.begin (text, pos);
if (it._pos == pos)
{
//cout << "Recursing to [" << element << "]" << endl;
int i;
Variable::VariableVector variables;
/**
* We start by decoding all [variable=value] pairs from the arguments
* A vector of Variables is filled from them.
*/
int multiple_count = 0;
CmtSystem::cmt_string_vector values;
cmt_string name;
cmt_string value;
for (i = 1; i < subargs.size (); i++)
{
const cmt_string& arg = subargs[i];
int p = arg.find ("=");
arg.substr (0, p, name);
arg.substr (p + 1, value);
if (value[0] == '"')
{
value.erase (0, 1);
if (value[value.size()-1] == '"') value.erase (value.size ()-1);
}
else if (value[0] == '\'')
{
value.erase (0, 1);
if (value[value.size()-1] == '\'') value.erase (value.size ()-1);
}
//cout << "+ name = [" << value << "]" << endl;
if (multiple)
{
values.clear ();
CmtSystem::split (value, " \t", values);
int n = values.size ();
if (n > multiple_count) multiple_count = n;
}
Variable* v = Variable::find (variables, name);
if (v == 0)
{
v = &(variables.add ());
v->set (name);
}
(*v) = value;
}
cmt_string sub_text;
FragmentHandle fragment (element);
if (multiple)
{
//cout << "+ count = " << multiple_count << endl;
for (int n = 0; n < multiple_count; n++)
{
for (i = 1; i < subargs.size (); i++)
{
const cmt_string& arg = subargs[i];
int p = arg.find ("=");
arg.substr (p + 1, value);
if (value[0] == '"')
{
value.erase (0, 1);
if (value[value.size()-1] == '"') value.erase (value.size ()-1);
}
else if (value[0] == '\'')
{
value.erase (0, 1);
if (value[value.size()-1] == '\'') value.erase (value.size ()-1);
}
//cout << "+ values = [" << value << "]" << endl;
values.clear ();
CmtSystem::split (value, " \t", values);
if (n < values.size ())
{
value = values[n];
}
else
{
value = "";
}
Variable& v = variables[i-1];
//cout << "+ value = [" << value << "]" << endl;
v = value;
}
fragment.copy (sub_text, variables, 0);
expand_level++;
strict_expand (sub_text);
expand_level--;
}
}
else
{
fragment.copy (sub_text, variables, 0);
expand_level++;
strict_expand (sub_text);
expand_level--;
}
pos += it._length;
break;
}
//cout << "Try attribute at pos=" << pos << " [" << text.substr (pos) << "]" << endl;
it = exp_attribute.begin (text, pos);
if (it._pos != pos)
{
cerr << "Syntax error : no attribute before closing the element [" << text.substr (pos) << "]" << endl;
break;
}
//cout << "pos=" << pos << " attribute -> p=" << it._pos << " l=" << it._length << endl;
//cout << "pos=" << pos << " attr=[" << it (text) << "]" << endl;
{
cmt_string& s = subargs.add ();
s = it (text);
}
pos += it._length;
}
}
if (expand_level == 0) cout << endl;
}
void CmtModel::test_regexp (const cmt_string& pattern, const cmt_string& input_text)
{
cout << "Testing pattern [" << pattern << "] against [" << input_text << "]" << endl;
cmt_regexp exp (pattern);
cmt_regexp::iterator it;
for (int pos = 0; pos < 10; pos++)
{
it = exp.begin (input_text, pos);
if (it == exp.end ())
{
cout << "No match" << endl;
}
else
{
cout << "p=" << it._pos << " l=" << it._length << " -> [" << it (input_text) << "]" << endl;
}
}
}
/**
* Expands a model file
* Arguments are :
* model-name : name of a model file
* var=value : variable value to be expanded
* (will take the form ${var} )
*/
void CmtModel::expand (const CmtSystem::cmt_string_vector& arguments)
{
int i;
Variable::VariableVector variables;
/**
* We start by decoding all [variable=value] pairs from the arguments
* A vector of Variables is filled from them.
*/
for (i = 0; i < arguments.size (); i++)
{
const cmt_string& arg = arguments[i];
if (arg.find ("=") != cmt_string::npos)
{
cmt_string name;
cmt_string value;
int pos = arg.find ("=");
arg.substr (0, pos, name);
arg.substr (pos + 1, value);
Variable* v = Variable::find (variables, name);
if (v == 0)
{
v = &(variables.add ());
v->set (name);
}
(*v) = value;
}
}
/**
* Then model names are extracted.
* Each model may contain a set of <...> patterns.
* The expected syntax for each of them is :
*
*
* Therefore the current expand function is recursively restarted.
*
* Text around patterns is displayed after replacements of all
* variable values detected by ${variable-name} patterns
*/
cmt_string text;
for (i = 0; i < arguments.size (); i++)
{
const cmt_string& arg = arguments[i];
if (arg.find ("=") == cmt_string::npos)
{
FragmentHandle fragment (arg);
fragment.copy (text, variables, 0);
filter (text);
int openmarker;
int closemarker;
CmtSystem::cmt_string_vector subargs;
cmt_string remaining;
for (;;)
{
/**
* Look for the next <...> pattern
* If not found, then simply dump the text as it is.
*/
openmarker = text.find ("<");
if (openmarker == cmt_string::npos) break;
closemarker = text.find (openmarker, "/>");
if (closemarker == cmt_string::npos)
{
/**
* The opening < was in the text
*/
/**
* Get what is left from the original text beyond the pattern
*/
text.substr (openmarker + 1, remaining);
text.erase (openmarker + 1);
/**
* Now display it
*/
display (text);
}
else
{
/**
* Extract the command from the pattern
*/
cmt_string command;
text.substr (openmarker + 1, closemarker - openmarker - 1, command);
/**
* Get what is left from the original text beyond the pattern
*/
text.substr (closemarker + 2, remaining);
text.erase (openmarker);
/**
* Now display it
*/
display (text);
/**
* Convert the extracted command into words
*/
CmtSystem::split (command, " ", subargs);
/**
* Recursively expand it
*/
expand (subargs);
}
/**
* The next iteration will operate on the remaining text
*/
text = remaining;
}
/**
* Display what is left after extracting the last pattern
*/
display (text);
}
}
}