campo-sirio/src/include/transaction.cpp
Alessandro Bonazzi 706303297c Patch level : 12.0 1086
Files correlati     : bs0.exe bs0500a.msk ba3.exe cg0.exe ve0.exe ve2.exe

Commento        :

Importazione Bee Store
2021-10-04 22:05:52 +02:00

819 lines
21 KiB
C++

#include <array.h>
#include <config.h>
#include <execp.h>
#include <diction.h>
#include <isam.h>
#include <strings.h>
#include <transaction.h>
#include <utility.h>
#include <tabutil.h>
#include <tabmod.h>
#include <xml.h>
const char* TTransaction::build_rowkey(const char * table, int row) const
{
TString& tmp = get_tmp_string();
tmp << table;
if (row > 0)
tmp << format(",%03d", row);
return tmp;
}
const char * TTransaction::get_rowkey_logicnum(const TString & var) const
{
const int pos = var.find(",");
if (pos > 0)
return var.left(pos);
return var;
}
int TTransaction::get_rowkey_row(const TString & var) const
{
const int pos = var.find(",");
if (pos > 0)
return atoi(var.mid(pos + 1));
return 0;
}
const char* TTransaction::build_varkey(const char* var, int index) const
{
if (index >= 0)
{
TString& tmp = get_tmp_string();
tmp << var << '(' << index << ')';
return tmp;
}
return var;
}
int TTransaction::get_varkey_index(const TString & var) const
{
const int pos = var.find(",");
if (pos > 0)
return atoi(var.mid(pos + 1));
return -1;
}
const char * TTransaction::get_varkey_name(const TString & var) const
{
const int pos = var.find(",");
if (pos > 0)
return var.left(pos);
return var;
}
TTransaction & TTransaction::copy(const TTransaction & t)
{
_head = t._head;
_rows = t._rows;
_file = t._file;
_type = t._type;
_executer = t._executer;
return *this;
}
// @doc EXTERNAL
// @mfunc Controlla se esite una variabile
//
// @rdesc Ritorna i seguenti valori:
//
// @flag true | Se la variabile esiste
// @flag false | Se la variabile non esiste
bool TTransaction::exist(
const char* var, // @parm Nome della variabile
int index, // @parm Indice dell'elemento dell'array (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) // @parm riga
// @comm Se <p index> e' <gt>= 0 viene costruito il nome dell'elemento
// dell'array da cercare, diversamente viene cercata la variabile
// normale passata in <p var>.
{
const char* key = build_varkey(var, index);
if (!table || *table == '\0')
return _head.is_key(key);
else
{
const char* rowkey = build_rowkey(table, row);
TAssoc_array * row_data = (TAssoc_array *)_rows.objptr(rowkey);
if (row_data != nullptr)
return row_data->is_key(key);
}
return false;
}
// @doc EXTERNAL
// @mfunc Elimina una variabile
//
// @rdesc Ritorna i seguenti valori:
//
// @flag TRUE | Se la variabile esiteva
// @flag FALSE | Se la variabile non esiteva
bool TTransaction::remove(
const char* var, // @parm Nome della variabile
int index, // @parm Indice dell'elemento dell'array (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) // @parm riga
// @comm Se <p index> e' <gt>= 0 viene costruito il nome dell'elemento
// dell'array da cercare, diversamente viene cercata la variabile
// normale passata in <p var>.
{
const char* key = build_varkey(var, index);
bool ok = false;
if (!table || *table == '\0')
ok = _head.remove(key);
else
{
const char* rowkey = build_rowkey(table, row);
TAssoc_array * row_data = (TAssoc_array *)_rows.objptr(rowkey);
if (row_data != nullptr)
ok = row_data->remove(key);
}
return ok;
}
// @doc EXTERNAL
// @mfunc Elimina una serie di variabili dal paragrafo corrente
//
// @rdesc Ritorna i seguenti valori:
//
// @flag TRUE | Se la variabile esiteva
// @flag FALSE | Se la variabile non esiteva
bool TTransaction::remove_array(
const char* var, // @parm Nome della variabile
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) // @parm riga
// @comm Viene cancellata l'aray di variabili passata in <p var>.
{
bool ok = false;
TString_array arr;
TString80 s = var; s << '(';
if (!table || *table == '\0')
{
_head.get_keys(arr);
FOR_EACH_ARRAY_ROW(arr, r, str)
{
if (str->starts_with(s))
{
ok = remove(*str, r, nullptr);
}
}
}
else
{
const char* rowkey = build_rowkey(table, row);
TAssoc_array * row_data = (TAssoc_array *)_rows.objptr(rowkey);
if (row_data != nullptr)
{
row_data->get_keys(arr);
FOR_EACH_ARRAY_ROW(arr, r, str)
{
if (str->starts_with(s))
ok = remove(*str, r, table);
}
}
}
return ok;
}
void TTransaction::remove_all()
{
_head.destroy();
_rows.destroy();
}
// @doc EXTERNAL
// @mfunc Ritorna il valore della variabile nella sezione corrente o in
// quella specificata
//
// @rdesc Ritorna la stringa contenuta nella variabile, se questa esiste, altrimenti
// il valore di default che dovrebbe assumere determinato dal parametro
// <p def>
const TString& TTransaction::get(
const char* var, // @parm Variabile della quale ritornare il valore
int index, // @parm Eventuale indice della variabile (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) const // @parm riga
// @comm Passando <p index> <gt>= 0 viene appeso al nome della variabile per
// implementare un array.
// @xref <mf TTransaction::get_long> <mf TTransaction::get_int> <mf TTransaction::get_bool>
// <mf TTransaction::get_color>
{
const char* key = build_varkey(var, index);
const TString* val = nullptr;
if (!table || *table == '\0')
val = (TString*)_head.objptr(key);
else
{
const char* rowkey = build_rowkey(table, row);
TAssoc_array * row_data = (TAssoc_array *)_rows.objptr(rowkey);
if (row_data != nullptr)
val = (TString*) row_data->objptr(key);
}
if (val == nullptr) // Se non la trova inserisci il default
val = &EMPTY_STRING;
return *val;
}
// @doc EXTERNAL
// @mfunc Ritorna il valore della variabile nella sezione corrente o in
// quella specificata
//
// @rdesc Ritorna i seguenti valori
//
// @flag TRUE | Se la varabile e' settata con X
// @flag FALSE | Se la varabile nen e' settata con X
// @flag <p def> | Se la varabile non esiste
bool TTransaction::get_bool(
const char* var, // @parm Variabile della quale ritornare il valore
int index, // @parm Eventuale indice della variabile (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) const // @parm riga
// @comm Viene chiamata la funzione <mf TTransaction::get>.
// <nl>Passando <p index> <gt>= 0 viene appeso al nome variabile per
// implementare un array.
// <nl>Il paragrafo passato in <p section> diventa quello attivo.
//
// @xref <mf TTransaction::get> <mf TTransaction::get_long> <mf TTransaction::get_int>
// <mf TTransaction::get_color>
{
bool yes = false;
TString& s = (TString &) get(var, index, table, row);
if (s.full())
{
s.upper();
yes = s == "X" || s == "Y" || s == "1" || s == "ON" || s == "YES" || s == "OK" || s == "TRUE";
}
return yes;
}
// @doc EXTERNAL
// @mfunc Ritorna il valore del colore settato nella variabile nella
// sezione corrente o in quella specificata
COLOR TTransaction::get_color(
const char* var, // @parm Variabile della quale ritornare il valore
int index, // @parm Eventuale indice della variabile (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) const // @parm riga
// @comm Passando <p index> <gt>= 0 viene appeso al nome variabile per
// implementare un array.
// <nl>Il paragrafo passato in <p section> diventa quello attivo.
//
// @xref <mf TTransaction::get> <mf TTransaction::get_long> <mf TTransaction::get_int>
// <mf TTransaction::get_bool>
{
TToken_string s(get(var, index, table, row), ',');
COLOR col = COLOR_BLACK;
if (s.full())
{
if (s.find(',') > 0)
{
const byte r = (byte)s.get_int();
const byte g = (byte)s.get_int();
const byte b = (byte)s.get_int();
col = RGB2COLOR(r, g, b);
}
else
{
col = atol(s);
if (col == 0L)
col = COLOR_BLACK;
}
}
return col;
}
// @doc EXTERNAL
// @mfunc Setta la variabile nella sezione corrente o specificata
//
// @rdesc Ritorna i seguenti valori:
//
// @flag TRUE | Se la variabile era gia' esistente
// @flag FALSE | Se la variabile non era gia' esistente
bool TTransaction::set(
const char* var, // @parm Nome della variabile da settare
const char* value, // @parm Stringa da assegnare alla variabile
int index, // @parm Eventuale indice della variabile (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) // @parm riga
{
// @syntax set(const char* var, const char* value, const char* section, bool force, int index);
// @syntax set(const char* var, long value, const char* section, bool force, int index);
//
// @comm Se <p force> == TRUE crea il paragrafo e la variabile se non esistono;
// altrimenti da' errore.
// <nl>Passando <p index> <gt>= 0 viene appeso al nome variabile per
// implementare un array.
// <nl>Il paragrafo passato in <p section> diventa quello attivo.
const char* key = build_varkey(var, index);
TString* val = nullptr;
bool itwas = false;
if (!table || *table == '\0')
{
val = (TString*)_head.objptr(key);
itwas = val != nullptr;
if (itwas)
{
const TFixed_string str(value);
// Se la variabile esisteva ed aveva un valore diverso ...
if (*val != str && !(str.blank() && val->empty()))
{
*val = str; // ... allora la sostituisco ...
val->trim();
}
}
else
{
// Se la variabile non esisteva allora la aggiungo e metto a dirty.
val = new TString(value);
val->trim();
itwas = _head.add(key, val, true);
}
}
else
{
const char* rowkey = build_rowkey(table, row);
TAssoc_array * row_data = (TAssoc_array *)_rows.objptr(rowkey);
if (_executer.blank())
_executer = table;
if (row_data == nullptr)
_rows.add(rowkey, row_data = new TAssoc_array, true);
if (row_data != nullptr)
{
val = (TString*)row_data->objptr(key);
itwas = val != nullptr;
if (itwas)
{
const TFixed_string str(value);
// Se la variabile esisteva ed aveva un valore diverso ...
if (*val != str && !(str.blank() && val->empty()))
{
*val = str; // ... allora la sostituisco ...
val->trim();
}
}
else
{
// Se la variabile non esisteva allora la aggiungo e metto a dirty.
val = new TString(value);
val->trim();
itwas = row_data->add(key, val, true);
}
}
}
return itwas;
}
bool TTransaction::set(
const char* var, // @parm Nome della variabile da settare
long value, // @parm Stringa da assegnare alla variabile
int index, // @parm Eventuale indice della variabile (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) // @parm riga
{
TString16 t;
t << value;
return set(var, t, index, table, row);
}
bool TTransaction::set(
const char* var, // @parm Nome della variabile da settare
real value, // @parm Stringa da assegnare alla variabile
int index, // @parm Eventuale indice della variabile (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) // @parm riga
{
TString40 t;
t << value;
return set(var, t, index, table, row);
}
bool TTransaction::set(
const char* var, // @parm Nome della variabile da settare
int value, // @parm Stringa da assegnare alla variabile
int index, // @parm Eventuale indice della variabile (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) // @parm riga
{
TString16 t;
t << value;
return set(var, t, index, table, row);
}
bool TTransaction::set(
const char* var, // @parm Nome della variabile da settare
bool value, // @parm Stringa da assegnare alla variabile
int index, // @parm Eventuale indice della variabile (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) // @parm riga
{
TString16 t;
t << value ? "X" : " ";
return set(var, t, index, table, row);
}
bool TTransaction::set(
const char* var, // @parm Nome della variabile da settare
COLOR col, // @parm Colore da assegnare alla variabile
int index, // @parm Eventuale indice della variabile (default -1)
const char * table, // @parm testata(TRANSACTION_HEADER) o tabella/file
int row) // @parm riga
{
TString16 t;
t.format("%d,%d,%d", XVT_COLOR_GET_RED(col), XVT_COLOR_GET_GREEN(col), XVT_COLOR_GET_BLUE(col));
return set(var, t, index, table, row);
}
bool TTransaction::read_ini()
{
remove_all();
if (_file.exist())
{
TConfig cnf(_file, "Transaction");
TString_array paragraphs;
cnf.list_paragraphs(paragraphs);
FOR_EACH_ARRAY_ROW(paragraphs, r, para)
{
TAssoc_array & vars = cnf.list_variables(*para);
TString table;
int row = 0;
if (*para != "Transaction")
{
table = get_rowkey_logicnum(*para);
row = get_rowkey_row(*para);
}
FOR_EACH_ASSOC_OBJECT(vars, obj, k, itm)
{
const TString key(k);
int index = get_varkey_index(key);
TString name = get_varkey_name(key);
set(name, cnf.get(name, *para, index), index, table, row);
}
}
return true;
}
return false;
}
bool TTransaction::read_xml()
{
remove_all();
if (_file.exist())
{
TXmlItem xml;
xml.Load(_file);
TXmlItem * child = xml.GetChild(0);
if (child->GetTag() == "Transaction")
{
const int nrows = child->GetChildren();
TString_array vars;
child->ListAttrs(vars);
FOR_EACH_ARRAY_ROW(vars, r, str)
{
int index = get_varkey_index(*str);
TString name = get_varkey_name(*str);
set(name, child->GetAttr(*str), index, nullptr);
}
for(int n = 0; n < nrows; n++)
{
TXmlItem * child_row = child->GetChild(n);
const TString row_name = child_row->GetTag();
TString logicnum = get_rowkey_logicnum(row_name);
const int row = get_rowkey_row(row_name);
child_row->ListAttrs(vars);
FOR_EACH_ARRAY_ROW(vars, r1, str)
{
int index = get_varkey_index(*str);
TString name = get_varkey_name(*str);
set(name, child_row->GetAttr(*str), index, logicnum, row);
}
}
}
return true;
}
return false;
}
void TTransaction::write_ini_row_para(TConfig & cnf, const TString & rowkey, bool exec)
{
TString_array arr;
TAssoc_array & row = *((TAssoc_array *)_rows.objptr(rowkey));
cnf.set_paragraph(rowkey);
row.get_keys(arr);
FOR_EACH_ARRAY_ROW(arr, r1, str)
{
int index = get_varkey_index(*str);
const TString name = get_varkey_name(*str);
cnf.set(name, *((TString *)row.objptr(*str)), nullptr, true, index);
}
}
bool TTransaction::write_ini()
{
bool ok = _head.items() > 0 && _rows.items();
if (ok)
{
TString_array arr;
TConfig cnf(_file, "Transaction");
TString_array row_arr;
_head.get_keys(arr);
cnf.set("Version", "2.0");
FOR_EACH_ARRAY_ROW(arr, r, str)
{
int index = get_varkey_index(*str);
const TString name = get_varkey_name(*str);
cnf.set(name, *((TString *)_head.objptr(*str)), nullptr, true, index);
}
_rows.get_keys(row_arr);
write_ini_row_para(cnf, _executer);
row_arr.sort();
FOR_EACH_ARRAY_ROW(row_arr, r1, rowkey)
write_ini_row_para(cnf, *rowkey, false);
}
else
_file.fremove();
return ok;
}
void TTransaction::write_xml_row_para(TXmlItem & xml, const TString & rowkey, bool exec)
{
TString_array arr;
TAssoc_array & row = *((TAssoc_array *)_rows.objptr(rowkey));
TXmlItem & child = xml.AddChild(rowkey);
row.get_keys(arr);
FOR_EACH_ARRAY_ROW(arr, r1, str)
{
TXmlItem & child_row = xml.AddChild(rowkey);
row.get_keys(arr);
FOR_EACH_ARRAY_ROW(arr, r1, str)
child.AddEnclosedText(*str, *((TString *)row.objptr(*str)));
}
}
bool TTransaction::write_xml()
{
bool ok = _head.items() > 0 && _rows.items();
if (ok)
{
TString_array arr;
TXmlItem xml;
TString_array row_arr;
TXmlItem & child = xml.AddChild("Transaction");
_head.get_keys(arr);
child.AddEnclosedText("Version", "2.0");
FOR_EACH_ARRAY_ROW(arr, r, str)
child.AddEnclosedText(*str, *((TString *)_head.objptr(*str)));
_rows.get_keys(row_arr);
row_arr.sort();
write_xml_row_para(xml, _executer);
FOR_EACH_ARRAY_ROW(row_arr, r1, rowkey)
write_xml_row_para(xml, *rowkey, false);
xml.Save(_file);
}
else
_file.fremove();
return ok;
}
const char * TTransaction::record_header() const
{
TString &str = get_tmp_string(2569);
int logicnum = atoi(_executer);
if (logicnum == 0)
logicnum = table2logic(_executer);
TToken_string keyfields(prefix().get_keyexpr(logicnum), '+');
str = "Record ";
FOR_EACH_STR_TOKEN(keyfields, fld)
if (fld.full())
str << fld << " = " << get(fld, -1, _executer) << " ";
return str;
}
bool TTransaction::get_errors(TString_array & errors) const
{
TString error = get("ErrorMsg", 0, nullptr);
errors.destroy();
for (int i = 0; error.full(); error = get("ErrorMsg", ++i, nullptr))
errors.add(error);
return errors.items() > 0;
}
bool TTransaction::get_warnings(TString_array & warnings) const
{
TString warning = get("WarningMsg", 0, nullptr);
warnings.destroy();
for (int i = 0; warning.full(); warning = get("WarningMsg", i++, nullptr))
warnings.add(warning);
return warnings.items() > 0;
}
bool TTransaction::read()
{
if (_type == ini_transaction)
return read_ini();
else
return read_xml();
}
bool TTransaction::write()
{
if (_type == ini_transaction)
return write_ini();
else
return write_xml();
}
bool file2app(TString & file ,TString& app)
{
TString16 appname; appname << "Edit_" << file;
app = ini_get_string(CONFIG_INSTALL, "ba7", appname);
if (app.empty())
{
if (isdigit(file[0]))
{
const int filenum = atoi(file);
if (filenum >= LF_USER && filenum < prefix().items())
{
TLocalisamfile isf(filenum);
isf.get_relapp(app);
}
}
else
{
const int len = file.len();
if (len == 3 || (len == 4 && file[0] == '%'))
{
TTable table(file);
table.get_relapp(app);
}
else
if (len >= 4 && file[0] == '&')
{
TModule_table tabmod(file);
tabmod.get_relapp(app);
}
}
}
return app.full();
}
void execute_transactions(TArray & transactions, TLog_report & log, bool interactive, const char * msg)
{
TString prog_msg(msg);
if (transactions.items() > 0)
{
TBit_array processed;
const int first = transactions.first();
const int last = transactions.last();
while (true)
{
int i = first;
TTransaction t = (TTransaction &)transactions[i];
TString table = t.executer();
int logicnum = atoi(table);
while (processed[i])
i++;
if (i > last)
break;
if (table.full())
{
TFilename pref = t.name();
pref.ext("");
while (isdigit(pref[pref.len() - 1]))
pref.rtrim(1);
while (i >= 0)
{
if (t.executer() == table && t.name().starts_with(pref))
{
t.write();
processed.set(i);
}
i = transactions.succ(i);
while (processed[i])
i++;
if (i > last)
break;
t = (TTransaction &)transactions[i];
}
TString app;
if (file2app(table, app))
{
TFilename filemask(pref);
TString_array files;
filemask << "*" << "." << t.ext();
app << (interactive ? " -i" : " -b") << filemask;
if (prog_msg.full())
app << " -m\"" << prog_msg << "\"";
app << " -u" << user();
TExternal_app cmd(app);
cmd.run();
list_files(filemask, files);
FOR_EACH_ARRAY_ROW(files, r, str)
{
TTransaction t(*str);
TString_array msgs;
log.log(0, t.record_header());
t.get_warnings(msgs);
FOR_EACH_ARRAY_ROW(msgs, nm, msg)
log.log(1, *msg);
if (t.result_ok())
log.log(0, "Eseguita");
else
{
t.get_errors(msgs);
FOR_EACH_ARRAY_ROW(msgs, nm, msg)
log.log(2, *msg);
}
}
remove_files(filemask, false);
}
else
{
TString msg(TR("Esecutore sconosciuto per le transazioni sul file "));
msg << (logicnum == 0) ? t.executer() : prefix().description(logicnum);
log.log(2, msg);
}
}
}
}
}