Patch level : 2.1 nopatch
Files correlati : ba8.exe Ricompilazione Demo : [ ] Commento : Ultime correzioni per nuovi report git-svn-id: svn://10.65.10.50/trunk@12003 c028cbd2-c16b-5b4b-a496-9718f37d4682
This commit is contained in:
parent
e34627d5d6
commit
dbc8341d80
@ -579,6 +579,17 @@ bool TRecordset::save_as(const char* path, TRecordsetExportFormat fmt)
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int TRecordset::find_column(const char* column_name) const
|
||||||
|
{
|
||||||
|
for (int i = columns()-1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
const TRecordset_column_info& info = column_info(i);
|
||||||
|
if (info._name == column_name)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
const TVariant& TRecordset::get(const char* column_name) const
|
const TVariant& TRecordset::get(const char* column_name) const
|
||||||
{
|
{
|
||||||
if (*column_name == '#')
|
if (*column_name == '#')
|
||||||
@ -592,12 +603,34 @@ const TVariant& TRecordset::get(const char* column_name) const
|
|||||||
column_name++;
|
column_name++;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i = 0; i < columns(); i++)
|
char* dot = strchr(column_name, ':');
|
||||||
|
if (dot != NULL)
|
||||||
{
|
{
|
||||||
const TRecordset_column_info& info = column_info(i);
|
*dot = '\0';
|
||||||
if (info._name == column_name)
|
const int i = find_column(column_name);
|
||||||
|
*dot = ':';
|
||||||
|
if (i >= 0)
|
||||||
|
{
|
||||||
|
const TString& str = get(i).as_string();
|
||||||
|
TString subfield; subfield << (dot+1) << '=';
|
||||||
|
int s = str.find(subfield);
|
||||||
|
if (s == 0 || (s > 0 && str[s-1] < ' '))
|
||||||
|
{
|
||||||
|
static TVariant var;
|
||||||
|
s += subfield.len();
|
||||||
|
const int e = str.find('\n', s);
|
||||||
|
var.set(str.sub(s, e));
|
||||||
|
return var;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const int i = find_column(column_name);
|
||||||
|
if (i >= 0)
|
||||||
return get(i);
|
return get(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL_VARIANT;
|
return NULL_VARIANT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1153,7 +1186,7 @@ void TSQL_recordset::parsed_sql_text(TString& sql) const
|
|||||||
const TString& after = sql.mid(pos+name->len());
|
const TString& after = sql.mid(pos+name->len());
|
||||||
sql.cut(pos);
|
sql.cut(pos);
|
||||||
TString s = var.as_string();
|
TString s = var.as_string();
|
||||||
if ((var.type() == _alfafld && s[0] != '\'') || var.is_null())
|
if ((var.is_string() && s[0] != '\'') || var.is_null())
|
||||||
{
|
{
|
||||||
s.insert("'");
|
s.insert("'");
|
||||||
s << '\'';
|
s << '\'';
|
||||||
|
@ -34,8 +34,8 @@ protected:
|
|||||||
void copy(const TVariant& var);
|
void copy(const TVariant& var);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TFieldtypes type() const { return _type; }
|
TFieldtypes type() const { return _type; } // Internal use only
|
||||||
|
bool is_string() const { return _type == _alfafld; }
|
||||||
bool is_null() const { return _type == _nullfld; }
|
bool is_null() const { return _type == _nullfld; }
|
||||||
bool is_zero() const;
|
bool is_zero() const;
|
||||||
void set_null();
|
void set_null();
|
||||||
@ -116,6 +116,7 @@ public: // Absolutely needed methods
|
|||||||
virtual bool ask_variables(bool all);
|
virtual bool ask_variables(bool all);
|
||||||
|
|
||||||
virtual const TString& query_text() const;
|
virtual const TString& query_text() const;
|
||||||
|
virtual int find_column(const char* column_name) const;
|
||||||
virtual const TVariant& get(const char* column_name) const;
|
virtual const TVariant& get(const char* column_name) const;
|
||||||
virtual const TToken_string& sheet_head() const;
|
virtual const TToken_string& sheet_head() const;
|
||||||
|
|
||||||
|
@ -210,7 +210,7 @@ void TReport_field_mask::vedo_non_vedo()
|
|||||||
const char type = get(F_TYPE)[0];
|
const char type = get(F_TYPE)[0];
|
||||||
const bool is_currency = type == 'P' || type == 'V';
|
const bool is_currency = type == 'P' || type == 'V';
|
||||||
const bool is_numeric = is_currency || type == 'N';
|
const bool is_numeric = is_currency || type == 'N';
|
||||||
const bool is_text = is_numeric || strchr("DST", type) != NULL;
|
const bool is_text = is_numeric || strchr("ADST", type) != NULL;
|
||||||
|
|
||||||
show(F_HIDE_ZEROES, is_numeric || type == 'D'),
|
show(F_HIDE_ZEROES, is_numeric || type == 'D'),
|
||||||
show(F_HALIGN, is_text);
|
show(F_HALIGN, is_text);
|
||||||
@ -230,6 +230,9 @@ void TReport_field_mask::vedo_non_vedo()
|
|||||||
show(F_SOURCE, (is_text || type == 'I') && type != 'T');
|
show(F_SOURCE, (is_text || type == 'I') && type != 'T');
|
||||||
show(F_CODVAL, is_currency); // Codice valuta di riferimento
|
show(F_CODVAL, is_currency); // Codice valuta di riferimento
|
||||||
show(F_LINK, strchr("DNS", type) != NULL); // Chi puo' essere un link?
|
show(F_LINK, strchr("DNS", type) != NULL); // Chi puo' essere un link?
|
||||||
|
show(F_PRESCRIPT, is_text);
|
||||||
|
show(F_POSTSCRIPT, is_text);
|
||||||
|
enable_page(3, type == 'A');
|
||||||
|
|
||||||
if (is_running())
|
if (is_running())
|
||||||
force_update();
|
force_update();
|
||||||
@ -267,6 +270,20 @@ bool TReport_field_mask::on_field_event(TOperable_field& o, TField_event e, long
|
|||||||
force_update();
|
force_update();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case F_LIST:
|
||||||
|
if (e == fe_close)
|
||||||
|
{
|
||||||
|
TSheet_field& sheet = sfield(F_LIST);
|
||||||
|
TAssoc_array ass;
|
||||||
|
FOR_EACH_SHEET_ROW(sheet, i, row)
|
||||||
|
{
|
||||||
|
if (ass.add(row->get(0)))
|
||||||
|
return error_box(TR("E' necessario specificare codici diversi"));
|
||||||
|
}
|
||||||
|
if (ass.items() < 2)
|
||||||
|
return error_box(TR("Specificare almeno due codici"));
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -304,6 +321,12 @@ void TReport_field_mask::set_field(const TReport_field& rf)
|
|||||||
|
|
||||||
set(F_PRESCRIPT, rf.prescript());
|
set(F_PRESCRIPT, rf.prescript());
|
||||||
set(F_POSTSCRIPT, rf.postscript());
|
set(F_POSTSCRIPT, rf.postscript());
|
||||||
|
|
||||||
|
if (rf.type() == 'A')
|
||||||
|
{
|
||||||
|
TSheet_field& list = sfield(F_LIST);
|
||||||
|
rf.get_list(list.rows_array());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TReport_field_mask::get_field(TReport_field& rf) const
|
void TReport_field_mask::get_field(TReport_field& rf) const
|
||||||
@ -331,6 +354,11 @@ void TReport_field_mask::get_field(TReport_field& rf) const
|
|||||||
|
|
||||||
rf.set_prescript(get(F_PRESCRIPT));
|
rf.set_prescript(get(F_PRESCRIPT));
|
||||||
rf.set_postscript(get(F_POSTSCRIPT));
|
rf.set_postscript(get(F_POSTSCRIPT));
|
||||||
|
if (rf.type() == 'A')
|
||||||
|
{
|
||||||
|
TSheet_field& list = sfield(F_LIST);
|
||||||
|
rf.set_list(list.rows_array());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#define F_GROUPS 139
|
#define F_GROUPS 139
|
||||||
#define F_CODVAL 140
|
#define F_CODVAL 140
|
||||||
#define F_LINK 141
|
#define F_LINK 141
|
||||||
|
#define F_LIST 142
|
||||||
|
|
||||||
#define F_LEVEL 160
|
#define F_LEVEL 160
|
||||||
#define F_GROUP_BY 161
|
#define F_GROUP_BY 161
|
||||||
|
@ -11,6 +11,7 @@ BEGIN
|
|||||||
ITEM "V|Valuta"
|
ITEM "V|Valuta"
|
||||||
ITEM "P|Prezzo"
|
ITEM "P|Prezzo"
|
||||||
ITEM "D|Data"
|
ITEM "D|Data"
|
||||||
|
ITEM "A|Array"
|
||||||
ITEM "I|Immagine"
|
ITEM "I|Immagine"
|
||||||
ITEM "L|Linea"
|
ITEM "L|Linea"
|
||||||
ITEM "R|Rettangolo"
|
ITEM "R|Rettangolo"
|
||||||
@ -181,7 +182,59 @@ BEGIN
|
|||||||
PROMPT -33 -1 ""
|
PROMPT -33 -1 ""
|
||||||
END
|
END
|
||||||
|
|
||||||
ENDMASK
|
ENDPAGE
|
||||||
|
|
||||||
|
PAGE "Lista" -1 -1 72 16
|
||||||
|
|
||||||
|
SPREADSHEET F_LIST -1 -3
|
||||||
|
BEGIN
|
||||||
|
PROMPT 1 1 ""
|
||||||
|
ITEM "Codice"
|
||||||
|
ITEM "Decodifica@50"
|
||||||
|
FLAGS "H"
|
||||||
|
END
|
||||||
|
|
||||||
|
BUTTON DLG_CANCEL 10 2
|
||||||
|
BEGIN
|
||||||
|
PROMPT -13 -1 ""
|
||||||
|
END
|
||||||
|
|
||||||
|
BUTTON DLG_OK 10 2
|
||||||
|
BEGIN
|
||||||
|
PROMPT -33 -1 ""
|
||||||
|
END
|
||||||
|
|
||||||
|
ENDPAGE
|
||||||
|
|
||||||
ENDMASK
|
ENDMASK
|
||||||
|
|
||||||
|
PAGE "List" -1 -1 72 11
|
||||||
|
|
||||||
|
STRING 101 3
|
||||||
|
BEGIN
|
||||||
|
PROMPT 1 0 "Codice "
|
||||||
|
END
|
||||||
|
|
||||||
|
STRING 102 50
|
||||||
|
BEGIN
|
||||||
|
PROMPT 13 0 "Decodifica "
|
||||||
|
END
|
||||||
|
|
||||||
|
BUTTON DLG_CANCEL 10 2
|
||||||
|
BEGIN
|
||||||
|
PROMPT -13 -1 ""
|
||||||
|
END
|
||||||
|
|
||||||
|
BUTTON DLG_DELREC 10 2
|
||||||
|
BEGIN
|
||||||
|
PROMPT -23 -1 ""
|
||||||
|
END
|
||||||
|
|
||||||
|
BUTTON DLG_OK 10 2
|
||||||
|
BEGIN
|
||||||
|
PROMPT -33 -1 ""
|
||||||
|
END
|
||||||
|
|
||||||
|
ENDPAGE
|
||||||
|
|
||||||
|
ENDMASK
|
||||||
|
235
ba/ba8302.cpp
235
ba/ba8302.cpp
@ -422,6 +422,26 @@ void TReport_section::set_font(const TReport_font& f)
|
|||||||
_font = new TReport_font(f);
|
_font = new TReport_font(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TString& TReport_section::prescript() const
|
||||||
|
{ return _prescript.get(); }
|
||||||
|
|
||||||
|
void TReport_section::set_prescript(const char* src)
|
||||||
|
{
|
||||||
|
TString desc; desc << type() << level() << " PRESCRIPT";
|
||||||
|
_prescript.set_description(desc);
|
||||||
|
_prescript.set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TString& TReport_section::postscript() const
|
||||||
|
{ return _postscript.get(); }
|
||||||
|
|
||||||
|
void TReport_section::set_postscript(const char* src)
|
||||||
|
{
|
||||||
|
TString desc; desc << type() << level() << " POSTSCRIPT";
|
||||||
|
_postscript.set_description(desc);
|
||||||
|
_postscript.set(src);
|
||||||
|
}
|
||||||
|
|
||||||
void TReport_section::unmap_font()
|
void TReport_section::unmap_font()
|
||||||
{
|
{
|
||||||
if (_font != NULL)
|
if (_font != NULL)
|
||||||
@ -681,6 +701,7 @@ TString& TReport_script::translate_message() const
|
|||||||
fld = arg;
|
fld = arg;
|
||||||
if (fld[0] != '#')
|
if (fld[0] != '#')
|
||||||
fld.insert("#", 0);
|
fld.insert("#", 0);
|
||||||
|
fld.insert("REPORT.", 1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -691,11 +712,11 @@ TString& TReport_script::translate_message() const
|
|||||||
|
|
||||||
if (cmd.starts_with("CO")) // COPY
|
if (cmd.starts_with("CO")) // COPY
|
||||||
{
|
{
|
||||||
alex << "#THIS @ " << fld << " ! ";
|
alex << "#REPORT.THIS @ " << fld << " ! ";
|
||||||
} else
|
} else
|
||||||
if (cmd.starts_with("AD")) // ADD
|
if (cmd.starts_with("AD")) // ADD
|
||||||
{
|
{
|
||||||
alex << "#THIS @ " << fld << " @ + "<< fld << " ! ";
|
alex << "#REPORT.THIS @ " << fld << " @ + "<< fld << " ! ";
|
||||||
} else
|
} else
|
||||||
if (cmd.starts_with("IN")) // INC
|
if (cmd.starts_with("IN")) // INC
|
||||||
{
|
{
|
||||||
@ -738,6 +759,10 @@ void TReport_script::set(const char* source)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TReport_script::copy(const TReport_script& rs)
|
||||||
|
{
|
||||||
|
set(rs.get());
|
||||||
|
}
|
||||||
|
|
||||||
bool TReport_script::execute(TReport& rep, TString& output)
|
bool TReport_script::execute(TReport& rep, TString& output)
|
||||||
{
|
{
|
||||||
@ -751,6 +776,7 @@ bool TReport_script::execute(TReport& rep, TString& output)
|
|||||||
good = rep.compile(translate_message(), *_bc);
|
good = rep.compile(translate_message(), *_bc);
|
||||||
else
|
else
|
||||||
good = rep.compile(_src, *_bc);
|
good = rep.compile(_src, *_bc);
|
||||||
|
_bc->set_name(_desc);
|
||||||
}
|
}
|
||||||
if (good)
|
if (good)
|
||||||
good = rep.execute(*_bc, output);
|
good = rep.execute(*_bc, output);
|
||||||
@ -786,6 +812,7 @@ void TReport_script::save(TXmlItem& root, const char* tag) const
|
|||||||
if (ok())
|
if (ok())
|
||||||
{
|
{
|
||||||
TXmlItem& script = root.AddChild(tag);
|
TXmlItem& script = root.AddChild(tag);
|
||||||
|
script.SetAttr("description", _desc);
|
||||||
script << _src;
|
script << _src;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -795,7 +822,10 @@ bool TReport_script::load(const TXmlItem& root, const char* tag)
|
|||||||
destroy();
|
destroy();
|
||||||
TXmlItem* script = root.FindFirstChild(tag);
|
TXmlItem* script = root.FindFirstChild(tag);
|
||||||
if (script != NULL)
|
if (script != NULL)
|
||||||
|
{
|
||||||
|
_desc = script->GetAttr("description");
|
||||||
script->GetEnclosedText(_src);
|
script->GetEnclosedText(_src);
|
||||||
|
}
|
||||||
return ok();
|
return ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -849,6 +879,26 @@ void TReport_field::unmap_font()
|
|||||||
_font->unmap();
|
_font->unmap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TString& TReport_field::prescript() const
|
||||||
|
{ return _prescript.get(); }
|
||||||
|
|
||||||
|
void TReport_field::set_prescript(const char* src)
|
||||||
|
{
|
||||||
|
TString desc; desc << section().type() << section().level() << '.' << id() << " PRESCRIPT";
|
||||||
|
_prescript.set_description(desc);
|
||||||
|
_prescript.set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TString& TReport_field::postscript() const
|
||||||
|
{ return _postscript.get(); }
|
||||||
|
|
||||||
|
void TReport_field::set_postscript(const char* src)
|
||||||
|
{
|
||||||
|
TString desc; desc << section().type() << section().level() << '.' << id() << " POSTSCRIPT";
|
||||||
|
_postscript.set_description(desc);
|
||||||
|
_postscript.set(src);
|
||||||
|
}
|
||||||
|
|
||||||
void TReport_field::copy(const TReport_field& rf)
|
void TReport_field::copy(const TReport_field& rf)
|
||||||
{
|
{
|
||||||
_section = rf._section;
|
_section = rf._section;
|
||||||
@ -863,6 +913,10 @@ void TReport_field::copy(const TReport_field& rf)
|
|||||||
_deactivated = rf.deactivated();
|
_deactivated = rf.deactivated();
|
||||||
_hide_zeroes = rf._hide_zeroes;
|
_hide_zeroes = rf._hide_zeroes;
|
||||||
_selected = false;
|
_selected = false;
|
||||||
|
_prescript = rf._prescript;
|
||||||
|
_postscript = rf._postscript;
|
||||||
|
_list = rf._list;
|
||||||
|
|
||||||
set_font(rf.font());
|
set_font(rf.font());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,6 +925,7 @@ const char* TReport_field::type_name() const
|
|||||||
const char* n = NULL;
|
const char* n = NULL;
|
||||||
switch (_type)
|
switch (_type)
|
||||||
{
|
{
|
||||||
|
case 'A': n = "Array"; break;
|
||||||
case 'D': n = "Data"; break;
|
case 'D': n = "Data"; break;
|
||||||
case 'E': n = "Ellisse"; break;
|
case 'E': n = "Ellisse"; break;
|
||||||
case 'I': n = "Immagine"; break;
|
case 'I': n = "Immagine"; break;
|
||||||
@ -896,6 +951,7 @@ TFieldtypes TReport_field::var_type() const
|
|||||||
case 'V': // Valuta
|
case 'V': // Valuta
|
||||||
case 'N': ft = _realfld; break;
|
case 'N': ft = _realfld; break;
|
||||||
case 'I':
|
case 'I':
|
||||||
|
case 'A':
|
||||||
case 'S': ft = _alfafld; break;
|
case 'S': ft = _alfafld; break;
|
||||||
default : ft = _nullfld; break;
|
default : ft = _nullfld; break;
|
||||||
}
|
}
|
||||||
@ -1043,6 +1099,23 @@ const TString& TReport_field::formatted_text() const
|
|||||||
|
|
||||||
switch (_type)
|
switch (_type)
|
||||||
{
|
{
|
||||||
|
case 'A':
|
||||||
|
{
|
||||||
|
const TString& val = _var.as_string();
|
||||||
|
TString_array list; get_list(list);
|
||||||
|
int i;
|
||||||
|
for (i = list.last(); i > 0; i--)
|
||||||
|
if (val == list.row(i).get(0))
|
||||||
|
break;
|
||||||
|
if (i >= 0)
|
||||||
|
{
|
||||||
|
TString& fmt = get_tmp_string();
|
||||||
|
TToken_string& tok = list.row(i);
|
||||||
|
tok.get(1, fmt);
|
||||||
|
return fmt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
{
|
{
|
||||||
const TDate d = _var.as_date();
|
const TDate d = _var.as_date();
|
||||||
@ -1270,12 +1343,26 @@ void TReport_field::save(TXmlItem& root) const
|
|||||||
fld.AddChild("source") << field();
|
fld.AddChild("source") << field();
|
||||||
_prescript.save(fld, "prescript");
|
_prescript.save(fld, "prescript");
|
||||||
_postscript.save(fld, "postscript");
|
_postscript.save(fld, "postscript");
|
||||||
|
|
||||||
|
if (_type == 'A')
|
||||||
|
{
|
||||||
|
TString_array arr; get_list(arr);
|
||||||
|
TXmlItem& list = fld.AddChild("list");
|
||||||
|
FOR_EACH_ARRAY_ROW(arr, i, row)
|
||||||
|
{
|
||||||
|
TXmlItem& li = list.AddChild("li");
|
||||||
|
li.SetAttr("Code", row->get(0));
|
||||||
|
li << row->get();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool TReport_field::load(const TXmlItem& fld)
|
bool TReport_field::load(const TXmlItem& fld)
|
||||||
{
|
{
|
||||||
set_type(get_chr_attr(fld, "type", 'T'));
|
const TString& t = fld.GetAttr("type");
|
||||||
|
set_type(t[0]);
|
||||||
|
|
||||||
set_id(fld.GetIntAttr("id"));
|
set_id(fld.GetIntAttr("id"));
|
||||||
set_column(get_num_attr(fld, "x"));
|
set_column(get_num_attr(fld, "x"));
|
||||||
set_row(get_num_attr(fld, "y"));
|
set_row(get_num_attr(fld, "y"));
|
||||||
@ -1309,9 +1396,39 @@ bool TReport_field::load(const TXmlItem& fld)
|
|||||||
_prescript.load(fld, "prescript");
|
_prescript.load(fld, "prescript");
|
||||||
_postscript.load(fld, "postscript");
|
_postscript.load(fld, "postscript");
|
||||||
|
|
||||||
|
_list.cut(0);
|
||||||
|
if (_type == 'A')
|
||||||
|
{
|
||||||
|
TXmlItem* list = fld.FindFirstChild("list");
|
||||||
|
TToken_string tok;
|
||||||
|
TString str;
|
||||||
|
for (int i = 0; i < list->GetChildren(); i++)
|
||||||
|
{
|
||||||
|
const TXmlItem* li = list->GetChild(i);
|
||||||
|
tok = li->GetAttr("Code");
|
||||||
|
tok.add(li->GetEnclosedText(str));
|
||||||
|
_list.add(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TReport_field::get_list(TString_array& list) const
|
||||||
|
{
|
||||||
|
list.destroy();
|
||||||
|
TToken_string& toklst = (TToken_string&)_list;
|
||||||
|
FOR_EACH_TOKEN(toklst, tok)
|
||||||
|
list.add(tok);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TReport_field::set_list(const TString_array& list)
|
||||||
|
{
|
||||||
|
_list.cut(0);
|
||||||
|
FOR_EACH_ARRAY_ROW(list, i, row)
|
||||||
|
_list.add(*row);
|
||||||
|
}
|
||||||
|
|
||||||
int TReport_field::compare(const TSortable& s) const
|
int TReport_field::compare(const TSortable& s) const
|
||||||
{
|
{
|
||||||
const TReport_field& rf = (TReport_field&)s;
|
const TReport_field& rf = (TReport_field&)s;
|
||||||
@ -1330,7 +1447,7 @@ TReport_field::TReport_field(TReport_section* sec)
|
|||||||
: _section(sec), _id(0), _type('T'),
|
: _section(sec), _id(0), _type('T'),
|
||||||
_font(NULL), _halign('L'), _valign('T'),
|
_font(NULL), _halign('L'), _valign('T'),
|
||||||
_selected(false), _hidden(false), _deactivated(false), _hide_zeroes(false),
|
_selected(false), _hidden(false), _deactivated(false), _hide_zeroes(false),
|
||||||
_border(0), _fgcolor(COLOR_BLACK), _bgcolor(COLOR_WHITE)
|
_border(0), _fgcolor(COLOR_BLACK), _bgcolor(COLOR_WHITE), _list(32, '\n')
|
||||||
{
|
{
|
||||||
set_pos(0,0);
|
set_pos(0,0);
|
||||||
set_size(1600,100);
|
set_size(1600,100);
|
||||||
@ -1491,7 +1608,7 @@ int TReport::parse_field(const char* code, char& type, int& level, int& id) cons
|
|||||||
if (code[0] == '#')
|
if (code[0] == '#')
|
||||||
code++;
|
code++;
|
||||||
|
|
||||||
if (isdigit(code[0]) || strcmp(code, "THIS") == 0) // Niente sezione davanti
|
if (isdigit(code[0]) || strncmp(code, "THIS", 4) == 0) // Niente sezione davanti
|
||||||
{
|
{
|
||||||
TReport_field* rf = curr_field();
|
TReport_field* rf = curr_field();
|
||||||
if (rf != NULL)
|
if (rf != NULL)
|
||||||
@ -1548,11 +1665,10 @@ bool TReport::evaluate(const char* expr, TVariant& var, TFieldtypes force_type)
|
|||||||
// Caso semplice nonche' standard
|
// Caso semplice nonche' standard
|
||||||
if (e.numvar() == 1)
|
if (e.numvar() == 1)
|
||||||
{
|
{
|
||||||
const char* name = e.varname(0);
|
const TFixed_string name(e.varname(0));
|
||||||
if (strcmp(name, expr) == 0)
|
if (name == expr)
|
||||||
{
|
{
|
||||||
const TFixed_string usr(name);
|
if (get_usr_val(name, var))
|
||||||
if (get_usr_val(usr, var))
|
|
||||||
{
|
{
|
||||||
if (force_type != _nullfld)
|
if (force_type != _nullfld)
|
||||||
var.convert_to(force_type);
|
var.convert_to(force_type);
|
||||||
@ -1563,21 +1679,11 @@ bool TReport::evaluate(const char* expr, TVariant& var, TFieldtypes force_type)
|
|||||||
|
|
||||||
for (int i = 0; i < e.numvar(); i++)
|
for (int i = 0; i < e.numvar(); i++)
|
||||||
{
|
{
|
||||||
const char* name = e.varname(i);
|
const TFixed_string name(e.varname(i));
|
||||||
bool ok = false;
|
const bool ok = get_usr_val(name, var);
|
||||||
if (name[0] == '#')
|
|
||||||
{
|
|
||||||
const TFixed_string usr(name+1);
|
|
||||||
ok = get_usr_val(usr, var);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
const TFixed_string usr(name);
|
|
||||||
ok = get_usr_val(usr, var);
|
|
||||||
}
|
|
||||||
if (!ok)
|
if (!ok)
|
||||||
var = name;
|
var = name;
|
||||||
if (var.type() == _alfafld)
|
if (var.is_string())
|
||||||
e.setvar(i, var.as_string());
|
e.setvar(i, var.as_string());
|
||||||
else
|
else
|
||||||
e.setvar(i, var.as_real());
|
e.setvar(i, var.as_real());
|
||||||
@ -1694,6 +1800,22 @@ void TReport::unmap_font()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const TString& TReport::prescript() const
|
||||||
|
{ return _prescript.get(); }
|
||||||
|
|
||||||
|
void TReport::set_prescript(const char* src)
|
||||||
|
{
|
||||||
|
_prescript.set(src);
|
||||||
|
}
|
||||||
|
|
||||||
|
const TString& TReport::postscript() const
|
||||||
|
{ return _postscript.get(); }
|
||||||
|
|
||||||
|
void TReport::set_postscript(const char* src)
|
||||||
|
{
|
||||||
|
_postscript.set(src);
|
||||||
|
}
|
||||||
|
|
||||||
bool TReport::execute_prescript()
|
bool TReport::execute_prescript()
|
||||||
{
|
{
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
@ -1732,39 +1854,91 @@ bool TReport::execute_postscript()
|
|||||||
return _postscript.execute(*this, str);
|
return _postscript.execute(*this, str);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TReport::get_usr_val(const TString& name, TVariant& var) const
|
bool TReport::get_report_field(const TString& name, TVariant& var) const
|
||||||
{
|
{
|
||||||
if (name == "#PAGE")
|
bool found = false;
|
||||||
|
const char* str = name;
|
||||||
|
if (name[0] == '#')
|
||||||
|
{
|
||||||
|
if (name.starts_with("#REPORT."))
|
||||||
|
{
|
||||||
|
str += 8;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
const TFixed_string n(str);
|
||||||
|
|
||||||
|
if (n == "PAGE")
|
||||||
{
|
{
|
||||||
var = curr_page();
|
var = curr_page();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
TReport_field* fld = ((TReport*)this)->field(n);
|
||||||
TReport_field* fld = ((TReport*)this)->field(name);
|
|
||||||
if (fld != NULL)
|
if (fld != NULL)
|
||||||
{
|
{
|
||||||
var = fld->get();
|
var = fld->get();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TReport::get_record_field(const TString& name, TVariant& var) const
|
||||||
|
{
|
||||||
|
bool found = false;
|
||||||
if (_recordset != NULL)
|
if (_recordset != NULL)
|
||||||
{
|
{
|
||||||
var = _recordset->get(name);
|
const char* str = name;
|
||||||
|
if (name[0] == '#')
|
||||||
|
{
|
||||||
|
if (name.starts_with("#RECORD."))
|
||||||
|
{
|
||||||
|
str += 8;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
var = _recordset->get(str);
|
||||||
if (!var.is_null())
|
if (!var.is_null())
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool TReport::get_usr_val(const TString& name, TVariant& var) const
|
||||||
|
{
|
||||||
|
if (get_report_field(name, var))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (get_record_field(name, var))
|
||||||
|
return true;
|
||||||
|
|
||||||
return TAlex_virtual_machine::get_usr_val(name, var);
|
return TAlex_virtual_machine::get_usr_val(name, var);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TReport::set_usr_val(const TString& name, const TVariant& var)
|
bool TReport::set_usr_val(const TString& name, const TVariant& var)
|
||||||
{
|
{
|
||||||
TReport_field* fld = field(name);
|
const char* str = name;
|
||||||
|
if (name[0] == '#')
|
||||||
|
{
|
||||||
|
if (name.starts_with("#REPORT."))
|
||||||
|
str += 8;
|
||||||
|
else
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
const TFixed_string n(str);
|
||||||
|
TReport_field* fld = field(n);
|
||||||
if (fld != NULL)
|
if (fld != NULL)
|
||||||
{
|
{
|
||||||
fld->set(var);
|
fld->set(var);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return TAlex_virtual_machine::set_usr_val(name, var);
|
return TAlex_virtual_machine::set_usr_val(name, var);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1979,6 +2153,9 @@ TReport::TReport() : _lpi(6), _recordset(NULL), _curr_field(NULL)
|
|||||||
{
|
{
|
||||||
// Brutte inizializzazioni, ma inevitabili
|
// Brutte inizializzazioni, ma inevitabili
|
||||||
_expressions.set_report(this);
|
_expressions.set_report(this);
|
||||||
|
|
||||||
|
_prescript.set_description("PRESCRIPT");
|
||||||
|
_postscript.set_description("POSTSCRIPT");
|
||||||
}
|
}
|
||||||
|
|
||||||
TReport::~TReport()
|
TReport::~TReport()
|
||||||
|
43
ba/ba8302.h
43
ba/ba8302.h
@ -107,23 +107,28 @@ public:
|
|||||||
class TReport_script : public TObject
|
class TReport_script : public TObject
|
||||||
{
|
{
|
||||||
TBytecode* _bc; // Chesire's cat class
|
TBytecode* _bc; // Chesire's cat class
|
||||||
TString _src;
|
TString _src, _desc;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void destroy();
|
void destroy();
|
||||||
TString& translate_message() const;
|
TString& translate_message() const;
|
||||||
|
void copy(const TReport_script& rs);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual bool ok() const { return !_src.blank(); }
|
virtual bool ok() const { return !_src.blank(); }
|
||||||
void set(const char* source);
|
void set(const char* source);
|
||||||
const TString& get() const { return _src; }
|
const TString& get() const { return _src; }
|
||||||
|
void set_description(const char* d) { _desc = d; }
|
||||||
|
|
||||||
bool execute(TReport& report, TString& output);
|
bool execute(TReport& report, TString& output);
|
||||||
bool execute(TReport_field& rf);
|
bool execute(TReport_field& rf);
|
||||||
|
|
||||||
void save(TXmlItem& root, const char* tag) const;
|
void save(TXmlItem& root, const char* tag) const;
|
||||||
bool load(const TXmlItem& root, const char* tag);
|
bool load(const TXmlItem& root, const char* tag);
|
||||||
|
|
||||||
|
TReport_script& operator =(const TReport_script& rs) { copy(rs); return *this; }
|
||||||
TReport_script();
|
TReport_script();
|
||||||
|
TReport_script(const TReport_script& rs) { copy(rs); }
|
||||||
virtual ~TReport_script();
|
virtual ~TReport_script();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -131,7 +136,7 @@ public:
|
|||||||
// TReport_section
|
// TReport_section
|
||||||
///////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////
|
||||||
|
|
||||||
enum TReport_draw_mode { rdm_edit, rdm_print, rdm_print_preview };
|
enum TReport_draw_mode { rdm_edit, rdm_print, rdm_print_preview, rdm_spooler, rdm_textonly };
|
||||||
|
|
||||||
class TReport_section : public TArray
|
class TReport_section : public TArray
|
||||||
{
|
{
|
||||||
@ -148,6 +153,7 @@ class TReport_section : public TArray
|
|||||||
TReport_font* _font;
|
TReport_font* _font;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual const char* class_name() const { return "ReportSection"; }
|
||||||
TReport_section* father_section() const;
|
TReport_section* father_section() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -189,10 +195,10 @@ public:
|
|||||||
void activate(bool on) { _deactivated = !on; }
|
void activate(bool on) { _deactivated = !on; }
|
||||||
void deactivate() { activate(false); }
|
void deactivate() { activate(false); }
|
||||||
|
|
||||||
const TString& prescript() const { return _prescript.get(); }
|
const TString& prescript() const;
|
||||||
void set_prescript(const char* src) { _prescript.set(src); }
|
void set_prescript(const char* src);
|
||||||
const TString& postscript() const { return _postscript.get(); }
|
const TString& postscript() const;
|
||||||
void set_postscript(const char* src) { _postscript.set(src); }
|
void set_postscript(const char* src);
|
||||||
|
|
||||||
bool has_font() const { return _font != NULL; }
|
bool has_font() const { return _font != NULL; }
|
||||||
const TReport_font& font() const;
|
const TReport_font& font() const;
|
||||||
@ -224,11 +230,13 @@ class TReport_field : public TSortable
|
|||||||
TString _picture, _field, _codval, _link;
|
TString _picture, _field, _codval, _link;
|
||||||
TVariant _var;
|
TVariant _var;
|
||||||
TReport_script _prescript, _postscript;
|
TReport_script _prescript, _postscript;
|
||||||
|
TToken_string _list; // Elementi di un campo lista
|
||||||
|
|
||||||
TReport_font* _font;
|
TReport_font* _font;
|
||||||
bool _hidden, _deactivated, _hide_zeroes, _selected;
|
bool _hidden, _deactivated, _hide_zeroes, _selected;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual const char* class_name() const { return "ReportField"; }
|
||||||
virtual int compare(const TSortable& s) const;
|
virtual int compare(const TSortable& s) const;
|
||||||
void copy(const TReport_field& rf);
|
void copy(const TReport_field& rf);
|
||||||
TFieldtypes var_type() const;
|
TFieldtypes var_type() const;
|
||||||
@ -261,6 +269,9 @@ public:
|
|||||||
bool execute_prescript();
|
bool execute_prescript();
|
||||||
bool execute_postscript();
|
bool execute_postscript();
|
||||||
|
|
||||||
|
void get_list(TString_array& list) const;
|
||||||
|
void set_list(const TString_array& list);
|
||||||
|
|
||||||
int id() const { return _id; }
|
int id() const { return _id; }
|
||||||
void set_id(int id) { _id = id; }
|
void set_id(int id) { _id = id; }
|
||||||
char type() const { return _type; }
|
char type() const { return _type; }
|
||||||
@ -305,10 +316,10 @@ public:
|
|||||||
void set_vertical_alignment(char a) { _valign = a; }
|
void set_vertical_alignment(char a) { _valign = a; }
|
||||||
char vertical_alignment() const { return _valign; }
|
char vertical_alignment() const { return _valign; }
|
||||||
|
|
||||||
const TString& prescript() const { return _prescript.get(); }
|
const TString& prescript() const;
|
||||||
void set_prescript(const char* src) { _prescript.set(src); }
|
void set_prescript(const char* src);
|
||||||
const TString& postscript() const { return _postscript.get(); }
|
const TString& postscript() const;
|
||||||
void set_postscript(const char* src) { _postscript.set(src); }
|
void set_postscript(const char* src);
|
||||||
|
|
||||||
void select(bool ok = true) { _selected = ok; }
|
void select(bool ok = true) { _selected = ok; }
|
||||||
bool selected() const { return _selected; }
|
bool selected() const { return _selected; }
|
||||||
@ -366,6 +377,7 @@ class TReport : public TAlex_virtual_machine
|
|||||||
TReport_field* _curr_field;
|
TReport_field* _curr_field;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
virtual const char* class_name() const { return "Report"; }
|
||||||
virtual unsigned int compile_usr_word(const TString& name) const;
|
virtual unsigned int compile_usr_word(const TString& name) const;
|
||||||
virtual bool execute_usr_word(unsigned int opcode, TVariant_stack& stack);
|
virtual bool execute_usr_word(unsigned int opcode, TVariant_stack& stack);
|
||||||
virtual bool get_usr_val(const TString& name, TVariant& var) const;
|
virtual bool get_usr_val(const TString& name, TVariant& var) const;
|
||||||
@ -381,6 +393,9 @@ protected:
|
|||||||
void load_sections(const TXmlItem& xml);
|
void load_sections(const TXmlItem& xml);
|
||||||
void save_section(const TReport_section& rs, TXmlItem& item) const;
|
void save_section(const TReport_section& rs, TXmlItem& item) const;
|
||||||
|
|
||||||
|
bool get_report_field(const TString& name, TVariant& var) const;
|
||||||
|
bool get_record_field(const TString& name, TVariant& var) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
TReport_section* find_section(char type, int level) const;
|
TReport_section* find_section(char type, int level) const;
|
||||||
TReport_section& section(char type, int level);
|
TReport_section& section(char type, int level);
|
||||||
@ -403,10 +418,10 @@ public:
|
|||||||
bool evaluate_atom(const char* atom, TVariant& var);
|
bool evaluate_atom(const char* atom, TVariant& var);
|
||||||
bool evaluate(const char* expr, TVariant& var, TFieldtypes force_type);
|
bool evaluate(const char* expr, TVariant& var, TFieldtypes force_type);
|
||||||
|
|
||||||
const TString& prescript() const { return _prescript.get(); }
|
const TString& prescript() const;
|
||||||
void set_prescript(const char* src) { _prescript.set(src); }
|
void set_prescript(const char* src);
|
||||||
const TString& postscript() const { return _postscript.get(); }
|
const TString& postscript() const;
|
||||||
void set_postscript(const char* src) { _postscript.set(src); }
|
void set_postscript(const char* src);
|
||||||
bool execute_prescript();
|
bool execute_prescript();
|
||||||
bool execute_postscript();
|
bool execute_postscript();
|
||||||
|
|
||||||
|
258
ba/ba8304.cpp
258
ba/ba8304.cpp
@ -93,8 +93,9 @@ enum AVM_opcode
|
|||||||
avm_j,
|
avm_j,
|
||||||
avm_loop,
|
avm_loop,
|
||||||
avm_mod, avm_mon, avm_mul,
|
avm_mod, avm_mon, avm_mul,
|
||||||
|
avm_negate,
|
||||||
avm_or, avm_over,
|
avm_or, avm_over,
|
||||||
avm_plus_loop, avm_push,
|
avm_pick, avm_plus_loop, avm_push,
|
||||||
avm_repeat, avm_rdrop, avm_rpeek, avm_rpush, avm_rot,
|
avm_repeat, avm_rdrop, avm_rpeek, avm_rpush, avm_rot,
|
||||||
avm_store, avm_sub, avm_swap,
|
avm_store, avm_sub, avm_swap,
|
||||||
avm_then, avm_true,
|
avm_then, avm_true,
|
||||||
@ -117,8 +118,9 @@ const char* AVM_TOKENS[avm_zzz+1] =
|
|||||||
"J",
|
"J",
|
||||||
"LOOP",
|
"LOOP",
|
||||||
"MOD", "MON", "*",
|
"MOD", "MON", "*",
|
||||||
|
"NEGATE",
|
||||||
"OR", "OVER",
|
"OR", "OVER",
|
||||||
"+LOOP", "PUSH",
|
"PICK", "+LOOP", "PUSH",
|
||||||
"REPEAT", "R>", "R@", ">R", "ROT",
|
"REPEAT", "R>", "R@", ">R", "ROT",
|
||||||
"!", "-", "SWAP",
|
"!", "-", "SWAP",
|
||||||
"THEN", "TRUE",
|
"THEN", "TRUE",
|
||||||
@ -126,16 +128,22 @@ const char* AVM_TOKENS[avm_zzz+1] =
|
|||||||
"WARM", "WHILE"
|
"WARM", "WHILE"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum TBreakpointType { brk_none = 0x0, brk_user = 0x1, brk_auto = 0x2 };
|
||||||
|
|
||||||
class TAVM_op : public TObject
|
class TAVM_op : public TObject
|
||||||
{
|
{
|
||||||
AVM_opcode _op;
|
AVM_opcode _op;
|
||||||
TVariant _var;
|
TVariant _var;
|
||||||
bool _break_pointer;
|
int _break_pointer;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const TVariant& var() const { return _var; }
|
const TVariant& var() const { return _var; }
|
||||||
TVariant& var() { return _var; }
|
TVariant& var() { return _var; }
|
||||||
AVM_opcode op() const { return _op; }
|
AVM_opcode op() const { return _op; }
|
||||||
|
bool has_break() const { return _break_pointer != brk_none; }
|
||||||
|
bool has_auto_break() const { return (_break_pointer & brk_auto) != 0; }
|
||||||
|
void set_user_break(bool on);
|
||||||
|
void set_auto_break(bool on);
|
||||||
|
|
||||||
TAVM_op(AVM_opcode o, const TString& str);
|
TAVM_op(AVM_opcode o, const TString& str);
|
||||||
TAVM_op(AVM_opcode o, const real& num);
|
TAVM_op(AVM_opcode o, const real& num);
|
||||||
@ -143,6 +151,20 @@ public:
|
|||||||
TAVM_op(AVM_opcode o);
|
TAVM_op(AVM_opcode o);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void TAVM_op::set_user_break(bool on)
|
||||||
|
{
|
||||||
|
_break_pointer = on ? brk_user : brk_none;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TAVM_op::set_auto_break(bool on)
|
||||||
|
{
|
||||||
|
if (on)
|
||||||
|
_break_pointer |= brk_auto;
|
||||||
|
else
|
||||||
|
_break_pointer &= ~brk_auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
TAVM_op::TAVM_op(AVM_opcode o, const TString& str)
|
TAVM_op::TAVM_op(AVM_opcode o, const TString& str)
|
||||||
: _op(o), _var(str), _break_pointer(false)
|
: _op(o), _var(str), _break_pointer(false)
|
||||||
{ }
|
{ }
|
||||||
@ -165,25 +187,45 @@ TAVM_op::TAVM_op(AVM_opcode o)
|
|||||||
|
|
||||||
class TAVM_list_window : public TField_window
|
class TAVM_list_window : public TField_window
|
||||||
{
|
{
|
||||||
const TBytecode* _bc;
|
TBytecode* _bc;
|
||||||
int _ip;
|
int _ip;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void update();
|
virtual void update();
|
||||||
|
virtual void handler(WINDOW win, EVENT* ep);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void set_bytecode(const TBytecode* bc, int ip);
|
void set_bytecode(const TBytecode* bc, int ip);
|
||||||
TAVM_list_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
|
TAVM_list_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void TAVM_list_window::handler(WINDOW win, EVENT* ep)
|
||||||
|
{
|
||||||
|
if (ep->type == E_MOUSE_DOWN)
|
||||||
|
{
|
||||||
|
const TPoint pt = dev2log(ep->v.mouse.where);
|
||||||
|
if (pt.x <= 5)
|
||||||
|
{
|
||||||
|
TAVM_op& op = *(TAVM_op*)_bc->objptr(pt.y-1);
|
||||||
|
op.set_user_break(ep->v.mouse.button == 0);
|
||||||
|
force_update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TField_window::handler(win, ep);
|
||||||
|
}
|
||||||
|
|
||||||
void TAVM_list_window::update()
|
void TAVM_list_window::update()
|
||||||
{
|
{
|
||||||
clear(NORMAL_BACK_COLOR);
|
clear(NORMAL_BACK_COLOR);
|
||||||
if (_bc != NULL)
|
if (_bc != NULL)
|
||||||
{
|
{
|
||||||
|
autoscroll(false);
|
||||||
set_brush(DISABLED_BACK_COLOR);
|
set_brush(DISABLED_BACK_COLOR);
|
||||||
bar(0, 0, 5, _bc->items());
|
bar(0, 0, columns()+1, 1);
|
||||||
|
bar(0, 0, 5, rows()+1);
|
||||||
set_brush(NORMAL_BACK_COLOR);
|
set_brush(NORMAL_BACK_COLOR);
|
||||||
|
printat(0, 0, _bc->name());
|
||||||
|
autoscroll(true);
|
||||||
|
|
||||||
TString str;
|
TString str;
|
||||||
int tab = 6;
|
int tab = 6;
|
||||||
@ -191,24 +233,29 @@ void TAVM_list_window::update()
|
|||||||
const int last = min(_bc->items(), rows());
|
const int last = min(_bc->items(), rows());
|
||||||
for (int i = 0; i < last; i++)
|
for (int i = 0; i < last; i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const int y = i+1;
|
||||||
if (_ip == i)
|
if (_ip == i)
|
||||||
{
|
{
|
||||||
set_brush(FOCUS_BACK_COLOR);
|
set_brush(FOCUS_BACK_COLOR);
|
||||||
bar(0, i, 80, i+1);
|
bar(0, y, 80, y+1);
|
||||||
set_brush(NORMAL_BACK_COLOR);
|
set_brush(NORMAL_BACK_COLOR);
|
||||||
}
|
}
|
||||||
printat(0, i, "%04d", i);
|
printat(0, y, "%04d", i);
|
||||||
const TAVM_op& op = *(const TAVM_op*)_bc->objptr(i);
|
const TAVM_op& op = *(const TAVM_op*)_bc->objptr(i);
|
||||||
const AVM_opcode co = op.op();
|
const AVM_opcode co = op.op();
|
||||||
const TVariant& var = op.var();
|
const TVariant& var = op.var();
|
||||||
|
|
||||||
|
if (op.has_break())
|
||||||
|
printat(4, y, "<");
|
||||||
|
|
||||||
if (co == avm_else || co == avm_then ||
|
if (co == avm_else || co == avm_then ||
|
||||||
co == avm_loop || co == avm_plus_loop ||
|
co == avm_loop || co == avm_plus_loop ||
|
||||||
co == avm_repeat || co == avm_until)
|
co == avm_repeat || co == avm_until)
|
||||||
tab -= 2;
|
tab -= 2;
|
||||||
if (co == avm_push)
|
if (co == avm_push)
|
||||||
{
|
{
|
||||||
if (var.type() == _alfafld && var.as_string()[0] != '#')
|
if (var.is_string() && var.as_string()[0] != '#')
|
||||||
str.cut(0) << '"' << var.as_string() << '"';
|
str.cut(0) << '"' << var.as_string() << '"';
|
||||||
else
|
else
|
||||||
str = var.as_string();
|
str = var.as_string();
|
||||||
@ -223,7 +270,7 @@ void TAVM_list_window::update()
|
|||||||
if (!var.is_null())
|
if (!var.is_null())
|
||||||
str << " (" << var.as_string() << ')';
|
str << " (" << var.as_string() << ')';
|
||||||
}
|
}
|
||||||
printat(tab, i, str);
|
printat(tab, y, str);
|
||||||
if (co == avm_if || co == avm_else ||
|
if (co == avm_if || co == avm_else ||
|
||||||
co == avm_do || co == avm_begin || co == avm_while)
|
co == avm_do || co == avm_begin || co == avm_while)
|
||||||
tab += 2;
|
tab += 2;
|
||||||
@ -233,7 +280,7 @@ void TAVM_list_window::update()
|
|||||||
|
|
||||||
void TAVM_list_window::set_bytecode(const TBytecode* bc, int ip)
|
void TAVM_list_window::set_bytecode(const TBytecode* bc, int ip)
|
||||||
{
|
{
|
||||||
_bc = bc;
|
_bc = (TBytecode*)bc;
|
||||||
_ip = ip;
|
_ip = ip;
|
||||||
set_scroll_max(80, _bc->items() - rows());
|
set_scroll_max(80, _bc->items() - rows());
|
||||||
}
|
}
|
||||||
@ -353,6 +400,7 @@ class TAVM
|
|||||||
TVariant_stack _stack, _rstack;
|
TVariant_stack _stack, _rstack;
|
||||||
const TBytecode* _bc; // Current word (or command line)
|
const TBytecode* _bc; // Current word (or command line)
|
||||||
int _ip; // Current instruction pointer
|
int _ip; // Current instruction pointer
|
||||||
|
ostream* _outstr;
|
||||||
|
|
||||||
TAssoc_array _words;
|
TAssoc_array _words;
|
||||||
TAVM_monitor _mon;
|
TAVM_monitor _mon;
|
||||||
@ -365,12 +413,13 @@ protected:
|
|||||||
int find_matching(const TBytecode& bytecode, AVM_opcode op1, AVM_opcode op2 = avm_nop) const;
|
int find_matching(const TBytecode& bytecode, AVM_opcode op1, AVM_opcode op2 = avm_nop) const;
|
||||||
void execute(const TAVM_op& op);
|
void execute(const TAVM_op& op);
|
||||||
void do_call(const TString& func);
|
void do_call(const TString& func);
|
||||||
|
void do_fload(const char* fname);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const TString& get_last_error() const { return _last_error; }
|
const TString& get_last_error() const { return _last_error; }
|
||||||
|
|
||||||
bool compile(istream& instr, TBytecode& bc);
|
bool compile(istream& instr, TBytecode& bc);
|
||||||
bool execute(const TBytecode& bc, ostream& outstr);
|
bool execute(const TBytecode& bc, ostream* outstr = NULL);
|
||||||
void restart(bool cold);
|
void restart(bool cold);
|
||||||
|
|
||||||
TAVM(TAlex_virtual_machine* vm);
|
TAVM(TAlex_virtual_machine* vm);
|
||||||
@ -457,7 +506,7 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
|
|||||||
str.rtrim(1); str.ltrim(1);
|
str.rtrim(1); str.ltrim(1);
|
||||||
op = new TAVM_op(avm_push, str);
|
op = new TAVM_op(avm_push, str);
|
||||||
} else
|
} else
|
||||||
if (isdigit(str[0]) || (str[0]=='-' && isdigit(str[1])))
|
if ((isdigit(str[0]) || (str[0]=='-')) && isdigit(str[str.len()-1]))
|
||||||
{
|
{
|
||||||
const real r(str);
|
const real r(str);
|
||||||
op = new TAVM_op(avm_push, r);
|
op = new TAVM_op(avm_push, r);
|
||||||
@ -474,6 +523,7 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
|
|||||||
bc->set_name(str);
|
bc->set_name(str);
|
||||||
_words.add(str, bc);
|
_words.add(str, bc);
|
||||||
compile(instr, *bc);
|
compile(instr, *bc);
|
||||||
|
op = new TAVM_op(avm_nop);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -554,7 +604,12 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (op != NULL)
|
if (op != NULL)
|
||||||
bytecode.add(op);
|
{
|
||||||
|
if (op->op() != avm_nop)
|
||||||
|
bytecode.add(op);
|
||||||
|
else
|
||||||
|
delete op;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
_last_error.cut(0) << "Unknown WORD: " << str;
|
_last_error.cut(0) << "Unknown WORD: " << str;
|
||||||
@ -567,9 +622,9 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
|
|||||||
|
|
||||||
int TAVM::compare_tos_nos()
|
int TAVM::compare_tos_nos()
|
||||||
{
|
{
|
||||||
const TVariant& v0 = _stack.pop();
|
const TVariant& tos = _stack.pop();
|
||||||
const TVariant& v1 = _stack.pop();
|
const TVariant& nos = _stack.pop();
|
||||||
return v1.compare(v0);
|
return nos.compare(tos);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TAVM::do_call(const TString& func)
|
void TAVM::do_call(const TString& func)
|
||||||
@ -580,6 +635,18 @@ void TAVM::do_call(const TString& func)
|
|||||||
_bc = (TBytecode*)_words.objptr(func);
|
_bc = (TBytecode*)_words.objptr(func);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TAVM::do_fload(const char* fname)
|
||||||
|
{
|
||||||
|
TFilename name = fname;
|
||||||
|
if (name.custom_path())
|
||||||
|
{
|
||||||
|
TBytecode bc;
|
||||||
|
ifstream inf(name);
|
||||||
|
if (compile(inf, bc))
|
||||||
|
execute(bc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void TAVM::execute(const TAVM_op& op)
|
void TAVM::execute(const TAVM_op& op)
|
||||||
{
|
{
|
||||||
switch(op.op())
|
switch(op.op())
|
||||||
@ -631,13 +698,24 @@ void TAVM::execute(const TAVM_op& op)
|
|||||||
_ip = op.var().as_int();
|
_ip = op.var().as_int();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case avm_dot: /* *_outstr << _stack.pop().as_string(); */ break;
|
case avm_dot:
|
||||||
|
if (_outstr != NULL)
|
||||||
|
*_outstr << _stack.pop().as_string();
|
||||||
|
break;
|
||||||
case avm_drop: _stack.drop(); break;
|
case avm_drop: _stack.drop(); break;
|
||||||
case avm_dup: _stack.push(_stack.peek()); break;
|
case avm_dup: _stack.push(_stack.peek()); break;
|
||||||
case avm_else:
|
case avm_else:
|
||||||
_ip = op.var().as_int();
|
_ip = op.var().as_int();
|
||||||
break;
|
break;
|
||||||
case avm_execute: do_call(_stack.pop().as_string()); break;
|
case avm_execute:
|
||||||
|
{
|
||||||
|
const TString& cmd = _stack.pop().as_string();
|
||||||
|
istrstream instr((char*)(const char*)cmd, cmd.len());
|
||||||
|
TBytecode bc;
|
||||||
|
if (compile(instr, bc))
|
||||||
|
execute(bc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case avm_false: _stack.push(0L); break;
|
case avm_false: _stack.push(0L); break;
|
||||||
case avm_fetch:
|
case avm_fetch:
|
||||||
{
|
{
|
||||||
@ -652,12 +730,7 @@ void TAVM::execute(const TAVM_op& op)
|
|||||||
_stack.push(var);
|
_stack.push(var);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case avm_fload:
|
case avm_fload: do_fload(_stack.pop().as_string()); break;
|
||||||
{
|
|
||||||
const TString& name = _stack.pop().as_string();
|
|
||||||
ifstream inf(name); TBytecode bc;
|
|
||||||
compile(inf, bc); // Loads new words but desn't execute statements
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case avm_i: _stack.push(_rstack.peek()); break;
|
case avm_i: _stack.push(_rstack.peek()); break;
|
||||||
case avm_if:
|
case avm_if:
|
||||||
@ -683,13 +756,8 @@ void TAVM::execute(const TAVM_op& op)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case avm_mon:
|
case avm_mon:
|
||||||
{
|
if (!_mon.is_open())
|
||||||
lock_preview_update(true);
|
_mon.open_modal();
|
||||||
TAVM_list_window& monitor = _mon.monitor();
|
|
||||||
monitor.set_bytecode(_bc, _ip);
|
|
||||||
if (!_mon.is_open())
|
|
||||||
_mon.open();
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case avm_mul:
|
case avm_mul:
|
||||||
{
|
{
|
||||||
@ -699,15 +767,27 @@ void TAVM::execute(const TAVM_op& op)
|
|||||||
v0.set(m);
|
v0.set(m);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case avm_negate:
|
||||||
|
{
|
||||||
|
TVariant& tos = _stack.peek();
|
||||||
|
tos.set(~tos.as_int());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case avm_or:
|
case avm_or:
|
||||||
{
|
{
|
||||||
const TVariant& v1 = _stack.pop();
|
const TVariant& tos = _stack.pop();
|
||||||
TVariant& v0 = (TVariant&)_stack.peek();
|
TVariant& nos = (TVariant&)_stack.peek();
|
||||||
const long r = v0.as_int() | v1.as_int();
|
const long r = nos.as_int() | tos.as_int();
|
||||||
v0.set(r);
|
nos.set(r);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case avm_over: _stack.push(_stack.peek(1)); break;
|
case avm_over: _stack.push(_stack.peek(1)); break;
|
||||||
|
case avm_pick:
|
||||||
|
{
|
||||||
|
const int depth = _stack.pop().as_int();
|
||||||
|
_stack.push(_stack.peek(depth));
|
||||||
|
}
|
||||||
|
break;
|
||||||
case avm_plus_loop:
|
case avm_plus_loop:
|
||||||
{
|
{
|
||||||
TVariant& start = _rstack.pop();
|
TVariant& start = _rstack.pop();
|
||||||
@ -766,10 +846,15 @@ void TAVM::execute(const TAVM_op& op)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TAVM::execute(const TBytecode& cmdline, ostream& outstr)
|
bool TAVM::execute(const TBytecode& cmdline, ostream* outstr)
|
||||||
{
|
{
|
||||||
|
const TBytecode* old_bc = _bc;
|
||||||
|
const int old_ip = _ip;
|
||||||
|
|
||||||
_bc = &cmdline;
|
_bc = &cmdline;
|
||||||
_ip = 0;
|
_ip = 0;
|
||||||
|
if (outstr != NULL)
|
||||||
|
_outstr = outstr;
|
||||||
while (_bc != NULL)
|
while (_bc != NULL)
|
||||||
{
|
{
|
||||||
if (_ip >= _bc->items()) // Fine funzione
|
if (_ip >= _bc->items()) // Fine funzione
|
||||||
@ -778,13 +863,23 @@ bool TAVM::execute(const TBytecode& cmdline, ostream& outstr)
|
|||||||
{
|
{
|
||||||
_ip = _rstack.pop().as_int();
|
_ip = _rstack.pop().as_int();
|
||||||
const TString& str = _rstack.pop().as_string();
|
const TString& str = _rstack.pop().as_string();
|
||||||
if (str.blank())
|
if (str == cmdline.name())
|
||||||
_bc = &cmdline;
|
_bc = &cmdline;
|
||||||
else
|
else
|
||||||
_bc = (const TBytecode*)_words.objptr(str);
|
_bc = (const TBytecode*)_words.objptr(str);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
break; // Fine esecuzione
|
break; // Fine esecuzione
|
||||||
|
if (_bc == NULL)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
TAVM_op& op = *(TAVM_op*)_bc->objptr(_ip);
|
||||||
|
if (op.has_break() && !_mon.is_open())
|
||||||
|
{
|
||||||
|
if (op.has_auto_break())
|
||||||
|
op.set_auto_break(false);
|
||||||
|
_mon.open_modal();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_mon.is_open()) // Gestione debugger
|
if (_mon.is_open()) // Gestione debugger
|
||||||
@ -799,14 +894,21 @@ bool TAVM::execute(const TBytecode& cmdline, ostream& outstr)
|
|||||||
const KEY k = _mon.run();
|
const KEY k = _mon.run();
|
||||||
switch (k)
|
switch (k)
|
||||||
{
|
{
|
||||||
case K_NEXT: monitor.force_update(); stacker.force_update(); rstacker.force_update(); break;
|
case K_F11: monitor.force_update(); stacker.force_update(); rstacker.force_update(); break;
|
||||||
|
case K_F10:
|
||||||
|
if (_ip < _bc->items()-1)
|
||||||
|
{
|
||||||
|
_mon.close_modal();
|
||||||
|
TAVM_op& op = *(TAVM_op*)_bc->objptr(_ip+1);
|
||||||
|
op.set_auto_break(true);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case K_DEL : abort_printing();
|
case K_DEL : abort_printing();
|
||||||
case K_QUIT: _mon.close(); lock_preview_update(false); break;
|
case K_QUIT: _mon.close_modal(); lock_preview_update(false); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const TAVM_op& op = *(const TAVM_op*)_bc->objptr(_ip);
|
|
||||||
execute(op);
|
execute(op);
|
||||||
|
|
||||||
_ip++;
|
_ip++;
|
||||||
@ -814,11 +916,15 @@ bool TAVM::execute(const TBytecode& cmdline, ostream& outstr)
|
|||||||
|
|
||||||
if (_mon.is_open()) // Chiudi debugger
|
if (_mon.is_open()) // Chiudi debugger
|
||||||
{
|
{
|
||||||
_mon.close();
|
_mon.close_modal();
|
||||||
lock_preview_update(false);
|
lock_preview_update(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool ok = _bc != NULL; // Not aborted
|
||||||
|
_bc = old_bc;
|
||||||
|
_ip = old_ip;
|
||||||
|
|
||||||
return _bc != NULL;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TAVM::restart(bool cold)
|
void TAVM::restart(bool cold)
|
||||||
@ -828,8 +934,10 @@ void TAVM::restart(bool cold)
|
|||||||
}
|
}
|
||||||
|
|
||||||
TAVM::TAVM(TAlex_virtual_machine* vm)
|
TAVM::TAVM(TAlex_virtual_machine* vm)
|
||||||
: _vm(vm)
|
: _vm(vm), _outstr(NULL)
|
||||||
{ }
|
{
|
||||||
|
do_fload("alex.alx");
|
||||||
|
}
|
||||||
|
|
||||||
TAVM::~TAVM()
|
TAVM::~TAVM()
|
||||||
{
|
{
|
||||||
@ -860,7 +968,7 @@ bool TAlex_virtual_machine::compile(istream& instr, TBytecode& bc)
|
|||||||
|
|
||||||
bool TAlex_virtual_machine::execute(const TBytecode& bc, ostream& outstr)
|
bool TAlex_virtual_machine::execute(const TBytecode& bc, ostream& outstr)
|
||||||
{
|
{
|
||||||
return avm().execute(bc, outstr);
|
return avm().execute(bc, &outstr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TAlex_virtual_machine::compile(const char* cmd, TBytecode& bc)
|
bool TAlex_virtual_machine::compile(const char* cmd, TBytecode& bc)
|
||||||
@ -889,40 +997,48 @@ void TAlex_virtual_machine::cold_restart() // Ripartenza a freddo
|
|||||||
|
|
||||||
bool TAlex_virtual_machine::get_usr_val(const TString& name, TVariant& var) const
|
bool TAlex_virtual_machine::get_usr_val(const TString& name, TVariant& var) const
|
||||||
{
|
{
|
||||||
if (name == "#ADMINISTATOR")
|
if (name.starts_with("#SYSTEM."))
|
||||||
{
|
{
|
||||||
var.set(dongle().administrator());
|
const TFixed_string n((const char*)name+8);
|
||||||
return true;
|
if (n == "ADMINISTATOR")
|
||||||
}
|
{
|
||||||
if (name == "#FIRM")
|
var.set(dongle().administrator());
|
||||||
{
|
return true;
|
||||||
var.set(prefix().get_codditta());
|
}
|
||||||
return true;
|
if (n == "FIRM")
|
||||||
}
|
{
|
||||||
if (name == "#STUDY")
|
var.set(prefix().get_codditta());
|
||||||
{
|
return true;
|
||||||
var.set(firm2dir(-1));
|
}
|
||||||
return true;
|
if (n == "STUDY")
|
||||||
}
|
{
|
||||||
if (name == "#TODAY")
|
var.set(firm2dir(-1));
|
||||||
{
|
return true;
|
||||||
const TDate oggi(TODAY);
|
}
|
||||||
var.set(oggi);
|
if (n == "DATE")
|
||||||
return true;
|
{
|
||||||
}
|
const TDate oggi(TODAY);
|
||||||
if (name == "#USER")
|
var.set(oggi);
|
||||||
{
|
return true;
|
||||||
var.set(user());
|
}
|
||||||
return true;
|
if (n == "USER")
|
||||||
|
{
|
||||||
|
var.set(user());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TAlex_virtual_machine::set_usr_val(const TString& name, const TVariant& var)
|
bool TAlex_virtual_machine::set_usr_val(const TString& name, const TVariant& var)
|
||||||
{
|
{
|
||||||
if (name == "#FIRM")
|
if (name.starts_with("#SYSTEM."))
|
||||||
{
|
{
|
||||||
return prefix().set_codditta(var.as_int());
|
const TFixed_string n((const char*)name+8);
|
||||||
|
if (n == "FIRM")
|
||||||
|
{
|
||||||
|
return prefix().set_codditta(var.as_int());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -17,19 +17,28 @@ END
|
|||||||
|
|
||||||
BUTTON DLG_NEXTREC 10 2
|
BUTTON DLG_NEXTREC 10 2
|
||||||
BEGIN
|
BEGIN
|
||||||
PROMPT -13 -1 ""
|
PROMPT -14 -1 ""
|
||||||
PICTURE 124
|
PICTURE 124
|
||||||
MESSAGE EXIT,K_NEXT
|
MESSAGE EXIT,K_F11
|
||||||
END
|
END
|
||||||
|
|
||||||
BUTTON DLG_QUIT 10 2
|
BUTTON DLG_LASTREC 10 2
|
||||||
BEGIN
|
BEGIN
|
||||||
PROMPT -23 -1 ""
|
PROMPT -24 -1 ""
|
||||||
|
PICTURE 1671
|
||||||
|
MESSAGE EXIT,K_F10
|
||||||
|
END
|
||||||
|
|
||||||
|
BUTTON DLG_ELABORA 10 2
|
||||||
|
BEGIN
|
||||||
|
PROMPT -34 -1 ""
|
||||||
|
PICTURE BMP_LASTREC
|
||||||
|
MESSAGE EXIT,K_QUIT
|
||||||
END
|
END
|
||||||
|
|
||||||
BUTTON DLG_DELREC 10 2
|
BUTTON DLG_DELREC 10 2
|
||||||
BEGIN
|
BEGIN
|
||||||
PROMPT -33 -1 "Abort"
|
PROMPT -44 -1 "Abort"
|
||||||
MESSAGE EXIT,K_DEL
|
MESSAGE EXIT,K_DEL
|
||||||
END
|
END
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user