campo-sirio/include/filetext.cpp
sauro 30b648d1da Abilitata la scrittura dei sottofiles nella relazione dichiarata
nel tracciato record con USE/JOIN


git-svn-id: svn://10.65.10.50/trunk@5568 c028cbd2-c16b-5b4b-a496-9718f37d4682
1997-11-06 14:39:42 +00:00

838 lines
25 KiB
C++
Executable File
Raw Blame History

#include <filetext.h>
#include <utility.h>
//////////////////////////////////////// TTracciato_Campo ////////////////////////////////////////
TTracciato_campo::TTracciato_campo(int position, int length, int decimal, const char align, const char filler)
:_position(position), _length(length), _decimal(decimal), _align(align), _filler(filler) {}
TObject* TTracciato_campo::dup() const
{
TTracciato_campo* t = new TTracciato_campo(*this);
return t;
}
const TTracciato_campo& TTracciato_campo::operator =(const TTracciato_campo& tc)
{
copy(tc);
return *this;
}
void TTracciato_campo::copy(const TTracciato_campo& tc)
{
set_name(tc._name);
set_type(tc._type);
set_field(tc._field);
set_ftype(tc._ftype);
set_position(tc._position);
set_length(tc._length);
set_decimal(tc._decimal);
set_align(tc._align);
set_filler(tc._filler);
set_picture(tc._picture);
set_message(tc._message);
}
const int TFile_text::fdecimal(const TTracciato_campo &tc ) const
{
if (tc.ftype().empty())
return tc.decimal();
else
return ((TTracciato_campo &)_tipi[tc.ftype()]).decimal();
}
const char TFile_text::falign(const TTracciato_campo &tc ) const
{
if (tc.ftype().empty())
return tc.align();
else
return ((TTracciato_campo &)_tipi[tc.ftype()]).align();
}
const char TFile_text::ffiller(const TTracciato_campo &tc ) const
{
if (tc.ftype().empty())
return tc.filler();
else
return ((TTracciato_campo &)_tipi[tc.ftype()]).filler();
}
const TString& TFile_text::fpicture(const TTracciato_campo &tc ) const
{
if (tc.ftype().empty())
return tc.picture();
else
return ((TTracciato_campo &)_tipi[tc.ftype()]).picture();
}
//////////////////////////////////////// TTracciato_record ////////////////////////////////////////
TObject* TTracciato_record::dup() const
{
TTracciato_record* t = new TTracciato_record(*this);
return t;
}
TTracciato_record::TTracciato_record(const TTracciato_record& tr)
{
set_relation(tr.relation());
set_type(tr.type());
_tracciati_campo = tr._tracciati_campo;
}
TTracciato_record::~TTracciato_record()
{
if (_rel) delete _rel;
}
void TTracciato_record::add(const TTracciato_campo& tc, int pos)
{
_tracciati_campo.add(tc,pos);
}
void TTracciato_record::add(TTracciato_campo* tc, int pos)
{
_tracciati_campo.add(tc,pos);
}
int TTracciato_record::get_pos(const char* name) const
{
for (int i = _tracciati_campo.last(); i >= 0; i = _tracciati_campo.pred(i))
{
const TTracciato_campo& tc = get(i);
if (tc.name() == name)
break;
}
return i;
}
TTracciato_campo& TTracciato_record::get(int n)
{
if (TTracciato_record::ptr(n) == NULL)//se non esiste lo creo
{
TTracciato_campo* t = new TTracciato_campo();
add(t, n);
}
return (TTracciato_campo&)_tracciati_campo[n];
}
//////////////////////////////////////// TRecord_text ////////////////////////////////////////
const TString& TRecord_text::row(int pos) const
{
return _array.row(pos);
}
TString& TRecord_text::row(int pos)
{
return _array.row(pos);
}
void TRecord_text::add(const TString& c, int pos)
{
_array.add(c, pos);
}
//////////////////////////////////////// TFile_text ////////////////////////////////////////
TTracciato_record* TFile_text::t_rec(const char* type)
{
return (TTracciato_record*)_tracciati_record.objptr(type);
}
TTracciato_record* TFile_text::t_rec(int mainfile)
{
TTracciato_record *trrd;
_tracciati_record.restart();
while (trrd=(TTracciato_record *)_tracciati_record.get())
{
if (trrd->relation() && trrd->relation()->lfile().num()==mainfile)
break;
}
return trrd;
}
void TFile_text::set_gen_parm(TConfig& config, const TString& section)
{
_decsep = config.get_char("DECSEP",section);
_recordsize = config.get_int("RECORDSIZE",section); // solo se a lung. fissa
_fieldsep = config.get_char("FIELDSEP",section); // solo se a lung. variabile
_recordsep = config.get("RECORDSEP",section); // solo se a lung. variabile
if (_recordsize <= 0 && (_recordsep.empty())) // separatore di record standard
_recordsep = "\r\n";
_typefield = config.get_int("TYPEFIELD",section); // Numero del campo tipo (puo' essere -1)
_fixedlen = _fieldsep <= ' '; // && _recordsep.blank();
_typepos = -1;
_typelen = -1;
}
void TFile_text::set_type_parm(TConfig& config, TString& section)
{
TString lavoro = section;
lavoro.ltrim(4);//elimino la parola 'TYPE' e gli spazi vuoti
lavoro.trim();//per avere solo il nome del tipo predefinito
TTracciato_campo tipo;
tipo.set_type(lavoro);
tipo.set_length(config.get_int("LENGTH", section));
tipo.set_decimal(config.get_int("DECIMAL", section));
tipo.set_align(config.get_char("ALIGN", section));
TString s = config.get("FILLER", section);
if (s.len() > 1)
tipo.set_filler(s[1]);
else
tipo.set_filler(s[0]);
tipo.set_picture(config.get("PICTURE", section));
_tipi.add(lavoro, tipo);// aggiungo il tracciato campo all'assoc_array dei tipi predefiniti
}
void TFile_text::set_rec_parm(TConfig& config, const char* section)
{
TString sectkey = section;
sectkey.ltrim(6);//elimino la parola 'RECORD' o 'HEADER' o 'FOOTER' e gli spazi vuoti
sectkey.trim();//per avere solo il nome del tipo del record
TTracciato_record *tr=new TTracciato_record(sectkey);//istanzio un tracciato_record del tipo corrente
//setto tutti i dati relatvi ai tipi predefini nei tracciati campo per i diversi campi del record
TRelation *tmprel=NULL; // relazione associata al tracciato record
config.set_paragraph(section);
TString lavoro;
TString_array variables;
const int numvar = config.list_variables(variables, TRUE);//scarico tutte le variabili della sezione
TBit_array indici(numvar);
indici.reset();
for (int j = 0; j < numvar; j++)//scandisco tutte le variabili della sezione
{
const TString key = variables.row(j).get(0);//estraggo nome
const TString& obj = variables.row(j).get(1);//estraggo valore
lavoro = key.left(3);
int pos = key.find('(');
int n = atoi(key.mid(pos+1, -1));//estraggo l'indice
if (!indici[n])
{
if (config.exist("TYPE", n))
{
TString tipo = config.get("TYPE", section, n);
if (!tipo.empty())
{
TTracciato_campo& tc = (TTracciato_campo&)_tipi[tipo];
tr->add(tc, n);
}
}
indici.set(n);
}
if (lavoro == "USE") // setta la relazione
{
CHECKS(tmprel==NULL,"Relazione gi<67> definita per il tracciato: %s",sectkey);
if (atoi((const char *)obj)!=0)
tmprel= new TRelation(atoi((const char *)obj));
else
tmprel= new TRelation((const char *)obj);
}
if (lavoro == "JOI") // setta i join
{
CHECKS(tmprel, "Can't join to NULL relation ", (const char*)j);
TToken_string join_expr((const char *)obj,' '); // Join expression
int token=0;
TString16 j(join_expr.get(token++)); // file or table
int to=0; // 'to' default: _relation->lfile()->num();
if (strcmp(join_expr.get(token++),"TO")==0) // TO keyword
{
const char* t = join_expr.get(token++);
to = name2log(t);
} else
token --;
int key = 1;
if (strcmp(join_expr.get(token++),"KEY")==0)
key = join_expr.get_int(token++);
else
token--;
int alias = 0;
if (strcmp(join_expr.get(token++),"ALIAS")==0)
alias = join_expr.get_int(token++);
else
token--;
TToken_string exp(80);
if (strcmp(join_expr.get(token++),"INTO")==0)
{
const char* r = join_expr.get(token++);
while (r && strchr(r, '=') != NULL)
{
exp.add(r);
r = join_expr.get(token++);
}
}
#ifdef DBG
if (exp.empty()) yesnofatal_box("JOIN senza espressioni INTO");
#endif
if (isdigit(j[0]))
tmprel->add(atoi(j), exp, key, to, alias); // join file
else
{
#ifdef DBG
if (j.len() > 4)
yesnofatal_box("'%s' non e' una tabella valida: %d", (const char*)j);
else
#endif
tmprel->add(j, exp, key, to, alias); // join table
}
tmprel->write_enable();
continue;
}
TTracciato_campo& tc = tr->get(n);//prendo il tracciato campo con indice <n>
if (lavoro == "NAM")
{
tc.set_name(obj);
continue;
}
if (lavoro == "FIE")
{
TFieldref field;
field = obj;
tc.set_field(field);
continue;
}
if (lavoro == "FTY") // field type
{
CHECKS(_tipi.objptr(obj)!=NULL,"Riferimento a campo inesistente:%s",obj);
tc.set_ftype(obj);
continue;
}
if (lavoro == "POS")
{
int pos = atoi(obj);
tc.set_position(pos);
if (_fixedlen && _typepos < 0 && n == _typefield)
_typepos = pos;
continue;
}
if (lavoro == "LEN")
{
int len = atoi(obj);
if (tc.length() <= 0 && len >= 0 && tc.length() != len)
tc.set_length(len);
continue;
}
if (lavoro == "DEC")
{
int dec = atoi(obj);
if (tc.decimal() <= 0 && dec >= 0 && tc.decimal() != dec)
tc.set_decimal(dec);
continue;
}
if (lavoro == "ALI")
{
bool condition = tc.align() != obj[0];
if (condition)
tc.set_align(obj[0]);
continue;
}
if (lavoro == "FIL")
{
if (!obj.blank())
{
bool condition = tc.filler() != obj[1];
if (condition)
{
if (obj.len() > 1)
tc.set_filler(obj[1]);
else
tc.set_filler(obj[0]);
}
}
continue;
}
if (lavoro == "PIC")
{
if (tc.picture().blank() && (!obj.blank()))
tc.set_picture(obj);
continue;
}
if (lavoro == "MES")
{
tc.set_message(obj);
continue;
}
if (_fixedlen && _typelen < 0 && n == _typefield)
_typelen = tc.length();
}
tr->set_relation(tmprel);
//aggiungo il tracciato record all'assoc_array dei tracciati record
_tracciati_record.add(sectkey, tr);
}
TFile_text::TFile_text(const char* file_name, const char* config_name)
: _name(file_name)
{
_read_file = NULL;
_write_file = NULL;
TConfig config(config_name);
TString_array paragraphs;
config.list_paragraphs(paragraphs);//scarico la lista dei paragrafi
int items = paragraphs.items();//quanti paragrafi ho scaricato
TString section, sec;
for (int i = 0; i < items; i++)//scandisco tutti i paragrafi
{
section = paragraphs.row(i) ;//prendo il nome del paragrafo
sec = section.left(3);//prendo le prime tre lettere del nome
if (sec == "MAI") //inizializzo i parametri generali del file
{
set_gen_parm(config,section);
continue;
}
if (sec == "TYP")
{
set_type_parm(config, section);
continue;
}
if (sec == "FTY") // field type
{
set_type_parm(config, section);
continue;
}
if ((sec == "REC")||(sec == "HEA")||(sec == "FOO"))
{
set_rec_parm(config, section);
continue;
}
}
}
TFile_text::~TFile_text()
{
if (_read_file)
delete _read_file;
if (_write_file)
delete _write_file;
}
//Legge da file il record text
int TFile_text::read(TRecord_text& rec)
{
CHECK(_read_file, "Impossibile leggere da un file chiuso.");
TToken_string buffer(_recordsize), lavoro;
if (_recordsize>0)
{
buffer.cut(0);
_read_file->read(buffer.get_buffer(),buffer.size());
if (!ok_r()) return 1; //non ritorna errore se fine file ed il record e' completo!
}
else
{
//legge carattere per carattere fino a quando non si trova il separatore di record
char c = _read_file->get();
if (c == EOF)
return EOF;
while (c != _recordsep[0])
{
buffer << c;
c = _read_file->get();
if (!ok_r())
return EOF; //non ritorna errore se fine file ed il record e' completo!
}
// prendo il resto del separatore
int l = _recordsep.len()-1;
for (int j = 0; j < l;c = _read_file-> get (), j++);
}
if (_fieldsep > ' ')
{
buffer.separator(_fieldsep);
const char* tipo = _typefield >= 0 ? buffer.get(_typefield) : "";
TTracciato_record& tr = *t_rec(tipo);
rec.set_type(tipo);//istanzio il tipo del record text
TArray& a_tc = tr.tracciati_campo();
int items = a_tc.items();
buffer.restart();
for (int i = 0; i < items; i++)
{
// TTracciato_campo& tc = tr.get(i);
lavoro = buffer.get();
rec.add(lavoro, i);
}
}
else
{
TString tipo = buffer.mid(_typepos, _typelen);
tipo.trim();
rec.set_type(tipo);//istanzio il tipo del record text
TTracciato_record* tr = t_rec(tipo);
CHECK(tr,"Tipo di tracciato record non riconosciuto");
//ora che ho il tracciato record devo scandire i tracciati campo e caricare il record text
TArray& a_tc = tr->tracciati_campo();
int items = a_tc.items();
for (int i = 0; i < items; i++)
{
TTracciato_campo& tc = tr->get(i);
int pos = tc.position();
int len = tc.length();
lavoro = buffer.mid(pos, len);
rec.add(lavoro, i);
}
}
return 0;
}
//Scrive su file il record_text (valido anche per header e footer)
int TFile_text::write(TRecord_text& rec)
{
TString buffer;
TString campo;
const TString& type = rec.type();
TTracciato_record& tr = *t_rec(type);
TArray& a_tc = tr.tracciati_campo();
int items = rec.items();
if (_typepos>=0)
rec.add(type,_typepos);
if (_fixedlen) // campi a lunghezza fissa
{
for (int i = 0; i < items; i++)
{
TTracciato_campo& tc = tr.get(i);
campo = rec.row(i);
campo = format_textfield(tc, campo);
buffer.insert(campo, tc.position());
//buffer << campo;
campo.cut(0);
}
CHECK(_write_file, "Impossibile scrivere su un file chiuso.");
*_write_file << buffer;
if (_recordsize<=0) // Record a lunghezza var
*_write_file << _recordsep;
if (!ok_w()) return 1;
buffer.cut(0);
}
else
{
TToken_string ts(buffer, _fieldsep);
for (int i = 0; i < items; i++)
{
TTracciato_campo& tc = tr.get(i);
campo = rec.row(i);
campo = format_textfield(tc, campo);
ts.add(campo, i);
campo.cut(0);
}
CHECK(_write_file, "Impossibile scrivere su un file chiuso.");
*_write_file << ts;
*_write_file << _recordsep;
if (!ok_w()) return 1;
ts.cut(0);
}
return 0;
}
// Carica tutti i dati del tracciato record (anche header o footer)
// nel record_text
void TFile_text::autoload(TRecord_text& rec, int mainfile)
{
TTracciato_record* tr = t_rec(mainfile);
if (tr)
{
// esiste il tracciato e posso fare l'autoload
TCursor cur(tr->relation());
rec.set_type(tr->type());
_autoload(rec,cur,*tr);
}
}
//Carica tutti i dati nel tracciato record (valido anche per header e footer) nel record_text
void TFile_text::autoload(TRecord_text& rec, TCursor& cur , const TString* tipo)
{
const TString& type = rec.type();
if (tipo == NULL) tipo = &type;
TTracciato_record& tr = *t_rec(*tipo);
_autoload(rec,cur,tr);
}
void TFile_text::autoload(TCursor& cur, const TString* tipo)
{
CHECK(_current,"Record corrente non settato");
autoload(*_current, cur, tipo);
}
//Carica tutti i dati nel tracciato record (valido anche per header e footer) nel record_text
void TFile_text::_autoload(TRecord_text& rec, TCursor& cur , TTracciato_record& tr )
{
TString campo;
TRelation& rel = *cur.relation();
TArray& a_tc = tr.tracciati_campo();
int items = a_tc.items();
for (int i = 0; i < items; i++)
{
TTracciato_campo& tc = tr.get(i);
TFieldref field = tc.field();
if (field.file()==0)
field.set_file(rel.lfile().num());
if (!field.name().empty())
campo = field.read(rel);
TString message = tc.message();
if (!message.empty())
{
TToken_string msg (message, ',');
if (!msg.blank())
validate(cur, rec, msg, campo);
}
rec.add(campo, i);
campo.cut(0);
}
}
int TFile_text::autosave(int mainfile, const TRecord_text& rec)
{
const TString& type = rec.type();//prendo il tracciato record del tipo del record_text
TTracciato_record* tr = t_rec(type);
if (tr)
if (tr->relation())
if (tr->relation()->lfile().num()==mainfile)
return _autosave(*(tr->relation()),rec, *tr);
return NOERR; // l'assenza del tracciato non significa un errore
}
int TFile_text::autosave(TRelation& rel, const TRecord_text& rec)
{
const TString& type = rec.type();//prendo il tracciato record del tipo del record_text
TTracciato_record& tr = *t_rec(type);
return _autosave(rel,rec, tr);
}
int TFile_text::autosave(int mainfile)
{
CHECK(_current,"Record corrente non settato");
return autosave(mainfile,*_current);
}
//Carico la relazione con i dati del record text
int TFile_text::_autosave(TRelation& rel, const TRecord_text& rec, TTracciato_record& tr )
{
TArray& a_tc = tr.tracciati_campo();
int items = a_tc.items();
TString valore;
for (int i = 0; i < items; i++)
{
const TTracciato_campo& tc = tr.get(i);
TFieldref field(tc.field());
if (field.name().not_empty())
{
if (field.file()==0)
field.set_file(rel.lfile().num());
valore = rec.row(i);
// formatta il campo del file di testo secondo le specifiche del campo su file isam
preformat_field(field,valore,rel,tr.type());
const TRectype& rel_rec = rel.curr(field.file());
TFieldtypes tipo_campo = rel_rec.type(field.name());
switch(tipo_campo)
{
case _datefld:
{
TDate data(valore);
format_date(data, fpicture(tc), valore);//formatta la data secondo le specifiche del tracciato
}
break;
case _realfld:
case _intfld:
case _longfld:
{
real numero(valore);
valore = numero.string(fpicture(tc));//formatta il numero secondo le specifiche del tracciato
int length = rel_rec.length(field.name());
if (falign(tc) == 'R')
valore.right_just(length, ffiller(tc));
else
valore.left_just(length, ffiller(tc));
int j = valore.replace('.', _decsep); //!?!?! consento decsep diversi per isam e text ?
CHECK(j >= 0 && j <= 1 , "Impossibile scrivere pi<70> separatori decimali.");
}
break;
default:
valore = format_field(tc, rel.lfile().num(), valore);//formatta il campo secondo le specifiche del record
break;
}
field.write(valore, rel);//faccio una write sulla relazione del fieldref
}
}
if (pre_writerel(rel,rec))
{
int err= rel.write();
if (err == _isdupkey || err ==_isreinsert)
err = rel.rewrite();
return err;
} else
return NOERR;
}
//Scarica dal record_text il campo alla posizione <ncampo>
const TString& TFile_text::get_field(const TRecord_text& rec, int ncampo)
{
/* Guy was here
const TString& type = rec.type();//prendo il tracciato record del tipo del record_text
TTracciato_record tr(type);
TTracciato_campo& tc = tr.get(ncampo);
*/
return rec.row(ncampo);
}
//Scarica dal record_text il campo <name>
const TString& TFile_text::get_field(const TRecord_text& rec, const char* name)
{
TTracciato_record& tr = *t_rec(rec.type());
int ncampo = tr.get_pos(name);
CHECKS(ncampo >= 0, "Campo inesistente ", name);
return rec.row(ncampo);
}
//Carica nel record_text il campo alla posizione <ncampo> con il valore <val> gi<67> formattato
void TFile_text::add_field(TRecord_text& rec, const int ncampo, const char* val)
{
TTracciato_record& tr = *t_rec(rec.type());
TTracciato_campo& tc = tr.get(ncampo);
TString valore = val;
//valore =format_textfield(tc, valore);
rec.add(valore, ncampo);
}
//Formatta la data in base al tracciato
void TFile_text::format_date(const TDate& data, const TString& form, TString& data_str)
{
int i = 1, cnt = 0;
char x = form[0];
do
{
char k = x;
if (k != 'a' && k != 'm'&& k != 'g')
data_str << k;
else
cnt++;
x = form[i];
i++;
if (k != x)
switch (k)
{
case 'g': CHECKD(cnt >= 1 && cnt <= 4, "Formato per giorno non valido ", cnt);
if (cnt == 1) data_str << data.day();
if (cnt == 2) data_str << format("%02d", data.day());
if (cnt == 3) {TString s = itow(data.wday());s.cut(3);data_str << s;}
if (cnt == 4) data_str << itow(data.wday());
cnt = 0;
break;
case 'm': CHECKD(cnt >= 1 && cnt <= 4, "Formato per mese non valido ", cnt);
if (cnt == 1) data_str << data.month();
if (cnt == 2) data_str << format("%02d", data.month());
if (cnt == 3) {TString s = itom(data.month());s.cut(3);data_str << s;}
if (cnt == 4) data_str << itom(data.month());
cnt = 0;
break;
case 'a': CHECKD(cnt >= 2 && cnt <= 4, "Formato per anno non valido ", cnt);
if (cnt == 2) {TString s;s << data.year();s.ltrim(2);data_str << s;}
if (cnt == 3) {TString s;s << data.year();s.ltrim(1);data_str << s;}
if (cnt == 4) data_str << data.year();
cnt = 0;
break;
}
}
while (i <= form.len());
}
//Formatta la stringa in base al tracciato
TString& TFile_text::format_textfield(const TTracciato_campo& tc, TString& campo)
{
//int pos = tc.position();
int length = tc.length();
char fillch=tc.filler();
if (!tc.picture().blank())
{ TString tmp;
tmp.picture(tc.picture(), campo);
campo=tmp;
}
if (length > campo.len())
{
if (fillch == '\0' && _fixedlen)
fillch=' ';
if (tc.align() == 'R')
campo.right_just(length,fillch);
else
campo.left_just(length, fillch);
}
else
if (length > 0)
if (tc.align() == 'R')
campo=campo.right(length);
else
campo.cut(length);
return campo;
}
//Formatta la stringa in base al field del file isam
TString& TFile_text::format_field(const TTracciato_campo& tc, short lfile, TString& campo)
{
const TRectype record(tc.field().file() ? tc.field().file() : lfile);
int length = tc.field().len(record);
if (!fpicture(tc).blank())
{ TString tmp;
tmp.picture(fpicture(tc), campo);
campo=tmp;
}
if (length > campo.len())
{
if (falign(tc) == 'R')
campo.right_just(length, ffiller(tc));
else
campo.left_just(length, ffiller(tc));
}
else
if (length > 0)
if (falign(tc) == 'R')
campo=campo.right(length);
else
campo.cut(length);
return campo;
}
int TFile_text::open(char mode)
{
if (mode == 'r')//apertura in lettura
{
if (_read_file)
delete _read_file;
_read_file = new ifstream(_name, ios::binary | ios::nocreate);
if (!ok_r())
{
error_box("Impossibile aprire il file %s in lettura", (const char *)_name);
return _read_file->rdstate() != ios::goodbit;
}
}
if (mode == 'w')//apertura in scrittura
{
if (_write_file)
delete _write_file;
_write_file = new ofstream(_name, ios::binary|ios::app);
}
return 0;
}
int TFile_text::open(const char* name, char mode)
{
set_name(name);
return open(mode);
}
int TFile_text::close()
{
_name = "";
_current = NULL;
_tipi.destroy();
_tracciati_record.destroy();
if (_read_file) _read_file->close();
if (_write_file) _write_file->close();
return 0;
}