#include #include //////////////////////////////////////// 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ą 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 { NFCHECK("Join non ancora supportati"); continue; } TTracciato_campo& tc = tr->get(n);//prendo il tracciato campo con indice 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); if (_fixedlen && _typelen < 0 && n == _typefield) _typelen = 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; } } 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); //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); } //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); const TFieldref& field = tc.field(); 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); } //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); const TFieldref& field = tc.field(); if (field.name().not_empty()) { valore = rec.row(i); // formatta il campo del file di testo secondo le specifiche del campo su file isam // preformat_field(rel,field,rec,valore); preformat_field(field,valore); 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ł separatori decimali."); } break; default: valore = format_field(tc, valore);//formatta il campo secondo le specifiche del record break; } field.write(valore, rel);//faccio una write sulla relazione del fieldref } } pre_write(rel,rec); int err = rel.write(); if (err == _isdupkey || err ==_isreinsert) err = rel.rewrite(); return err; } //Scarica dal record_text il campo alla posizione 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 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 con il valore gią 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, TString& campo) { const TRectype record(tc.field().file()); 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; }