#include #include #include #include #include #include #include #include // CGetPrawinName bool TConfig::add_line(const TString& l) { const int ind = l.find('='); if (ind < 0) return FALSE; TString256 key = l.left(ind); key.trim(); TString val = l.mid(ind+1); val.trim(); if (val[0] == '%') { if (val == "%yr%") { struct tm * oggi = xvt_time_now(); 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(); if (_file.exist()) { TScanner scan(_file); itwas = scan.paragraph(_paragraph); if (itwas) { // populate array for(;;) { 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); 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 (xvt_fsys_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; } bool TConfig::set_paragraph(int par, int sub) { CHECKD(par > 0 && sub >= 0, "Invalid numeric paragraph ", par); TString16 pa; pa << par; if (sub > 0) pa << ',' << sub; return set_paragraph(pa); } const char* TConfig::get_varkey(const char* var, int index) const { if (index >= 0) { TString& tmp = get_tmp_string(); tmp << var << '(' << index << ')'; return tmp; } return var; } // @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

. { const char* key = get_varkey(var, index); return _data.is_key(key); } // @doc EXTERNAL // @mfunc Controlla se esite una variabile nel paragrafo section // // @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 const char* section, // @parm Sezione 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 (section && *section) // Cambia paragrafo se necessario set_paragraph(section); const char* key = get_varkey(var, index); return exist(var, index); } // @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

