#include #include #include #include #include #include #include #include #include // GetPrawinName bool TConfig::add_line(const TString& l) { const int ind = l.find('='); if (ind < 0) return FALSE; TString80 key = l.left(ind); key.trim(); TString& val = (TString&)l.mid(ind+1); val.trim(); if (val[0] == '%') { if (val == "%yr%") { time_t ora; time(&ora); struct tm * oggi = localtime(&ora); if (oggi != NULL) val.format("%04d", 1900 + oggi->tm_year); else NFCHECK("Impossibile reperire la data corrente del sistema."); } else { if (val == "%frm%") val.format("%05ld", prefix().get_codditta()); } } // sostituzione abilitata return _data.add(key,val,TRUE); } // @doc EXTERNAL // @mfunc Legge i dati del paragrafo // // @rdesc Ritorna i seguenti valori: // // @flag TRUE | Se il paragrafo c'ere // @flag FALSE | Se il pragarafo non e' esitente bool TConfig::_read_paragraph() // @comm Legge il contenuto di tutte le variabili del paragrafo attivo { bool itwas = FALSE; _data.destroy(); TScanner scan(_file); if (scan.paragraph(_paragraph)) { itwas = TRUE; // populate array while(TRUE) { const TString& l = scan.line(); if (l.empty() || l[0] == '[') break; // Fine paragrafo if (l[0] == '#' || l[0] == '/') continue; // Riga di commento add_line(l); } } return itwas; } // @doc EXTERNAL // @mfunc Scrive i dati del paragrafo void TConfig::_write_paragraph( ofstream& out) // @parm Indirizzo dell'utput sul quale scrivere il paragrafo // @comm Scrive sullo stream

