#include #include #include #include #include #include #include #include #include #include #include "ba2.h" #include "ba2700.h" /////////////////////////////////////////////////////////// // TDictionary_entry /////////////////////////////////////////////////////////// class TDictionary_entry : public TSortable { public: TString _ita, _eng; TToken_string _src; int _max_length; virtual int compare(const TSortable& obj) const; virtual void print_on(ostream& out) const; void set_translation(const char* eng) { _eng = eng; } void add_source(const char* orig); void set_sources(const char* orig); void update_max_length(int len); TDictionary_entry(const char* ita) : _ita(ita), _eng("???"), _src(12, ','), _max_length(0) { } }; void TDictionary_entry::add_source(const char* orig) { TFilename n(orig); n.lower(); const char* src = n.name(); if (_src.get_pos(src) < 0) _src.add(src); } void TDictionary_entry::set_sources(const char* orig) { _src = orig; } void TDictionary_entry::update_max_length(int len) { if (len > 0 && (_max_length <= 0 || len < _max_length)) _max_length = len; } int TDictionary_entry::compare(const TSortable& obj) const { const TDictionary_entry& e = (const TDictionary_entry&)obj; return _ita.compare(e._ita, -1, true); } void TDictionary_entry::print_on(ostream& out) const { out << " " << endl; out << " " << txt2xml(_ita) << "" << endl; out << " " << txt2xml(_eng) << "" << endl; if (_max_length > 0) out << " " << _max_length << "" << endl; out << " " << txt2xml(_src) << "" << endl; out << " " << endl; } /////////////////////////////////////////////////////////// // TDictionary /////////////////////////////////////////////////////////// class TDictionary : public TAssoc_array { TFilename _filename; TPointer_array _sort; bool _sort_needed, _save_needed; public: TDictionary_entry& get_entry(const char* ita); TPointer_array& sorted(); void set_translation(const char* ita, const char* eng); void update_max_length(const char* ita, int len); bool read(const char* fname); bool write(); bool write_if_needed(); void zap_sources(const char * module); void pack(); TDictionary() : _sort_needed(false), _save_needed(false) { } }; TDictionary_entry& TDictionary::get_entry(const char* ita) { TDictionary_entry* entry = (TDictionary_entry*)objptr(ita); if (entry == NULL) { entry = new TDictionary_entry(ita); add(ita, entry); _sort_needed = _save_needed = true; } return *entry; } void TDictionary::set_translation(const char* ita, const char* eng) { TDictionary_entry& entry = get_entry(ita); entry.set_translation(eng); _save_needed = true; } void TDictionary::update_max_length(const char* ita, int len) { TDictionary_entry& entry = get_entry(ita); entry.update_max_length(len); _save_needed = true; } bool TDictionary::read(const char* fname) { _filename = fname; bool ok = _filename.exist(); if (ok) { TProgind pi(fsize(_filename), "Lettura dizionario", false, true); destroy(); TScanner scan(_filename); TString ita; for (int c = 0; scan.ok(); c++) { TString& line = scan.line(); if (line.empty()) break; if (c % 100 == 0) pi.setstatus(scan.tellg()); line.trim(); if (line.starts_with("")) { const int eoi = line.find(""); ita = xml2txt(line.sub(5, eoi)); } else if (line.starts_with("") && ita.not_empty()) { const int eoe = line.find(""); TString& eng = xml2txt(line.sub(5, eoe)); if (eng.blank()) set_translation(ita, "???"); else set_translation(ita, eng.trim()); } if (line.starts_with("") && ita.not_empty()) { const int eom = line.find(""); const int len = atoi(line.sub(5, eom)); update_max_length(ita, len); } if (line.starts_with("") && ita.not_empty()) { TDictionary_entry& entry = get_entry(ita); const int eos = line.find(""); entry.set_sources(xml2txt(line.sub(5, eos))); } } _save_needed = false; } return ok; } void TDictionary::zap_sources(const char * module) { TProgind pi(items(), "Azzeramento sorgenti", false, true); TPointer_array& ref = sorted(); const bool zap = module == NULL || *module == '\0'; for (int i = 0; i < ref.items(); i++) { pi.addstatus(1); TDictionary_entry& e = (TDictionary_entry&)ref[i]; if (zap) e._src.cut(0); else { TToken_string new_src; FOR_EACH_TOKEN(e._src, tok) { if (strncmp(tok, module, 2) != 0) new_src.add(tok); } e._src = new_src; } } } void TDictionary::pack() { TProgind pi(items(), "Compattamento dizionario", false, true); FOR_EACH_ASSOC_OBJECT((*this), h, k, o) { pi.addstatus(1); const TDictionary_entry& e = (const TDictionary_entry&)*o; if (e._src.blank()) { remove(k); _save_needed = true; _sort_needed = true; } } } bool TDictionary::write() { TProgind pi(items(), "Salvataggio dizionario", false, true); TPointer_array& ref = sorted(); ofstream outf(_filename); outf << "" << endl; outf << "" << endl; for (int i = 0; i < ref.items(); i++) { pi.addstatus(1); const TDictionary_entry& e = (const TDictionary_entry&)ref[i]; outf << e; } outf << "" << endl; _save_needed = false; return true; } bool TDictionary::write_if_needed() { bool ok = _save_needed; if (ok) { ok = yesno_box("Si desidera registrare le modifiche al dizionario %s?", (const char*)_filename); if (ok) ok = write(); } return ok; } static int sort_entries(const TObject** o1, const TObject** o2) { const TDictionary_entry* e1 = (const TDictionary_entry*)*o1; const TDictionary_entry* e2 = (const TDictionary_entry*)*o2; return e1->compare(*e2); } TPointer_array& TDictionary::sorted() { if (_sort_needed) { _sort.destroy(); FOR_EACH_ASSOC_OBJECT((*this), h, k, o) _sort.add(o); _sort.sort(sort_entries); _sort_needed = false; } return _sort; } /////////////////////////////////////////////////////////// // TDictionary_mask /////////////////////////////////////////////////////////// class TDictionary_mask : public TAutomask { TDictionary _dictionary; bool _filtered; bool _errors; bool _new; TToken_string _modules; protected: virtual bool on_field_event(TOperable_field& o, TField_event e, long jolly); const TString& get_dictionary_name() const; void set_dictionary_name(const char* name); bool is_a_word(const TString& ita) const; void add_line(const TString& ita, const char* origin); void read_txt_file(const char* fname, int filetype); bool read_txt_files(const char* msk); bool read_bin_file(const char* fname); bool read_bin_files(const char* msk); void build_dictionary(); bool read_dictionary(); void fill_index(); bool check_translation(const TString & ita, const TString & eng, const char tag); bool good_translation(const TString & ita, const TString & eng, const TString & src, int maxlen); void fill_chapter(); public: TDictionary_mask(); ~TDictionary_mask(); }; const TString& TDictionary_mask::get_dictionary_name() const { TConfig ini("servers/servers.ini", "Dictionary"); TFilename n = ini.get("Dictionary"); if (n.is_relative_path()) n.insert("servers/"); TString& tmp = get_tmp_string(); tmp = n; return tmp; } void TDictionary_mask::set_dictionary_name(const char* name) { TFilename n(name); if (n.starts_with("servers")) n.ltrim(); TConfig ini("servers/servers.ini", "Dictionary"); ini.set("Dictionary", n); } bool TDictionary_mask::read_dictionary() { _dictionary.write_if_needed(); const TFilename fname = get_dictionary_name(); const bool ok = _dictionary.read(fname); fill_index(); fill_chapter(); return ok; } bool TDictionary_mask::is_a_word(const TString& ita) const { for (int i = 0; ita[i]; i++) { if (isalpha(ita[i])) { if (i == 0 || ita[i-1] != '@') return true; } } return false; } inline bool valid_char(char c) { return isalnum(c) || strchr("@%'", c); } void TDictionary_mask::add_line(const TString& ita, const char* origin) { int prefix = 0, suffix = 0; for (prefix = 0; ita[prefix] != '\0' && !valid_char(ita[prefix]); prefix++); for (suffix = ita.len()-1; suffix > prefix && !valid_char(ita[suffix]); suffix--); const TString& text = ita.sub(prefix, suffix+1); if (is_a_word(text)) { TDictionary_entry& entry = _dictionary.get_entry(text); entry.add_source(origin); int spaces = 0; for (int i = ita.len()-1; i > 0 && ita[i] == ' '; i--, spaces++); if (spaces > 0) entry.update_max_length(text.len() + spaces); } } void TDictionary_mask::read_txt_file(const char* fname, int filetype) { TScanner scan(fname); TString ita; while (scan.ok()) { TString& line = scan.line(); if (line.empty()) break; line.trim(); bool good = false; switch (filetype) { case 1: good = line.starts_with("IT") || line.starts_with("PA") || line.starts_with("PR") || line.starts_with("WA") || line.starts_with("DI"); break; case 2: good = line.starts_with("IT") || line.starts_with("PR"); break; case 3: good = line.starts_with("Caption ") || line.starts_with("Item_"); break; case 4: good = line.starts_with("Item_"); if (good) { TToken_string str(line); line.cut(0); line << "PR \"" << str.get(1) << '"'; } break; default: break; } if (good) { int apicia = 0, apicic = 0; if (filetype == 1 && line.starts_with("DI")) { const int at = line.find('@'); if (at > 0) line[at] = '"'; } if (filetype <= 2 && line.starts_with("IT")) { apicia = line.find('|'); if (apicia < 0) apicia = line.find('"'); const int at = line.find('@', apicia+1); const int ap = line.find('"', apicia+1); apicic = (at > 0 && at < ap) ? at : ap; } else { apicia = line.find('"'); apicic = line.find('"', apicia+1); } if (apicic > apicia) { ita = line.sub(apicia+1, apicic); if (filetype <= 2 && line.starts_with("PR")) { if (ita[0] == '@') ita.ltrim(2); if (ita[0] == '$') { const int closed = ita.find(']'); ita.ltrim(closed+1); } if (filetype == 1 || filetype == 4) ita.strip("~&"); } add_line(ita, fname); } } } } bool TDictionary_mask::read_txt_files(const char* msk) { TString_array arr; list_files(msk, arr); TString msg; msg << "Scansione files " << msk; TProgind pi(arr.items(), msg, true, true); TString strmsk(msk); strmsk.upper(); int filetype = 0; if (strmsk.find(".MSK") > 0) filetype = 1; else if (strmsk.find(".FRM") > 0) filetype = 2; else if (strmsk.find(".MEN") > 0) filetype = 3; if (strmsk.find(".INI") > 0) filetype = 4; bool finished = true; FOR_EACH_ARRAY_ROW(arr, i, row) { pi.addstatus(1); if (pi.iscancelled()) { finished = false; break; } TFilename n = *row; read_txt_file(n, filetype); n.custom_path(); if (n != *row) read_txt_file(n, filetype); } return finished; } bool TDictionary_mask::read_bin_file(const char* fname) { TProgind bi(fsize(fname), fname, true, true); const int match[4] = { 3, 2, 1, 0 }; int counter = 0; bool finished = true; TString ita(1024); ifstream scan(fname, ios::binary); while (!scan.eof()) { bi.addstatus(1); const int ch = scan.get(); if (ch == EOF) break; if (counter < 4) { if (ch == match[counter]) counter++; else counter = 0; } else { const int index = counter-4; if (index == 0) { ita.cut(0); if (bi.iscancelled()) { finished = false; break; } } ita << char(ch); if (ch == 0) { if (index > 0) add_line(ita, fname); counter = 0; } else counter++; } } return finished; } bool TDictionary_mask::read_bin_files(const char* msk) { TString_array arr; list_files(msk, arr); TString msg; msg << "Scansione programmi " << msk; TProgind pi(arr.items(), msg, false, true); FOR_EACH_ARRAY_ROW(arr, i, row) { pi.addstatus(1); if (!read_bin_file(*row)) break; } return true; } void TDictionary_mask::build_dictionary() { TMask m("ba2700a"); if (m.run() == K_ENTER) { const TString4 module = m.get(F_MODULE); TString16 mask = module; const bool delete_obs = m.get_bool(F_DELETE_OBS); if (delete_obs) _dictionary.zap_sources(module); mask << "*.msk"; bool go = read_txt_files(mask); if (go) { mask = module; mask << "*.frm"; go = read_txt_files(mask); } if (go) { mask = module; mask << "*.men"; go = read_txt_files(mask); } if (go) go = read_txt_files("res/resource.ini"); if (go) { if (module.full()) mask = module; else mask = "??"; mask << "?.exe"; go = read_bin_files(mask); } if (delete_obs) _dictionary.pack(); fill_index(); fill_chapter(); } } void TDictionary_mask::fill_index() { TToken_string letters = " "; char last_letter = ' '; TPointer_array& ref = _dictionary.sorted(); for (int i = 0; i < ref.items(); i++) { const TDictionary_entry& entry = (const TDictionary_entry&)ref[i]; const char letter = toupper(entry._ita[0]); if (letter != last_letter) { last_letter = letter; letters.add(letter); } } set(F_TOTAL, ref.items()); TList_field& alfabeto = (TList_field&)field(F_ALFABETO); alfabeto.replace_items(letters, letters); alfabeto.set("A"); } bool TDictionary_mask::check_translation(const TString & ita, const TString & eng, const char tag) { bool ok = true; int p_ita = ita.find(tag); int p_eng = eng.find(tag); while (ok && (p_ita >= 0) && (p_eng >= 0)) { ok = (p_ita >= 0) && (p_eng >= 0) && (ita[p_ita + 1] == eng[p_eng + 1]); if (ok) { p_ita = ita.find(tag, p_ita + 1); p_eng = eng.find(tag, p_eng + 1); } } ok &= ((p_ita < 0) && (p_eng <0)); #ifdef DBG if (!ok) int i = 0; #endif return ok; } bool TDictionary_mask::good_translation(const TString & ita, const TString & eng, const TString & src, int maxlen) { if (ita.find('#') >= 0 || eng.find('#') >= 0) return false; if (ita.find('&') >= 0 || eng.find('&') >= 0) return false; if (!check_translation(ita, eng, '@')) return false; if (src.find(".exe") > 0 && !check_translation(ita, eng, '%')) return false; if (maxlen > 0) if (eng.len() > maxlen) return false; return true; } void TDictionary_mask::fill_chapter() { const char letter = get(F_ALFABETO)[0]; const bool chk_modules = _modules.full(); TString_array modules; TToken_string str; FOR_EACH_TOKEN(_modules, m) { str = m; if (str.find('*') < 0) { str.insert("*"); str << '*'; } modules.add(str); } TSheet_field& s = sfield(F_CAPITOLO); s.destroy(); TPointer_array& ref = _dictionary.sorted(); for (int i = 0; i < ref.items(); i++) { const TDictionary_entry& e = (const TDictionary_entry&)ref[i]; if (toupper(e._ita[0]) == letter) { const bool good = good_translation(e._ita, e._eng, e._src, e._max_length); const bool translated = e._eng != "???"; const bool not_error = good || !translated; if (_filtered) { bool skip = false; if (_errors) skip |= !chk_modules && good && translated; else skip |= !good; if (_new) { if (_errors) skip |= !chk_modules && good && translated; else skip |= !chk_modules && translated; } else skip |= !translated; if (!skip && chk_modules) { if (not_error && _errors) continue; if (translated && _new) continue; FOR_EACH_ARRAY_ROW(modules, i, m) { skip = !e._src.match((const char *) *m); if (!skip) break; } } if (skip) continue; } TToken_string& row = s.row(-1); row = e._ita; row.add(e._eng); row.add(e._max_length); row.add(e._src); if (!good || !translated) s.set_back_and_fore_color(REQUIRED_BACK_COLOR, COLOR_RED, s.items() - 1); else s.set_back_and_fore_color(NORMAL_BACK_COLOR, NORMAL_COLOR, s.items() - 1); } } s.force_update(); set(F_ENTRIES, s.items()); enable(DLG_SAVEREC, ref.items() > 0); } bool TDictionary_mask::on_field_event(TOperable_field& o, TField_event e, long jolly) { switch (o.dlg()) { case F_FILENAME: if (e == fe_init) { o.set(get_dictionary_name()); read_dictionary(); } if (e == fe_modify) { const TFilename n = o.get(); if (n.exist()) { set_dictionary_name(n); o.set(get_dictionary_name()); read_dictionary(); } else return error_box("File assente"); } break; case F_ALFABETO: if (e == fe_modify) fill_chapter(); break; case DLG_SAVEREC: if (e == fe_button) { _dictionary.write(); send_key(K_SPACE, F_ALFABETO); } break; case DLG_FILTER: if (e == fe_button) { TMask m("ba2700b"); m.set(F_FILTER, _filtered); m.set(F_ERRORS_ONLY, _errors); m.set(F_NEW, _new); m.set(F_MODULE, _modules); if (m.run()) { _filtered = m.get_bool(F_FILTER); _errors = m.get_bool(F_ERRORS_ONLY); _new = m.get_bool(F_NEW); _modules = m.get(F_MODULE); } send_key(K_SPACE, F_ALFABETO); } break; case DLG_ELABORA: if (e == fe_button) build_dictionary(); break; case F_CAPITOLO: if (e == se_query_add) return false; if (e == se_notify_modify) { TSheet_field& s = (TSheet_field&)o; TToken_string& row = s.row(jolly); const TString ita = row.get(0); const TString eng = row.get(1); const int len = row.get_int(2); const TString src = row.get(3); _dictionary.set_translation(ita, eng); if (len > 0 && eng.len() > len) warning_box("La traduzione e' lunga %d caratteri (max. %d)!", eng.len(), len); if (!good_translation(ita, eng, src, len) || eng == "???") s.set_back_and_fore_color(REQUIRED_BACK_COLOR, COLOR_RED, jolly); else s.set_back_and_fore_color(NORMAL_BACK_COLOR, NORMAL_COLOR, jolly); s.force_update(jolly); } break; case DLG_USER: if (e == fe_button) { TMask & sms = o.mask(); if (sms.is_running()) sms.set(F_ENG, sms.get(F_ITA)); else { TSheet_field* s = (TSheet_field*)sms.get_sheet(); const int nrow = s->selected(); TToken_string& row = s->row(nrow); const TString ita = row.get(0); row.add(ita, 1); s->force_update(nrow); } } break; default: break; } return true; } TDictionary_mask::TDictionary_mask() : _filtered(false), _errors(false), _new(false), _modules("", ',') { // Allarga numero di riga degli spreadsheet TSheet_field::set_line_number_width(4); // Simula lettura ed inizilizzazione della Automak read_mask("ba2700", 0, MAX_PAGES); set_handlers(); } TDictionary_mask::~TDictionary_mask() { _dictionary.write_if_needed(); } class TDictionary_manager : public TSkeleton_application { public: virtual void main_loop(); }; void TDictionary_manager::main_loop() { TDictionary_mask dm; dm.run(); } int ba2700(int argc, char* argv[]) { TDictionary_manager a; a.run(argc, argv, TR("Creazione dizionario")); return 0; }