. { const char* key = get_varkey(var, index); const bool ok = _data.remove(key); if (ok) _dirty = true; 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 TConfig::remove_array( const char* var) // @parm Nome della variabile // @comm Viene cancellata l'aray di variabili passata in

. { TAssoc_array & arr = list_variables(); bool ok = false; TString80 s = var; s << '('; FOR_EACH_ASSOC_STRING(arr, obj, key, str) { const TFixed_string k(key); if (k.starts_with(s)) ok = 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 variabile (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 && *section) // Cambia paragrafo se necessario set_paragraph(section); const char* key = get_varkey(var, index); const TString* val = (TString*)_data.objptr(key); 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 variabile (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 variabile (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 // { bool yes = false; TString& s = (TString&)get(var, section, index, def ? "X" : ""); 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 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 // { TToken_string s(get(var, section, index), ','); 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(); def = RGB2COLOR(r, g, b); } else { def = atol(s); if (def == 0L) def = COLOR_BLACK; } } 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 char* key = get_varkey(var, 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 { int cnt; if (section && *section) set_paragraph(section); for (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 // @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()) { 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) { pl.destroy(); if (_file.exist()) { TScanner s(_file); 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; } static void cfg2file(int which_config, TFilename& file) { switch (which_config) { case CONFIG_GENERAL: file = "./install.ini"; break; case CONFIG_DITTA: file = firm2dir(prefix().get_codditta()); file.add("ditta.ini"); if (!file.exist()) { TFilename oldfile = file; const int pos = oldfile.find("ditta.ini"); oldfile.cut(pos); oldfile.add("prassid.ini"); // Old config file! if (oldfile.exist()) fcopy(oldfile, file); } break; case CONFIG_STUDIO: case CONFIG_STAMPE: case CONFIG_GUI: case CONFIG_USER: case CONFIG_WST: 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("studio.ini"); if (!file.exist()) { TFilename oldfile = file; const int pos = oldfile.find("studio.ini"); oldfile.cut(pos); oldfile.add("prassis.ini"); // Old config file! if (oldfile.exist()) fcopy(oldfile, file); } break; case CONFIG_STAMPE: file.add("print.ini"); break; case CONFIG_GUI: { TFilename gui = "gui.ini"; if (gui.custom_path()) { file = gui; // I colori sono qui ... break; // ... scavalca utente } } case CONFIG_USER: { TString80 u = user(); if (u.blank()) u = ::dongle().administrator(); u.lower(); file.add(u); file.ext("ini"); if (u != "admin" && !file.exist()) { TFilename prassi = file.path(); prassi.add("admin.ini"); fcopy(prassi, file); } } break; case CONFIG_WST: { TString80 u = get_hostname(); if (u.blank()) u = "localhost"; u.lower(); file.add(u); file.ext("ini"); } break; default: break; } break; case CONFIG_FCONV: file = "fconv.ini"; break; case CONFIG_INSTALL: file = CGetCampoIni(); break; case CONFIG_OEM: file = "setup/oem.ini"; break; default: NFCHECK("Chi usa questo strano .ini?"); break; } } TConfig::TConfig(int which_config, const char* paragraph) { cfg2file(which_config, _file); init(_file, paragraph); } TConfig::TConfig(const char *fn, const char* pa) { TFilename f(fn); f.custom_path(); init(f, pa); } TConfig::TConfig(const char* file, int num, int sub) { CHECKD(num > 0 && num < 10000, "Invalid paragraph ", num); TFilename f(file); f.custom_path(); TString16 pa; pa << num; if (sub > 0) pa << ',' << sub; init(f, pa); } TConfig::~TConfig() { // il distruttore riscrive il file con le modifiche se necessario if (_dirty && !_write_protected) _write_file(); } /////////////////////////////////////////////////////////// // Utilities /////////////////////////////////////////////////////////// #define DECLARE_VARNAME(name, idx) const char* varname = idx >= 0 ? (const char*)(get_tmp_string() << name << '(' << idx << ')') : name #define DECLARE_FILENAME(cfg) TFilename filename; cfg2file(cfg, filename) const TString& ini_get_string(const char* file, const char* paragraph, const char* name, const char* defval, int idx) { DECLARE_VARNAME(name, idx); TString& tmp = get_tmp_string(); const int len = xvt_sys_get_profile_string(file, paragraph, varname, defval, tmp.get_buffer(), tmp.size()); if (len > tmp.size()) { tmp.get_buffer(len); xvt_sys_get_profile_string(file, paragraph, varname, defval, tmp.get_buffer(), tmp.size()); } if (tmp[0] == '"') { tmp.rtrim(1); tmp.ltrim(1); } else tmp.trim(); return tmp; } bool ini_set_string(const char* file, const char* paragraph, const char* name, const char* val, int idx) { DECLARE_VARNAME(name, idx); return xvt_sys_set_profile_string(file, paragraph, varname, val) != 0; } bool ini_get_bool(const char* file, const char* para, const char* name, bool defval, int idx) { const char b = ini_get_string(file, para, name, defval ? "1" : "0", idx)[0]; return (b > ' ') && (strchr("1SXY", b) != NULL); } bool ini_get_bool(int cfg, const char* para, const char* name, bool defval, int idx) { DECLARE_FILENAME(cfg); return ini_get_bool(filename, para, name, defval, idx); } int ini_get_int(const char* file, const char* para, const char* name, int defval, int idx) { DECLARE_VARNAME(name, idx); return xvt_sys_get_profile_int(file, para, varname, defval); } bool ini_set_int(const char* file, const char* paragraph, const char* name, int val, int idx) { TString16 value; value << val; return ini_set_string(file, paragraph, name, value, idx); } bool ini_set_bool(const char* file, const char* paragraph, const char* name, bool val, int idx) { return ini_set_string(file, paragraph, name, val ? "1" : "0", idx); } const TString& ini_get_string(int cfg, const char* paragraph, const char* name, const char* defval, int idx) { DECLARE_FILENAME(cfg); return ini_get_string(filename, paragraph, name, defval, idx); } bool ini_set_string(int cfg, const char* paragraph, const char* name, const char* val, int idx) { DECLARE_FILENAME(cfg); return ini_set_string(filename, paragraph, name, val); } int ini_get_int(int cfg, const char* paragraph, const char* name, int defval, int idx) { DECLARE_FILENAME(cfg); return ini_get_int(filename, paragraph, name, defval, idx); } bool ini_set_int(int cfg, const char* paragraph, const char* name, int val, int idx) { DECLARE_FILENAME(cfg); return ini_set_int(filename, paragraph, name, val, idx); } bool ini_set_bool(int cfg, const char* paragraph, const char* name, bool val, int idx) { DECLARE_FILENAME(cfg); return ini_set_string(filename, paragraph, name, val ? "1" : "0", idx); } const TString& get_oem_info(const char* varname, const char* def) { TString& tmp = get_tmp_string(50); xvt_sys_get_oem_string(varname, def, tmp.get_buffer(), tmp.size()); return tmp; }