Patch level : 2.1 nopatch

Files correlati     : ba1.exe ba8.exe
Ricompilazione Demo : [ ]
Commento            :

ba1 Tolte righe commentate inutili
ba8 Migliorata gestione query per quanto rigurda: date; memo; selezioni Dal/Al.


git-svn-id: svn://10.65.10.50/trunk@11990 c028cbd2-c16b-5b4b-a496-9718f37d4682
This commit is contained in:
guy 2004-04-22 15:53:08 +00:00
parent 912337c3e7
commit 5738d39723
14 changed files with 1102 additions and 321 deletions

View File

@ -30,18 +30,10 @@ void TDir_sheet::add ()
d.zero();
d.put(nitems, _nordir, _sysdirop);
_items = nitems;
/*
isfdptr *newopenf = new isfdptr[_items];
for (int i = 0; i<_items; i++)
newopenf[i] = i<(_items-1) ? openf[i] : NULL;
delete openf;
openf = newopenf;
*/
}
TDir_sheet::TDir_sheet(const char* title, byte buttons, const char* colonne)
:TSheet(0, 0, 0, 0, title, colonne, buttons)
: TSheet(0, 0, 0, 0, title, colonne, buttons)
{
_dir = new TDir;
_rec = new TTrec;
@ -55,7 +47,6 @@ TDir_sheet::~TDir_sheet()
delete _rec;
}
void TDir_sheet::get_row(long n, TToken_string& l)
{
n++;
@ -73,7 +64,6 @@ void TDir_sheet::get_row(long n, TToken_string& l)
TRec_sheet::TRec_sheet(int logicnum, const char * tab)
: _descr(NULL), _tab(tab)
{
_external = FALSE;
_dir = new TDir;

View File

@ -139,7 +139,7 @@ public:
~TTable_mask();
};
// Converte un nome di tabella nel suo numero loigico
// Converte un nome di tabella nel suo numero logico
int TTable_mask::name2num(const TString& name) const
{
int num = 0;
@ -643,6 +643,13 @@ inline bool tok_get_bool(TToken_string& tok, int pos)
return str && *str > ' ';
}
static void add_where_clause(TString& where, const char* field, const char* cmp, const char* expr)
{
if (where.not_empty())
where << "AND";
where << '(' << field << cmp << expr << ')';
}
// Genera una query SQL a partire dallo spreadsheet F_SHEET
void TQuery_mask::sheet2sql()
{
@ -653,7 +660,7 @@ void TQuery_mask::sheet2sql()
const bool multiple = _tree.has_son();
TToken_string from(50, ','), groupby(50, ','), orderby(50, ',');
TString where;
TString where, expr_from, expr_to;
TString field;
FOR_EACH_SHEET_ROW(sheet, i, row)
@ -672,7 +679,25 @@ void TQuery_mask::sheet2sql()
orderby.add(field);
if (tok_get_bool(*row, 4)) // Group
groupby.add(field);
expr_from = row->get(5); expr_from.trim();
expr_to = row->get(6); expr_to.trim();
if (expr_from.not_empty() || expr_to.not_empty())
{
if (expr_from == expr_to)
{
add_where_clause(where, field, "=", expr_from);
}
else
{
if (expr_from.not_empty())
add_where_clause(where, field, ">=", expr_from);
if (expr_to.not_empty())
add_where_clause(where, field, "<=", expr_to);
}
}
}
}
tree2sql(from, where);
@ -680,7 +705,8 @@ void TQuery_mask::sheet2sql()
TString sql;
sql << "SELECT " << select << '\n';
sql << "FROM " << from << '\n';
sql << "WHERE " << where << '\n';
if (!where.blank())
sql << "WHERE " << where << '\n';
if (groupby.not_empty())
sql << "GROUP BY " << groupby << '\n';
if (orderby.not_empty())
@ -833,7 +859,10 @@ bool TQuery_mask::save_fields_sheet(TXmlItem& xml)
field.SetAttr("Group", tok_get_bool(*row,4));
const char* str = row->get(5);
if (str && *str > ' ')
field.SetAttr("Expr", str);
field.SetAttr("ExprFrom", str);
str = row->get(6);
if (str && *str > ' ')
field.SetAttr("ExprTo", str);
}
}
return ok;
@ -939,7 +968,8 @@ bool TQuery_mask::load_fields_sheet(TXmlItem& xml)
row.add(field.GetBoolAttr("Hidden") ? "X" : "",2);
row.add(field.GetBoolAttr("Sort") ? "X" : "",3);
row.add(field.GetBoolAttr("Group") ? "X" : "",4);
row.add(field.GetAttr("Expr"),5);
row.add(field.GetAttr("ExprFrom"),5);
row.add(field.GetAttr("ExprTo"),6);
}
sheet.force_update();
}
@ -1072,7 +1102,7 @@ bool TQuery_mask::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
next_page(1001);
bool ok = true;
if (_sql_dirty)
if (_sql_dirty && !field(F_SQL).empty())
ok = yesno_box(TR("Attenzione: la query verra' rigenerata\n"
"annullando eventuali modifiche manuali.\n"
"Si desidera proseguire?"));

View File

@ -98,11 +98,12 @@ SPREADSHEET F_SHEET -5
BEGIN
PROMPT 0 13 ""
ITEM "Tabella@12F"
ITEM "Colonna@32F"
ITEM "Colonna@30F"
ITEM "Nas.@3"
ITEM "Ord.@3"
ITEM "Grp.@3"
ITEM "Condizione@50"
ITEM "Da@30"
ITEM "A@30"
END
BUTTON F_MOVEUP 2 2
@ -233,10 +234,14 @@ BEGIN
PROMPT 35 2 "Raggruppa"
END
MEMO 106 58 8
STRING 106 70 50
BEGIN
PROMPT 1 3 "Condizione "
FLAGS "D"
PROMPT 1 3 "Da "
END
STRING 107 70 50
BEGIN
PROMPT 1 4 "A "
END
BUTTON DLG_CANCEL 10 2

View File

