campo-sirio/include/textset.cpp

731 lines
16 KiB
C++
Raw Normal View History

#include <textset.h>
///////////////////////////////////////////////////////////
// TText_recordset
///////////////////////////////////////////////////////////
bool TText_recordset::destroy(TRecnotype r)
{
const bool ok = _rec.destroy(r, true);
if (ok && (_curr == r || _curr > _rec.items()))
_curr = -1;
return ok;
}
const TRecordset_column_info& TText_recordset::column_info(const char* column) const
{
return column_info(find_column(column));
}
TRecnotype TText_recordset::new_rec(const char* rec)
{
_curr = _rec.add(rec);
const int l = row(_curr).size(); // Forse sarebbe piu' sicuro len()
if (l > _info._width)
_info._width = l;
return _curr;
}
TRecnotype TText_recordset::insert_rec(TRecnotype r, const char* buf)
{
TRecnotype pos = new_rec(buf);
if ((r >= 0) && (r != pos))
{
TObject* last = _rec.remove(pos);
_rec.insert(last, r);
_curr = pos = r;
}
return pos;
}
TToken_string& TText_recordset::row(TRecnotype n) const
{
if (n < 0)
n = current_row();
if (n < 0 || n >= items())
n = ((TText_recordset*)this)->new_rec(); // Clausola di salvaguardia
return (TToken_string&)_rec.row(n);
}
TRecnotype TText_recordset::items() const
{
TRecnotype n = _rec.items();
if (n == 0 && _query.full() && _query.find("CREATE ") < 0)
{
((TText_recordset*)this)->exec(_query);
n = _rec.items();
}
return n;
}
bool TText_recordset::move_to(TRecnotype pos)
{
const bool ok = pos >= 0 && pos < items();
_curr = pos;
return ok;
}
void TText_recordset::requery()
{
}
bool TText_recordset::load_file(const TFilename& n)
{
TString str(4096);
char* buf = str.get_buffer();
ifstream f(n);
while (f && !f.eof())
{
f.getline(buf, str.size());
new_rec(buf);
}
return _rec.items() > 0;
}
int TText_recordset::find_column(const char* column) const
{
int n = -1;
if (column && *column && *column != '#')
{
if (real::is_natural(column))
n = atoi(column);
if (strlen(column) > 2)
n = TRecordset::find_column(column);
else
{
n = 0;
for (const char* c = column; isalpha(*c); c++)
{
n *= 26;
n += toupper(*c)-'@';
}
n--;
}
}
return n;
}
const TVariant& TText_recordset::get(unsigned int column) const
{
const TRecnotype n = current_row();
if (column == 0 && n >= 0 && n < items())
{
TVariant& var = get_tmp_var();
var.set(((TText_recordset*)this)->row(n));
return var;
}
return NULL_VARIANT;
}
bool TText_recordset::set(unsigned int column, const TVariant& var)
{
const bool ok = column == 0;
if (ok)
row() = var.as_string();
return ok;
}
bool TText_recordset::set(const char* column, const TVariant& var)
{
return set(find_column(column), var);
}
TQuery_type TText_recordset::parse_query(const char* query, TFilename& table)
{
TQuery_type qt = _qt_none;
TString q(query); q.trim();
const int ct = q.find("CREATE TABLE ");
if (ct >= 0)
{
const TToken_string t(q.mid(ct), ' ');
t.get(2, table); // Furbastro: prendo la terza parola della query
table.trim();
if (table.not_empty())
qt = _qt_create;
}
else
{
const int se = q.find("SELECT ");
if (se >= 0)
{
int n = q.find("FROM ", se);
table = q.mid(n+5);
n = table.find("WHERE");
if (n > 0)
table.cut(n-1);
n = table.find(',');
if (n > 0)
table.cut(n);
}
else
{
table = query;
}
table.trim();
if (table.not_empty())
qt = _qt_select;
}
return qt;
}
bool TText_recordset::exec(const char* query)
{
TFilename name;
const TQuery_type qt = parse_query(query, name);
if (qt != _qt_none)
{
_query = query; _query.trim();
if (qt == _qt_select)
{
destroy();
load_file(name);
}
}
return qt != _qt_none;
}
bool TText_recordset::save_as_text(const char* path)
{
bool valid = path && *path;
if (valid)
{
ofstream out(path);
if (out.good())
{
for (bool ok = move_first(); ok; ok = move_next())
out << row() << endl;
}
else
valid = false;
}
return valid;
}
bool TText_recordset::save_as(const char* path, TRecordsetExportFormat fmt)
{
if (fmt == fmt_text)
{
TFilename n = path;
if (n.blank())
parse_query(_query, n);
if (n.full())
return save_as_text(n);
}
return TRecordset::save_as(path, fmt);
}
void TText_recordset::sort(COMPARE_FUNCTION f)
{
if (f == NULL)
_rec.sort(true); // Ordina alfabeticamante
else
_rec.TArray::sort(f); // Usa la funzione definita dall'utente
}
TText_recordset::TText_recordset(const char* query) : _query(query), _curr(-1)
{
_info._name = "A";
_info._pos = _info._width = 0;
_info._type = _alfafld;
}
///////////////////////////////////////////////////////////
// TCSV_recordset
///////////////////////////////////////////////////////////
TQuery_type TCSV_recordset::parse_query(const char* query, TFilename& table)
{
TString q(query);
if (q.starts_with("CSV(", true))
{
switch (q[4])
{
case '\'':
case '"' :
if (q[5] == '\\' && q[6] == 't')
_separator = '\t';
else
_separator = q[5];
break;
default :
if (q[4] != ')')
_separator = q[4];
else
_separator = ',';
break;
}
q = q.after(')');
q.trim();
}
return TText_recordset::parse_query(q, table);
}
unsigned int TCSV_recordset::columns() const
{
unsigned int c = _trc.items();
if (c == 0)
{
const TRecnotype i = items(); //rilegge fai di testo e tenta di crearne il tracciato _trc
c = _trc.items();
if (c == 0 && i > 0)
c = ((TCSV_recordset*)this)->build_trc();
}
return c;
}
const TRecordset_column_info& TCSV_recordset::column_info(unsigned int column) const
{
if (column >= 0 && column < columns())
{
TRecordset_column_info* ci = (TRecordset_column_info*)_trc.objptr(column);
if (ci != NULL)
return *ci;
}
return TText_recordset::column_info(column);
}
TRecnotype TCSV_recordset::new_rec(const char* rec)
{
const TRecnotype n = TText_recordset::new_rec(rec);
if (n >= 0)
row(n).separator(_separator);
return n;
}
void TCSV_recordset::create_column(const char* name, TFieldtypes type)
{
TRecordset_column_info * info = new TRecordset_column_info;
info->_name = name;
info->_type = type;
info->_pos = _trc.add(info);
}
unsigned int TCSV_recordset::build_trc()
{
_trc.destroy();
int cols = 1;
int i;
for (i = items()-1; i >= 0; i--)
{
const TToken_string& r = row(i);
const int c = r.items();
if (c > cols)
cols = c;
}
for (i = 0; i < cols; i++)
_trc.add(new TRecordset_column_info);
TString val;
for (i = items()-1; i >= 0; i--)
{
const TToken_string& r = row(i);
for (int c = r.items()-1; c >= 0; c--)
{
r.get(c, val);
if (val.full())
{
TRecordset_column_info& ci = *(TRecordset_column_info*)_trc.objptr(c);
const int l = val.len();
if (l > ci._width)
{
ci._width = l;
if (l == 8 || l == 10 && TDate::isdate(val))
ci._type = _datefld;
else
{
if (!real::is_null(val))
{
if (real::is_natural(val))
ci._type = _intfld;
else
ci._type = _realfld;
}
}
}
}
}
}
return _trc.items();
}
bool TCSV_recordset::load_file(const TFilename& n)
{
if (!TText_recordset::load_file(n))
return false;
if (_trc.empty())
build_trc();
return columns() > 0;
}
bool TCSV_recordset::set(unsigned int column, const TVariant& var)
{
TToken_string& r = row();
r.add(var.as_string(), column);
return true;
}
const TVariant& TCSV_recordset::get(unsigned int column) const
{
const TRecnotype n = current_row();
if (n >= 0 && n < items())
{
const char* val = row(n).get(column);
if (val != NULL)
{
TVariant& var = get_tmp_var();
var.set(val);
return var;
}
}
return NULL_VARIANT;
}
TCSV_recordset::TCSV_recordset(const char* query)
: TText_recordset(query), _separator(',')
{
TFilename n;
if (parse_query(query, n) == _qt_select && n.exist())
load_file(n);
}
///////////////////////////////////////////////////////////
// TAS400_recordset
///////////////////////////////////////////////////////////
bool TAS400_recordset::load_file(const TFilename& n)
{
TString row(record_length(), ' ');
ifstream f(n, ios::binary);
char* buf = row.get_buffer();
TRecnotype r = -1;
while (f)
{
*buf = '\0';
f.read(buf, record_length());
if (*buf)
r = new_rec(buf);
else
break;
}
return r >= 0;
}
TQuery_type TAS400_recordset::parse_query(const char* query, TFilename& table)
{
TString q(query);
if (q.find("AS400(") >= 0)
{
const int da = q.find('(');
const int al = q.find(')', da);
TToken_string k(q.sub(da+1, al), ',');
_info._width = k.get_int(0);
_key._width = k.get_int();
_key._pos = k.get_int();
q = q.mid(al+1);
q.trim();
}
return TText_recordset::parse_query(q, table);
}
bool TAS400_recordset::set_field(const TAS400_column_info& fi, const TVariant& var)
{
TToken_string& r = row();
switch (fi._type)
{
case _intfld:
case _longfld:
{
TString80 str;
if (fi._width > 8)
str = var.as_real().string(fi._width, 0, ' ');
else
str.format("%*ld", fi._width, var.as_int());
r.overwrite(str, fi._pos);
}
break;
case _intzerofld:
case _longzerofld:
{
TString80 str;
if (fi._width > 8)
str = var.as_real().string(fi._width, 0, '0');
else
str.format("%0*ld", fi._width, var.as_int());
r.overwrite(str, fi._pos);
}
break;
case _realfld:
{
const char* str = var.as_real().string(fi._width);
r.overwrite(str, fi._pos);
}
break;
case _datefld:
if (fi._width == 8)
{
TString8 str; str << var.as_date().date2ansi();
r.overwrite(str, fi._pos, fi._width);
break;
}
// fall down to default
default:
r.overwrite(var.as_string(), fi._pos, fi._width);
break;
}
bool ok = true;
if (fi._required && var.is_empty())
ok = false;
return ok;
}
TAS400_column_info* TAS400_recordset::parse_field(const char* column, int& c, bool create)
{
CHECK(column && *column > ' ', "NULL field name");
TAS400_column_info* ci = NULL;
TString16 trc;
TString80 fld(column);
const int dot = fld.find('.');
if (dot > 0)
{
trc = fld.left(dot);
fld.ltrim(dot+1);
}
else
trc = rec_type();
TArray* info = (TArray*)_trc.objptr(trc);
if (info == NULL && create)
{
info = new TArray;
_trc.add(trc, info);
}
if (info != NULL)
{
if (create)
{
ci = new TAS400_column_info;
ci->_name = fld;
if (info->items() > 0)
{
const TAS400_column_info& last = *(const TAS400_column_info*)info->objptr(info->last());
ci->_pos = last._pos+last._width;
}
c = info->add(ci);
}
else
{
for (c = info->last(); c >= 0; c--)
{
TAS400_column_info* aci = (TAS400_column_info*)info->objptr(c);
if (aci->_name == fld)
{
ci = aci;
break;
}
}
}
}
return ci;
}
unsigned int TAS400_recordset::columns() const
{
const TArray* info = (const TArray*)_trc.objptr(rec_type());
if (info)
return info->items();
return TText_recordset::columns();
}
const TRecordset_column_info& TAS400_recordset::column_info(unsigned int c) const
{
const TArray* info = (const TArray*)_trc.objptr(rec_type());
if (info)
{
TRecordset_column_info* i = (TRecordset_column_info*)info->objptr(c);
if (i != NULL)
return *i;
}
return TText_recordset::column_info(c);
}
int TAS400_recordset::find_column(const char* column) const
{
int c = -1;
((TAS400_recordset*)this)->parse_field(column, c, false);
return c;
}
const TRecordset_column_info& TAS400_recordset::column_info(const char* column) const
{
int c = -1;
TRecordset_column_info* ci = ((TAS400_recordset*)this)->parse_field(column, c, false);
if (ci != NULL)
{
return *ci;
}
return TText_recordset::column_info(column);
}
const TVariant& TAS400_recordset::get_field(const TAS400_column_info& ci) const
{
const TRecnotype n = current_row();
if (n >= 0 && n < items())
{
const TString& str = row(n).mid(ci._pos, ci._width);
TVariant& var = get_tmp_var();
var.set(str); var.convert_to(ci._type);
return var;
}
return ci._default;
}
const TVariant& TAS400_recordset::get(unsigned int column) const
{
const TArray* info = (const TArray*)_trc.objptr(rec_type());
if (info)
{
const TAS400_column_info* ci = (const TAS400_column_info*)info->objptr(column);
if (ci != NULL)
return get_field(*ci);
}
return TText_recordset::get(column);
}
const TVariant& TAS400_recordset::get(const char* column) const
{
if (column && *column != '#')
{
int c = -1;
if (column[1] != '\0')
{
const TAS400_column_info* ci = ((TAS400_recordset*)this)->parse_field(column, c, false);
if (ci != NULL)
return get_field(*ci);
}
c = TText_recordset::find_column(column);
if (c >= 0)
return TText_recordset::get(c);
}
return TRecordset::get(column);
}
TRecnotype TAS400_recordset::new_rec(const char* trc)
{
CHECK(record_length() > 0, "Lunghezza record nulla");
if (trc && (int)strlen(trc) == record_length())
return TText_recordset::new_rec(trc);
else
{
const TString str(record_length(), ' ');
const TRecnotype n = TText_recordset::new_rec(str);
if (trc && (int)strlen(trc) == key_length())
{
TArray* info = (TArray*)_trc.objptr(trc);
if (info != NULL) // Se il tracciato e' noto, riempio di zeri i campi opportuni
{
FOR_EACH_ARRAY_ITEM_BACK((*info), i, obj)
{
const TAS400_column_info& ci = *(const TAS400_column_info*)obj;
if (ci._default.is_null())
{
if (ci._type == _intzerofld || ci._type == _longzerofld)
set_field(ci, NULL_VARIANT);
}
else
set_field(ci, ci._default);
}
}
row(n).overwrite(trc, key_position(), key_length());
}
return n;
}
}
const TString& TAS400_recordset::rec_type(TRecnotype r) const
{
if (key_length() > 0)
{
const TToken_string& riga = row(r);
return riga.mid(key_position(), key_length());
}
return EMPTY_STRING;
}
bool TAS400_recordset::create_field(const char* nam, int pos, int len,
TFieldtypes typ, bool req, const TVariant& def)
{
CHECK(nam && *nam > ' ', "Null field name");
int c = -1;
TAS400_column_info* ci = parse_field(nam, c, true);
const bool ok = ci != NULL;
if (ok)
{
if (pos >= 0) // Se l'utente fissa una posizione impostala, altrimenti tieni quella automatica
ci->_pos = pos;
ci->_width = len;
ci->_type = typ;
ci->_required = req;
ci->_default = def;
CHECKS(ci->_pos >= 0 && ci->_pos < record_length(), "Invalid position for field ", nam);
CHECKS(ci->_width > 0 && ci->_pos+ci->_width <= record_length(), "Invalid lenght for field ", nam);
}
return ok;
}
bool TAS400_recordset::set(const char* column, const TVariant& var)
{
int c = -1;
TAS400_column_info* ci = parse_field(column, c, false);
bool ok = ci != NULL;
if (ok)
ok = set_field(*ci, var);
return ok;
}
bool TAS400_recordset::set(unsigned int column, const TVariant& var)
{
const TAS400_column_info& ci = (const TAS400_column_info&)column_info(column);
return set_field(ci, var);
}
bool TAS400_recordset::save_as_text(const char* path)
{
bool valid = path && *path;
if (valid)
{
ofstream out(path, ios::binary);
if (out.good())
{
for (bool ok = move_first(); ok; ok = move_next())
out << row(); // NON mettere << endl
}
else
valid = false;
}
return valid;
}
TAS400_recordset::TAS400_recordset(const char* query)
: TText_recordset(query)
{
TFilename n;
if (parse_query(query, n) == _qt_select && n.exist())
load_file(n);
}