1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
11 #include <anna/core/functions.hpp>
12 #include <anna/core/mt/Guard.hpp>
13 #include <anna/core/tracing/Logger.hpp>
14 #include <anna/core/tracing/TraceMethod.hpp>
15 #include <anna/core/util/Tokenizer.hpp>
16 #include <anna/core/util/defines.hpp>
18 #include <anna/core/util/TextComposer.hpp>
19 #include <anna/core/util/TextVariable.hpp>
24 //---------------------------------------------------------------------------------------
25 // (1) Cada uno de los DynamicText se encarga de liberar la memoria de sus componentes.
26 //---------------------------------------------------------------------------------------
27 TextComposer::~TextComposer() {
28 for(variable_iterator ii = begin(), maxii = end(); ii != maxii; ii ++)
29 delete textVariable(ii);
36 * Este método se invoca desde el TextManager::create.
37 * Divide la expressión en partes más fáciles de analizar.
39 * La expresión puede tener la forma "texto inicial ${variable1:%s} siguiente texto ${variable2:%02d} el resto"
42 * a_prefix = "texto inicial "
43 * var1 => nombre = variable1 => "%s siguiente texto"
44 * var2 => nombre = variable2 => "%02d el resto"
46 void TextComposer::initialize()
48 Tokenizer variables(a_expression, "${");
50 Tokenizer nameAndFormat;
52 Variable::Type::_v type;
53 TextVariable* variable;
55 // Si el texto no tiene ninguna variable
56 if(variables.size() == 1) {
57 a_prefix = new String(a_expression);
64 for(Tokenizer::const_iterator ii = variables.begin(), maxii = variables.end(); ii != maxii; ii ++) {
65 if(anna_strchr(Tokenizer::data(ii), '}') == NULL) {
67 a_prefix = new String(Tokenizer::data(ii));
71 throw RuntimeException("Parenthesis are not balanced", ANNA_FILE_LOCATION);
74 // El id [0] contendrá el <name>:<format>
75 // El id [1] contendrá el texto (si es que hay).
76 idAndText.apply(Tokenizer::data(ii), "}");
77 nameAndFormat.apply(idAndText [0], ":");
79 if(find(nameAndFormat [0], Exception::Mode::Ignore) != NULL) {
80 String msg("Variable ");
81 msg << nameAndFormat [0] << " already defined";
82 throw RuntimeException(msg, ANNA_FILE_LOCATION);
85 type = calculeType(nameAndFormat [1]);
86 expression = nameAndFormat [1];
88 // Es posible que no haya texto que acompañe a identificador
89 if(idAndText.size() > 1)
90 expression += idAndText [1];
92 push_back(variable = new TextVariable(nameAndFormat [0], type, expression));
94 String msg("TextComposer::initialize | New Variable: ");
95 msg << variable->asString();
96 Logger::debug(msg, ANNA_FILE_LOCATION)
100 } catch(RuntimeException& ex) {
101 String msg(asString());
102 msg << " | " << ex.getText();
103 throw RuntimeException(msg, ex.getFromFile(), ex.getFromLine());
107 TextVariable* TextComposer::find(const char* name, const Exception::Mode::_v emode)
109 for(variable_iterator ii = begin(), maxii = end(); ii != maxii; ii ++) {
110 if(anna_strcmp(textVariable(ii)->getName(), name) == 0)
111 return textVariable(ii);
114 if(emode == Exception::Mode::Ignore)
117 String msg(asString());
118 msg << " | TextVariable: " << name << " | It was not found";
120 if(emode == Exception::Mode::Throw)
121 throw RuntimeException(msg, ANNA_FILE_LOCATION);
123 Logger::error(msg, ANNA_FILE_LOCATION);
127 String TextComposer::apply() const
129 LOGMETHOD(TraceMethod ttmm(Logger::Local7, "TextComposer::apply", ANNA_FILE_LOCATION));
131 // No hace falta proteger porque sólo se podrá acceder desde el Protector
132 // Guard <TextComposer> guard (this);
140 for(const_variable_iterator ii = begin(), maxii = end(); ii != maxii; ii ++)
141 result += textVariable(ii)->compose(a_buffer);
144 String msg("TextComposer { Id: ");
145 msg << a_id << " | Text: " << result << " }";
146 Logger::debug(msg, ANNA_FILE_LOCATION);
148 } catch(RuntimeException& ex) {
149 String msg(asString());
150 msg << " | " << ex.getText();
151 throw RuntimeException(msg, ANNA_FILE_LOCATION);
157 String TextComposer::asString() const
159 String result("TextComposer { Id: ");
161 result << " | Expression: " << a_expression;
162 return result << " }";
166 TextVariable::Type::_v TextComposer::calculeType(const char* format)
168 static const char* typeInteger = "[:digit:]*d";
169 static const char* typeString = "[:digit:]*s";
170 static const char* typeFloat = "([:digit:]*.[:digit:]|.[:digit:]*)f|f";
171 static const char* typeInteger64 = "[:digit:]*(ld|lld)";
174 throw RuntimeException("Format must begin with character %%", ANNA_FILE_LOCATION);
176 if(functions::isLike(typeInteger, format))
177 return Variable::Type::Integer;
179 if(functions::isLike(typeString, format))
180 return Variable::Type::String;
182 if(functions::isLike(typeFloat, format))
183 return Variable::Type::Float;
185 if(functions::isLike(typeInteger64, format))
186 return Variable::Type::Integer64;
188 String msg("Format '");
189 msg << format << "' is not recognized";
190 throw RuntimeException(msg, ANNA_FILE_LOCATION);