@ -81,7 +81,7 @@ bool TVariant::is_zero() const
case _datefld: return !as_date().ok();
case _longfld: return _ptr == NULL;
case _realfld: return as_real().is_zero();
case _alfafld: return as_string().blank();
case _alfafld: return real::is_null(as_string());
default: break;
}
return true;
@ -248,6 +248,87 @@ TVariant& TVariant::sub(const TVariant& var)
return *this;
}
///////////////////////////////////////////////////////////
// TTable name converter
///////////////////////////////////////////////////////////
class TTable_names : public TObject
{
TAssoc_array _names;
TArray _ids;
protected:
void fill();
void add_file(int logic, const TString& table);
public:
const TString& name(int logic_num);
int logic_num(const TString& name);
} _table_names;
void TTable_names::add_file(int logic, const TString& table)
{
TString8* id = new TString8;
id->format("%d", logic);
_names.add(table, id);
_ids.add(table, logic);
}
void TTable_names::fill()
{
FileDes dir;
CGetFile(LF_DIR, &dir, _nolock, NORDIR);
const int nfiles = (int)dir.EOD;
TFilename n;
for (int logic = LF_USER; logic < nfiles; logic++)
{
const FileDes& fd = prefix().get_filedes(logic);
n = fd.SysName; n = n.name(); n.upper();
if (_names.objptr(n) == NULL)
add_file(logic, n);
}
}
int TTable_names::logic_num(const TString& name)
{
TString* str = (TString*)_names.objptr(name);
if (str == NULL)
{
fill();
str = (TString*)_names.objptr(name);
}
if (str == NULL)
{
if (isdigit(name[0]))
add_file(atoi(name), name); else
if (name[0] == '%')
add_file(LF_TABCOM, name); else
if (name.len() == 3)
add_file(LF_TAB, name); else
str = (TString*)_names.objptr(name);
}
return str == NULL ? 0 : atoi(*str);
}
const TString& TTable_names::name(int logic_num)
{
TString* str = (TString*)_ids.objptr(logic_num);
if (str == NULL)
{
fill();
str = (TString*)_ids.objptr(logic_num);
}
return str == NULL ? (const TString&)EMPTY_STRING : *str;
}
const TString& logic2table(int logic_num)
{ return _table_names.name(logic_num); }
int table2logic(const TString& name)
{ return _table_names.logic_num(name); }
///////////////////////////////////////////////////////////
// Utility
@ -584,7 +665,6 @@ bool TRecordset::ask_variables(bool all)
set_var(*name, var);
}
}
move_to(-1);
}
return ok;
}
@ -654,12 +734,8 @@ class TSQLite : public TObject
{
sqlite* _handle;
TFilename _currdb;
TAssoc_array _names;
protected:
void logicnum2name(int logicnum, TString& name) const;
int name2logicnum(const TString& name) const;
TVariant& get_sql_value(const TRectype& curr, const RecFieldDes& fd, TVariant& tmp) const;
void build_curr_path(TFilename& name) const;
@ -763,7 +839,7 @@ bool TSQLite::create_dbf_times()
if (!ok)
{
TString sql;
sql << "CREATE TABLE " << DBF_TIMES_TABLE << " (name,time);\n"
sql << "CREATE TABLE " << DBF_TIMES_TABLE << " (name TEXT,time NUMERIC);\n"
<< "CREATE UNIQUE INDEX " << DBF_TIMES_TABLE << "_1 ON " << DBF_TIMES_TABLE << " (name);";
ok = exec(sql);
}
@ -773,7 +849,6 @@ bool TSQLite::create_dbf_times()
bool TSQLite::set_dbf_time(const TString& table, long last)
{
TString sql;
// sql << "INSERT OR REPLACE INTO " << DBF_TIMES_TABLE << " VALUES("
sql << "REPLACE INTO " << DBF_TIMES_TABLE << " VALUES("
<< '\'' << table << "','" << last << "');";
return exec(sql);
@ -795,37 +870,6 @@ long TSQLite::get_dbf_time(const TString& table)
return last;
}
void TSQLite::logicnum2name(int logicnum, TString& name) const
{
const FileDes& fd = prefix().get_filedes(logicnum);
const TFilename n = fd.SysName;
name = n.name(); name.upper();
}
int TSQLite::name2logicnum(const TString& name) const
{
TString* cod = (TString*)_names.objptr(name);
if (cod == NULL)
{
FileDes dir;
CGetFile(LF_DIR, &dir, _nolock, NORDIR);
const int nfiles = (int)dir.EOD;
TString8 n;
for (int logic = LF_USER; logic < nfiles; logic++)
{
logicnum2name(logic, n);
cod = new TString4; cod->format("%d", logic);
((TAssoc_array&)_names).add(n, cod);
}
cod = (TString*)_names.objptr(name);
if (cod == NULL) // Continua ostinatamente a non esistere?
return 0;
}
return atoi(*cod);
}
TVariant& TSQLite::get_sql_value(const TRectype& curr, const RecFieldDes& fd, TVariant& tmp) const
{
switch (fd.TypeF)
@ -836,8 +880,20 @@ TVariant& TSQLite::get_sql_value(const TRectype& curr, const RecFieldDes& fd, TV
case _wordfld :
case _intzerofld :
case _longzerofld: tmp.set(curr.get_long(fd.Name)); break;
case _datefld : tmp.set(curr.get_date(fd.Name)); break;
case _datefld :
{
const TDate date = curr.get_date(fd.Name);
tmp.set(date.date2ansi());
}
break;
case _boolfld : tmp.set(curr.get_bool(fd.Name)); break;
case _memofld:
{
TString memo = curr.get(fd.Name);
memo.replace('\n', char(0xB6)); // Simbolo di paragrafo
tmp.set(memo);
}
break;
default : tmp.set(curr.get(fd.Name)); break;
}
return tmp;
@ -866,13 +922,8 @@ bool TSQLite::esporta(const TRectype& rec, ostream& sql) const
for (int i = 0; i < rd.NFields; i++)
{
if (i > 0) sql << '\t';
if (rd.Fd[i].TypeF == _memofld)
sql << "\\N";
else
{
get_sql_value(rec, rd.Fd[i], tmp);
sql << tmp.as_string();
}
get_sql_value(rec, rd.Fd[i], tmp);
sql << tmp.as_string();
}
sql << '\n';
return true;
@ -880,7 +931,7 @@ bool TSQLite::esporta(const TRectype& rec, ostream& sql) const
bool TSQLite::import(int logicnum)
{
TString table; logicnum2name(logicnum, table);
const TString& table = logic2table(logicnum);
long last = get_dbf_time(table);
if (logicnum >= LF_USER) // Dummy test
@ -905,26 +956,33 @@ bool TSQLite::import(int logicnum)
for (int i = 0; i < rd.NFields; i++)
{
if (i > 0) sql << ',';
sql << rd.Fd[i].Name;
sql << rd.Fd[i].Name << ' ';
switch (rd.Fd[i].TypeF)
{
case _alfafld:
case _memofld: sql << "TEXT"; break;
case _datefld: sql << "DATE"; break;
default : sql << "NUMERIC"; break;
}
}
sql << ");";
if (!exec(sql))
return false;
// Create main index
// sql.cut(0) << "CREATE UNIQUE INDEX " << table << "_1 ON "<< table << "\n(";
sql.cut(0) << "CREATE INDEX " << table << "_1 ON "<< table << "\n(";
const KeyDes& kd = rd.Ky[0];
for (int k = 0; k < kd.NkFields; k++)
// Creazione indici
for (int index = 0; index < rd.NKeys; index++)
{
if (k > 0) sql << ',';
const int ndx = kd.FieldSeq[k] % MaxFields;
sql << rd.Fd[ndx].Name;
sql.cut(0) << "CREATE INDEX " << table << '_' << (index+1) << " ON "<< table << "\n(";
const KeyDes& kd = rd.Ky[index];
for (int k = 0; k < kd.NkFields; k++)
{
if (k > 0) sql << ',';
const int ndx = kd.FieldSeq[k] % MaxFields;
sql << rd.Fd[ndx].Name;
}
sql << ");";
exec(sql);
}
sql << ");";
if (!exec(sql))
return false;
TRelation rel(logicnum);
TCursor cur(&rel);
@ -995,7 +1053,7 @@ bool TSQLite::parse_select_from(const char* szSql)
if (table[i] <= ' ' || table[i] == ';')
{ table.cut(i); break; }
}
const int logicnum = name2logicnum(table);
const int logicnum = table2logic(table);
if (logicnum > 0)
import(logicnum);
}
@ -1004,8 +1062,7 @@ bool TSQLite::parse_select_from(const char* szSql)
}
TSQLite::TSQLite() : _handle(NULL)
{
}
{ }
TSQLite::~TSQLite()
{
@ -1033,7 +1090,21 @@ int TSQL_recordset::on_get_items(int argc, char** values, char** columns)
TRecordset_column_info* info = new TRecordset_column_info;
info->_name = columns[i];
info->_width = 1;
info->_type = _realfld;
info->_type = _alfafld;
const char* fldtype = columns[argc+i];
if (fldtype != NULL)
{
if (xvt_str_compare_ignoring_case(fldtype, "DATE") == 0)
{
info->_type = _datefld;
info->_width = 10;
} else
if (xvt_str_compare_ignoring_case(fldtype, "NUMERIC") == 0)
{
info->_type = _realfld;
}
}
_column.add(info);
}
}
@ -1045,8 +1116,6 @@ int TSQL_recordset::on_get_items(int argc, char** values, char** columns)
const int len = strlen(values[i]);
if (len > info._width)
info._width = len;
if (info._type != _alfafld && isalpha(*values[i]))
info._type = _alfafld;
}
}
@ -1057,8 +1126,7 @@ int TSQL_recordset::on_get_items(int argc, char** values, char** columns)
static int query_get_items(void* jolly, int argc, char** values, char** columns)
{
TSQL_recordset* q = (TSQL_recordset*)jolly;
q->on_get_items(argc, values, columns);
return SQLITE_OK;
return q->on_get_items(argc, values, columns);
}
void TSQL_recordset::parsed_sql_text(TString& sql) const
@ -1088,12 +1156,20 @@ void TSQL_recordset::parsed_sql_text(TString& sql) const
}
}
bool TSQL_recordset::ask_variables(bool all)
{
_page.destroy();
return TRecordset::ask_variables(all);
}
TRecnotype TSQL_recordset::items() const
{
if (_items == 0)
{
TString sql; parsed_sql_text(sql);
_TheDataBase.exec("PRAGMA show_datatypes = ON;", NULL, NULL);
_TheDataBase.exec(sql, query_get_items, (TSQL_recordset*)this);
_TheDataBase.exec("PRAGMA show_datatypes = OFF;", NULL, NULL);
}
return _items;
}
@ -1110,33 +1186,41 @@ const TRecordset_column_info& TSQL_recordset::column_info(unsigned int c) const
return (const TRecordset_column_info&)_column[c];
}
static int query_get_rows(void* jolly, int argc, char** values, char** columns)
int TSQL_recordset::on_get_rows(int argc, char** values, char** columns)
{
TArray& arr = *(TArray*)jolly;
TArray* a = new TArray;
for (int c = 0; c < argc; c++)
{
TVariant* var = new TVariant;
if (is_numeric(values[c]))
var->set(real(values[c]));
else
var->set(values[c]);
switch (column_info(c)._type)
{
case _alfafld: var->set(values[c]); break;
case _datefld: var->set(TDate(values[c])); break;
default : var->set(real(values[c])); break;
}
a->add(var, c);
}
arr.add(a);
_page.add(a);
return SQLITE_OK;
}
static int query_get_rows(void* jolly, int argc, char** values, char** columns)
{
TSQL_recordset* rs = (TSQL_recordset*)jolly;
return rs->on_get_rows(argc, values, columns);
}
bool TSQL_recordset::move_to(TRecnotype n)
{
_current_row = n;
if (n < 0 || n >= items())
{
_page.destroy(); // Forza rilettura la prossiva volta
_first_row = 0;
return false;
}
if (n < _firstrow || n >= _firstrow+_page.items())
if (n < _first_row || n >= _first_row+_page.items())
{
TString sql; parsed_sql_text(sql);
if (sql.find("LIMIT ") < 0)
@ -1147,12 +1231,12 @@ bool TSQL_recordset::move_to(TRecnotype n)
sql.trim();
_page.destroy();
if (n >= _pagesize)
_firstrow = n-_pagesize/8; // Prendo qualche riga dalla pagina precedente, per velocizzare il pagina su
_first_row = n-_pagesize/8; // Prendo qualche riga dalla pagina precedente, per velocizzare il pagina su
else
_firstrow = n;
sql << "\nLIMIT " << _pagesize << " OFFSET " << _firstrow << ';';
_first_row = n;
sql << "\nLIMIT " << _pagesize << " OFFSET " << _first_row << ';';
}
_TheDataBase.exec(sql, query_get_rows, &_page);
_TheDataBase.exec(sql, query_get_rows, this);
}
return true;
@ -1162,13 +1246,13 @@ const TArray* TSQL_recordset::row(TRecnotype n)
{
const TArray* a = NULL;
if (move_to(n))
a = (const TArray*)_page.objptr(n-_firstrow);
a = (const TArray*)_page.objptr(n-_first_row);
return a;
}
const TVariant& TSQL_recordset::get(unsigned int c) const
{
const TArray* a = (const TArray*)_page.objptr(_current_row-_firstrow);
const TArray* a = (const TArray*)_page.objptr(_current_row-_first_row);
if (a != NULL)
{
const TVariant* s = (const TVariant*)a->objptr(c);

View File

@ -113,7 +113,7 @@ public: // Absolutely needed methods
virtual const TString_array& variables() const { return _varnames; }
virtual const TVariant& get_var(const char* name) const;
virtual bool set_var(const char* name, const TVariant& var, bool create = false);
bool ask_variables(bool all);
virtual bool ask_variables(bool all);
virtual const TString& query_text() const;
virtual const TVariant& get(const char* column_name) const;
@ -130,7 +130,7 @@ class TSQL_recordset : public TRecordset
{
TString _sql;
TRecnotype _firstrow, _pagesize, _items, _current_row;
TRecnotype _first_row, _pagesize, _items, _current_row;
TArray _column;
TArray _page;
@ -145,6 +145,7 @@ public: // TRecordset
virtual unsigned int columns() const;
virtual const TRecordset_column_info& column_info(unsigned int c) const;
virtual const TVariant& get(unsigned int column) const;
virtual bool ask_variables(bool all);
const TString& query_text() const { return _sql; }
public:
@ -152,6 +153,7 @@ public:
// Internal use only
virtual int on_get_items(int argc, char** values, char** columns);
virtual int on_get_rows(int argc, char** values, char** columns);
const TArray* row(TRecnotype n);
TSQL_recordset(const char* sql);
@ -179,7 +181,8 @@ public:
///////////////////////////////////////////////////////////
bool select_custom_file(TFilename& path, const char* ext);
const TString& logic2table(int logic_num);
int table2logic(const TString& name);
#endif

View File

@ -208,16 +208,28 @@ void TReport_field_mask::update()
void TReport_field_mask::vedo_non_vedo()
{
const char type = get(F_TYPE)[0];
const bool is_text = strchr("DNPSTV", type) != NULL;
const bool is_currency = type == 'P' || type == 'V';
const bool is_numeric = is_currency || type == 'N';
const bool is_text = is_numeric || strchr("DST", type) != NULL;
show(F_HIDE_ZEROES, strchr("DNPV", type) != NULL),
show(F_HIDE_ZEROES, is_numeric || type == 'D'),
show(F_HALIGN, is_text);
if (is_numeric)
{
disable(F_HALIGN);
set(F_HALIGN, "R"); // Allineo a destra i numeri
}
else
enable(F_HALIGN);
show(F_VALIGN, is_text);
show(F_TEXT, is_text);
show(F_TEXT, is_text && !is_currency);
show(F_FGCOLOR, type != 'I');
show(F_BGCOLOR, type != 'L' && type != 'I');
show(F_BGCOLOR, type != 'L');
show(F_FONT_SELECT, is_text);
show(F_SOURCE, (is_text || type == 'I') && type != 'T');
show(F_CODVAL, is_currency); // Codice valuta di riferimento
show(F_LINK, strchr("DNS", type) != NULL); // Chi puo' essere un link?
if (is_running())
force_update();
@ -276,6 +288,8 @@ void TReport_field_mask::set_field(const TReport_field& rf)
set(F_DISABLED, rf.deactivated() ? "X" : "");
set(F_HIDE_ZEROES, rf.zeroes_hidden() ? "X" : "");
set(F_GROUPS, rf.groups());
set(F_CODVAL, rf.codval());
set(F_LINK, rf.link());
str[0] = rf.horizontal_alignment();
set(F_HALIGN, str);
@ -302,7 +316,8 @@ void TReport_field_mask::get_field(TReport_field& rf) const
rf.activate(!get_bool(F_DISABLED));
rf.hide_zeroes(get_bool(F_HIDE_ZEROES));
rf.set_groups(get(F_GROUPS));
rf.set_codval(get(F_CODVAL));
rf.set_link(get(F_LINK));
rf.set_horizontal_alignment(get(F_HALIGN)[0]);
rf.set_vertical_alignment(get(F_VALIGN)[0]);
rf.set_border(get_int(F_BORDER));

View File

@ -9,31 +9,33 @@
#define F_SEC_PROPERTIES 108
#define F_REP_PROPERTIES 109
#define F_TYPE 109
#define F_ID 110
#define F_X 111
#define F_Y 112
#define F_DX 113
#define F_DY 114
#define F_TEXT 115
#define F_SOURCE 116
#define F_HALIGN 117
#define F_VALIGN 118
#define F_BORDER 119
#define F_FGCOLOR 120
#define F_BGCOLOR 121
#define F_FONT_SELECT 122
#define F_HIDDEN 123
#define F_DISABLED 124
#define F_HIDE_ZEROES 125
#define F_PRESCRIPT 126
#define F_POSTSCRIPT 127
#define F_GROUPS 128
#define F_TYPE 120
#define F_ID 121
#define F_X 122
#define F_Y 123
#define F_DX 124
#define F_DY 125
#define F_TEXT 126
#define F_SOURCE 127
#define F_HALIGN 128
#define F_VALIGN 129
#define F_BORDER 130
#define F_FGCOLOR 131
#define F_BGCOLOR 132
#define F_FONT_SELECT 133
#define F_HIDDEN 134
#define F_DISABLED 135
#define F_HIDE_ZEROES 136
#define F_PRESCRIPT 137
#define F_POSTSCRIPT 138
#define F_GROUPS 139
#define F_CODVAL 140
#define F_LINK 141
#define F_LEVEL 130
#define F_GROUP_BY 131
#define F_HIDE_IF_NEEDED 132
#define F_PAGE_BREAK 133
#define F_LEVEL 160
#define F_GROUP_BY 161
#define F_HIDE_IF_NEEDED 162
#define F_PAGE_BREAK 163
#define F_SQL 201
#define F_IMPORT_QRY 202

View File

@ -67,6 +67,17 @@ BEGIN
PROMPT 1 3 "Gruppi "
END
STRING F_CODVAL 32 8
BEGIN
PROMPT 1 4 "Divisa "
FLAGS "U"
END
STRING F_LINK 34
BEGIN
PROMPT 21 4 "Collegamento "
END
MEMO F_TEXT 68 4
BEGIN
PROMPT 1 5 "@bTesto"

View File

@ -962,14 +962,30 @@ void TReport_field::draw_rect(TWindow& win) const
advanced_draw_rect(win, r, border(), fore_color(), back_color());
}
void TReport_field::draw_text(TWindow& win, const char* text) const
COLOR TReport_field::link_color() const
{
return COLOR_BLUE;
}
void TReport_field::draw_text(TWindow& win, const char* text, TReport_draw_mode rdm) const
{
const TRectangle& rct = get_rect();
RCT r; win.log2dev(rct, r);
advanced_draw_rect(win, r, border(), fore_color(), back_color());
xvt_dwin_set_font(win.win(), font().get_xvt_font(win));
win.set_color(fore_color(), back_color());
if (rdm == rdm_print_preview && link().not_empty())
{
XVT_FNTID lnkfont = xvt_font_create();
xvt_font_copy(lnkfont, font().get_xvt_font(win), XVT_FA_ALL);
xvt_font_set_style(lnkfont, XVT_FS_UNDERLINE);
xvt_dwin_set_font(win.win(), lnkfont);
win.set_color(link_color(), back_color());
}
else
{
xvt_dwin_set_font(win.win(), font().get_xvt_font(win));
win.set_color(fore_color(), back_color());
}
if (rct.height() > 100)
{
@ -991,7 +1007,7 @@ void TReport_field::draw_text(TWindow& win, const char* text) const
for (int row = 0; row < rows; row++)
{
TRectangle rctline = rct;
rctline.y = ybase+100*row;
rctline.y = ybase + 100*row;
rctline.set_height(100);
win.log2dev(rctline, r);
if (halign == 'J' && row == rows-1)
@ -1003,6 +1019,18 @@ void TReport_field::draw_text(TWindow& win, const char* text) const
advanced_draw_text(win, text, r, _halign, _valign);
}
void TReport_field::get_currency(TCurrency& cur) const
{
if (_codval.not_empty())
{
TVariant val;
section().report().evaluate(_codval, val, _alfafld);
cur.force_value(val.as_string());
}
cur.set_price(_type == 'P');
cur.set_num(_var.as_real());
}
const TString& TReport_field::formatted_text() const
{
if (_hide_zeroes && _var.is_zero())
@ -1041,17 +1069,10 @@ const TString& TReport_field::formatted_text() const
}
break;
case 'P':
{
TString& tmp = get_tmp_string();
TPrice cur(_var.as_real());
tmp = cur.string(true);
return tmp;
}
break;
case 'V':
{
TString& tmp = get_tmp_string();
TCurrency cur(_var.as_real());
TCurrency cur; get_currency(cur);
tmp = cur.string(true);
return tmp;
}
@ -1136,12 +1157,7 @@ void TReport_field::draw(TWindow& win, TReport_draw_mode rdm) const
}
break;
case 'R': draw_rect(win); break;
case 'T': draw_text(win, _picture); break;
case 'N':
case 'P':
case 'V':
if (zeroes_hidden() && _var.as_real().is_zero())
break;
case 'T': draw_text(win, _picture, rdm); break;
default :
if (rdm == rdm_edit)
{
@ -1153,15 +1169,16 @@ void TReport_field::draw(TWindow& win, TReport_draw_mode rdm) const
if (id() > 0)
{
TString16 str; str << id();
draw_text(win, str);
draw_text(win, str, rdm);
}
else
draw_text(win, _field);
draw_text(win, _field, rdm);
}
else
else // Real printing
{
const TString& str = formatted_text();
draw_text(win, str);
if (!str.blank())
draw_text(win, str, rdm);
}
break;
}
@ -1242,6 +1259,8 @@ void TReport_field::save(TXmlItem& root) const
};
fld.SetAttr("border", border());
fld.SetAttr("text", picture());
fld.SetAttr("codval", codval());
fld.SetAttr("link", link());
if (field().not_empty())
fld.AddChild("source") << field();
_prescript.save(fld, "prescript");
@ -1266,6 +1285,8 @@ bool TReport_field::load(const TXmlItem& fld)
set_horizontal_alignment(get_chr_attr(fld, "align", 'L'));
set_vertical_alignment(get_chr_attr(fld, "valign", 'B'));
set_picture(fld.GetAttr("text"));
set_codval(fld.GetAttr("codval"));
set_link(fld.GetAttr("link"));
TXmlItem* src = fld.FindFirstChild("source");
if (src != NULL)
src->GetEnclosedText(_field);
@ -1321,6 +1342,63 @@ TReport_field::~TReport_field()
delete _font;
}
///////////////////////////////////////////////////////////
// TReport_link
///////////////////////////////////////////////////////////
void TReport_link::set(const char* field, const TVariant& var)
{
_fields.add(field, var, true);
}
const TVariant& TReport_link::get(const char* field) const
{
const TVariant* var = (const TVariant*)_fields.objptr(field);
return var != NULL ? *var : NULL_VARIANT;
}
void TReport_link::add_rect(const RCT& rct)
{
// Non memorizzo tutti i rettangoli del link, ma la loro unione
if (xvt_rect_is_empty(&_rct))
_rct = rct;
else
{
if (rct.left < _rct.left) _rct.left = rct.left;
if (rct.top < _rct.top) _rct.top = rct.top;
if (rct.right > _rct.right) _rct.right = rct.right;
if (rct.bottom > _rct.bottom) _rct.bottom = rct.bottom;
}
}
int TReport_link::hit_test(const PNT& p) const
{
if (p.v < _rct.top)
return -1;
if (p.v > _rct.bottom)
return +1;
if (p.h < _rct.left)
return -1;
if (p.h > _rct.right)
return +1;
return 0;
}
int TReport_link::compare(const TSortable& s) const
{
const TReport_link& lnk = (const TReport_link&)s;
int cmp = _rct.top - lnk._rct.top;
if (cmp == 0)
cmp = _rct.left - lnk._rct.left;
return cmp;
}
TReport_link::TReport_link(const char* table)
: _table(table)
{
xvt_rect_set_empty(&_rct);
}
///////////////////////////////////////////////////////////
// TReport
///////////////////////////////////////////////////////////
@ -1608,6 +1686,7 @@ bool TReport::execute_prescript()
{
bool ok = true;
warm_restart();
if (_prescript.ok())
{
TString80 str;
@ -1863,6 +1942,25 @@ bool TReport::execute_usr_word(unsigned int opcode, TVariant_stack& stack)
return true;
}
bool TReport::on_link(const TReport_link& lnk)
{
const TString& table = lnk.table();
const int logicnum = table2logic(table);
if (logicnum >= LF_USER)
{
TRectype rec(logicnum);
TAssoc_array& fields = lnk.fields();
FOR_EACH_ASSOC_OBJECT(fields, h, k, o)
{
const TVariant* var = (const TVariant*)o;
rec.put(k, var->as_string());
}
return rec.edit();
}
return false;
}
TReport::TReport() : _lpi(6), _recordset(NULL), _curr_field(NULL)
{
// Brutte inizializzazioni, ma inevitabili

View File

@ -218,7 +218,7 @@ class TReport_field : public TSortable
short _border;
char _halign, _valign;
TBit_array _groups;
TString _picture, _field;
TString _picture, _field, _codval, _link;
TVariant _var;
TReport_script _prescript, _postscript;
@ -230,6 +230,7 @@ protected:
void copy(const TReport_field& rf);
TFieldtypes var_type() const;
const TString& formatted_text() const;
void get_currency(TCurrency& cur) const;
public:
virtual TObject* dup() const { return new TReport_field(*this); }
@ -284,11 +285,16 @@ public:
void set_groups(const TString& groups);
const TString& groups() const;
bool in_group(int group) const;
void set_codval(const char* cod) { _codval = cod; }
const TString& codval() const { return _codval; }
void set_link(const char* l) { _link = l; }
const TString& link() const { return _link; } // TABLE.FIELD
void set_fore_color(COLOR c) { _fgcolor = c; }
COLOR fore_color() const { return _fgcolor; }
void set_back_color(COLOR c) { _bgcolor = c; }
COLOR back_color() const { return _bgcolor; }
COLOR link_color() const;
void set_border(short b) { _border = b; }
short border() const { return _border; }
void set_horizontal_alignment(char a) { _halign = a; }
@ -306,7 +312,7 @@ public:
void offset(const TPoint& pt);
virtual void draw_rect(TWindow& win) const;
virtual void draw_text(TWindow& win, const char* text) const;
virtual void draw_text(TWindow& win, const char* text, TReport_draw_mode mode) const;
virtual void draw(TWindow& win, TReport_draw_mode mode) const;
void save(TXmlItem& root) const;
@ -317,6 +323,29 @@ public:
virtual ~TReport_field();
};
class TReport_link : public TSortable
{
TString _table;
TAssoc_array _fields;
RCT _rct;
protected:
virtual int compare(const TSortable& s) const;
public:
const TString& table() const { return _table; }
void set(const char* field, const TVariant& value);
const TVariant& get(const char* field) const;
void add_rect(const RCT& rct); // Aggiunge un rettangolo al link
int hit_test(const PNT& p) const;
TAssoc_array& fields() const { return (TAssoc_array&)_fields; }
TReport_link(const char* table);
virtual ~TReport_link() { }
};
// Internal usage only
typedef void (*FLDMSG_FUNC)(TReport_field& rf, void* jolly);
class TReport : public TAlex_virtual_machine
@ -355,6 +384,8 @@ public:
bool kill_section(char type, int level);
int find_max_level(char type) const;
virtual bool on_link(const TReport_link& link);
const TReport_font& font() const { return _font; }
void set_font(const TReport_font& f) { _font = f; }
void unmap_font();

View File

@ -16,6 +16,7 @@ class TPrint_preview_window : public TField_window
TPage_printer* _printer;
word _page, _last;
int _zoom;
static bool _locked;
protected:
void page_select();
@ -26,12 +27,15 @@ protected:
public:
virtual PNT log2dev(long lx, long ly) const;
static void lock_preview_update(bool yes) { _locked = yes; }
void set_printer(TPage_printer* printer) { _printer = printer; }
TPrint_preview_window(int x, int y, int dx, int dy, WINDOW parent,
TWindowed_field* owner, TPage_printer* printer);
};
bool TPrint_preview_window::_locked = false;
PNT TPrint_preview_window::log2dev(long lx, long ly) const
{
PNT pnt;
@ -47,7 +51,8 @@ PNT TPrint_preview_window::log2dev(long lx, long ly) const
void TPrint_preview_window::update()
{
_printer->print_page(_page);
if (!_locked)
_printer->print_page(_page);
}
#define POPUP_FIRST 20883
@ -96,8 +101,20 @@ void TPrint_preview_window::handler(WINDOW win, EVENT* ep)
{
switch (ep->type)
{
case E_MOUSE_MOVE:
if (_printer->find_link(ep->v.mouse.where) != NULL)
xvt_win_set_cursor(win, CURSOR_CROSS);
else
xvt_win_set_cursor(win, CURSOR_ARROW);
break;
case E_MOUSE_DOWN:
if (ep->v.mouse.button != 0)
if (ep->v.mouse.button == 0)
{
const TReport_link* lnk = _printer->find_link(ep->v.mouse.where);
if (lnk != NULL)
_printer->on_link(*lnk);
}
else
popup_menu(ep);
break;
case E_COMMAND:
@ -154,7 +171,8 @@ bool TPrint_preview_window::on_key(KEY k)
TPrint_preview_window::TPrint_preview_window(int x, int y, int dx, int dy, WINDOW parent,
TWindowed_field* owner, TPage_printer* printer)
: TField_window(x, y, dx, dy, parent, owner), _printer(printer), _page(1), _last(0), _zoom(100)
: TField_window(x, y, dx, dy, parent, owner), _printer(printer),
_page(1), _last(0), _zoom(100)
{
RCT r; xvt_vobj_get_client_rect(win(), &r);
_zoom = 100 * r.right / 800;
@ -301,6 +319,8 @@ TPreview_mask::TPreview_mask(TPage_printer* printer)
// TPage_printer
///////////////////////////////////////////////////////////
static bool _print_aborted = false;
const char* TPage_printer::form_name() const
{
return printer().get_form_name();
@ -368,6 +388,7 @@ bool TPage_printer::main_loop()
if (!ok)
return false;
}
_print_aborted = false;
for (word c = 0; c < _copies && ok; c++)
{
@ -411,7 +432,12 @@ bool TPage_printer::open_page()
if (print_mode())
_page_is_open = xvt_print_open_page(_rcd) != 0;
else
{
_page_is_open = true;
_links.destroy(); // Distrugge elenco dei links
_links_sorted = false;
}
}
else
_page_is_open = false;
@ -432,6 +458,12 @@ bool TPage_printer::close_page()
return was_open;
}
void TPage_printer::add_link(TReport_link* link)
{
_links.add(link);
_links_sorted = false;
}
static BOOLEAN main_loop_callback(long jolly)
{
TPage_printer* pp = (TPage_printer*)jolly;
@ -440,6 +472,7 @@ static BOOLEAN main_loop_callback(long jolly)
bool TPage_printer::do_print()
{
_print_aborted = true;
bool ok = ask_pages();
if (ok)
ok = xvt_print_start_thread(main_loop_callback, long(this)) == FALSE;
@ -455,6 +488,8 @@ void TPage_printer::print_page(word page)
bool TPage_printer::do_preview()
{
_print_aborted = true;
TPrinter& p = printer();
_rcd = p.get_printrcd();
if (!xvt_print_is_valid(_rcd))
@ -470,6 +505,7 @@ bool TPage_printer::do_preview()
set_win(_preview_window->win());
_pagefrom = _pageto = _page = 1;
_print_aborted = false;
const KEY key = _preview_mask->run();
set_win(NULL_WIN);
@ -482,6 +518,36 @@ bool TPage_printer::do_preview()
return true;
}
const TReport_link* TPage_printer::find_link(const PNT& pnt) const
{
if (!_links_sorted)
{
TPage_printer* myself = (TPage_printer*)this;
myself->_links.sort();
myself->_links_sorted = true;
}
int primo = 0, ultimo = _links.last();
while (primo <= ultimo)
{
const int in_mezzo = (primo+ultimo)/2;
const TReport_link* lnk = (const TReport_link*)_links.objptr(in_mezzo);
const int cmp = lnk->hit_test(pnt);
if (cmp == 0)
return lnk;
if (cmp < 0)
ultimo = in_mezzo-1;
else
primo = in_mezzo+1;
}
return NULL;
}
bool TPage_printer::on_link(const TReport_link& lnk)
{
return false;
}
bool TPage_printer::print(bool prev_mode)
{
return prev_mode ? do_preview() : do_print();
@ -611,8 +677,42 @@ bool TReport_printer::close_page()
return TPage_printer::close_page();
}
void TReport_printer::create_links(const TReport_section& rs)
{
TAssoc_array* links = NULL;
for (int i = 0; i < rs.items(); i++)
{
const TReport_field& rf = rs.field(i);
if (rf.link().not_empty())
{
if (links == NULL)
links = new TAssoc_array;
TToken_string tok(rf.link(), '.');
TString table, field;
tok.get(0, table); tok.get(1, field);
TReport_link* rl = (TReport_link*)links->objptr(table);
if (rl == NULL)
{
rl = new TReport_link(table);
links->add(table, rl);
}
RCT rct; TWindow::log2dev(rf.get_rect(), rct);
rl->add_rect(rct);
rl->set(field, rf.get());
}
}
if (links != NULL)
{
FOR_EACH_ASSOC_OBJECT((*links), h, key, l)
add_link((TReport_link*)l);
}
}
long TReport_printer::print_section(TReport_section& rs)
{
if (_print_aborted)
return 0;
rs.load_fields();
rs.execute_prescript();
const long height = rs.compute_size().y; // Compute size after the initilization script!
@ -628,13 +728,16 @@ long TReport_printer::print_section(TReport_section& rs)
open_page();
}
if (_page_is_open)
rs.draw(*this, rdm_print);
rs.draw(*this, preview_mode() ? rdm_print_preview : rdm_print);
if (rs.level() > 0) // Ho stampa qualcosa che non sia lo sfondo!
_page_break_allowed = true;
}
rs.execute_postscript();
if (_page_is_open && preview_mode())
create_links(rs);
return height;
}
@ -677,7 +780,7 @@ bool TReport_printer::print_loop()
bool aborted = false;
for (bool ok = rex.move_to(0); ok; ok = rex.move_next())
{
if (_pageto >= _pagefrom && _page > _pageto) // out of range
if (_pageto >= _pagefrom && _page > _pageto || _print_aborted) // out of range
{
aborted = true;
break;
@ -691,7 +794,8 @@ bool TReport_printer::print_loop()
{
const TString& expr = _report.section('H', g).grouped_by();
_report.evaluate(expr, var, _alfafld);
newgroup.add(var.as_string(), g);
const TString& grp = var.as_string();
newgroup.add(grp, g);
if (newgroup.row(g) != oldgroup.row(g) || rex.current_row() == 0)
changed = g;
}
@ -769,3 +873,19 @@ bool TReport_printer::print(bool preview_mode)
return ok;
}
bool TReport_printer::on_link(const TReport_link& lnk)
{
return _report.on_link(lnk);
}
///////////////////////////////////////////////////////////
// Remote control interface
///////////////////////////////////////////////////////////
void lock_preview_update(bool yes)
{ TPrint_preview_window::lock_preview_update(yes); }
void abort_printing()
{ _print_aborted = true; }

View File

@ -9,6 +9,8 @@ class TPage_printer : public TWindow
{
PRINT_RCD* _rcd;
long _pw, _ph, _phr, _pvr; // Printer width, height, horizontal and vertical resolution
TArray _links;
bool _links_sorted;
protected:
word _copies, _pagefrom, _pageto, _page, _lastprinted;
@ -54,6 +56,10 @@ public:
void toggle_preview_grid() { _draw_grid = !_draw_grid; }
bool show_preview_grid() const { return _draw_grid; }
void add_link(TReport_link* link);
const TReport_link* find_link(const PNT& pnt) const;
virtual bool on_link(const TReport_link& lnk);
TPage_printer();
virtual ~TPage_printer();
};
@ -79,15 +85,16 @@ protected:
virtual bool close_page();
long print_section(TReport_section& rs);
long print_section(char type, int level);
void create_links(const TReport_section& rs);
public:
virtual bool print(bool preview = false);
virtual bool on_link(const TReport_link& lnk);
TReport_printer(TReport& r) : _report(r) { }
};
void advanced_draw_rect(TWindow& win, const RCT& r, int border, COLOR fore, COLOR back);
void advanced_draw_text(TWindow& win, const char* text, const RCT& r,
char halign, char valign);
void lock_preview_update(bool yes);
void abort_printing();
#endif

View File

@ -1,7 +1,10 @@
#include <ctype.h>
#include <stdlib.h>
#include <automask.h>
#include <colors.h>
#include <prefix.h>
#include "ba8303.h"
#include "ba8304.h"
TVariant& TVariant_stack::peek(int depth)
@ -59,15 +62,66 @@ bool TVariant_stack::push(const real& n)
return push(var);
}
bool TVariant_stack::push(const TString& str)
{
const TVariant var(str);
return push(var);
}
void TVariant_stack::reset()
{
_sp = 0;
}
///////////////////////////////////////////////////////////
// TAVM_op
///////////////////////////////////////////////////////////
enum AVM_opcode { avm_nop, avm_add, avm_div, avm_dot,
avm_cmp_eq, avm_cmp_gt, avm_cmp_gteq, avm_cmp_lt, avm_cmp_lteq, avm_cmp_noteq,
avm_drop, avm_dup, avm_else,
avm_fetch, avm_if, avm_push, avm_rot, avm_store,
avm_sub, avm_swap, avm_then, avm_usrword };
enum AVM_opcode
{
avm_nop,
avm_add, avm_and,
avm_begin,
avm_call_word, avm_cold,
avm_cmp_eq, avm_cmp_gt, avm_cmp_gteq, avm_cmp_lt, avm_cmp_lteq, avm_cmp_noteq,
avm_div, avm_do, avm_dot, avm_drop, avm_dup,
avm_else, avm_execute,
avm_false, avm_fetch,
avm_if,
avm_loop,
avm_mon, avm_mul,
avm_or, avm_over,
avm_push,
avm_repeat, avm_rdrop, avm_rpeek, avm_rpush, avm_rot,
avm_store, avm_sub, avm_swap,
avm_then, avm_true,
avm_usrword,
avm_warm, avm_while,
avm_zzz
};
const char* AVM_TOKENS[avm_zzz+1] =
{
"$NOP$",
"+", "AND",
"BEGIN",
"$CALL_WORD$", "COLD",
"=", ">", ">=", "<", "<=", "<>",
"/", "DO", ".", "DROP", "DUP",
"ELSE", "EXECUTE",
"FALSE", "@",
"IF",
"LOOP",
"MON", "*",
"OR", "OVER",
"PUSH",
"REPEAT", "R>", "R@", ">R", "ROT",
"!", "-", "SWAP",
"THEN", "TRUE",
"#",
"WARM", "WHILE"
};
class TAVM_op : public TObject
{
@ -101,6 +155,186 @@ TAVM_op::TAVM_op(AVM_opcode o)
: _op(o)
{ }
///////////////////////////////////////////////////////////
// TAVM_monitor
///////////////////////////////////////////////////////////
class TAVM_list_window : public TField_window
{
const TBytecode* _bc;
int _ip;
protected:
virtual void update();
public:
void set_bytecode(const TBytecode* bc, int ip);
TAVM_list_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
};
void TAVM_list_window::update()
{
clear(NORMAL_BACK_COLOR);
if (_bc != NULL)
{
set_brush(DISABLED_BACK_COLOR);
bar(0, 0, 5, _bc->items());
set_brush(NORMAL_BACK_COLOR);
TString str;
int tab = 6;
const int first = origin().y;
const int last = min(_bc->items(), first+rows());
for (int i = first; i < last; i++)
{
if (_ip == i)
{
set_brush(FOCUS_BACK_COLOR);
bar(0, i, 80, i+1);
set_brush(NORMAL_BACK_COLOR);
}
printat(0, i, "%04d", i);
const TAVM_op& op = *(const TAVM_op*)_bc->objptr(i);
const AVM_opcode co = op.op();
const TVariant& var = op.var();
if (co == avm_else || co == avm_then)
tab -= 2;
if (co == avm_push)
{
if (var.type() == _alfafld && var.as_string()[0] != '#')
str.cut(0) << '"' << var.as_string() << '"';
else
str = var.as_string();
} else
if (co == avm_call_word)
{
str = var.as_string();
}
else
{
str = AVM_TOKENS[co];
if (!var.is_null())
str << " (" << var.as_string() << ')';
}
printat(tab, i, str);
if (co == avm_if || co == avm_else)
tab += 2;
}
}
}
void TAVM_list_window::set_bytecode(const TBytecode* bc, int ip)
{
_bc = bc;
_ip = ip;
set_scroll_max(80, _bc->items() - rows());
}
TAVM_list_window::TAVM_list_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner)
: TField_window(x, y, dx, dy, parent, owner), _bc(NULL)
{
autoscroll(true);
}
class TAVM_stack_window : public TField_window
{
TVariant_stack* _stack;
protected:
virtual void update();
public:
void set_stack(TVariant_stack& s);
TAVM_stack_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner);
};
void TAVM_stack_window::update()
{
clear(NORMAL_BACK_COLOR);
if (_stack != NULL)
{
for (int i = 0; i < _stack->items(); i++)
printat(0, i, _stack->peek(i).as_string());
}
}
void TAVM_stack_window::set_stack(TVariant_stack& s)
{
_stack = &s;
set_scroll_max(80, s.items() - rows());
}
TAVM_stack_window::TAVM_stack_window(int x, int y, int dx, int dy, WINDOW parent, TWindowed_field* owner)
: TField_window(x, y, dx, dy, parent, owner), _stack(NULL)
{
autoscroll(true);
}
class TAVM_list_field : public TWindowed_field
{
protected:
virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent);
public:
TAVM_list_field(TMask* m) : TWindowed_field(m) { }
virtual ~TAVM_list_field() { }
};
TField_window* TAVM_list_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
{
return new TAVM_list_window(x, y, dx, dy, parent, this);
}
class TAVM_stack_field : public TWindowed_field
{
protected:
virtual TField_window* create_window(int x, int y, int dx, int dy, WINDOW parent);
public:
TAVM_stack_field(TMask* m) : TWindowed_field(m) { }
virtual ~TAVM_stack_field() { }
};
TField_window* TAVM_stack_field::create_window(int x, int y, int dx, int dy, WINDOW parent)
{
return new TAVM_stack_window(x, y, dx, dy, parent, this);
}
class TAVM_monitor : public TAutomask
{
protected:
TMask_field* parse_field(TScanner& scanner);
virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly);
public:
TAVM_list_window& monitor() { return (TAVM_list_window&)((TAVM_list_field&)field(101)).win(); }
TAVM_stack_window& stacker() { return (TAVM_stack_window&)((TAVM_list_field&)field(102)).win(); }
TAVM_monitor();
};
bool TAVM_monitor::on_field_event(TOperable_field& o, TField_event e, long jolly)
{
return true;
}
TMask_field* TAVM_monitor::parse_field(TScanner& scanner)
{
if (scanner.token().starts_with("LI"))
return new TAVM_list_field(this);
if (scanner.token().starts_with("ST"))
return new TAVM_stack_field(this);
return TAutomask::parse_field(scanner);
}
TAVM_monitor::TAVM_monitor()
{
read_mask("ba8304", 0, -1);
set_handlers();
}
///////////////////////////////////////////////////////////
// TAVM
///////////////////////////////////////////////////////////
@ -109,21 +343,31 @@ class TAVM
{
TAlex_virtual_machine* _vm;
TString _last_error;
TVariant_stack _stack;
TVariant_stack _stack, _rstack;
const TBytecode* _bc; // Current word (or command line)
int _ip; // Current instruction pointer
TAssoc_array _words;
TAVM_monitor _mon;
protected:
bool get_token(istream& instr, TString& str) const;
AVM_opcode token2opcode(const TString& str) const;
void log_error(const char* str);
int compare_tos_nos();
int find_matching(const TBytecode& bytecode, AVM_opcode op1, AVM_opcode op2 = avm_nop) const;
void execute(const TAVM_op& op);
void do_call(const TString& func);
public:
const TString& get_last_error() const { return _last_error; }
bool compile(istream& instr, TBytecode& bc);
bool execute(const TBytecode& bc, ostream& outstr);
void restart(bool cold);
TAVM(TAlex_virtual_machine* vm) : _vm(vm) { }
TAVM(TAlex_virtual_machine* vm);
virtual ~TAVM();
};
void TAVM::log_error(const char* str)
@ -161,31 +405,39 @@ bool TAVM::get_token(istream& instr, TString& str) const
return *str > ' ';
}
#define ALEX_TOKENS 24
AVM_opcode TAVM::token2opcode(const TString& str) const
{
const char* AVM_TOKENS[20] = {
"+", "-", ".", "!", "@", "/",
"=", "<>", ">", "<", ">=", "<=",
"DROP", "DUP", "ELSE", "IF", "ROT",
"SWAP", "THEN",
NULL
};
AVM_opcode AVM_OPCODES[20] = {
avm_add, avm_sub, avm_dot, avm_store, avm_fetch, avm_div,
avm_cmp_eq, avm_cmp_noteq, avm_cmp_gt, avm_cmp_lt, avm_cmp_gteq, avm_cmp_lteq,
avm_drop, avm_dup, avm_else, avm_if, avm_rot, avm_swap, avm_then,
avm_nop
};
for (int i = 0; AVM_TOKENS[i] != NULL; i++)
{
if (str == AVM_TOKENS[i])
return AVM_OPCODES[i];
return AVM_opcode(i);
}
const TBytecode* bc =(const TBytecode*)_words.objptr(str);
if (bc != NULL)
return avm_call_word;
return avm_nop;
}
int TAVM::find_matching(const TBytecode& bytecode, AVM_opcode op1, AVM_opcode op2) const
{
int i;
for (i = bytecode.last(); i >= 0; i--)
{
TAVM_op& theop = (TAVM_op&)bytecode[i];
if ((theop.op() == op1 || theop.op() == op2) && theop.var().is_null())
{
theop.var() = bytecode.items();
break;
}
}
return i;
}
bool TAVM::compile(istream& instr, TBytecode& bytecode)
{
TString str(256);
@ -199,7 +451,7 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
str.rtrim(1); str.ltrim(1);
op = new TAVM_op(avm_push, str);
} else
if (isdigit(str[0]))
if (isdigit(str[0]) || (str[0]=='-' && isdigit(str[1])))
{
const real r(str);
op = new TAVM_op(avm_push, r);
@ -207,7 +459,27 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
if (str[0] == '#') // User variable
{
op = new TAVM_op(avm_push, str);
}
} else
if (str == ":") // User word
{
if (get_token(instr, str))
{
TBytecode* bc = new TBytecode;
bc->set_name(str);
_words.add(str, bc);
compile(instr, *bc);
}
else
{
_last_error = "Missing word after :";
log_error(_last_error);
return false;
}
} else
if (str == ";")
{
return true;
}
else
{
const AVM_opcode oc = token2opcode(str);
@ -216,44 +488,38 @@ bool TAVM::compile(istream& instr, TBytecode& bytecode)
switch (oc)
{
case avm_else:
if (find_matching(bytecode, avm_if) < 0)
{
for (int i = bytecode.last(); i >= 0; i--)
{
TAVM_op& ifop = (TAVM_op&)bytecode[i];
if (ifop.op() == avm_if && ifop.var().is_null())
{
ifop.var() = bytecode.items();
break;
}
}
if (i < 0)
{
_last_error = "ELSE without matching IF";
log_error(_last_error);
return false;
}
_last_error = "ELSE without matching IF";
log_error(_last_error);
return false;
}
op = new TAVM_op(oc);
break;
case avm_then:
if (find_matching(bytecode, avm_if, avm_else) < 0)
{
for (int i = bytecode.last(); i >= 0; i--)
_last_error = "THEN without matching IF";
log_error(_last_error);
return false;
}
op = new TAVM_op(oc);
break;
case avm_repeat:
{
const int begin_pos = find_matching(bytecode, avm_begin);
if (begin_pos < 0)
{
TAVM_op& ifop = (TAVM_op&)bytecode[i];
if ((ifop.op() == avm_if || ifop.op() == avm_else) && ifop.var().is_null())
{
ifop.var() = bytecode.items();
break;
}
}
if (i < 0)
{
_last_error = "THEN without matching IF";
_last_error = "REPEAT without matching BEGIN";
log_error(_last_error);
return false;
}
find_matching(bytecode, avm_while);
op = new TAVM_op(oc, begin_pos);
}
op = new TAVM_op(oc);
break;
case avm_call_word:
op = new TAVM_op(oc, str);
break;
default:
op = new TAVM_op(oc);
@ -283,111 +549,216 @@ int TAVM::compare_tos_nos()
{
const TVariant& v0 = _stack.pop();
const TVariant& v1 = _stack.pop();
return v0.compare(v1);
return v1.compare(v0);
}
bool TAVM::execute(const TBytecode& bc, ostream& outstr)
void TAVM::do_call(const TString& func)
{
for (int ip = 0; ip < bc.items(); ip++)
_rstack.push(_bc->name());
_rstack.push(_ip+1);
_ip = -1; // will be incremented!
_bc = (TBytecode*)_words.objptr(func);
}
void TAVM::execute(const TAVM_op& op)
{
switch(op.op())
{
const TAVM_op& op = *(const TAVM_op*)bc.objptr(ip);
switch(op.op())
case avm_add :
{
case avm_add :
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
v0.add(v1);
}
break;
case avm_cmp_eq:
_stack.push(compare_tos_nos() == 0);
break;
case avm_cmp_gt:
_stack.push(compare_tos_nos() > 0);
break;
case avm_cmp_gteq:
_stack.push(compare_tos_nos() >= 0);
break;
case avm_cmp_lt:
_stack.push(compare_tos_nos() < 0);
break;
case avm_cmp_lteq:
_stack.push(compare_tos_nos() <= 0);
break;
case avm_cmp_noteq:
_stack.push(compare_tos_nos() != 0);
break;
case avm_div:
{
const real& r0 = _stack.pop().as_real();
const real& r1 = _stack.pop().as_real();
real n;
if (!r0.is_zero())
n = r1 / r0;
const TVariant var(n);
_stack.push(var);
}
break;
case avm_dot: outstr << _stack.pop().as_string(); break;
case avm_drop: _stack.drop(); break;
case avm_dup: _stack.push(_stack.peek()); break;
case avm_else:
ip = op.var().as_int();
break;
case avm_fetch:
{
const TString& name = _stack.pop().as_string();
TVariant var;
if (name[0] == '#')
_vm->get_usr_val(name, var);
else
{
// TBI: Get global var
}
_stack.push(var);
}
break;
case avm_if:
if (!_stack.pop().as_bool())
ip = op.var().as_int();
break;
case avm_push: _stack.push(op.var()); break;
case avm_rot: _stack.roll(2); break;
case avm_store:
{
const TString& name = _stack.pop().as_string();
const TVariant& var = _stack.pop();
if (name[0] == '#')
_vm->set_usr_val(name, var);
else
{
// TBI: Set global var
}
}
break;
case avm_sub :
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
v0.sub(v1);
}
break;
case avm_swap: _stack.roll(1); break;
case avm_then: break;
case avm_usrword:
{
const long usrword = op.var().as_int();
_vm->execute_usr_word(usrword, _stack);
}
break;
default:
_last_error << "Bad op code: " << op.op() << '\n';
log_error(_last_error);
return false;
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
v0.add(v1);
}
break;
case avm_and :
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
const long r = v0.as_int() & v1.as_int();
v0.set(r);
}
break;
case avm_call_word: do_call(op.var().as_string()); break;
case avm_cold: restart(true); _bc = NULL; break;
case avm_cmp_eq : _stack.push(compare_tos_nos() == 0); break;
case avm_cmp_gt : _stack.push(compare_tos_nos() > 0); break;
case avm_cmp_gteq : _stack.push(compare_tos_nos() >= 0); break;
case avm_cmp_lt : _stack.push(compare_tos_nos() < 0); break;
case avm_cmp_lteq : _stack.push(compare_tos_nos() <= 0); break;
case avm_cmp_noteq: _stack.push(compare_tos_nos() != 0); break;
case avm_div:
{
const real& r0 = _stack.pop().as_real();
const real& r1 = _stack.pop().as_real();
real n;
if (!r0.is_zero())
n = r1 / r0;
_stack.push(n);
}
break;
case avm_do: break;
case avm_dot: /* *_outstr << _stack.pop().as_string(); */ break;
case avm_drop: _stack.drop(); break;
case avm_dup: _stack.push(_stack.peek()); break;
case avm_else:
_ip = op.var().as_int();
break;
case avm_execute: do_call(_stack.pop().as_string()); break;
case avm_false: _stack.push(0L); break;
case avm_fetch:
{
const TString& name = _stack.pop().as_string();
TVariant var;
if (name[0] == '#')
_vm->get_usr_val(name, var);
else
{
// TBI: Get global var
}
_stack.push(var);
}
break;
case avm_if:
if (_stack.pop().is_zero())
_ip = op.var().as_int();
break;
case avm_loop: break;
case avm_mon:
{
lock_preview_update(true);
TAVM_list_window& monitor = _mon.monitor();
monitor.set_bytecode(_bc, _ip);
if (!_mon.is_open())
_mon.open();
}
break;
case avm_mul:
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
const real m = v0.as_real() * v1.as_real();
v0.set(m);
}
break;
case avm_or:
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
const long r = v0.as_int() | v1.as_int();
v0.set(r);
}
break;
case avm_over: _stack.push(_stack.peek(1)); break;
case avm_push: _stack.push(op.var()); break;
case avm_repeat: _ip = op.var().as_int(); break;
case avm_rdrop: _stack.push(_rstack.pop()); break;
case avm_rpeek: _stack.push(_rstack.peek()); break;
case avm_rpush: _rstack.push(_stack.pop()); break;
case avm_rot: _stack.roll(2); break;
case avm_store:
{
const TString& name = _stack.pop().as_string();
const TVariant& var = _stack.pop();
if (name[0] == '#')
_vm->set_usr_val(name, var);
else
{
// TBI: Set global var
}
}
break;
case avm_sub :
{
const TVariant& v1 = _stack.pop();
TVariant& v0 = (TVariant&)_stack.peek();
v0.sub(v1);
}
break;
case avm_swap: _stack.roll(1); break;
case avm_then: break;
case avm_true: _stack.push(1L); break;
case avm_usrword:
{
const long usrword = op.var().as_int();
_vm->execute_usr_word(usrword, _stack);
}
break;
case avm_warm: restart(false); _bc = NULL; break;
case avm_while: _ip = op.var().as_int(); break; // Jump to BEGIN
default:
_last_error << "Unimplemented op code: " << op.op() << '\n';
log_error(_last_error);
_bc = NULL; // force exit
break;
}
return true;
}
bool TAVM::execute(const TBytecode& cmdline, ostream& outstr)
{
_bc = &cmdline;
_ip = 0;
while (_bc != NULL)
{
if (_ip >= _bc->items()) // Fine funzione
{
if (_rstack.items() >= 2) // Controllo il return stack
{
_ip = _rstack.pop().as_int();
const TString& str = _rstack.pop().as_string();
if (str.blank())
_bc = &cmdline;
else
_bc = (const TBytecode*)_words.objptr(str);
}
else
break; // Fine esecuzione
}
if (_mon.is_open()) // Gestione debugger
{
lock_preview_update(true);
TAVM_list_window& monitor = _mon.monitor();
monitor.set_bytecode(_bc, _ip);
TAVM_stack_window& stacker = _mon.stacker();
stacker.set_stack(_stack);
const KEY k = _mon.run();
switch (k)
{
case K_NEXT: monitor.force_update(); stacker.force_update(); break;
case K_DEL : abort_printing();
case K_QUIT: _mon.close(); lock_preview_update(false); break;
default: break;
}
}
const TAVM_op& op = *(const TAVM_op*)_bc->objptr(_ip);
execute(op);
_ip++;
}
if (_mon.is_open()) // Chiudi debugger
{
_mon.close();
lock_preview_update(false);
}
return _bc != NULL;
}
void TAVM::restart(bool cold)
{
_stack.reset();
_rstack.reset();
}
TAVM::TAVM(TAlex_virtual_machine* vm)
: _vm(vm)
{ }
TAVM::~TAVM()
{
}
///////////////////////////////////////////////////////////
@ -432,6 +803,16 @@ bool TAlex_virtual_machine::execute(const TBytecode& bc, TString& outs)
return execute(bc, outstr);
}
void TAlex_virtual_machine::warm_restart() // Ripartenza a caldo
{
avm().restart(false);
}
void TAlex_virtual_machine::cold_restart() // Ripartenza a freddo
{
avm().restart(true);
}
bool TAlex_virtual_machine::get_usr_val(const TString& name, TVariant& var) const
{
if (name == "#TODAY")

View File

@ -20,6 +20,8 @@ public:
bool push(const TVariant& var);
bool push(long n);
bool push(const real& n);
bool push(const TString& str);
void reset();
TVariant_stack() : _sp(0) { }
};
@ -31,7 +33,7 @@ class TBytecode : public TArray
TString _name;
public:
const set_name(const char* name) { _name = name; }
void set_name(const char* name) { _name = name; }
const TString& name() const { return _name; }
};
@ -57,6 +59,8 @@ public:
bool compile(const char* cmd, TBytecode& bc);
bool execute(const TBytecode& bc, ostream& outstr);
bool execute(const TBytecode& bc, TString& outstr);
void warm_restart();
void cold_restart();
TAlex_virtual_machine();
virtual ~TAlex_virtual_machine();