-
Botond Baranyi authored
Signed-off-by:
Botond Baranyi <botond.baranyi@ericsson.com> Change-Id: I54eb249100e7202b47290836ac84210b80cbcd17 Signed-off-by:
Botond Baranyi <botond.baranyi@ericsson.com>
Botond Baranyi authoredSigned-off-by:
Botond Baranyi <botond.baranyi@ericsson.com> Change-Id: I54eb249100e7202b47290836ac84210b80cbcd17 Signed-off-by:
Botond Baranyi <botond.baranyi@ericsson.com>
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
PatternString.cc 25.92 KiB
/******************************************************************************
* Copyright (c) 2000-2020 Ericsson Telecom AB
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html
*
* Contributors:
* Balasko, Jeno
* Baranyi, Botond
* Delic, Adam
* Forstner, Matyas
* Raduly, Csaba
* Szabo, Bence Janos
* Szabo, Janos Zoltan – initial implementation
* Zalanyi, Balazs Andor
*
******************************************************************************/
#include "PatternString.hh"
#include "../../common/pattern.hh"
#include "../CompilerError.hh"
#include "../Code.hh"
#include "../../common/JSON_Tokenizer.hh"
#include "../main.hh"
#include "TtcnTemplate.hh"
namespace Ttcn {
// =================================
// ===== PatternString::ps_elem_t
// =================================
struct PatternString::ps_elem_t {
enum kind_t {
PSE_STR,
PSE_REF,
PSE_REFDSET
} kind;
string *str;
Ttcn::Reference *ref;
Type * t; // The type of the reference in the case of PSE_REFDSET
boolean with_N; // If the reference was given as \N{ref} in the pattern
boolean is_charstring; // \N{charstring}
boolean is_universal_charstring; // \N{universal charstring}
ps_elem_t(kind_t p_kind, const string& p_str);
ps_elem_t(kind_t p_kind, Ttcn::Reference *p_ref, boolean N);
ps_elem_t(const ps_elem_t& p);
~ps_elem_t();
ps_elem_t* clone() const;
void set_fullname(const string& p_fullname);
void set_my_scope(Scope *p_scope);
void chk_ref(PatternString::pstr_type_t pstr_type, Type::expected_value_t expected_value);
void set_code_section(GovernedSimple::code_section_t p_code_section);
};
PatternString::ps_elem_t::ps_elem_t(kind_t p_kind, const string& p_str)
: kind(p_kind), ref(NULL), t(NULL), with_N(FALSE), is_charstring(FALSE),
is_universal_charstring(FALSE)
{
str = new string(p_str);
}
PatternString::ps_elem_t::ps_elem_t(kind_t p_kind, Ttcn::Reference *p_ref, boolean N)
: kind(p_kind), str(NULL), with_N(N), is_charstring(FALSE),
is_universal_charstring(FALSE)
{
if (!p_ref) FATAL_ERROR("PatternString::ps_elem_t::ps_elem_t()");
ref = p_ref;
}
PatternString::ps_elem_t::ps_elem_t(const PatternString::ps_elem_t& p)
: kind(p.kind), str(NULL), ref(NULL), t(NULL), with_N(FALSE),
is_charstring(FALSE), is_universal_charstring(FALSE)
{
switch(kind) {
case PSE_STR:
str = new string(*p.str);
break;
case PSE_REF:
ref = p.ref->clone();
break;
case PSE_REFDSET:
FATAL_ERROR("PatternString::ps_elem_t::ps_elem_t");
}
}
PatternString::ps_elem_t::~ps_elem_t()
{
switch(kind) {
case PSE_STR:
delete str;
// fall through
case PSE_REF:
case PSE_REFDSET:
delete ref;
// do not delete t
break;
} // switch kind
}
PatternString::ps_elem_t* PatternString::ps_elem_t::clone() const
{
return new ps_elem_t(*this);
}
void PatternString::ps_elem_t::set_fullname(const string& p_fullname)
{
switch(kind) {
case PSE_REF:
case PSE_REFDSET:
ref->set_fullname(p_fullname);
break;
default:
;
} // switch kind
}
void PatternString::ps_elem_t::set_my_scope(Scope *p_scope)
{
switch(kind) {
case PSE_REF:
case PSE_REFDSET:
ref->set_my_scope(p_scope);
break;
default:
;
} // switch kind
}
void PatternString::ps_elem_t::chk_ref(PatternString::pstr_type_t pstr_type, Type::expected_value_t expected_value)
{
if (kind != PSE_REF) FATAL_ERROR("PatternString::ps_elem_t::chk_ref()");
Value* v = 0;
Value* v_last = 0;
if (ref->get_id()->get_name() == "CHARSTRING") {
is_charstring = TRUE;
return;
} else if (ref->get_id()->get_name() == "UNIVERSAL_CHARSTRING") {
is_universal_charstring = TRUE;
return;
}
Common::Assignment* ass = ref->get_refd_assignment();
if (!ass)
return;
Ttcn::FieldOrArrayRefs* t_subrefs = ref->get_subrefs();
Type* ref_type = ass->get_Type()->get_type_refd_last()->get_field_type(
t_subrefs, expected_value);
Type::typetype_t tt;
switch (pstr_type) {
case PatternString::CSTR_PATTERN:
tt = Type::T_CSTR;
if (ref_type->get_typetype() != Type::T_CSTR)
TTCN_pattern_error("Type of the referenced %s '%s' should be "
"'charstring'", ass->get_assname(), ref->get_dispname().c_str());
break;
case PatternString::USTR_PATTERN:
tt = ref_type->get_typetype();
if (tt != Type::T_CSTR && tt != Type::T_USTR)
TTCN_pattern_error("Type of the referenced %s '%s' should be either "
"'charstring' or 'universal charstring'", ass->get_assname(),
ref->get_dispname().c_str());
break;
default:
FATAL_ERROR("Unknown pattern string type");
}
Type* refcheckertype = Type::get_pooltype(tt);
switch (ass->get_asstype()) {
case Common::Assignment::A_TYPE:
kind = PSE_REFDSET;
t = ass->get_Type();
break;
case Common::Assignment::A_MODULEPAR_TEMP:
case Common::Assignment::A_VAR_TEMPLATE:
case Common::Assignment::A_PAR_TEMPL_IN:
case Common::Assignment::A_PAR_TEMPL_OUT:
case Common::Assignment::A_PAR_TEMPL_INOUT:
// error reporting moved up
break;
case Common::Assignment::A_TEMPLATE: {
Template* templ = ass->get_Template();
refcheckertype->chk_this_template_ref(templ);
refcheckertype->chk_this_template_generic(templ, INCOMPLETE_ALLOWED,
OMIT_ALLOWED, ANY_OR_OMIT_ALLOWED, SUB_CHK, NOT_IMPLICIT_OMIT, 0);
switch (templ->get_templatetype()) {
case Template::SPECIFIC_VALUE:
v_last = templ->get_specific_value();
break;
case Template::TEMPLATE_CONCAT:
if (!use_runtime_2) {
FATAL_ERROR("PatternString::ps_elem_t::chk_ref()");
}
if (templ->is_Value()) {
v = templ->get_Value();
v->set_my_governor(refcheckertype);
v->set_my_scope(ref->get_my_scope());
v->set_location(*ref);
refcheckertype->chk_this_value(v, 0, expected_value,
INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK);
v_last = v->get_value_refd_last();
}
else {
TTCN_pattern_error("Unable to resolve referenced '%s' to character "
"string type. Result of template concatenation is not a specific "
"value.", ref->get_dispname().c_str());
}
break;
case Template::CSTR_PATTERN:
if (!with_N) {
Ttcn::PatternString* ps = templ->get_cstr_pattern();
if (!ps->has_refs())
v_last = ps->get_value();
break;
}
case Template::USTR_PATTERN:
if (!with_N) {
Ttcn::PatternString* ps = templ->get_ustr_pattern();
if (!ps->has_refs())
v_last = ps->get_value();
break;
}
default:
TTCN_pattern_error("Unable to resolve referenced '%s' to character "
"string type. '%s' template cannot be used.",
ref->get_dispname().c_str(), templ->get_templatetype_str());
break;
}
break; }
default: {
Reference *t_ref = ref->clone();
t_ref->set_location(*ref);
v = new Value(Value::V_REFD, t_ref);
v->set_my_governor(refcheckertype);
v->set_my_scope(ref->get_my_scope());
v->set_location(*ref);
refcheckertype->chk_this_value(v, 0, expected_value,
INCOMPLETE_NOT_ALLOWED, OMIT_NOT_ALLOWED, SUB_CHK);
v_last = v->get_value_refd_last();
}
}
if (v_last && (v_last->get_valuetype() == Value::V_CSTR ||
v_last->get_valuetype() == Value::V_USTR)) {
// the reference points to a constant
// substitute the reference with the known value
if (v_last->get_valuetype() == Value::V_CSTR) {
if (with_N && v_last->get_val_str().size() != 1) {
ref->error("The length of the charstring must be of length one, when it is being referenced in a pattern with \\N{ref}");
}
str = new string(v_last->get_val_str());
} else {
if (with_N && v_last->get_val_ustr().size() != 1) {
ref->error("The length of the universal charstring must be of length one, when it is being referenced in a pattern with \\N{ref}");
}
str = new string(v_last->get_val_ustr().get_stringRepr_for_pattern());
}
kind = PSE_STR;
}
delete v;
}
void PatternString::ps_elem_t::set_code_section
(GovernedSimple::code_section_t p_code_section)
{
switch(kind) {
case PSE_REF:
case PSE_REFDSET:
ref->set_code_section(p_code_section);
break;
default:
;
} // switch kind
}
// =================================
// ===== PatternString
// =================================
PatternString::PatternString(const PatternString& p)
: Node(p), my_scope(0), cstr_value(0), pattern_type(p.pattern_type),
nocase(p.nocase)
{
size_t nof_elems = p.elems.size();
for (size_t i = 0; i < nof_elems; i++) elems.add(p.elems[i]->clone());
}
PatternString::ps_elem_t *PatternString::get_last_elem() const
{
if (elems.empty()) return 0;
ps_elem_t *last_elem = elems[elems.size() - 1];
if (last_elem->kind == ps_elem_t::PSE_STR) return last_elem;
else return 0;
}
PatternString::~PatternString()
{
size_t nof_elems = elems.size();
for (size_t i = 0; i < nof_elems; i++) delete elems[i];
elems.clear();
delete cstr_value;
}
PatternString *PatternString::clone() const
{
return new PatternString(*this);
}
void PatternString::set_fullname(const string& p_fullname)
{
Node::set_fullname(p_fullname);
size_t nof_elems = elems.size();
for(size_t i = 0; i < nof_elems; i++) elems[i]->set_fullname(p_fullname);
}
void PatternString::set_my_scope(Scope *p_scope)
{
my_scope = p_scope;
size_t nof_elems = elems.size();
for (size_t i = 0; i < nof_elems; i++) elems[i]->set_my_scope(p_scope);
}
void PatternString::set_code_section
(GovernedSimple::code_section_t p_code_section)
{
size_t nof_elems = elems.size();
for (size_t i = 0; i < nof_elems; i++)
elems[i]->set_code_section(p_code_section);
}
void PatternString::addChar(char c)
{
ps_elem_t *last_elem = get_last_elem();
if (last_elem) *last_elem->str += c;
else elems.add(new ps_elem_t(ps_elem_t::PSE_STR, string(c)));
}
void PatternString::addString(const char *p_str)
{
ps_elem_t *last_elem = get_last_elem();
if (last_elem) *last_elem->str += p_str;
else elems.add(new ps_elem_t(ps_elem_t::PSE_STR, string(p_str)));
}
void PatternString::addString(const string& p_str)
{
ps_elem_t *last_elem = get_last_elem();
if (last_elem) *last_elem->str += p_str;
else elems.add(new ps_elem_t(ps_elem_t::PSE_STR, p_str));
}
void PatternString::addStringUSI(char **usi_str, const size_t size)
{
ustring s = ustring(const_cast<const char**>(usi_str), size);
ps_elem_t *last_elem = get_last_elem();
if (last_elem) *last_elem->str += s.get_stringRepr_for_pattern().c_str();
else elems.add(new ps_elem_t(ps_elem_t::PSE_STR, s.get_stringRepr_for_pattern()));
}
void PatternString::addRef(Ttcn::Reference *p_ref, boolean N)
{
elems.add(new ps_elem_t(ps_elem_t::PSE_REF, p_ref, N));
}
string PatternString::get_full_str() const
{
string s;
for(size_t i=0; i<elems.size(); i++) {
ps_elem_t *pse=elems[i];
switch(pse->kind) {
case ps_elem_t::PSE_STR:
s+=*pse->str;
break;
case ps_elem_t::PSE_REFDSET:
s+="\\N";
/* no break */
case ps_elem_t::PSE_REF:
s+='{';
s+=pse->ref->get_dispname();
s+='}';
} // switch kind
} // for
return s;
}
void PatternString::set_pattern_type(pstr_type_t p_type) {
pattern_type = p_type;
}
PatternString::pstr_type_t PatternString::get_pattern_type() const {
return pattern_type;
}
bool PatternString::has_refs() const
{
for (size_t i = 0; i < elems.size(); i++) {
switch (elems[i]->kind) {
case ps_elem_t::PSE_REF:
case ps_elem_t::PSE_REFDSET:
return true;
default:
break;
}
}
return false;
}
void PatternString::chk_refs(Type::expected_value_t expected_value)
{
for(size_t i=0; i<elems.size(); i++) {
ps_elem_t *pse=elems[i];
switch(pse->kind) {
case ps_elem_t::PSE_STR:
break;
case ps_elem_t::PSE_REFDSET:
/* actually, not supported */
break;
case ps_elem_t::PSE_REF:
pse->chk_ref(pattern_type, expected_value);
break;
} // switch kind
} // for
}
/** \todo implement */
void PatternString::chk_recursions(ReferenceChain&)
{
}
void PatternString::chk_pattern()
{
string str;
for (size_t i = 0; i < elems.size(); i++) {
ps_elem_t *pse = elems[i];
if (pse->kind != ps_elem_t::PSE_STR)
FATAL_ERROR("PatternString::chk_pattern()");
str += *pse->str;
}
char* posix_str = 0;
switch (pattern_type) {
case CSTR_PATTERN:
posix_str = TTCN_pattern_to_regexp(str.c_str());
break;
case USTR_PATTERN:
posix_str = TTCN_pattern_to_regexp_uni(str.c_str(), nocase);
}
Free(posix_str);
}
bool PatternString::chk_self_ref(Common::Assignment *lhs)
{
for (size_t i = 0, e = elems.size(); i < e; ++i) {
ps_elem_t *pse = elems[i];
switch (pse->kind) {
case ps_elem_t::PSE_STR:
break;
case ps_elem_t::PSE_REFDSET:
/* actually, not supported */
break;
case ps_elem_t::PSE_REF: {
Ttcn::Assignment *ass = pse->ref->get_refd_assignment();
if (ass == lhs) return true;
break; }
} // switch
}
return false;
}
void PatternString::join_strings()
{
// points to the previous string element otherwise it is NULL
ps_elem_t *prev_str = 0;
for (size_t i = 0; i < elems.size(); ) {
ps_elem_t *pse = elems[i];
if (pse->kind == ps_elem_t::PSE_STR) {
const string& str = *pse->str;
if (str.size() > 0) {
// the current element is a non-empty string
if (prev_str) {
// append str to prev_str and drop pse
*prev_str->str += str;
delete pse;
elems.replace(i, 1);
// don't increment i
} else {
// keep pse for the next iteration
prev_str = pse;
i++;
}
} else {
// the current element is an empty string
// simply drop it
delete pse;
elems.replace(i, 1);
// don't increment i
}
} else {
// pse is not a string
// forget prev_str
prev_str = 0;
i++;
}
}
}
string PatternString::create_charstring_literals(Common::Module *p_mod, string& preamble)
{
/* The cast is there for the benefit of OPTIONAL<CHARSTRING>, because
* it doesn't have operator+(). In most cases only the first member needs
* the cast (the others will be automagically converted to satisfy
* CHARSTRING::operator+(const CHARSTRING&) ) */
string s;
if (pattern_type == CSTR_PATTERN)
s = "CHARSTRING_template(STRING_PATTERN, (CHARSTRING)";
else
s = "UNIVERSAL_CHARSTRING_template(STRING_PATTERN, (CHARSTRING)";
size_t nof_elems = elems.size();
if (nof_elems > 0) {
// the pattern is not empty
for (size_t i = 0; i < nof_elems; i++) {
if (i > 0) s += " + ";
ps_elem_t *pse = elems[i];
// \N{charstring} and \N{universal charstring}
if (pse->is_charstring) {
s += p_mod->add_charstring_literal(string("?"));
continue;
} else if (pse->is_universal_charstring) {
s += p_mod->add_charstring_literal(string("?"));
continue;
}
switch (pse->kind) {
// Known in compile time: string literal, const etc.
case ps_elem_t::PSE_STR:
s += p_mod->add_charstring_literal(*pse->str);
break;
// Known in compile time: string type with(out) range or list
case ps_elem_t::PSE_REFDSET: {
if (!pse->t)
FATAL_ERROR("PatternString::create_charstring_literals()");
if (!pse->t->get_sub_type()) {
// just a string type without any restrictions (or alias)
s += "\"?\"";
continue;
}
vector<Common::SubTypeParse> * vec = pse->t->get_sub_type()->get_subtype_parsed();
while (vec == NULL) { // go through aliases to find where the restrictions are
if (pse->t->get_Reference()) {
pse->t = pse->t->get_Reference()->get_refd_assignment(FALSE)->get_Type();
} else {
break;
}
if (pse->t->get_sub_type()) {
vec = pse->t->get_sub_type()->get_subtype_parsed();
} else {
break;
}
}
if (vec == NULL) {
// I don't think it can happen, but to be sure...
s += "\"?\"";
continue;
}
s+= "\"";
if (vec->size() > 1) s+= "(";
for (size_t j = 0; j < vec->size(); j++) {
Common::SubTypeParse* stp = (*vec)[j];
if (j > 0) {
s+="|\"+"; // todo what if default
}else {
s+= "\"+";
}
switch (stp->get_selection()) {
case SubTypeParse::STP_RANGE: // type charstring ("a" .. "z")
s+="\"[\" + ";
switch (stp->Min()->get_valuetype()) {
case Value::V_CSTR:
s+= p_mod->add_charstring_literal(stp->Min()->get_val_str());
s+= "+ \"-\" +";
s+= p_mod->add_charstring_literal(stp->Max()->get_val_str());
break;
case Value::V_USTR:
s+= p_mod->add_charstring_literal(stp->Min()->get_val_ustr().get_stringRepr_for_pattern());
s+= "+ \"-\" +";
s+= p_mod->add_charstring_literal(stp->Max()->get_val_ustr().get_stringRepr_for_pattern());
break;
default:
FATAL_ERROR("PatternString::create_charstring_literals()");
}
s+=" + \"]\"";
break;
case SubTypeParse::STP_SINGLE: // type charstring ("a", "b")
switch (stp->Single()->get_valuetype()) {
case Value::V_CSTR:
s+= p_mod->add_charstring_literal(stp->Single()->get_val_str());
break;
case Value::V_USTR:
s+= p_mod->add_charstring_literal(stp->Single()->get_val_ustr().get_stringRepr_for_pattern());
break;
default:
FATAL_ERROR("PatternString::create_charstring_literals()");
break;
}
break;
default:
FATAL_ERROR("PatternString::create_charstring_literals()");
}
s+= "+\"";
}
if (vec->size() > 1) s+= ")";
s+= "\"";
break; }
// Not known in compile time
case ps_elem_t::PSE_REF: {
Common::Assignment* assign = pse->ref->get_refd_assignment();
if (use_runtime_2 && i > 0 &&
assign->get_Type()->field_is_optional(pse->ref->get_subrefs())) {
// in RT2 convert all operands of type OPTIONAL<CHARSTRING> to
// CHARSTRING, not just the first one
s += "(CHARSTRING)";
}
expression_struct expr;
Code::init_expr(&expr);
pse->ref->generate_code(&expr);
if (expr.preamble || expr.postamble)
FATAL_ERROR("PatternString::create_charstring_literals()");
s += expr.expr;
char* str = NULL;
// TODO: these checks will generated each time a reference is referenced in a pattern
// and it could be generated once
if (pse->with_N) {
if ((assign->get_asstype() == Common::Assignment::A_TEMPLATE
|| assign->get_asstype() == Common::Assignment::A_MODULEPAR_TEMP
|| assign->get_asstype() == Common::Assignment::A_VAR_TEMPLATE
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_IN
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_OUT
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_INOUT))
{
string value_literal = p_mod->add_charstring_literal(string("value"));
str = mputprintf(str,
"if (%s.get_istemplate_kind(%s) == FALSE) {\n"
"TTCN_error(\"Only specific value template allowed in pattern reference with \\\\N{ref}\");\n"
"}\n"
, expr.expr
, value_literal.c_str());
}
str = mputprintf(str,
"if (%s.lengthof() != 1)\n"
"{\n"
"TTCN_error(\"The length of the %scharstring must be of length one, when it is being referenced in a pattern with \\\\N{ref}\");\n"
"}\n"
, expr.expr
, assign->get_Type()->get_typetype() == Type::T_USTR ? "universal " : "");
preamble += str;
Free(str);
}
if ((assign->get_asstype() == Common::Assignment::A_TEMPLATE
|| assign->get_asstype() == Common::Assignment::A_MODULEPAR_TEMP
|| assign->get_asstype() == Common::Assignment::A_VAR_TEMPLATE
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_IN
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_OUT
|| assign->get_asstype() == Common::Assignment::A_PAR_TEMPL_INOUT))
{
if ((assign->get_Type()->get_typetype() == Type::T_CSTR
|| assign->get_Type()->get_typetype() == Type::T_USTR) && !pse->with_N) {
s += ".get_single_value()";
}
else if (assign->get_Type()->get_typetype() == Type::T_USTR && pse->with_N) {
s += ".valueof().get_stringRepr_for_pattern()";
} else {
s += ".valueof()";
}
} else if ((assign->get_asstype() == Common::Assignment::A_MODULEPAR
|| assign->get_asstype() == Common::Assignment::A_VAR
|| assign->get_asstype() == Common::Assignment::A_PAR_VAL
|| assign->get_asstype() == Common::Assignment::A_PAR_VAL_IN
|| assign->get_asstype() == Common::Assignment::A_PAR_VAL_OUT
|| assign->get_asstype() == Common::Assignment::A_PAR_VAL_INOUT)
&& assign->get_Type()->get_typetype() == Type::T_USTR) {
s += ".get_stringRepr_for_pattern()";
}
Code::free_expr(&expr);
break; }
} // switch kind
} // for
} else {
// empty pattern: create an empty string literal for it
s += p_mod->add_charstring_literal(string());
}
s += ", ";
s += nocase ? "TRUE" : "FALSE";
s += ')';
return s;
}
void PatternString::dump(unsigned level) const
{
if (nocase) {
DEBUG(level, "@nocase");
}
DEBUG(level, "%s", get_full_str().c_str());
}
Common::Value* PatternString::get_value() {
if (!cstr_value && !has_refs())
cstr_value = new Common::Value(Common::Value::V_CSTR,
new string(get_full_str()));
return cstr_value;
}
char* PatternString::convert_to_json()
{
string pstr = get_value()->get_val_str();
// convert the pattern into an extended regular expression
char* regex_str = NULL;
if (CSTR_PATTERN == pattern_type) {
regex_str = TTCN_pattern_to_regexp(pstr.c_str());
}
else { // USTR_PATTERN
// handle the unicode characters in \q{g,p,r,c} format
string utf8str;
for (size_t i = 0; i < pstr.size(); ++i) {
if ('\\' == pstr[i]) {
if ('q' == pstr[i + 1]) {
// extract the unicode character
unsigned int group, plane, row, cell;
i = pstr.find('{', i + 1);
sscanf(pstr.c_str() + i + 1, "%u", &group);
i = pstr.find(',', i + 1);
sscanf(pstr.c_str() + i + 1, "%u", &plane);
i = pstr.find(',', i + 1);
sscanf(pstr.c_str() + i + 1, "%u", &row);
i = pstr.find(',', i + 1);
sscanf(pstr.c_str() + i + 1, "%u", &cell);
i = pstr.find('}', i + 1);
// convert the character to UTF-8 format
utf8str += ustring_to_uft8(ustring((unsigned char)group, (unsigned char)plane, (unsigned char)row, (unsigned char)cell));
continue;
}
else if ('\\' == pstr[i + 1]) {
// must be handled separately, so we don't confuse \\q with \q
++i;
utf8str += '\\';
}
}
utf8str += pstr[i];
}
// use the pattern converter for charstrings, the pattern should be in UTF-8
// format now (setting the 2nd parameter will make sure that no error
// messages are displayed for extended ASCII characters)
regex_str = TTCN_pattern_to_regexp(utf8str.c_str(), true);
}
char* json_str = convert_to_json_string(regex_str);
Free(regex_str);
return json_str;
}
} // namespace Ttcn
// =================================
// ===== TTCN_pattern_XXXX
// =================================
/* These functions are used by common charstring pattern parser. */
void TTCN_pattern_error(const char *fmt, ...)
{
char *msg=mcopystr("Charstring pattern: ");
msg=mputstr(msg, fmt);
va_list args;
va_start(args, fmt);
Common::Error_Context::report_error(0, msg, args);
va_end(args);
Free(msg);
}
void TTCN_pattern_warning(const char *fmt, ...)
{
char *msg=mcopystr("Charstring pattern: ");
msg=mputstr(msg, fmt);
va_list args;
va_start(args, fmt);
Common::Error_Context::report_warning(0, msg, args);
va_end(args);
Free(msg);
}