out le variabili del paragrafo attivo. { if (_data.items() > 0) // Inutile scrivere paragrafi vuoti! { out << '[' << _paragraph << ']' << endl; /* _data.restart(); for (THash_object* o = _data.get_hashobj(); o; o = _data.get_hashobj()) out << o->key() << " = " << (TString&)(o->obj()) << '\n'; */ TString_array a; list_variables(a, FALSE,_paragraph,TRUE); // get array sorted by varname for (int i = 0; i < a.items(); i++) { TToken_string& name = a.row(i); out << name << " = "; out << get(name) << endl; } out << endl; } } void TConfig::_write_file() { if (_write_protected) return; TFilename temp; temp.temp("cnf"); ofstream out(temp); if (!out.good()) { NFCHECK("Impossibile scrivere %s per aggiornare %s", (const char*)temp, (const char*)_file); return; } bool skip = FALSE, done = FALSE, skip_empty = TRUE; if (_file.exist()) { ifstream in(_file, ios::in | ios::nocreate, filebuf::sh_read); if (in.good()) { TString l(1024); TString cnf; cnf << '[' << _paragraph << ']'; while (!in.eof()) { in.getline(l.get_buffer(), l.size()); l.trim(); if (cnf == l) { // write paragraph and all variables _write_paragraph(out); skip = skip_empty = done = TRUE; } else { if (skip) skip = l[0] != '['; if (!skip) { const bool empty = l.empty(); if (!empty || !skip_empty) out << l << endl; skip_empty = empty; } } } } else { NFCHECK("Impossibile aggiornare il file %s", (const char*)_file); return; } } // new paragraph if (!done) _write_paragraph(out); out.close(); if (fexist(_file)) { while (access(_file, 02) != 0) message_box("Il file %s e' gia' in uso", (const char*)_file); } fcopy(temp, _file); // Copia dalla tempdir al nuovo .ini ::remove(temp); // Cancella file temporaneo } bool TConfig::set_paragraph(const char* section) { bool ok = TRUE; if (section != NULL && _paragraph != section) { if (_dirty) _write_file(); _paragraph = section; _dirty = FALSE; _ispresent = _read_paragraph(); ok = _ispresent; } return ok; } // @doc EXTERNAL // @mfunc Controlla se esite una variabile nel paragrafo attivo // // @rdesc Ritorna i seguenti valori: // // @flag TRUE | Se la variabile esite // @flag FALSE | Se la variabile non esite bool TConfig::exist( const char* var, // @parm Nome della variabile int index) // @parm Indice dell'elemento dell'array (default -1) // @comm Se

e' = 0 viene costruito il nome dell'elemento // dell'array da cercare, diversamente viene cercata la variabile // normale passata in

. { if (index >= 0) { TString key(80); key << var << '(' << index << ')'; return _data.is_key(key); } return _data.is_key(var); } // @doc EXTERNAL // @mfunc Elimina una variabile dal paragrafo corrente // // @rdesc Ritorna i seguenti valori: // // @flag TRUE | Se la variabile esiteva // @flag FALSE | Se la variabile non esiteva bool TConfig::remove( const char* var, // @parm Nome della variabile int index) // @parm Indice dell'elemento dell'array (default -1) // @comm Se

e' = 0 viene costruito il nome dell'elemento // dell'array da cercare, diversamente viene cercata la variabile // normale passata in

. { TString key(var); if (index >= 0) key << '(' << index << ')'; const bool ok = _data.remove(key); if (ok) _dirty = TRUE; return ok; } void TConfig::remove_all() { if (_data.items() > 0) { _data.destroy(); _dirty = TRUE; } } // @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 //

const TString& TConfig::get( const char* var, // @parm Variabile della quale ritornare il valore const char* section, // @parm Sezione della varaibile (default NULL) int index, // @parm Eventuale indice della varaibailie (default -1) const char* def) // @parm Valore default della varaibile (default "") // @comm Passando

= 0 viene appeso al nome della variabile per // implementare un array. // Il paragrafo passato in

diventa quello attivo. // // @xref // { if (section) // Cambia paragrafo se necessario set_paragraph(section); const TString* val; if (index >= 0) { TString v(80); v << var << '(' << index << ')'; val = (TString*)_data.objptr(v); } else val = (TString*)_data.objptr(var); if (val == NULL) // Se non la trova inserisci il default { if (def && *def) { set(var, def, section, TRUE, index); val = &get(var, NULL, index); } else val = &EMPTY_STRING; } return *val; } // @doc EXTERNAL // @mfunc Ritorna il valore della variabile nella sezione corrente o in // quella specificata // // @rdesc Ritorna il numero contenuto nella variabile, se questa esiste, altrimenti // il valore di default che dovrebbe assumere determinato dal parametro //

long TConfig::get_long( const char* var, // @parm Variabile della quale ritornare il valore const char* section, // @parm Sezione della varaibile (default NULL) int index, // @parm Eventuale indice della varaibailie (default -1) long def) // @parm Valore default della varaibile (default 0L) // @comm Passando

= 0 viene appeso al nome variabile per // implementare un array. // Il paragrafo passato in

diventa quello attivo. // // @xref // { const char* n = get(var,section,index); if (*n) def = atol(n); else if (def != 0) { TString16 d; d << def; set(var, d, section, TRUE, index); } return def; } // @doc EXTERNAL // @mfunc Ritorna il valore della variabile nella sezione corrente o in // quella specificata // // @rdesc Ritorna il primo carattere della variabile, se questa esiste, altrimenti // il valore di default che dovrebbe assumere determinato dal parametro //

char TConfig::get_char( const char* var, // @parm Variabile della quale ritornare il valore const char* section, // @parm Sezione della varaibile (default NULL) int index, // @parm Eventuale indice della varaibailie (default -1) char def) // @parm Valore default della varaibile (default ' ') // @comm Passando

= 0 viene appeso al nome variabile per // implementare un array. // Il paragrafo passato in

diventa quello attivo. // // @xref // { const char* n = get(var,section,index); if (*n) def = *n; else if (!isspace(def)) { const char d[2] = { def, '\0' }; set(var, d, section, TRUE, index); } return def; } // @doc EXTERNAL // @mfunc Ritorna il valore della variabile nella sezione corrente o in // quella specificata // // @rdesc Ritorna l'intero contenuto nella variabile, se questa esiste, altrimenti // il valore di default che dovrebbe assumere determinato dal parametro //

int TConfig::get_int( const char* var, // @parm Variabile della quale ritornare il valore const char* section, // @parm Sezione della varaibile (default NULL) int index, // @parm Eventuale indice della varaibailie (default -1) int def) // @parm Valore default della varaibile (default 0) // @comm Chiama la funzione e ne ritorna un intero. // Passando

= 0 viene appeso al nome variabile per // implementare un array. // Il paragrafo passato in

diventa quello attivo. // // @xref // { return (int)get_long(var, section, index, def); } // @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

| Se la varabile non esiste bool TConfig::get_bool( const char* var, // @parm Variabile della quale ritornare il valore const char* section, // @parm Sezione della varaibile (default NULL) int index, // @parm Eventuale indice della varaibailie (default -1) bool def) // @parm Valore default della varaibile (default FALSE) // @comm Viene chiamata la funzione . // Passando

= 0 viene appeso al nome variabile per // implementare un array. // Il paragrafo passato in

diventa quello attivo. // // @xref // { const char* d = def ? "X" : ""; TString& s = (TString&)get(var, section, index, d); s.upper(); return s != "" && (s == "X" || s == "Y" || s == "1" || s == "ON" || s == "YES" || s == "OK" || s == "TRUE"); } // @doc EXTERNAL // @mfunc Ritorna il valore del colore settato nella variabile nella // sezione corrente o in quella specificata COLOR TConfig::get_color( const char* var, // @parm Variabile della quale ritornare il valore const char* section, // @parm Sezione della varaibile (default NULL) int index, // @parm Eventuale indice della varaibailie (default -1) COLOR def) // @parm Valore default della varaibile (default 0) // @comm Passando

= 0 viene appeso al nome variabile per // implementare un array. // Il paragrafo passato in

diventa quello attivo. // // @xref // { const char* c = get(var, section, index); if (*c) { TToken_string s(c, ','); const byte r = (byte)s.get_int(); const byte g = (byte)s.get_int(); const byte b = (byte)s.get_int(); def = RGB2COLOR(r, g, b); } else { TString16 d; d.format("%d,%d,%d", XVT_COLOR_GET_RED(def), XVT_COLOR_GET_GREEN(def), XVT_COLOR_GET_BLUE(def)); set(var, d, section, TRUE, index); } return def; } // @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 TConfig::set( const char* var, // @parm Nome della variabile da settare const char* value, // @parm Stringa da assegnare alla variabile const char* section, // @parm Nome del paragrafo a cui appartiene la variabile bool force, // @parm Per la creazione di una variabile inesistente int index) // @parm Eventuale indice della variabile // @parm long | value | Valore da assegnare alla variabile { // @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

== TRUE crea il paragrafo e la variabile se non esistono; // altrimenti da' errore. // Passando

= 0 viene appeso al nome variabile per // implementare un array. // Il paragrafo passato in

diventa quello attivo. if (section && *section) set_paragraph(section); /* const bool itwas = exist(var, index); if (itwas && !force) error_box("Tentativo di ridefinizione simbolo: %s(%d)", var, index); else { TString256 vvar(var); if (index >= 0) vvar << '(' << index << ')'; _data.add(vvar, new TString(value), force); _dirty = TRUE; } */ TString256 key(var); if (index >= 0) key << '(' << index << ')'; TString* val = (TString*)_data.objptr(key); const bool itwas = val != NULL; if (itwas && !force) error_box("Tentativo di ridefinizione simbolo: %s", (const char*)key); else { 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(); _dirty = TRUE; // ... e metto a dirty. } } else { // Se la variabile non esisteva allora la aggiungo e metto a dirty. val = new TString(value); val->trim(); _data.add(key, val, TRUE); _dirty = TRUE; } } return itwas; } bool TConfig::set(const char* var, long value, const char* section, bool force, int index) { TString16 t; t << value; return set(var,t,section,force,index); } bool TConfig::set_color(const char* var, COLOR col, const char* section, bool force, int index) { 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,section,force,index); } // @doc EXTERNAL // @mfunc Ritorna quanti elementi dell'array nominato sono presenti nella // sezione indicata. word TConfig::items( const char* var, // @parm Nome dell'array const char* section) // @parm Sezione indicata // @comm Il paragrafo passato in

diventa quello attivo. // Possono esserci dei "buchi" causati da set() errate { if (section) set_paragraph(section); for (int cnt = 0; exist(var, cnt); cnt++); return cnt; } // @doc EXTERNAL // @mfunc Inizializza il paragrafo leggendo dal file i dati void TConfig::init( const char *fn, // @parm Nome del file da leggere const char* pa, // @parm Nome del paragrafo da utilizzare bool warning) // @parm Segnala assenza del file // @comm Apre il file

e cerca il paragrafo

. Se il file non esiste // viene creato con il paragrafo passato. { _file = fn; _paragraph = pa; _dirty = FALSE; _write_protected = FALSE; if (!_file.exist()) { if (warning) warning_box("Creazione del file di configurazione %s", fn ); ofstream c(fn); c.close(); } if (_paragraph.blank()) { _paragraph = main_app().name(); _paragraph.cut(2); _paragraph.lower(); } _ispresent = _read_paragraph(); } int TConfig::list_paragraphs(TString_array& pl) { TScanner s(_file); pl.destroy(); while (s.line().not_empty()) { if (s.token()[0] == '[') { TToken_string* p = new TToken_string(s.token()); p->strip("[]"); pl.add(p); } } return pl.items(); } HIDDEN int compare_ini_variables(const TObject**o1, const TObject**o2) { const TString* s1 = (const TString*)*o1; const TString* s2 = (const TString*)*o2; const int p1 = s1->find('('); if (p1 < 0) return strcmp(*s1, *s2); else { // variabile tipo XX(i) int result= strncmp(*s1, *s2,p1); if (result==0) { if (s2->find('(')<0) result = 1; else { CHECKS(s1->find(')')>=0,"Errore: parentesi non chiusa in ",(const char *)(*s1)); CHECKS(s2->find(')')>=0,"Errore: parentesi non chiusa in ",(const char *)(*s2)); const int i1=atoi(s1->sub(p1+1,s1->len()-1)); const int i2=atoi(s2->sub(p1+1,s2->len()-1)); result = i1-i2; } } return result; } } int TConfig::list_variables(TString_array& vl, bool value, const char* section, const bool sort) { set_paragraph(section); vl.destroy(); _data.restart(); for (int i = 0; i < _data.items(); i++) { THash_object* o = _data.get_hashobj(); TToken_string* t = new TToken_string(o->key()); if (value) t->add((TString&)(o->obj())); vl.add(t); } if (sort) vl.TArray::sort(compare_ini_variables); return vl.items(); } TAssoc_array& TConfig::list_variables(const char* section) { set_paragraph(section); return _data; } int TConfig::for_each_paragraph(CONFIG_CALLBACK cfgcb, void* jolly) { int count = 0; TScanner scanner(_file); _paragraph.cut(0); bool needs_call = FALSE; while (scanner.line().not_empty()) { const TString& riga = scanner.token(); if (riga[0] == '[') { count++; if (needs_call) { needs_call = FALSE; if (cfgcb && cfgcb(*this, jolly)) break; } _paragraph = riga; _paragraph.strip("[]"); _data.destroy(); needs_call = TRUE; } else add_line(riga); } if (needs_call && cfgcb) cfgcb(*this, jolly); return count; } TConfig::TConfig(int which_config, const char* paragraph) { switch (which_config) { case CONFIG_DITTA: _file = firm2dir(prefix().get_codditta()); _file.add("prassid.ini"); if (!fexist(_file) && fexist("prassid.ini")) fcopy("prassid.ini", _file); break; case CONFIG_STUDIO: case CONFIG_USER: case CONFIG_STAMPE: _file = firm2dir(-1); // Directory dati _file.add("config"); // Directory config if (!_file.exist()) // Creala se necessario make_dir(_file); switch (which_config) { case CONFIG_STUDIO: _file.add("prassis.ini"); if (!_file.exist() && fexist("prassis.ini")) fcopy("prassis.ini", _file); break; case CONFIG_STAMPE: _file.add("print.ini"); break; case CONFIG_USER: { TString16 u = user(); if (u.blank()) u = ::dongle().administrator(); else u.upper(); _file.add(u); _file.ext("ini"); if (u != "PRASSI" && !fexist(_file)) { TFilename prassi = _file.path(); prassi.add("prassi.ini"); fcopy(prassi, _file); } } break; default: break; } break; case CONFIG_FCONV: _file = "fconv.ini"; break; case CONFIG_INSTALL: _file = CGetPrawinName(); break; default: _file = "prassi.ini"; NFCHECK("Chi usa prassi.ini?"); break; } init(_file, paragraph, FALSE); } TConfig::TConfig(const char *fn, const char* pa) { init(fn, pa, FALSE); } TConfig::~TConfig() { // il distruttore riscrive il file con le modifiche se necessario if (_dirty) _write_file(); }